Internal dynamic buffer updating (OpenGL only)

This commit is contained in:
Jack Andersen 2015-12-02 11:09:49 -10:00
parent cd4df5cb27
commit 13cf33d75f
4 changed files with 137 additions and 79 deletions

View File

@ -12,9 +12,10 @@ namespace boo
class GLDataFactory : public IGraphicsDataFactory class GLDataFactory : public IGraphicsDataFactory
{ {
friend struct GLCommandQueue;
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
IGraphicsData* m_deferredData = nullptr; struct GLData* m_deferredData = nullptr;
std::unordered_set<IGraphicsData*> m_committedData; std::unordered_set<struct GLData*> m_committedData;
std::vector<int> m_texUnis; std::vector<int> m_texUnis;
public: public:
GLDataFactory(IGraphicsContext* parent); GLDataFactory(IGraphicsContext* parent);

View File

@ -25,12 +25,6 @@ struct IGraphicsCommandQueue
virtual void setViewport(const SWindowRect& rect)=0; virtual void setViewport(const SWindowRect& rect)=0;
virtual void setScissor(const SWindowRect& rect)=0; virtual void setScissor(const SWindowRect& rect)=0;
/**
* @brief Which dynamic buffer slot is being populated for pending command list
* @return Index [0,2] indicating the buffer slot
*/
virtual int pendingDynamicSlot()=0;
virtual void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)=0; virtual void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)=0;
virtual void setClearColor(const float rgba[4])=0; virtual void setClearColor(const float rgba[4])=0;

View File

@ -127,12 +127,12 @@ ENABLE_BITWISE_ENUM(VertexSemantic)
/** Used to create IVertexFormat */ /** Used to create IVertexFormat */
struct VertexElementDescriptor struct VertexElementDescriptor
{ {
const IGraphicsBuffer* vertBuffer = nullptr; IGraphicsBuffer* vertBuffer = nullptr;
const IGraphicsBuffer* indexBuffer = nullptr; IGraphicsBuffer* indexBuffer = nullptr;
VertexSemantic semantic; VertexSemantic semantic;
int semanticIdx = 0; int semanticIdx = 0;
VertexElementDescriptor() = default; VertexElementDescriptor() = default;
VertexElementDescriptor(const IGraphicsBuffer* v, const IGraphicsBuffer* i, VertexSemantic s, int idx=0) VertexElementDescriptor(IGraphicsBuffer* v, IGraphicsBuffer* i, VertexSemantic s, int idx=0)
: vertBuffer(v), indexBuffer(i), semantic(s), semanticIdx(idx) {} : vertBuffer(v), indexBuffer(i), semantic(s), semanticIdx(idx) {}
}; };

View File

@ -65,14 +65,15 @@ class GLGraphicsBufferD : public IGraphicsBufferD
struct GLCommandQueue* m_q; struct GLCommandQueue* m_q;
GLuint m_bufs[3]; GLuint m_bufs[3];
GLenum m_target; GLenum m_target;
void* m_mappedBuf = nullptr; std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_mappedSize = 0; size_t m_cpuSz = 0;
GLGraphicsBufferD(GLCommandQueue* q, BufferUse use) int m_validMask = 0;
: m_q(q) GLGraphicsBufferD(GLCommandQueue* q, BufferUse use, size_t sz)
: m_q(q), m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz)
{ {
m_target = USE_TABLE[int(use)];
glGenBuffers(3, m_bufs); glGenBuffers(3, m_bufs);
} }
void update(int b);
public: public:
~GLGraphicsBufferD() {glDeleteBuffers(3, m_bufs);} ~GLGraphicsBufferD() {glDeleteBuffers(3, m_bufs);}
@ -80,9 +81,9 @@ public:
void* map(size_t sz); void* map(size_t sz);
void unmap(); void unmap();
void bindVertex(int b) const; void bindVertex(int b);
void bindIndex(int b) const; void bindIndex(int b);
void bindUniform(size_t idx, int b) const; void bindUniform(size_t idx, int b);
}; };
IGraphicsBufferS* IGraphicsBufferS*
@ -117,15 +118,31 @@ class GLTextureS : public ITextureS
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (fmt == TextureFormat::RGBA8)
GLenum intFormat, format;
int pxPitch;
switch (fmt)
{ {
for (size_t i=0 ; i<mips ; ++i) case TextureFormat::RGBA8:
{ intFormat = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataIt); format = GL_RGBA;
dataIt += width * height * 4; pxPitch = 4;
width /= 2; break;
height /= 2; case TextureFormat::I8:
} intFormat = GL_R8;
format = GL_RED;
pxPitch = 1;
break;
default:
Log.report(LogVisor::FatalError, "unsupported tex format");
}
for (size_t i=0 ; i<mips ; ++i)
{
glTexImage2D(GL_TEXTURE_2D, i, intFormat, width, height, 0, format, GL_UNSIGNED_BYTE, dataIt);
dataIt += width * height * pxPitch;
width /= 2;
height /= 2;
} }
} }
public: public:
@ -170,11 +187,14 @@ class GLTextureD : public ITextureD
friend struct GLCommandQueue; friend struct GLCommandQueue;
struct GLCommandQueue* m_q; struct GLCommandQueue* m_q;
GLuint m_texs[3]; GLuint m_texs[3];
void* m_mappedBuf = nullptr; std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_mappedSize = 0; size_t m_cpuSz = 0;
GLenum m_intFormat, m_format;
size_t m_width = 0; size_t m_width = 0;
size_t m_height = 0; size_t m_height = 0;
int m_validMask = 0;
GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt); GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt);
void update(int b);
public: public:
~GLTextureD(); ~GLTextureD();
@ -182,7 +202,7 @@ public:
void* map(size_t sz); void* map(size_t sz);
void unmap(); void unmap();
void bind(size_t idx) const; void bind(size_t idx, int b);
}; };
class GLTextureR : public ITextureR class GLTextureR : public ITextureR
@ -498,7 +518,7 @@ struct GLShaderDataBinding : IShaderDataBinding
switch (tex->type()) switch (tex->type())
{ {
case TextureType::Dynamic: case TextureType::Dynamic:
static_cast<GLTextureD*>(tex)->bind(i); static_cast<GLTextureD*>(tex)->bind(i, b);
break; break;
case TextureType::Static: case TextureType::Static:
static_cast<GLTextureS*>(tex)->bind(i); static_cast<GLTextureS*>(tex)->bind(i);
@ -514,10 +534,10 @@ struct GLShaderDataBinding : IShaderDataBinding
IShaderDataBinding* IShaderDataBinding*
GLDataFactory::newShaderDataBinding(IShaderPipeline* pipeline, GLDataFactory::newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat, IVertexFormat* vtxFormat,
IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*,
size_t ubufCount, IGraphicsBuffer** ubufs, size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs) size_t texCount, ITexture** texs)
{ {
GLShaderDataBinding* retval = GLShaderDataBinding* retval =
new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, texCount, texs); new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, texCount, texs);
@ -536,7 +556,7 @@ void GLDataFactory::reset()
IGraphicsData* GLDataFactory::commit() IGraphicsData* GLDataFactory::commit()
{ {
IGraphicsData* retval = m_deferredData; GLData* retval = m_deferredData;
m_deferredData = new struct GLData(); m_deferredData = new struct GLData();
m_committedData.insert(retval); m_committedData.insert(retval);
/* Let's go ahead and flush to ensure our data gets to the GPU /* Let's go ahead and flush to ensure our data gets to the GPU
@ -693,8 +713,8 @@ struct GLCommandQueue : IGraphicsCommandQueue
size_t offset = 0; size_t offset = 0;
size_t instOffset = 0; size_t instOffset = 0;
glBindVertexArray(fmt->m_vao[b]); glBindVertexArray(fmt->m_vao[b]);
const IGraphicsBuffer* lastVBO = nullptr; IGraphicsBuffer* lastVBO = nullptr;
const IGraphicsBuffer* lastEBO = nullptr; IGraphicsBuffer* lastEBO = nullptr;
for (size_t i=0 ; i<fmt->m_elementCount ; ++i) for (size_t i=0 ; i<fmt->m_elementCount ; ++i)
{ {
const VertexElementDescriptor* desc = &fmt->m_elements[i]; const VertexElementDescriptor* desc = &fmt->m_elements[i];
@ -702,17 +722,17 @@ struct GLCommandQueue : IGraphicsCommandQueue
{ {
lastVBO = desc->vertBuffer; lastVBO = desc->vertBuffer;
if (lastVBO->dynamic()) if (lastVBO->dynamic())
static_cast<const GLGraphicsBufferD*>(lastVBO)->bindVertex(b); static_cast<GLGraphicsBufferD*>(lastVBO)->bindVertex(b);
else else
static_cast<const GLGraphicsBufferS*>(lastVBO)->bindVertex(); static_cast<GLGraphicsBufferS*>(lastVBO)->bindVertex();
} }
if (desc->indexBuffer != lastEBO) if (desc->indexBuffer != lastEBO)
{ {
lastEBO = desc->indexBuffer; lastEBO = desc->indexBuffer;
if (lastEBO->dynamic()) if (lastEBO->dynamic())
static_cast<const GLGraphicsBufferD*>(lastEBO)->bindIndex(b); static_cast<GLGraphicsBufferD*>(lastEBO)->bindIndex(b);
else else
static_cast<const GLGraphicsBufferS*>(lastEBO)->bindIndex(); static_cast<GLGraphicsBufferS*>(lastEBO)->bindIndex();
} }
glEnableVertexAttribArray(i); glEnableVertexAttribArray(i);
int maskedSem = int(desc->semantic & VertexSemantic::SemanticMask); int maskedSem = int(desc->semantic & VertexSemantic::SemanticMask);
@ -911,11 +931,6 @@ struct GLCommandQueue : IGraphicsCommandQueue
cmds.emplace_back(Command::Op::SetScissor); cmds.emplace_back(Command::Op::SetScissor);
cmds.back().rect = rect; cmds.back().rect = rect;
} }
int pendingDynamicSlot()
{
return m_fillBuf;
}
void resizeRenderTexture(ITextureR* tex, size_t width, size_t height) void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)
{ {
@ -1022,7 +1037,6 @@ struct GLCommandQueue : IGraphicsCommandQueue
void execute() void execute()
{ {
glFlush();
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_completeBuf = m_fillBuf; m_completeBuf = m_fillBuf;
for (size_t i=0 ; i<3 ; ++i) for (size_t i=0 ; i<3 ; ++i)
@ -1032,44 +1046,67 @@ struct GLCommandQueue : IGraphicsCommandQueue
m_fillBuf = i; m_fillBuf = i;
break; break;
} }
/* Update dynamic data here */
GLDataFactory* gfxF = static_cast<GLDataFactory*>(m_parent->getDataFactory());
for (GLData* d : gfxF->m_committedData)
{
for (std::unique_ptr<GLGraphicsBufferD>& b : d->m_DBufs)
b->update(m_completeBuf);
for (std::unique_ptr<GLTextureD>& t : d->m_DTexs)
t->update(m_completeBuf);
}
for (std::unique_ptr<GLGraphicsBufferD>& b : gfxF->m_deferredData->m_DBufs)
b->update(m_completeBuf);
for (std::unique_ptr<GLTextureD>& t : gfxF->m_deferredData->m_DTexs)
t->update(m_completeBuf);
glFlush();
lk.unlock(); lk.unlock();
m_cv.notify_one(); m_cv.notify_one();
m_cmdBufs[m_fillBuf].clear(); m_cmdBufs[m_fillBuf].clear();
} }
}; };
void GLGraphicsBufferD::update(int b)
{
int slot = 1 << b;
if ((slot & m_validMask) == 0)
{
glBindBuffer(m_target, m_bufs[b]);
glBufferData(m_target, m_cpuSz, m_cpuBuf.get(), GL_DYNAMIC_DRAW);
m_validMask |= slot;
}
}
void GLGraphicsBufferD::load(const void* data, size_t sz) void GLGraphicsBufferD::load(const void* data, size_t sz)
{ {
glBindBuffer(m_target, m_bufs[m_q->m_fillBuf]); size_t bufSz = std::min(sz, m_cpuSz);
glBufferData(m_target, sz, data, GL_DYNAMIC_DRAW); memcpy(m_cpuBuf.get(), data, bufSz);
m_validMask = 0;
} }
void* GLGraphicsBufferD::map(size_t sz) void* GLGraphicsBufferD::map(size_t sz)
{ {
if (m_mappedBuf) if (sz < m_cpuSz)
free(m_mappedBuf); return nullptr;
m_mappedBuf = malloc(sz); return m_cpuBuf.get();
m_mappedSize = sz;
return m_mappedBuf;
} }
void GLGraphicsBufferD::unmap() void GLGraphicsBufferD::unmap()
{ {
glBindBuffer(m_target, m_bufs[m_q->m_fillBuf]); m_validMask = 0;
glBufferData(m_target, m_mappedSize, m_mappedBuf, GL_DYNAMIC_DRAW);
free(m_mappedBuf);
m_mappedBuf = nullptr;
} }
void GLGraphicsBufferD::bindVertex(int b) const void GLGraphicsBufferD::bindVertex(int b)
{glBindBuffer(GL_ARRAY_BUFFER, m_bufs[b]);} {glBindBuffer(GL_ARRAY_BUFFER, m_bufs[b]);}
void GLGraphicsBufferD::bindIndex(int b) const void GLGraphicsBufferD::bindIndex(int b)
{glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bufs[b]);} {glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bufs[b]);}
void GLGraphicsBufferD::bindUniform(size_t idx, int b) const void GLGraphicsBufferD::bindUniform(size_t idx, int b)
{glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_bufs[b]);} {glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_bufs[b]);}
IGraphicsBufferD* IGraphicsBufferD*
GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count) GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{ {
GLCommandQueue* q = static_cast<GLCommandQueue*>(m_parent->getCommandQueue()); GLCommandQueue* q = static_cast<GLCommandQueue*>(m_parent->getCommandQueue());
GLGraphicsBufferD* retval = new GLGraphicsBufferD(q, use); GLGraphicsBufferD* retval = new GLGraphicsBufferD(q, use, stride * count);
static_cast<GLData*>(m_deferredData)->m_DBufs.emplace_back(retval); static_cast<GLData*>(m_deferredData)->m_DBufs.emplace_back(retval);
return retval; return retval;
} }
@ -1077,41 +1114,67 @@ GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
GLTextureD::GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt) GLTextureD::GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt)
: m_q(q), m_width(width), m_height(height) : m_q(q), m_width(width), m_height(height)
{ {
int pxPitch;
switch (fmt)
{
case TextureFormat::RGBA8:
m_intFormat = GL_RGBA;
m_format = GL_RGBA;
pxPitch = 4;
break;
case TextureFormat::I8:
m_intFormat = GL_R8;
m_format = GL_RED;
pxPitch = 1;
break;
default:
Log.report(LogVisor::FatalError, "unsupported tex format");
}
m_cpuSz = width * height * pxPitch;
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
glGenTextures(3, m_texs); glGenTextures(3, m_texs);
glBindTexture(GL_TEXTURE_2D, m_texs[0]); glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, m_texs[1]); glBindTexture(GL_TEXTURE_2D, m_texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, m_texs[2]); glBindTexture(GL_TEXTURE_2D, m_texs[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, GL_UNSIGNED_BYTE, nullptr);
} }
GLTextureD::~GLTextureD() {glDeleteTextures(3, m_texs);} GLTextureD::~GLTextureD() {glDeleteTextures(3, m_texs);}
void GLTextureD::update(int b)
{
int slot = 1 << b;
if ((slot & m_validMask) == 0)
{
glBindTexture(GL_TEXTURE_2D, m_texs[b]);
glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, m_width, m_height, 0, m_format, GL_UNSIGNED_BYTE, m_cpuBuf.get());
m_validMask |= slot;
}
}
void GLTextureD::load(const void* data, size_t sz) void GLTextureD::load(const void* data, size_t sz)
{ {
glBindTexture(GL_TEXTURE_2D, m_texs[m_q->m_fillBuf]); size_t bufSz = std::min(sz, m_cpuSz);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); memcpy(m_cpuBuf.get(), data, bufSz);
m_validMask = 0;
} }
void* GLTextureD::map(size_t sz) void* GLTextureD::map(size_t sz)
{ {
if (m_mappedBuf) if (sz > m_cpuSz)
free(m_mappedBuf); return nullptr;
m_mappedBuf = malloc(sz); return m_cpuBuf.get();
m_mappedSize = sz;
return m_mappedBuf;
} }
void GLTextureD::unmap() void GLTextureD::unmap()
{ {
glBindTexture(GL_TEXTURE_2D, m_texs[m_q->m_fillBuf]); m_validMask = 0;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_mappedBuf);
free(m_mappedBuf);
m_mappedBuf = nullptr;
} }
void GLTextureD::bind(size_t idx) const void GLTextureD::bind(size_t idx, int b)
{ {
glActiveTexture(GL_TEXTURE0 + idx); glActiveTexture(GL_TEXTURE0 + idx);
glBindTexture(GL_TEXTURE_2D, m_texs[0]); glBindTexture(GL_TEXTURE_2D, m_texs[b]);
} }
ITextureD* ITextureD*