/**
A buffer for storing data in GL memory. Putting vertex and index data in
-buffers can improve rendering performance. The VertexArray and Mesh classes
-contain built-in support for buffers.
+buffers can improve rendering performance. The VertexArray, Mesh and
+UniformBlock classes contain built-in support for buffers.
*/
class Buffer
{
+#include "buffer.h"
#include "color.h"
#include "error.h"
#include "extension.h"
namespace GL {
ProgramData::ProgramData():
+ last_block(0),
+ buffer(0),
modified(false)
{
static RequireExtension _ext("GL_ARB_shader_objects");
// Blocks are intentionally left uncopied
ProgramData::ProgramData(const ProgramData &other):
uniforms(other.uniforms),
+ last_block(0),
+ buffer(0),
modified(false)
{
for(UniformMap::iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
uniform(name, new UniformArray<UniformMatrix4x4f>(n, v));
}
-const UniformBlock &ProgramData::get_block(const Program &prog) const
+const UniformBlock &ProgramData::get_block(const Program &prog, const string &name) const
{
if(modified)
{
modified = false;
}
- unsigned layout_hash = prog.get_uniform_layout_hash();
+ const Program::UniformBlockInfo *info = 0;
+ unsigned layout_hash;
+ if(!name.empty())
+ {
+ info = &prog.get_uniform_block_info(name);
+ layout_hash = info->layout_hash;
+ }
+ else
+ layout_hash = prog.get_uniform_layout_hash();
+
map<unsigned, Block>::iterator i = blocks.find(layout_hash);
if(i==blocks.end())
{
i = blocks.insert(BlockMap::value_type(layout_hash, Block())).first;
i->second.dirty = true;
- i->second.block = new UniformBlock;
+ if(info)
+ {
+ i->second.block = new UniformBlock(info->data_size);
+ if(!buffer)
+ buffer = new Buffer(UNIFORM_BUFFER);
+ i->second.block->use_buffer(buffer, last_block);
+ last_block = i->second.block;
+ }
+ else
+ i->second.block = new UniformBlock;
}
UniformBlock &block = *i->second.block;
if(i->second.dirty)
{
- for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j)
+ if(info)
{
- int loc = prog.get_uniform_location(j->first);
- if(loc>=0)
- block.attach(loc, *j->second);
+ for(vector<const Program::UniformInfo *>::const_iterator j=info->uniforms.begin(); j!=info->uniforms.end(); ++j)
+ {
+ // XXX individual array elements
+ UniformMap::const_iterator k = uniforms.find((*j)->name);
+ if(k!=uniforms.end())
+ block.attach(**j, *k->second);
+ }
+ }
+ else
+ {
+ for(UniformMap::const_iterator j=uniforms.begin(); j!=uniforms.end(); ++j)
+ {
+ int loc = prog.get_uniform_location(j->first);
+ if(loc>=0)
+ block.attach(loc, *j->second);
+ }
}
i->second.dirty = false;
}
if(!prog)
throw invalid_operation("ProgramData::apply");
- const UniformBlock &block = get_block(*prog);
+ const Program::UniformBlockMap &prog_blocks = prog->get_uniform_blocks();
+ for(Program::UniformBlockMap::const_iterator i=prog_blocks.begin(); i!=prog_blocks.end(); ++i)
+ {
+ const UniformBlock &block = get_block(*prog, i->second.name);
+ block.apply(i->second.bind_point);
+ }
+
+ const UniformBlock &block = get_block(*prog, string());
block.apply(-1);
}
namespace Msp {
namespace GL {
+class Buffer;
class Color;
class Matrix;
class Program;
typedef std::map<std::string, Uniform *> UniformMap;
typedef std::map<unsigned, Block> BlockMap;
+ // XXX All these mutables are a bit silly, but I'm out of better ideas
UniformMap uniforms;
mutable BlockMap blocks;
+ mutable UniformBlock *last_block;
+ mutable Buffer *buffer;
mutable bool modified;
ProgramData &operator=(const ProgramData &);
void uniform4_array(const std::string &, unsigned, const float *);
void uniform_matrix4_array(const std::string &, unsigned, const float *);
- const UniformBlock &get_block(const Program &) const;
+ const UniformBlock &get_block(const Program &, const std::string &) const;
void apply() const;
};
#define MSP_GL_UNIFORM_H_
#include <algorithm>
+#include "program.h"
namespace Msp {
namespace GL {
virtual ~Uniform() { }
virtual void apply(int) const = 0;
+ virtual void store(const Program::UniformInfo &, void *) const = 0;
virtual Uniform *clone() const = 0;
};
static void apply(int, unsigned, const T *);
+ virtual void store(const Program::UniformInfo &info, void *buffer) const
+ { store(info, buffer, &value); }
+
+ static void store(const Program::UniformInfo &, void *buffer, const T *value)
+ { *reinterpret_cast<T *>(buffer) = *value; }
+
virtual UniformScalar *clone() const
{ return new UniformScalar(value); }
};
static void apply(int index, unsigned size, const T *value);
+ virtual void store(const Program::UniformInfo &info, void *buffer) const
+ { store(info, buffer, value); }
+
+ static void store(const Program::UniformInfo &, void *buffer, const T *value)
+ { std::copy(value, value+vecsize, reinterpret_cast<T *>(buffer)); }
+
virtual UniformVector *clone() const
{ return new UniformVector(value); }
};
static void apply(int index, unsigned size, const T *value);
+ virtual void store(const Program::UniformInfo &info, void *buffer) const
+ { store(info, buffer, value); }
+
+ static void store(const Program::UniformInfo &info, void *buffer, const T *value)
+ {
+ for(unsigned i=0; i<cols; ++i)
+ UniformVector<T, rows>::store(info, reinterpret_cast<char *>(buffer)+i*info.matrix_stride, value+i*rows);
+ }
+
virtual UniformMatrix *clone() const
{ return new UniformMatrix(value); }
};
{
private:
typedef typename T::BaseType BaseType;
+ enum { elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType) };
BaseType *values;
unsigned size;
UniformArray(unsigned n, const BaseType *vp):
size(n)
{
- unsigned elemsize = sizeof(typename T::Type)/sizeof(typename T::BaseType);
values = new BaseType[elemsize*size];
std::copy(vp, vp+elemsize*size, values);
}
virtual void apply(int index) const
{ T::apply(index, size, values); }
+ virtual void store(const Program::UniformInfo &info, void *buffer) const
+ {
+ for(unsigned i=0; i<size; ++i)
+ T::store(info, reinterpret_cast<char *>(buffer)+i*info.array_stride, values+i*elemsize);
+ }
+
virtual UniformArray *clone() const
{ return new UniformArray(size, values); }
};
#include <stdexcept>
+#include "buffer.h"
#include "color.h"
+#include "error.h"
#include "matrix.h"
#include "uniform.h"
#include "uniformblock.h"
namespace Msp {
namespace GL {
+UniformBlock::UniformBlock()
+{ }
+
+UniformBlock::UniformBlock(unsigned s):
+ size(s),
+ data(size)
+{ }
+
void UniformBlock::attach(int index, const Uniform &uni)
{
uniforms[index] = &uni;
}
+void UniformBlock::attach(const Program::UniformInfo &info, const Uniform &uni)
+{
+ uniforms[info.location] = &uni;
+ if(buffer)
+ {
+ uni.store(info, &data[info.location]);
+ dirty = true;
+ }
+}
+
void UniformBlock::apply(int index) const
{
- if(index>=0)
- throw logic_error("GL_ARB_uniform_buffer_object support not implemented yet");
+ if((index>=0) != (buffer!=0))
+ throw invalid_operation("UniformBlock::apply");
- for(map<int, const Uniform *>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
- i->second->apply(i->first);
+ if(buffer)
+ {
+ if(dirty)
+ {
+ update_buffer_data();
+ if(!buf_range)
+ buf_range = new BufferRange(*buffer, buffer_offset, size);
+ }
+ buf_range->bind_to(UNIFORM_BUFFER, index);
+ }
+ else
+ {
+ for(map<int, const Uniform *>::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i)
+ i->second->apply(i->first);
+ }
}
} // namespace GL
#define MSP_GL_UNIFORMBLOCK_H_
#include <map>
+#include <vector>
+#include "bufferable.h"
+#include "program.h"
namespace Msp {
namespace GL {
+class BufferRange;
class Color;
class Matrix;
class Uniform;
class Vector3;
class Vector4;
-class UniformBlock
+class UniformBlock: public Bufferable
{
private:
std::map<int, const Uniform *> uniforms;
+ unsigned size;
+ std::vector<char> data;
+ mutable BufferRange *buf_range;
UniformBlock(const UniformBlock &);
UniformBlock &operator=(const UniformBlock &);
public:
- UniformBlock() { }
+ UniformBlock();
+ UniformBlock(unsigned);
+private:
+ virtual const void *get_data() const { return &data[0]; }
+ virtual unsigned get_data_size() const { return size; }
+
+public:
void attach(int, const Uniform &);
+ void attach(const Program::UniformInfo &, const Uniform &);
void apply(int) const;
};