OpenGL and metal rendering interface upgrades

This commit is contained in:
Jack Andersen 2017-03-13 21:02:53 -10:00
parent 73891af56a
commit 05c26a535b
14 changed files with 592 additions and 285 deletions

View File

@ -31,7 +31,8 @@ public:
ComPtr<ID3DBlob>* vertBlobOut, ComPtr<ID3DBlob>* fragBlobOut,
ComPtr<ID3DBlob>* pipelineBlob, IVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)=0;
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)=0;
};
};

View File

@ -30,7 +30,7 @@ public:
TextureFormat fmt, const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
ITextureR* newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding);
size_t colorBindingCount, size_t depthBindingCount);
bool bindingNeedsVertexFormat() const {return true;}
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
@ -40,7 +40,8 @@ public:
size_t texCount, const char** texNames,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling);
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling);
IShaderDataBinding*
newShaderDataBinding(IShaderPipeline* pipeline,
@ -48,7 +49,9 @@ public:
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0);
size_t texCount, ITexture** texs,
const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0);
};
};

View File

@ -32,7 +32,8 @@ struct IGraphicsCommandQueue
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 resolveBindTexture(ITextureR* texture, const SWindowRect& rect, bool tlOrigin, bool color, bool depth)=0;
virtual void resolveBindTexture(ITextureR* texture, const SWindowRect& rect,
bool tlOrigin, int bindIdx, bool color, bool depth)=0;
virtual void resolveDisplay(ITextureR* source)=0;
virtual void execute()=0;

View File

@ -11,12 +11,22 @@ namespace boo
{
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(bool dynamic) : m_dynamic(dynamic) {}
IGraphicsBuffer(IGraphicsData* parent, bool dynamic)
: m_parentData(parent), m_dynamic(dynamic) {}
virtual ~IGraphicsBuffer() = default;
};
@ -24,7 +34,7 @@ protected:
struct IGraphicsBufferS : IGraphicsBuffer
{
protected:
IGraphicsBufferS() : IGraphicsBuffer(false) {}
IGraphicsBufferS(IGraphicsData* parent) : IGraphicsBuffer(parent, false) {}
};
/** Dynamic resource buffer for verts, indices, uniform constants */
@ -34,7 +44,7 @@ struct IGraphicsBufferD : IGraphicsBuffer
virtual void* map(size_t sz)=0;
virtual void unmap()=0;
protected:
IGraphicsBufferD() : IGraphicsBuffer(true) {}
IGraphicsBufferD(IGraphicsData* parent) : IGraphicsBuffer(parent, true) {}
};
/** Supported buffer uses */
@ -57,9 +67,11 @@ enum class TextureType
struct ITexture
{
TextureType type() const {return m_type;}
IGraphicsData* m_parentData;
protected:
TextureType m_type;
ITexture(TextureType type) : m_type(type) {}
ITexture(IGraphicsData* parent, TextureType type)
: m_parentData(parent), m_type(type) {}
virtual ~ITexture() {}
};
@ -67,14 +79,14 @@ protected:
struct ITextureS : ITexture
{
protected:
ITextureS() : ITexture(TextureType::Static) {}
ITextureS(IGraphicsData* parent) : ITexture(parent, TextureType::Static) {}
};
/** Static-array resource buffer for array textures */
struct ITextureSA : ITexture
{
protected:
ITextureSA() : ITexture(TextureType::StaticArray) {}
ITextureSA(IGraphicsData* parent) : ITexture(parent, TextureType::StaticArray) {}
};
/** Dynamic resource buffer for textures */
@ -84,14 +96,14 @@ struct ITextureD : ITexture
virtual void* map(size_t sz)=0;
virtual void unmap()=0;
protected:
ITextureD() : ITexture(TextureType::Dynamic) {}
ITextureD(IGraphicsData* parent) : ITexture(parent, TextureType::Dynamic) {}
};
/** Resource buffer for render-target textures */
struct ITextureR : ITexture
{
protected:
ITextureR() : ITexture(TextureType::Render) {}
ITextureR(IGraphicsData* parent) : ITexture(parent, TextureType::Render) {}
};
/** Supported texture formats */
@ -106,7 +118,12 @@ enum class TextureFormat
/** 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 {};
struct IVertexFormat
{
IGraphicsData* m_parentData;
protected:
IVertexFormat(IGraphicsData* parent) : m_parentData(parent) {}
};
/** Types of vertex attributes */
enum class VertexSemantic
@ -141,21 +158,18 @@ struct VertexElementDescriptor
/** Opaque token for referencing a complete graphics pipeline state necessary
* to rasterize geometry (shaders and blending modes mainly) */
struct IShaderPipeline {};
struct IShaderPipeline
{
IGraphicsData* m_parentData;
protected:
IShaderPipeline(IGraphicsData* parent) : m_parentData(parent) {}
};
/** Opaque token serving as indirection table for shader resources
* and IShaderPipeline reference. Each renderable surface-material holds one
* as a reference */
struct IShaderDataBinding {};
/** Opaque object for maintaining ownership of factory-created resources */
struct IGraphicsData {};
class GraphicsDataToken;
/** Opaque object for maintaining ownership of factory-created pool buffers */
struct IGraphicsBufferPool {};
class GraphicsBufferPoolToken;
/** Used wherever distinction of pipeline stages is needed */
enum class PipelineStage
{
@ -178,6 +192,15 @@ enum class CullMode
Frontface
};
/** Used by platform shader pipeline constructors */
enum class ZTest
{
None,
LEqual, /* Flipped on Vulkan, D3D, Metal */
Greater,
Equal
};
/** Used by platform shader pipeline constructors */
enum class BlendFactor
{
@ -234,7 +257,7 @@ struct IGraphicsDataFactory
newDynamicTexture(size_t width, size_t height, TextureFormat fmt)=0;
virtual ITextureR*
newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding)=0;
size_t colorBindingCount, size_t depthBindingCount)=0;
virtual bool bindingNeedsVertexFormat() const=0;
virtual IVertexFormat*
@ -247,28 +270,33 @@ struct IGraphicsDataFactory
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0)=0;
size_t texCount, ITexture** texs,
const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0)=0;
IShaderDataBinding*
newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0)
size_t texCount, ITexture** texs,
const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0)
{
return newShaderDataBinding(pipeline, vtxFormat, vbo, instVbo, ibo,
ubufCount, ubufs, ubufStages, nullptr,
nullptr, texCount, texs, baseVert, baseInst);
nullptr, texCount, texs, texBindIdx, depthBind,
baseVert, baseInst);
}
};
virtual GraphicsDataToken commitTransaction(const std::function<bool(Context& ctx)>&)=0;
virtual GraphicsBufferPoolToken newBufferPool()=0;
virtual void destroyAllData()=0;
private:
friend class GraphicsDataToken;
virtual void destroyData(IGraphicsData*)=0;
virtual void destroyAllData()=0;
friend class GraphicsBufferPoolToken;
virtual void destroyPool(IGraphicsBufferPool*)=0;

View File

@ -31,7 +31,7 @@ public:
TextureFormat fmt, const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
ITextureR* newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding);
size_t colorBindCount, size_t depthBindCount);
bool bindingNeedsVertexFormat() const {return false;}
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
@ -40,7 +40,8 @@ public:
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
IVertexFormat* vtxFmt, unsigned targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling);
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling);
IShaderDataBinding*
newShaderDataBinding(IShaderPipeline* pipeline,
@ -48,7 +49,9 @@ public:
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0);
size_t texCount, ITexture** texs,
const int* texBindIdxs, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0);
};
};

View File

@ -132,11 +132,12 @@ public:
std::vector<unsigned int>* vertBlobOut, std::vector<unsigned int>* fragBlobOut,
std::vector<unsigned char>* pipelineBlob, IVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling);
ZTest depthTest, bool depthWrite, CullMode culling);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, IVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
{
return newShaderPipeline(vertSource, fragSource, nullptr, nullptr, nullptr,
vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, culling);

View File

@ -5,12 +5,12 @@
* binding lifetimes through rendering cycle */
#include <atomic>
#include <vector>
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
namespace boo
{
template <class DataImpl>
class IGraphicsDataPriv : public IGraphicsData
{
std::atomic_int m_refCount = {1};
@ -19,35 +19,50 @@ public:
void decrement()
{
if (m_refCount.fetch_sub(1) == 1)
delete static_cast<DataImpl*>(this);
delete this;
}
};
template <class DataImpl>
class IShaderDataBindingPriv : public IShaderDataBinding
{
IGraphicsDataPriv<DataImpl>* m_parent;
IGraphicsDataPriv* m_parent;
std::vector<IGraphicsDataPriv*> m_depDatas;
public:
IShaderDataBindingPriv(IGraphicsDataPriv<DataImpl>* p) : m_parent(p) {}
IShaderDataBindingPriv(IGraphicsDataPriv* p) : m_parent(p) {}
class Token
{
IGraphicsDataPriv<DataImpl>* m_data = nullptr;
IGraphicsDataPriv* m_data = nullptr;
public:
Token() = default;
Token(const IShaderDataBindingPriv* p)
: m_data(p->m_parent)
{ m_data->increment(); }
: 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() { if (m_data) { m_data->decrement(); } }
};
Token lock() const { return Token(this); }
~IShaderDataBindingPriv()
{
for (IGraphicsDataPriv* dep : m_depDatas)
dep->decrement();
}
protected:
void addDepData(IGraphicsData* data)
{
IGraphicsDataPriv* d = static_cast<IGraphicsDataPriv*>(data);
if (d != m_parent)
{
m_depDatas.push_back(d);
d->increment();
}
}
};
template <class FactoryImpl, class ShaderImpl>

View File

@ -501,7 +501,7 @@ class D3D11ShaderPipeline : public IShaderPipeline
D3D11ShareableShader::Token&& pixel,
const D3D11VertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, CullMode culling)
: m_vtxFmt(vtxFmt), m_vert(std::move(vert)), m_pixel(std::move(pixel)),
m_topology(PRIMITIVE_TABLE[int(prim)])
{
@ -538,6 +538,8 @@ class D3D11ShaderPipeline : public IShaderPipeline
blDesc.RenderTarget[0].BlendEnable = (dstFac != BlendFactor::Zero);
blDesc.RenderTarget[0].SrcBlend = BLEND_FACTOR_TABLE[int(srcFac)];
blDesc.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(dstFac)];
blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
ThrowIfFailed(ctx->m_dev->CreateBlendState(&blDesc, &m_blState));
const auto& vertBuf = m_vert.get().m_vtxBlob;
@ -1008,7 +1010,7 @@ struct D3D11CommandQueue : IGraphicsCommandQueue
func();
}
float m_clearColor[4] = {0.0,0.0,0.0,1.0};
float m_clearColor[4] = {0.0,0.0,0.0,0.0};
void setClearColor(const float rgba[4])
{
m_clearColor[0] = rgba[0];
@ -1336,7 +1338,7 @@ public:
ComPtr<ID3DBlob>* vertBlobOut, ComPtr<ID3DBlob>* fragBlobOut,
ComPtr<ID3DBlob>* pipelineBlob, IVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, CullMode culling)
{
XXH64_state_t hashState;
uint64_t srcHashes[2] = {};

View File

@ -470,7 +470,6 @@ class D3D12TextureR : public ITextureR
D3D12_CLEAR_VALUE colorClear = {};
colorClear.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
colorClear.Color[3] = 1.f;
ThrowIfFailed(ctx->m_dev->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE,
&rtvresdesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &colorClear,
__uuidof(ID3D12Resource), &m_colorTex));
@ -654,7 +653,7 @@ class D3D12ShaderPipeline : public IShaderPipeline
D3D12ShareableShader::Token&& pixel, ID3DBlob* pipeline,
const D3D12VertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, CullMode culling)
: m_vtxFmt(vtxFmt), m_vert(std::move(vert)), m_pixel(std::move(pixel)),
m_topology(PRIMITIVE_TABLE[int(prim)])
{
@ -685,6 +684,8 @@ class D3D12ShaderPipeline : public IShaderPipeline
desc.BlendState.RenderTarget[0].BlendEnable = true;
desc.BlendState.RenderTarget[0].SrcBlend = BLEND_FACTOR_TABLE[int(srcFac)];
desc.BlendState.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(dstFac)];
desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
}
desc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
desc.RasterizerState.FrontCounterClockwise = TRUE;
@ -1260,7 +1261,7 @@ struct D3D12CommandQueue : IGraphicsCommandQueue
func();
}
float m_clearColor[4] = {0.0,0.0,0.0,1.0};
float m_clearColor[4] = {0.0,0.0,0.0,0.0};
void setClearColor(const float rgba[4])
{
m_clearColor[0] = rgba[0];
@ -1767,7 +1768,7 @@ public:
ComPtr<ID3DBlob>* vertBlobOut, ComPtr<ID3DBlob>* fragBlobOut,
ComPtr<ID3DBlob>* pipelineBlob, IVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, CullMode culling)
{
XXH64_state_t hashState;
uint64_t srcHashes[2] = {};

View File

@ -65,7 +65,7 @@ public:
};
ThreadLocalPtr<struct GLData> GLDataFactoryImpl::m_deferredData;
struct GLData : IGraphicsDataPriv<GLData>
struct GLData : IGraphicsDataPriv
{
std::vector<std::unique_ptr<class GLShaderPipeline>> m_SPs;
std::vector<std::unique_ptr<struct GLShaderDataBinding>> m_SBinds;
@ -78,9 +78,19 @@ struct GLData : IGraphicsDataPriv<GLData>
std::vector<std::unique_ptr<struct GLVertexFormat>> m_VFmts;
};
struct GLPoolItem : IGraphicsDataPriv
{
std::unique_ptr<class GLGraphicsBufferD> m_buf;
};
struct GLPool : IGraphicsBufferPool
{
std::unordered_map<class GLGraphicsBufferD*, std::unique_ptr<class GLGraphicsBufferD>> m_DBufs;
std::unordered_set<GLPoolItem*> m_items;
~GLPool()
{
for (auto& item : m_items)
item->decrement();
}
};
static const GLenum USE_TABLE[] =
@ -97,7 +107,8 @@ class GLGraphicsBufferS : public IGraphicsBufferS
friend struct GLCommandQueue;
GLuint m_buf;
GLenum m_target;
GLGraphicsBufferS(BufferUse use, const void* data, size_t sz)
GLGraphicsBufferS(IGraphicsData* parent, BufferUse use, const void* data, size_t sz)
: IGraphicsBufferS(parent)
{
m_target = USE_TABLE[int(use)];
glGenBuffers(1, &m_buf);
@ -127,8 +138,9 @@ class GLGraphicsBufferD : public IGraphicsBufferD
std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0;
int m_validMask = 0;
GLGraphicsBufferD(BufferUse use, size_t sz)
: m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz)
GLGraphicsBufferD(IGraphicsData* parent, BufferUse use, size_t sz)
: boo::IGraphicsBufferD(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)
@ -154,8 +166,9 @@ public:
IGraphicsBufferS*
GLDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)
{
GLGraphicsBufferS* retval = new GLGraphicsBufferS(use, data, stride * count);
GLDataFactoryImpl::m_deferredData->m_SBufs.emplace_back(retval);
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLGraphicsBufferS* retval = new GLGraphicsBufferS(d, use, data, stride * count);
d->m_SBufs.emplace_back(retval);
return retval;
}
@ -163,8 +176,9 @@ class GLTextureS : public ITextureS
{
friend class GLDataFactory;
GLuint m_tex;
GLTextureS(size_t width, size_t height, size_t mips,
GLTextureS(GLData* parent, size_t width, size_t height, size_t mips,
TextureFormat fmt, const void* data, size_t sz)
: ITextureS(parent)
{
const uint8_t* dataIt = static_cast<const uint8_t*>(data);
glGenTextures(1, &m_tex);
@ -241,8 +255,9 @@ class GLTextureSA : public ITextureSA
{
friend class GLDataFactory;
GLuint m_tex;
GLTextureSA(size_t width, size_t height, size_t layers, size_t mips,
GLTextureSA(GLData* parent, size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, const void* data, size_t sz)
: ITextureSA(parent)
{
const uint8_t* dataIt = static_cast<const uint8_t*>(data);
glGenTextures(1, &m_tex);
@ -302,7 +317,7 @@ class GLTextureD : public ITextureD
size_t m_width = 0;
size_t m_height = 0;
int m_validMask = 0;
GLTextureD(size_t width, size_t height, TextureFormat fmt);
GLTextureD(IGraphicsData* parent, size_t width, size_t height, TextureFormat fmt);
void update(int b);
public:
~GLTextureD();
@ -314,27 +329,29 @@ public:
void bind(size_t idx, int b);
};
#define MAX_BIND_TEXS 4
class GLTextureR : public ITextureR
{
friend class GLDataFactory;
friend struct GLCommandQueue;
struct GLCommandQueue* m_q;
GLuint m_texs[2] = {};
GLuint m_bindTexs[2] = {};
GLuint m_bindTexs[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_target;
GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t samples,
bool enableShaderColorBinding, bool enableShaderDepthBinding);
GLTextureR(IGraphicsData* parent, GLCommandQueue* q, size_t width, size_t height, size_t samples,
size_t colorBindCount, size_t depthBindCount);
public:
~GLTextureR();
void bind(size_t idx) const
void bind(size_t idx, int bindIdx, bool depth) const
{
glActiveTexture(GL_TEXTURE0 + idx);
glBindTexture(m_target, m_bindTexs[0]);
glBindTexture(m_target, m_bindTexs[depth][bindIdx]);
}
void resize(size_t width, size_t height)
@ -349,15 +366,22 @@ public:
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
if (m_bindTexs[0])
for (int i=0 ; i<MAX_BIND_TEXS ; ++i)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[0]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA, width, height, GL_FALSE);
if (m_bindTexs[0][i])
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[0][i]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA, width, height, GL_FALSE);
}
}
if (m_bindTexs[1])
for (int i=0 ; i<MAX_BIND_TEXS ; ++i)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[1]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
if (m_bindTexs[1][i])
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[1][i]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
}
}
}
else
@ -371,15 +395,22 @@ public:
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (m_bindTexs[0])
for (int i=0 ; i<MAX_BIND_TEXS ; ++i)
{
glBindTexture(GL_TEXTURE_2D, m_bindTexs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
if (m_bindTexs[0][i])
{
glBindTexture(GL_TEXTURE_2D, m_bindTexs[0][i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
}
if (m_bindTexs[1])
for (int i=0 ; i<MAX_BIND_TEXS ; ++i)
{
glBindTexture(GL_TEXTURE_2D, m_bindTexs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
if (m_bindTexs[1][i])
{
glBindTexture(GL_TEXTURE_2D, m_bindTexs[1][i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
}
}
}
}
@ -389,8 +420,9 @@ ITextureS*
GLDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz)
{
GLTextureS* retval = new GLTextureS(width, height, mips, fmt, data, sz);
GLDataFactoryImpl::m_deferredData->m_STexs.emplace_back(retval);
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLTextureS* retval = new GLTextureS(d, width, height, mips, fmt, data, sz);
d->m_STexs.emplace_back(retval);
return retval;
}
@ -398,8 +430,9 @@ ITextureSA*
GLDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, const void *data, size_t sz)
{
GLTextureSA* retval = new GLTextureSA(width, height, layers, mips, fmt, data, sz);
GLDataFactoryImpl::m_deferredData->m_SATexs.emplace_back(retval);
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLTextureSA* retval = new GLTextureSA(d, width, height, layers, mips, fmt, data, sz);
d->m_SATexs.emplace_back(retval);
return retval;
}
@ -414,11 +447,13 @@ class GLShaderPipeline : public IShaderPipeline
GLenum m_sfactor = GL_ONE;
GLenum m_dfactor = GL_ZERO;
GLenum m_drawPrim = GL_TRIANGLES;
bool m_depthTest = true;
ZTest m_depthTest = ZTest::LEqual;
bool m_depthWrite = true;
bool m_colorWrite = true;
bool m_alphaWrite = true;
CullMode m_culling;
std::vector<GLint> m_uniLocs;
GLShaderPipeline() = default;
GLShaderPipeline(GLData* parent) : IShaderPipeline(parent) {}
public:
operator bool() const {return m_prog != 0;}
~GLShaderPipeline() { if (m_prog) glDeleteProgram(m_prog); }
@ -435,11 +470,14 @@ public:
m_drawPrim = other.m_drawPrim;
m_depthTest = other.m_depthTest;
m_depthWrite = other.m_depthWrite;
m_colorWrite = other.m_colorWrite;
m_alphaWrite = other.m_alphaWrite;
m_culling = other.m_culling;
m_uniLocs = std::move(other.m_uniLocs);
return *this;
}
GLShaderPipeline(GLShaderPipeline&& other) { *this = std::move(other); }
GLShaderPipeline(GLShaderPipeline&& other)
: IShaderPipeline(other.m_parentData) { *this = std::move(other); }
GLuint bind() const
{
@ -448,17 +486,32 @@ public:
if (m_dfactor != GL_ZERO)
{
glEnable(GL_BLEND);
glBlendFunc(m_sfactor, m_dfactor);
glBlendFuncSeparate(m_sfactor, m_dfactor, GL_ONE, GL_ZERO);
}
else
glDisable(GL_BLEND);
if (m_depthTest)
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::Equal:
glDepthFunc(GL_EQUAL);
break;
}
}
else
glDisable(GL_DEPTH_TEST);
glDepthMask(m_depthWrite);
glDepthFunc(GL_LEQUAL);
glColorMask(m_colorWrite, m_colorWrite, m_colorWrite, m_alphaWrite);
if (m_culling != CullMode::None)
{
@ -499,10 +552,12 @@ IShaderPipeline* GLDataFactory::Context::newShaderPipeline
size_t texCount, const char** texNames,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
{
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLDataFactoryImpl& factory = static_cast<GLDataFactoryImpl&>(m_parent);
GLShaderPipeline shader;
GLShaderPipeline shader(d);
XXH64_state_t hashState;
uint64_t hashes[2];
@ -634,11 +689,13 @@ IShaderPipeline* GLDataFactory::Context::newShaderPipeline
shader.m_dfactor = BLEND_FACTOR_TABLE[int(dstFac)];
shader.m_depthTest = depthTest;
shader.m_depthWrite = depthWrite;
shader.m_colorWrite = colorWrite;
shader.m_alphaWrite = alphaWrite;
shader.m_culling = culling;
shader.m_drawPrim = PRIMITIVE_TABLE[int(prim)];
GLShaderPipeline* retval = new GLShaderPipeline(std::move(shader));
GLDataFactoryImpl::m_deferredData->m_SPs.emplace_back(retval);
d->m_SPs.emplace_back(retval);
return retval;
}
@ -649,14 +706,14 @@ struct GLVertexFormat : IVertexFormat
size_t m_elementCount;
GLuint m_baseVert, m_baseInst;
std::unique_ptr<VertexElementDescriptor[]> m_elements;
GLVertexFormat(GLCommandQueue* q, size_t elementCount,
GLVertexFormat(IGraphicsData* parent, GLCommandQueue* q, size_t elementCount,
const VertexElementDescriptor* elements,
size_t baseVert, size_t baseInst);
~GLVertexFormat();
void bind(int idx) const {glBindVertexArray(m_vao[idx]);}
};
struct GLShaderDataBinding : IShaderDataBindingPriv<GLData>
struct GLShaderDataBinding : IShaderDataBindingPriv
{
const GLShaderPipeline* m_pipeline;
const GLVertexFormat* m_vtxFormat;
@ -664,22 +721,32 @@ struct GLShaderDataBinding : IShaderDataBindingPriv<GLData>
std::unique_ptr<IGraphicsBuffer*[]> m_ubufs;
std::vector<std::pair<size_t,size_t>> m_ubufOffs;
size_t m_texCount;
std::unique_ptr<ITexture*[]> m_texs;
struct BoundTex
{
ITexture* tex;
int idx;
bool depth;
};
std::unique_ptr<BoundTex[]> m_texs;
GLShaderDataBinding(GLData* d,
IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
size_t ubufCount, IGraphicsBuffer** ubufs,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs)
size_t texCount, ITexture** texs,
const int* bindTexIdx,
const bool* depthBind)
: IShaderDataBindingPriv(d),
m_pipeline(static_cast<GLShaderPipeline*>(pipeline)),
m_vtxFormat(static_cast<GLVertexFormat*>(vtxFormat)),
m_ubufCount(ubufCount),
m_ubufs(new IGraphicsBuffer*[ubufCount]),
m_texCount(texCount),
m_texs(new ITexture*[texCount])
m_texs(new BoundTex[texCount])
{
addDepData(m_pipeline->m_parentData);
addDepData(m_vtxFormat->m_parentData);
if (ubufOffs && ubufSizes)
{
m_ubufOffs.reserve(ubufCount);
@ -699,9 +766,15 @@ struct GLShaderDataBinding : IShaderDataBindingPriv<GLData>
Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i));
#endif
m_ubufs[i] = ubufs[i];
if (ubufs[i])
addDepData(ubufs[i]->m_parentData);
}
for (size_t i=0 ; i<texCount ; ++i)
m_texs[i] = texs[i];
{
m_texs[i] = {texs[i], bindTexIdx ? bindTexIdx[i] : 0, depthBind ? depthBind[i] : false};
if (texs[i])
addDepData(texs[i]->m_parentData);
}
}
void bind(int b) const
{
@ -740,22 +813,22 @@ struct GLShaderDataBinding : IShaderDataBindingPriv<GLData>
}
for (size_t i=0 ; i<m_texCount ; ++i)
{
ITexture* tex = m_texs[i];
if (tex)
BoundTex& tex = m_texs[i];
if (tex.tex)
{
switch (tex->type())
switch (tex.tex->type())
{
case TextureType::Dynamic:
static_cast<GLTextureD*>(tex)->bind(i, b);
static_cast<GLTextureD*>(tex.tex)->bind(i, b);
break;
case TextureType::Static:
static_cast<GLTextureS*>(tex)->bind(i);
static_cast<GLTextureS*>(tex.tex)->bind(i);
break;
case TextureType::StaticArray:
static_cast<GLTextureSA*>(tex)->bind(i);
static_cast<GLTextureSA*>(tex.tex)->bind(i);
break;
case TextureType::Render:
static_cast<GLTextureR*>(tex)->bind(i);
static_cast<GLTextureR*>(tex.tex)->bind(i, tex.idx, tex.depth);
break;
default: break;
}
@ -770,11 +843,13 @@ GLDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline,
IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst)
size_t texCount, ITexture** texs,
const int* texBindIdx, const bool* depthBind,
size_t baseVert, size_t baseInst)
{
GLShaderDataBinding* retval =
new GLShaderDataBinding(GLDataFactoryImpl::m_deferredData.get(), pipeline, vtxFormat, ubufCount, ubufs,
ubufOffs, ubufSizes, texCount, texs);
ubufOffs, ubufSizes, texCount, texs, texBindIdx, depthBind);
GLDataFactoryImpl::m_deferredData->m_SBinds.emplace_back(retval);
return retval;
}
@ -806,7 +881,7 @@ GraphicsDataToken GLDataFactoryImpl::commitTransaction(const FactoryCommitFunc&
/* 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();
//glFlush();
return GraphicsDataToken(this, retval);
}
@ -831,8 +906,8 @@ void GLDataFactoryImpl::destroyAllData()
std::unique_lock<std::mutex> lk(m_committedMutex);
for (GLData* data : m_committedData)
data->decrement();
for (IGraphicsBufferPool* pool : m_committedPools)
delete static_cast<GLPool*>(pool);
for (GLPool* pool : m_committedPools)
delete pool;
m_committedData.clear();
m_committedPools.clear();
}
@ -849,15 +924,22 @@ IGraphicsBufferD* GLDataFactoryImpl::newPoolBuffer(IGraphicsBufferPool* p, Buffe
size_t stride, size_t count)
{
GLPool* pool = static_cast<GLPool*>(p);
GLGraphicsBufferD* retval = new GLGraphicsBufferD(use, stride * count);
pool->m_DBufs.emplace(std::make_pair(retval, std::unique_ptr<GLGraphicsBufferD>(retval)));
GLPoolItem* item = new GLPoolItem;
GLGraphicsBufferD* retval = new GLGraphicsBufferD(item, use, stride * count);
item->m_buf.reset(retval);
pool->m_items.emplace(item);
return retval;
}
void GLDataFactoryImpl::deletePoolBuffer(IGraphicsBufferPool *p, IGraphicsBufferD *buf)
void GLDataFactoryImpl::deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf)
{
GLPool* pool = static_cast<GLPool*>(p);
pool->m_DBufs.erase(static_cast<GLGraphicsBufferD*>(buf));
auto search = pool->m_items.find(static_cast<GLPoolItem*>(buf->m_parentData));
if (search != pool->m_items.end())
{
(*search)->decrement();
pool->m_items.erase(search);
}
}
static const GLint SEMANTIC_COUNT_TABLE[] =
@ -911,6 +993,13 @@ struct GLCommandQueue : IGraphicsCommandQueue
const SystemChar* platformName() const {return _S("OpenGL");}
IGraphicsContext* m_parent = nullptr;
std::mutex m_mt;
std::condition_variable m_cv;
std::mutex m_initmt;
std::condition_variable m_initcv;
std::unique_lock<std::mutex> m_initlk;
std::thread m_thr;
struct Command
{
enum class Op
@ -947,8 +1036,9 @@ struct GLCommandQueue : IGraphicsCommandQueue
size_t instCount;
};
};
IShaderDataBindingPriv<GLData>::Token resToken;
IShaderDataBindingPriv::Token resToken;
const ITextureR* resolveTex;
int bindIdx;
bool resolveColor : 1;
bool resolveDepth : 1;
Command(Op op) : m_op(op) {}
@ -963,13 +1053,6 @@ struct GLCommandQueue : IGraphicsCommandQueue
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<std::mutex> m_initlk;
std::thread m_thr;
struct RenderTextureResize
{
GLTextureR* tex;
@ -1064,6 +1147,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
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);
}
self->m_initcv.notify_one();
while (self->m_running)
@ -1157,6 +1241,8 @@ struct GLCommandQueue : IGraphicsCommandQueue
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);
@ -1181,16 +1267,16 @@ struct GLCommandQueue : IGraphicsCommandQueue
GLenum target = (tex->m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo);
glActiveTexture(GL_TEXTURE9);
if (cmd.resolveColor && tex->m_bindTexs[0])
if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx])
{
glBindTexture(target, tex->m_bindTexs[0]);
glBindTexture(target, tex->m_bindTexs[0][cmd.bindIdx]);
glCopyTexSubImage2D(target, 0, cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.size[0], cmd.viewport.rect.size[1]);
}
if (cmd.resolveDepth && tex->m_bindTexs[1])
if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx])
{
glBindTexture(target, tex->m_bindTexs[1]);
glBindTexture(target, tex->m_bindTexs[1][cmd.bindIdx]);
glCopyTexSubImage2D(target, 0, cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.size[0], cmd.viewport.rect.size[1]);
@ -1230,14 +1316,20 @@ struct GLCommandQueue : IGraphicsCommandQueue
void stopRenderer()
{
m_running = false;
m_cv.notify_one();
m_thr.join();
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()
{
if (m_running) stopRenderer();
stopRenderer();
}
void setShaderDataBinding(IShaderDataBinding* binding)
@ -1245,7 +1337,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
std::vector<Command>& cmds = m_cmdBufs[m_fillBuf];
cmds.emplace_back(Command::Op::SetShaderDataBinding);
cmds.back().binding = binding;
cmds.back().resToken = static_cast<IShaderDataBindingPriv<GLData>*>(binding)->lock();
cmds.back().resToken = static_cast<IShaderDataBindingPriv*>(binding)->lock();
}
void setRenderTarget(ITextureR* target)
@ -1338,12 +1430,14 @@ struct GLCommandQueue : IGraphicsCommandQueue
cmds.back().instCount = instCount;
}
void resolveBindTexture(ITextureR* texture, const SWindowRect& rect, bool tlOrigin, bool color, bool depth)
void resolveBindTexture(ITextureR* texture, const SWindowRect& rect, bool tlOrigin,
int bindIdx, bool color, bool depth)
{
GLTextureR* tex = static_cast<GLTextureR*>(texture);
std::vector<Command>& 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;
SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height));
@ -1421,11 +1515,11 @@ struct GLCommandQueue : IGraphicsCommandQueue
}
for (GLPool* p : gfxF->m_committedPools)
{
for (auto& b : p->m_DBufs)
b.second->update(m_completeBuf);
for (auto& b : p->m_items)
b->m_buf->update(m_completeBuf);
}
datalk.unlock();
glFlush();
//glFlush();
for (auto& p : m_pendingPosts1)
m_pendingPosts2.push_back(std::move(p));
@ -1476,13 +1570,14 @@ void GLGraphicsBufferD::bindUniformRange(size_t idx, GLintptr off, GLsizeiptr si
IGraphicsBufferD*
GLDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{
GLGraphicsBufferD* retval = new GLGraphicsBufferD(use, stride * count);
GLDataFactoryImpl::m_deferredData->m_DBufs.emplace_back(retval);
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLGraphicsBufferD* retval = new GLGraphicsBufferD(d, use, stride * count);
d->m_DBufs.emplace_back(retval);
return retval;
}
GLTextureD::GLTextureD(size_t width, size_t height, TextureFormat fmt)
: m_width(width), m_height(height)
GLTextureD::GLTextureD(IGraphicsData* parent, size_t width, size_t height, TextureFormat fmt)
: boo::ITextureD(parent), m_width(width), m_height(height)
{
int pxPitch = 4;
switch (fmt)
@ -1551,20 +1646,29 @@ void GLTextureD::bind(size_t idx, int b)
ITextureD*
GLDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
{
GLTextureD* retval = new GLTextureD(width, height, fmt);
GLDataFactoryImpl::m_deferredData->m_DTexs.emplace_back(retval);
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLTextureD* retval = new GLTextureD(d, width, height, fmt);
d->m_DTexs.emplace_back(retval);
return retval;
}
GLTextureR::GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t samples,
bool enableShaderColorBinding, bool enableShaderDepthBinding)
: m_q(q), m_width(width), m_height(height), m_samples(samples)
GLTextureR::GLTextureR(IGraphicsData* parent, GLCommandQueue* q, size_t width, size_t height, size_t samples,
size_t colorBindingCount, size_t depthBindingCount)
: boo::ITextureR(parent), m_q(q), m_width(width), m_height(height), m_samples(samples)
{
glGenTextures(2, m_texs);
if (enableShaderColorBinding)
glGenTextures(1, &m_bindTexs[0]);
if (enableShaderDepthBinding)
glGenTextures(1, &m_bindTexs[1]);
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]);
}
if (samples > 1)
{
m_target = GL_TEXTURE_2D_MULTISAMPLE;
@ -1573,14 +1677,15 @@ GLTextureR::GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t sa
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
if (enableShaderColorBinding)
for (int i=0 ; i<colorBindingCount ; ++i)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[0]);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[0][i]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, width, height, GL_FALSE);
}
if (enableShaderDepthBinding)
for (int i=0 ; i<depthBindingCount ; ++i)
{
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[1]);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_bindTexs[1][i]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT24, width, height, GL_FALSE);
}
}
@ -1592,16 +1697,16 @@ GLTextureR::GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t sa
glBindTexture(GL_TEXTURE_2D, m_texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
if (enableShaderColorBinding)
for (int i=0 ; i<colorBindingCount ; ++i)
{
glBindTexture(GL_TEXTURE_2D, m_bindTexs[0]);
glBindTexture(GL_TEXTURE_2D, m_bindTexs[0][i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
if (enableShaderDepthBinding)
for (int i=0 ; i<depthBindingCount ; ++i)
{
glBindTexture(GL_TEXTURE_2D, m_bindTexs[1]);
glBindTexture(GL_TEXTURE_2D, m_bindTexs[1][i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -1612,27 +1717,29 @@ GLTextureR::GLTextureR(GLCommandQueue* q, size_t width, size_t height, size_t sa
GLTextureR::~GLTextureR()
{
glDeleteTextures(2, m_texs);
glDeleteTextures(2, m_bindTexs);
glDeleteTextures(MAX_BIND_TEXS * 2, m_bindTexs[0]);
m_q->delFBO(this);
}
ITextureR*
GLDataFactory::Context::newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding)
size_t colorBindingCount, size_t depthBindingCount)
{
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLDataFactoryImpl& factory = static_cast<GLDataFactoryImpl&>(m_parent);
GLCommandQueue* q = static_cast<GLCommandQueue*>(factory.m_parent->getCommandQueue());
GLTextureR* retval = new GLTextureR(q, width, height, factory.m_drawSamples,
enableShaderColorBinding, enableShaderDepthBinding);
GLTextureR* retval = new GLTextureR(d, q, width, height, factory.m_drawSamples,
colorBindingCount, depthBindingCount);
q->resizeRenderTexture(retval, width, height);
GLDataFactoryImpl::m_deferredData->m_RTexs.emplace_back(retval);
return retval;
}
GLVertexFormat::GLVertexFormat(GLCommandQueue* q, size_t elementCount,
GLVertexFormat::GLVertexFormat(IGraphicsData* parent, GLCommandQueue* q, size_t elementCount,
const VertexElementDescriptor* elements,
size_t baseVert, size_t baseInst)
: m_q(q),
: boo::IVertexFormat(parent),
m_q(q),
m_elementCount(elementCount),
m_elements(new VertexElementDescriptor[elementCount]),
m_baseVert(baseVert), m_baseInst(baseInst)
@ -1647,10 +1754,11 @@ IVertexFormat* GLDataFactory::Context::newVertexFormat
(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert, size_t baseInst)
{
GLData* d = GLDataFactoryImpl::m_deferredData.get();
GLDataFactoryImpl& factory = static_cast<GLDataFactoryImpl&>(m_parent);
GLCommandQueue* q = static_cast<GLCommandQueue*>(factory.m_parent->getCommandQueue());
GLVertexFormat* retval = new struct GLVertexFormat(q, elementCount, elements, baseVert, baseInst);
GLDataFactoryImpl::m_deferredData->m_VFmts.emplace_back(retval);
GLVertexFormat* retval = new struct GLVertexFormat(d, q, elementCount, elements, baseVert, baseInst);
d->m_VFmts.emplace_back(retval);
return retval;
}

View File

@ -62,7 +62,7 @@ public:
};
ThreadLocalPtr<struct MetalData> MetalDataFactoryImpl::m_deferredData;
struct MetalData : IGraphicsDataPriv<MetalData>
struct MetalData : IGraphicsDataPriv
{
std::vector<std::unique_ptr<class MetalShaderPipeline>> m_SPs;
std::vector<std::unique_ptr<struct MetalShaderDataBinding>> m_SBinds;
@ -75,9 +75,19 @@ struct MetalData : IGraphicsDataPriv<MetalData>
std::vector<std::unique_ptr<struct MetalVertexFormat>> m_VFmts;
};
struct MetalPoolItem : IGraphicsDataPriv
{
std::unique_ptr<class MetalGraphicsBufferD> m_buf;
};
struct MetalPool : IGraphicsBufferPool
{
std::unordered_map<class MetalGraphicsBufferD*, std::unique_ptr<class MetalGraphicsBufferD>> m_DBufs;
std::unordered_set<MetalPoolItem*> m_items;
~MetalPool()
{
for (auto& item : m_items)
item->decrement();
}
};
#define MTL_STATIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared
@ -87,8 +97,9 @@ class MetalGraphicsBufferS : public IGraphicsBufferS
{
friend class MetalDataFactory;
friend struct MetalCommandQueue;
MetalGraphicsBufferS(BufferUse use, MetalContext* ctx, const void* data, size_t stride, size_t count)
: m_stride(stride), m_count(count), m_sz(stride * count)
MetalGraphicsBufferS(IGraphicsData* parent, BufferUse use, MetalContext* ctx,
const void* data, size_t stride, size_t count)
: boo::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];
}
@ -108,8 +119,9 @@ class MetalGraphicsBufferD : public IGraphicsBufferD
MetalCommandQueue* m_q;
std::unique_ptr<uint8_t[]> m_cpuBuf;
int m_validSlots = 0;
MetalGraphicsBufferD(MetalCommandQueue* q, BufferUse use, MetalContext* ctx, size_t stride, size_t count)
: m_q(q), m_stride(stride), m_count(count), m_sz(stride * count)
MetalGraphicsBufferD(IGraphicsData* parent, MetalCommandQueue* q, BufferUse use,
MetalContext* ctx, size_t stride, size_t count)
: boo::IGraphicsBufferD(parent), m_q(q), m_stride(stride), m_count(count), m_sz(stride * count)
{
m_cpuBuf.reset(new uint8_t[m_sz]);
m_bufs[0] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
@ -131,8 +143,9 @@ public:
class MetalTextureS : public ITextureS
{
friend class MetalDataFactory;
MetalTextureS(MetalContext* ctx, size_t width, size_t height, size_t mips,
MetalTextureS(IGraphicsData* parent, MetalContext* ctx, size_t width, size_t height, size_t mips,
TextureFormat fmt, const void* data, size_t sz)
: ITextureS(parent)
{
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
NSUInteger ppitchNum = 4;
@ -182,8 +195,10 @@ public:
class MetalTextureSA : public ITextureSA
{
friend class MetalDataFactory;
MetalTextureSA(MetalContext* ctx, size_t width, size_t height, size_t layers, size_t mips,
MetalTextureSA(IGraphicsData* parent, MetalContext* ctx, size_t width,
size_t height, size_t layers, size_t mips,
TextureFormat fmt, const void* data, size_t sz)
: ITextureSA(parent)
{
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
NSUInteger ppitch = 4;
@ -243,8 +258,9 @@ class MetalTextureD : public ITextureD
size_t m_cpuSz;
size_t m_pxPitch;
int m_validSlots = 0;
MetalTextureD(MetalCommandQueue* q, MetalContext* ctx, size_t width, size_t height, TextureFormat fmt)
: m_q(q), m_width(width), m_height(height)
MetalTextureD(IGraphicsData* parent, MetalCommandQueue* q, MetalContext* ctx,
size_t width, size_t height, TextureFormat fmt)
: boo::ITextureD(parent), m_q(q), m_width(width), m_height(height)
{
MTLPixelFormat format;
switch (fmt)
@ -285,6 +301,8 @@ public:
void unmap();
};
#define MAX_BIND_TEXS 4
class MetalTextureR : public ITextureR
{
friend class MetalDataFactory;
@ -292,14 +310,20 @@ class MetalTextureR : public ITextureR
size_t m_width = 0;
size_t m_height = 0;
size_t m_samples = 0;
bool m_enableShaderBindTexture;
size_t m_colorBindCount;
size_t m_depthBindCount;
void Setup(MetalContext* ctx, size_t width, size_t height, size_t samples,
bool enableShaderBindTexture)
size_t colorBindCount, size_t depthBindCount)
{
m_width = width;
m_height = height;
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");
@autoreleasepool
{
MTLTextureDescriptor* desc =
@ -315,15 +339,23 @@ class MetalTextureR : public ITextureR
desc.usage = MTLTextureUsageRenderTarget;
m_colorTex = [ctx->m_dev newTextureWithDescriptor:desc];
if (enableShaderBindTexture)
if (colorBindCount)
{
desc.usage = MTLTextureUsageShaderRead;
m_colorBindTex = [ctx->m_dev newTextureWithDescriptor:desc];
for (int i=0 ; i<colorBindCount ; ++i)
m_colorBindTex[i] = [ctx->m_dev newTextureWithDescriptor:desc];
}
desc.usage = MTLTextureUsageRenderTarget;
desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
if (depthBindCount)
{
desc.usage = MTLTextureUsageShaderRead;
for (int i=0 ; i<depthBindCount ; ++i)
m_depthBindTex[i] = [ctx->m_dev newTextureWithDescriptor:desc];
}
}
else
{
@ -332,15 +364,23 @@ class MetalTextureR : public ITextureR
desc.usage = MTLTextureUsageRenderTarget;
m_colorTex = [ctx->m_dev newTextureWithDescriptor:desc];
if (enableShaderBindTexture)
if (colorBindCount)
{
desc.usage = MTLTextureUsageShaderRead;
m_colorBindTex = [ctx->m_dev newTextureWithDescriptor:desc];
for (int i=0 ; i<colorBindCount ; ++i)
m_colorBindTex[i] = [ctx->m_dev newTextureWithDescriptor:desc];
}
desc.usage = MTLTextureUsageRenderTarget;
desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
if (depthBindCount)
{
desc.usage = MTLTextureUsageShaderRead;
for (int i=0 ; i<depthBindCount ; ++i)
m_depthBindTex[i] = [ctx->m_dev newTextureWithDescriptor:desc];
}
}
{
@ -375,6 +415,7 @@ class MetalTextureR : public ITextureR
m_clearColorPassDesc.colorAttachments[0].texture = m_colorTex;
m_clearColorPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_clearColorPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_clearDepthPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
m_clearColorPassDesc.depthAttachment.texture = m_depthTex;
m_clearColorPassDesc.depthAttachment.loadAction = MTLLoadActionLoad;
@ -388,6 +429,7 @@ class MetalTextureR : public ITextureR
m_clearBothPassDesc.colorAttachments[0].texture = m_colorTex;
m_clearBothPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_clearBothPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_clearBothPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
m_clearBothPassDesc.depthAttachment.texture = m_depthTex;
m_clearBothPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
@ -397,18 +439,21 @@ class MetalTextureR : public ITextureR
}
}
MetalTextureR(MetalContext* ctx, size_t width, size_t height, size_t samples,
bool enableShaderBindTexture)
: m_width(width), m_height(height), m_samples(samples), m_enableShaderBindTexture(enableShaderBindTexture)
MetalTextureR(IGraphicsData* parent, MetalContext* ctx, size_t width, size_t height, size_t samples,
size_t colorBindCount, size_t depthBindCount)
: boo::ITextureR(parent), m_width(width), m_height(height), m_samples(samples),
m_colorBindCount(colorBindCount),
m_depthBindCount(depthBindCount)
{
if (samples == 0) m_samples = 1;
Setup(ctx, width, height, samples, enableShaderBindTexture);
Setup(ctx, width, height, samples, colorBindCount, depthBindCount);
}
public:
size_t samples() const {return m_samples;}
id<MTLTexture> m_colorTex;
id<MTLTexture> m_depthTex;
id<MTLTexture> m_colorBindTex;
id<MTLTexture> m_colorBindTex[MAX_BIND_TEXS] = {};
id<MTLTexture> m_depthBindTex[MAX_BIND_TEXS] = {};
MTLRenderPassDescriptor* m_passDesc;
MTLRenderPassDescriptor* m_clearDepthPassDesc;
MTLRenderPassDescriptor* m_clearColorPassDesc;
@ -423,7 +468,7 @@ public:
height = 1;
m_width = width;
m_height = height;
Setup(ctx, width, height, m_samples, m_enableShaderBindTexture);
Setup(ctx, width, height, m_samples, m_colorBindCount, m_depthBindCount);
}
};
@ -463,8 +508,8 @@ struct MetalVertexFormat : IVertexFormat
MTLVertexDescriptor* m_vdesc;
size_t m_stride = 0;
size_t m_instStride = 0;
MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
: m_elementCount(elementCount)
MetalVertexFormat(IGraphicsData* parent, size_t elementCount, const VertexElementDescriptor* elements)
: boo::IVertexFormat(parent), m_elementCount(elementCount)
{
for (size_t i=0 ; i<elementCount ; ++i)
{
@ -538,10 +583,12 @@ static const MTLPrimitiveType PRIMITIVE_TABLE[] =
MTLPrimitiveTypeTriangleStrip
};
#define COLOR_WRITE_MASK (MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue)
class MetalShaderPipeline : public IShaderPipeline
{
friend class MetalDataFactory;
friend class MetalCommandQueue;
friend struct MetalCommandQueue;
friend struct MetalShaderDataBinding;
MTLCullMode m_cullMode = MTLCullModeNone;
MTLPrimitiveType m_drawPrim;
@ -549,13 +596,16 @@ class MetalShaderPipeline : public IShaderPipeline
MetalShareableShader::Token m_vert;
MetalShareableShader::Token m_frag;
MetalShaderPipeline(MetalContext* ctx,
MetalShaderPipeline(IGraphicsData* parent,
MetalContext* ctx,
MetalShareableShader::Token&& vert,
MetalShareableShader::Token&& frag,
const MetalVertexFormat* vtxFmt, NSUInteger targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
: m_drawPrim(PRIMITIVE_TABLE[int(prim)]), m_vtxFmt(vtxFmt),
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
: boo::IShaderPipeline(parent),
m_drawPrim(PRIMITIVE_TABLE[int(prim)]), m_vtxFmt(vtxFmt),
m_vert(std::move(vert)), m_frag(std::move(frag))
{
switch (culling)
@ -578,9 +628,13 @@ class MetalShaderPipeline : public IShaderPipeline
desc.vertexDescriptor = vtxFmt->m_vdesc;
desc.sampleCount = targetSamples;
desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
desc.colorAttachments[0].writeMask = (colorWrite ? COLOR_WRITE_MASK : 0) |
(alphaWrite ? MTLColorWriteMaskAlpha : 0);
desc.colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero;
desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)];
desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)];
desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero;
desc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float;
desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
NSError* err = nullptr;
@ -590,8 +644,23 @@ class MetalShaderPipeline : public IShaderPipeline
[[err localizedDescription] UTF8String]);
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new];
if (depthTest)
switch (depthTest)
{
case ZTest::None:
default:
dsDesc.depthCompareFunction = MTLCompareFunctionAlways;
break;
case ZTest::LEqual:
dsDesc.depthCompareFunction = MTLCompareFunctionGreaterEqual;
break;
case ZTest::Greater:
dsDesc.depthCompareFunction = MTLCompareFunctionLess;
break;
case ZTest::Equal:
dsDesc.depthCompareFunction = MTLCompareFunctionEqual;
break;
}
dsDesc.depthWriteEnabled = depthWrite;
m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc];
}
@ -624,7 +693,23 @@ static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx)
}
}
static id<MTLTexture> GetTextureGPUResource(const ITexture* tex, int idx)
static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx, size_t& strideOut)
{
if (buf->dynamic())
{
const MetalGraphicsBufferD* cbuf = static_cast<const MetalGraphicsBufferD*>(buf);
strideOut = cbuf->m_stride;
return cbuf->m_bufs[idx];
}
else
{
const MetalGraphicsBufferS* cbuf = static_cast<const MetalGraphicsBufferS*>(buf);
strideOut = cbuf->m_stride;
return cbuf->m_buf;
}
}
static id<MTLTexture> GetTextureGPUResource(const ITexture* tex, int idx, int bindIdx, bool depth)
{
switch (tex->type())
{
@ -646,14 +731,14 @@ static id<MTLTexture> GetTextureGPUResource(const ITexture* tex, int idx)
case TextureType::Render:
{
const MetalTextureR* ctex = static_cast<const MetalTextureR*>(tex);
return ctex->m_colorBindTex;
return depth ? ctex->m_depthBindTex[bindIdx] : ctex->m_colorBindTex[bindIdx];
}
default: break;
}
return nullptr;
}
struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
struct MetalShaderDataBinding : IShaderDataBindingPriv
{
MetalShaderPipeline* m_pipeline;
IGraphicsBuffer* m_vbuf;
@ -664,7 +749,13 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
std::unique_ptr<size_t[]> m_ubufOffs;
std::unique_ptr<bool[]> m_fubufs;
size_t m_texCount;
std::unique_ptr<ITexture*[]> m_texs;
struct BoundTex
{
ITexture* tex;
int idx;
bool depth;
};
std::unique_ptr<BoundTex[]> m_texs;
size_t m_baseVert;
size_t m_baseInst;
@ -674,7 +765,9 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst)
size_t texCount, ITexture** texs,
const int* texBindIdxs, const bool* depthBind,
size_t baseVert, size_t baseInst)
: IShaderDataBindingPriv(d),
m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)),
m_vbuf(vbuf),
@ -683,10 +776,12 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
m_ubufCount(ubufCount),
m_ubufs(new IGraphicsBuffer*[ubufCount]),
m_texCount(texCount),
m_texs(new ITexture*[texCount]),
m_texs(new BoundTex[texCount]),
m_baseVert(baseVert),
m_baseInst(baseInst)
{
addDepData(m_pipeline->m_parentData);
if (ubufCount && ubufStages)
{
m_fubufs.reset(new bool[ubufCount]);
@ -713,10 +808,14 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i));
#endif
m_ubufs[i] = ubufs[i];
if (ubufs[i])
addDepData(ubufs[i]->m_parentData);
}
for (size_t i=0 ; i<texCount ; ++i)
{
m_texs[i] = texs[i];
m_texs[i] = {texs[i], texBindIdxs ? texBindIdxs[i] : 0, depthBind ? depthBind[i] : false};
if (texs[i])
addDepData(texs[i]->m_parentData);
}
}
@ -724,12 +823,17 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
{
m_pipeline->bind(enc);
size_t stride;
if (m_vbuf)
[enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b)
offset:m_pipeline->m_vtxFmt->m_stride * m_baseVert atIndex:0];
{
id<MTLBuffer> buf = GetBufferGPUResource(m_vbuf, b, stride);
[enc setVertexBuffer:buf offset:stride * m_baseVert atIndex:0];
}
if (m_instVbo)
[enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b)
offset:m_pipeline->m_vtxFmt->m_instStride * m_baseInst atIndex:1];
{
id<MTLBuffer> buf = GetBufferGPUResource(m_instVbo, b, stride);
[enc setVertexBuffer:buf offset:stride * m_baseInst atIndex:1];
}
if (m_ubufOffs)
for (size_t i=0 ; i<m_ubufCount ; ++i)
{
@ -747,8 +851,8 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv<MetalData>
[enc setVertexBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:0 atIndex:i+2];
}
for (size_t i=0 ; i<m_texCount ; ++i)
if (m_texs[i])
[enc setFragmentTexture:GetTextureGPUResource(m_texs[i], b) atIndex:i];
if (m_texs[i].tex)
[enc setFragmentTexture:GetTextureGPUResource(m_texs[i].tex, b, m_texs[i].idx, m_texs[i].depth) atIndex:i];
}
};
@ -801,9 +905,9 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void _setRenderTarget(ITextureR* target, bool clearColor, bool clearDepth)
{
MetalTextureR* ctarget = static_cast<MetalTextureR*>(target);
[m_enc endEncoding];
@autoreleasepool
{
[m_enc endEncoding];
if (clearColor && clearDepth)
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_clearBothPassDesc];
else if (clearColor)
@ -865,7 +969,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void flushBufferUpdates() {}
float m_clearColor[4] = {0.0,0.0,0.0,1.0};
float m_clearColor[4] = {0.0,0.0,0.0,0.0};
void setClearColor(const float rgba[4])
{
m_clearColor[0] = rgba[0];
@ -911,36 +1015,53 @@ struct MetalCommandQueue : IGraphicsCommandQueue
instanceCount:instCount];
}
void resolveBindTexture(ITextureR* texture, const SWindowRect& rect, bool tlOrigin, bool color, bool depth)
void resolveBindTexture(ITextureR* texture, const SWindowRect& rect, bool tlOrigin,
int bindIdx, bool color, bool depth)
{
MetalTextureR* tex = static_cast<MetalTextureR*>(texture);
if (color && tex->m_enableShaderBindTexture)
@autoreleasepool
{
[m_enc endEncoding];
@autoreleasepool
SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height));
NSUInteger y = tlOrigin ? intersectRect.location[1] : int(tex->m_height) -
intersectRect.location[1] - intersectRect.size[1];
MTLOrigin origin = {NSUInteger(intersectRect.location[0]), y, 0};
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
if (color && tex->m_colorBindTex[bindIdx])
{
SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height));
NSUInteger y = tlOrigin ? intersectRect.location[1] : int(tex->m_height) - intersectRect.location[1] - intersectRect.size[1];
MTLOrigin origin = {NSUInteger(intersectRect.location[0]), y, 0};
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:tex->m_colorTex
sourceSlice:0
sourceLevel:0
sourceOrigin:origin
sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1)
toTexture:tex->m_colorBindTex
toTexture:tex->m_colorBindTex[bindIdx]
destinationSlice:0
destinationLevel:0
destinationOrigin:origin];
[blitEnc endEncoding];
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_passDesc];
[m_enc setFrontFacingWinding:MTLWindingCounterClockwise];
if (m_boundVp.width || m_boundVp.height)
[m_enc setViewport:m_boundVp];
if (m_boundScissor.width || m_boundScissor.height)
[m_enc setScissorRect:m_boundScissor];
}
if (depth && tex->m_depthBindTex[bindIdx])
{
[blitEnc copyFromTexture:tex->m_depthTex
sourceSlice:0
sourceLevel:0
sourceOrigin:origin
sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1)
toTexture:tex->m_depthBindTex[bindIdx]
destinationSlice:0
destinationLevel:0
destinationOrigin:origin];
}
[blitEnc endEncoding];
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_passDesc];
[m_enc setFrontFacingWinding:MTLWindingCounterClockwise];
if (m_boundVp.width || m_boundVp.height)
[m_enc setViewport:m_boundVp];
if (m_boundScissor.width || m_boundScissor.height)
[m_enc setScissorRect:m_boundScissor];
}
}
@ -968,8 +1089,8 @@ struct MetalCommandQueue : IGraphicsCommandQueue
}
for (MetalPool* p : gfxF->m_committedPools)
{
for (auto& b : p->m_DBufs)
b.second->update(m_fillBuf);
for (auto& b : p->m_items)
b->m_buf->update(m_fillBuf);
}
datalk.unlock();
@ -999,38 +1120,35 @@ struct MetalCommandQueue : IGraphicsCommandQueue
if (m_needsDisplay)
{
MetalContext::Window& w = m_ctx->m_windows[m_parentWindow];
@autoreleasepool
{
std::unique_lock<std::mutex> lk(w.m_resizeLock);
if (w.m_needsResize)
{
std::unique_lock<std::mutex> lk(w.m_resizeLock);
if (w.m_needsResize)
{
w.m_metalLayer.drawableSize = w.m_size;
w.m_needsResize = NO;
m_needsDisplay = nullptr;
return;
}
w.m_metalLayer.drawableSize = w.m_size;
w.m_needsResize = NO;
m_needsDisplay = nullptr;
return;
}
id<CAMetalDrawable> drawable = [w.m_metalLayer nextDrawable];
if (drawable)
}
id<CAMetalDrawable> drawable = [w.m_metalLayer nextDrawable];
if (drawable)
{
id<MTLTexture> dest = drawable.texture;
if (m_needsDisplay->m_colorTex.width == dest.width &&
m_needsDisplay->m_colorTex.height == dest.height)
{
id<MTLTexture> dest = drawable.texture;
if (m_needsDisplay->m_colorTex.width == dest.width &&
m_needsDisplay->m_colorTex.height == dest.height)
{
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:m_needsDisplay->m_colorTex
sourceSlice:0
sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0)
sourceSize:MTLSizeMake(dest.width, dest.height, 1)
toTexture:dest
destinationSlice:0
destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)];
[blitEnc endEncoding];
[m_cmdBuf presentDrawable:drawable];
}
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:m_needsDisplay->m_colorTex
sourceSlice:0
sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0)
sourceSize:MTLSizeMake(dest.width, dest.height, 1)
toTexture:dest
destinationSlice:0
destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)];
[blitEnc endEncoding];
[m_cmdBuf presentDrawable:drawable];
}
}
m_needsDisplay = nullptr;
@ -1107,66 +1225,76 @@ MetalDataFactoryImpl::MetalDataFactoryImpl(IGraphicsContext* parent, MetalContex
IGraphicsBufferS* MetalDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalGraphicsBufferS* retval = new MetalGraphicsBufferS(use, factory.m_ctx, data, stride, count);
MetalDataFactoryImpl::m_deferredData->m_SBufs.emplace_back(retval);
MetalGraphicsBufferS* retval = new MetalGraphicsBufferS(d, use, factory.m_ctx, data, stride, count);
d->m_SBufs.emplace_back(retval);
return retval;
}
IGraphicsBufferD* MetalDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(factory.m_parent->getCommandQueue());
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, factory.m_ctx, stride, count);
MetalDataFactoryImpl::m_deferredData->m_DBufs.emplace_back(retval);
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(d, q, use, factory.m_ctx, stride, count);
d->m_DBufs.emplace_back(retval);
return retval;
}
ITextureS* MetalDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalTextureS* retval = new MetalTextureS(factory.m_ctx, width, height, mips, fmt, data, sz);
MetalDataFactoryImpl::m_deferredData->m_STexs.emplace_back(retval);
MetalTextureS* retval = new MetalTextureS(d, factory.m_ctx, width, height, mips, fmt, data, sz);
d->m_STexs.emplace_back(retval);
return retval;
}
ITextureSA* MetalDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, const void* data, size_t sz)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalTextureSA* retval = new MetalTextureSA(factory.m_ctx, width, height, layers, mips, fmt, data, sz);
MetalDataFactoryImpl::m_deferredData->m_SATexs.emplace_back(retval);
MetalTextureSA* retval = new MetalTextureSA(d, factory.m_ctx, width, height, layers, mips, fmt, data, sz);
d->m_SATexs.emplace_back(retval);
return retval;
}
ITextureD* MetalDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(factory.m_parent->getCommandQueue());
MetalTextureD* retval = new MetalTextureD(q, factory.m_ctx, width, height, fmt);
MetalDataFactoryImpl::m_deferredData->m_DTexs.emplace_back(retval);
MetalTextureD* retval = new MetalTextureD(d, q, factory.m_ctx, width, height, fmt);
d->m_DTexs.emplace_back(retval);
return retval;
}
ITextureR* MetalDataFactory::Context::newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding)
size_t colorBindCount, size_t depthBindCount)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalTextureR* retval = new MetalTextureR(factory.m_ctx, width, height, factory.m_sampleCount, enableShaderColorBinding);
MetalDataFactoryImpl::m_deferredData->m_RTexs.emplace_back(retval);
MetalTextureR* retval = new MetalTextureR(d, factory.m_ctx, width, height, factory.m_sampleCount,
colorBindCount, depthBindCount);
d->m_RTexs.emplace_back(retval);
return retval;
}
IVertexFormat* MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert, size_t baseInst)
{
MetalVertexFormat* retval = new struct MetalVertexFormat(elementCount, elements);
MetalDataFactoryImpl::m_deferredData->m_VFmts.emplace_back(retval);
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalVertexFormat* retval = new struct MetalVertexFormat(d, elementCount, elements);
d->m_VFmts.emplace_back(retval);
return retval;
}
IShaderPipeline* MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource,
IVertexFormat* vtxFmt, unsigned targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
{
MetalData* d = MetalDataFactoryImpl::m_deferredData.get();
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MTLCompileOptions* compOpts = [MTLCompileOptions new];
compOpts.languageVersion = MTLLanguageVersion1_1;
@ -1228,10 +1356,11 @@ IShaderPipeline* MetalDataFactory::Context::newShaderPipeline(const char* vertSo
fragShader = it->second->lock();
}
MetalShaderPipeline* retval = new MetalShaderPipeline(factory.m_ctx, std::move(vertShader), std::move(fragShader),
MetalShaderPipeline* retval = new MetalShaderPipeline(d, factory.m_ctx, std::move(vertShader), std::move(fragShader),
static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples,
srcFac, dstFac, prim, depthTest, depthWrite, culling);
MetalDataFactoryImpl::m_deferredData->m_SPs.emplace_back(retval);
srcFac, dstFac, prim, depthTest, depthWrite,
colorWrite, alphaWrite, culling);
d->m_SPs.emplace_back(retval);
return retval;
}
@ -1241,14 +1370,17 @@ MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst)
size_t texCount, ITexture** texs,
const int* texBindIdxs, const bool* depthBind,
size_t baseVert, size_t baseInst)
{
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalShaderDataBinding* retval =
new MetalShaderDataBinding(MetalDataFactoryImpl::m_deferredData.get(),
factory.m_ctx, pipeline, vbuf, instVbo, ibuf,
ubufCount, ubufs, ubufStages, ubufOffs,
ubufSizes, texCount, texs, baseVert, baseInst);
ubufSizes, texCount, texs, texBindIdxs,
depthBind, baseVert, baseInst);
MetalDataFactoryImpl::m_deferredData->m_SBinds.emplace_back(retval);
return retval;
}
@ -1295,8 +1427,8 @@ void MetalDataFactoryImpl::destroyAllData()
std::unique_lock<std::mutex> lk(m_committedMutex);
for (MetalData* data : m_committedData)
data->decrement();
for (IGraphicsBufferPool* pool : m_committedPools)
delete static_cast<MetalPool*>(pool);
for (MetalPool* pool : m_committedPools)
delete pool;
m_committedData.clear();
m_committedPools.clear();
}
@ -1314,15 +1446,22 @@ IGraphicsBufferD* MetalDataFactoryImpl::newPoolBuffer(IGraphicsBufferPool* p, Bu
{
MetalPool* pool = static_cast<MetalPool*>(p);
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent->getCommandQueue());
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_ctx, stride, count);
pool->m_DBufs.emplace(std::make_pair(retval, std::unique_ptr<MetalGraphicsBufferD>(retval)));
MetalPoolItem* item = new MetalPoolItem;
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);
pool->m_DBufs.erase(static_cast<MetalGraphicsBufferD*>(buf));
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,

View File

@ -1841,7 +1841,7 @@ class VulkanShaderPipeline : public IShaderPipeline
VkPipelineCache pipelineCache,
const VulkanVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, CullMode culling)
: m_ctx(ctx), m_pipelineCache(pipelineCache), m_vtxFmt(vtxFmt),
m_vert(std::move(vert)), m_frag(std::move(frag))
{
@ -2509,7 +2509,7 @@ struct VulkanCommandQueue : IGraphicsCommandQueue
func();
}
float m_clearColor[4] = {0.0,0.0,0.0,1.0};
float m_clearColor[4] = {0.0,0.0,0.0,0.0};
void setClearColor(const float rgba[4])
{
m_clearColor[0] = rgba[0];
@ -3081,7 +3081,7 @@ IShaderPipeline* VulkanDataFactory::Context::newShaderPipeline
std::vector<unsigned int>* vertBlobOut, std::vector<unsigned int>* fragBlobOut,
std::vector<unsigned char>* pipelineBlob, IVertexFormat* vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, CullMode culling)
ZTest depthTest, bool depthWrite, CullMode culling)
{
VulkanDataFactoryImpl& factory = static_cast<VulkanDataFactoryImpl&>(m_parent);

View File

@ -214,8 +214,10 @@ public:
~GraphicsContextCocoaGL()
{
delete m_dataFactory;
m_commandQueue->stopRenderer();
m_dataFactory->destroyAllData();
delete m_commandQueue;
delete m_dataFactory;
}
void _setCallback(IWindowCallback* cb)
@ -370,8 +372,10 @@ public:
~GraphicsContextCocoaMetal()
{
delete m_dataFactory;
m_commandQueue->stopRenderer();
m_dataFactory->destroyAllData();
delete m_commandQueue;
delete m_dataFactory;
m_metalCtx->m_windows.erase(m_parentWindow);
}

View File

@ -308,7 +308,7 @@ struct TestApplicationCallback : IApplicationCallback
pipeline = glF.newShaderPipeline(VS, FS, 1, &texName, 0, nullptr,
BlendFactor::One, BlendFactor::Zero,
Primitive::TriStrips, true, true, CullMode::None);
Primitive::TriStrips, boo::ZTest::LEqual, true, true, false, CullMode::None);
}
#if BOO_HAS_VULKAN
else if (plat == IGraphicsDataFactory::Platform::Vulkan)
@ -403,13 +403,14 @@ struct TestApplicationCallback : IApplicationCallback
pipeline = metalF.newShaderPipeline(VS, FS, vfmt, 1,
BlendFactor::One, BlendFactor::Zero, Primitive::TriStrips,
true, true, boo::CullMode::None);
boo::ZTest::LEqual, true, true, true, boo::CullMode::None);
}
#endif
/* Make shader data binding */
self->m_binding =
ctx.newShaderDataBinding(pipeline, vfmt, vbo, nullptr, nullptr, 0, nullptr, nullptr, 1, &texture);
ctx.newShaderDataBinding(pipeline, vfmt, vbo, nullptr, nullptr, 0, nullptr, nullptr,
1, &texture, nullptr, nullptr);
return true;
});