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
{
friend struct GLCommandQueue;
IGraphicsContext* m_parent;
IGraphicsData* m_deferredData = nullptr;
std::unordered_set<IGraphicsData*> m_committedData;
struct GLData* m_deferredData = nullptr;
std::unordered_set<struct GLData*> m_committedData;
std::vector<int> m_texUnis;
public:
GLDataFactory(IGraphicsContext* parent);

View File

@ -25,12 +25,6 @@ struct IGraphicsCommandQueue
virtual void setViewport(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 setClearColor(const float rgba[4])=0;

View File

@ -127,12 +127,12 @@ ENABLE_BITWISE_ENUM(VertexSemantic)
/** Used to create IVertexFormat */
struct VertexElementDescriptor
{
const IGraphicsBuffer* vertBuffer = nullptr;
const IGraphicsBuffer* indexBuffer = nullptr;
IGraphicsBuffer* vertBuffer = nullptr;
IGraphicsBuffer* indexBuffer = nullptr;
VertexSemantic semantic;
int semanticIdx = 0;
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) {}
};

View File

@ -65,14 +65,15 @@ class GLGraphicsBufferD : public IGraphicsBufferD
struct GLCommandQueue* m_q;
GLuint m_bufs[3];
GLenum m_target;
void* m_mappedBuf = nullptr;
size_t m_mappedSize = 0;
GLGraphicsBufferD(GLCommandQueue* q, BufferUse use)
: m_q(q)
std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0;
int m_validMask = 0;
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);
}
void update(int b);
public:
~GLGraphicsBufferD() {glDeleteBuffers(3, m_bufs);}
@ -80,9 +81,9 @@ public:
void* map(size_t sz);
void unmap();
void bindVertex(int b) const;
void bindIndex(int b) const;
void bindUniform(size_t idx, int b) const;
void bindVertex(int b);
void bindIndex(int b);
void bindUniform(size_t idx, int b);
};
IGraphicsBufferS*
@ -117,15 +118,31 @@ class GLTextureS : public ITextureS
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
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)
{
glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataIt);
dataIt += width * height * 4;
width /= 2;
height /= 2;
}
case TextureFormat::RGBA8:
intFormat = GL_RGBA;
format = GL_RGBA;
pxPitch = 4;
break;
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:
@ -170,11 +187,14 @@ class GLTextureD : public ITextureD
friend struct GLCommandQueue;
struct GLCommandQueue* m_q;
GLuint m_texs[3];
void* m_mappedBuf = nullptr;
size_t m_mappedSize = 0;
std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz = 0;
GLenum m_intFormat, m_format;
size_t m_width = 0;
size_t m_height = 0;
int m_validMask = 0;
GLTextureD(GLCommandQueue* q, size_t width, size_t height, TextureFormat fmt);
void update(int b);
public:
~GLTextureD();
@ -182,7 +202,7 @@ public:
void* map(size_t sz);
void unmap();
void bind(size_t idx) const;
void bind(size_t idx, int b);
};
class GLTextureR : public ITextureR
@ -498,7 +518,7 @@ struct GLShaderDataBinding : IShaderDataBinding
switch (tex->type())
{
case TextureType::Dynamic:
static_cast<GLTextureD*>(tex)->bind(i);
static_cast<GLTextureD*>(tex)->bind(i, b);
break;
case TextureType::Static:
static_cast<GLTextureS*>(tex)->bind(i);
@ -514,10 +534,10 @@ struct GLShaderDataBinding : IShaderDataBinding
IShaderDataBinding*
GLDataFactory::newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*,
size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs)
IVertexFormat* vtxFormat,
IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*,
size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs)
{
GLShaderDataBinding* retval =
new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, texCount, texs);
@ -536,7 +556,7 @@ void GLDataFactory::reset()
IGraphicsData* GLDataFactory::commit()
{
IGraphicsData* retval = m_deferredData;
GLData* retval = m_deferredData;
m_deferredData = new struct GLData();
m_committedData.insert(retval);
/* 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 instOffset = 0;
glBindVertexArray(fmt->m_vao[b]);
const IGraphicsBuffer* lastVBO = nullptr;
const IGraphicsBuffer* lastEBO = nullptr;
IGraphicsBuffer* lastVBO = nullptr;
IGraphicsBuffer* lastEBO = nullptr;
for (size_t i=0 ; i<fmt->m_elementCount ; ++i)
{
const VertexElementDescriptor* desc = &fmt->m_elements[i];
@ -702,17 +722,17 @@ struct GLCommandQueue : IGraphicsCommandQueue
{
lastVBO = desc->vertBuffer;
if (lastVBO->dynamic())
static_cast<const GLGraphicsBufferD*>(lastVBO)->bindVertex(b);
static_cast<GLGraphicsBufferD*>(lastVBO)->bindVertex(b);
else
static_cast<const GLGraphicsBufferS*>(lastVBO)->bindVertex();
static_cast<GLGraphicsBufferS*>(lastVBO)->bindVertex();
}
if (desc->indexBuffer != lastEBO)
{
lastEBO = desc->indexBuffer;
if (lastEBO->dynamic())
static_cast<const GLGraphicsBufferD*>(lastEBO)->bindIndex(b);
static_cast<GLGraphicsBufferD*>(lastEBO)->bindIndex(b);
else
static_cast<const GLGraphicsBufferS*>(lastEBO)->bindIndex();
static_cast<GLGraphicsBufferS*>(lastEBO)->bindIndex();
}
glEnableVertexAttribArray(i);
int maskedSem = int(desc->semantic & VertexSemantic::SemanticMask);
@ -911,11 +931,6 @@ struct GLCommandQueue : IGraphicsCommandQueue
cmds.emplace_back(Command::Op::SetScissor);
cmds.back().rect = rect;
}
int pendingDynamicSlot()
{
return m_fillBuf;
}
void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)
{
@ -1022,7 +1037,6 @@ struct GLCommandQueue : IGraphicsCommandQueue
void execute()
{
glFlush();
std::unique_lock<std::mutex> lk(m_mt);
m_completeBuf = m_fillBuf;
for (size_t i=0 ; i<3 ; ++i)
@ -1032,44 +1046,67 @@ struct GLCommandQueue : IGraphicsCommandQueue
m_fillBuf = i;
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();
m_cv.notify_one();
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)
{
glBindBuffer(m_target, m_bufs[m_q->m_fillBuf]);
glBufferData(m_target, sz, data, GL_DYNAMIC_DRAW);
size_t bufSz = std::min(sz, m_cpuSz);
memcpy(m_cpuBuf.get(), data, bufSz);
m_validMask = 0;
}
void* GLGraphicsBufferD::map(size_t sz)
{
if (m_mappedBuf)
free(m_mappedBuf);
m_mappedBuf = malloc(sz);
m_mappedSize = sz;
return m_mappedBuf;
if (sz < m_cpuSz)
return nullptr;
return m_cpuBuf.get();
}
void GLGraphicsBufferD::unmap()
{
glBindBuffer(m_target, m_bufs[m_q->m_fillBuf]);
glBufferData(m_target, m_mappedSize, m_mappedBuf, GL_DYNAMIC_DRAW);
free(m_mappedBuf);
m_mappedBuf = nullptr;
m_validMask = 0;
}
void GLGraphicsBufferD::bindVertex(int b) const
void GLGraphicsBufferD::bindVertex(int 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]);}
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]);}
IGraphicsBufferD*
GLDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{
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);
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)
: 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);
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]);
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]);
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);}
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)
{
glBindTexture(GL_TEXTURE_2D, m_texs[m_q->m_fillBuf]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
size_t bufSz = std::min(sz, m_cpuSz);
memcpy(m_cpuBuf.get(), data, bufSz);
m_validMask = 0;
}
void* GLTextureD::map(size_t sz)
{
if (m_mappedBuf)
free(m_mappedBuf);
m_mappedBuf = malloc(sz);
m_mappedSize = sz;
return m_mappedBuf;
if (sz > m_cpuSz)
return nullptr;
return m_cpuBuf.get();
}
void GLTextureD::unmap()
{
glBindTexture(GL_TEXTURE_2D, m_texs[m_q->m_fillBuf]);
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;
m_validMask = 0;
}
void GLTextureD::bind(size_t idx) const
void GLTextureD::bind(size_t idx, int b)
{
glActiveTexture(GL_TEXTURE0 + idx);
glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glBindTexture(GL_TEXTURE_2D, m_texs[b]);
}
ITextureD*