if(get_buffer())
{
- if(dirty)
- update_buffer();
+ refresh();
return reinterpret_cast<const void *>(get_offset());
}
offset(0),
next_in_buffer(0),
prev_in_buffer(0),
+ location_dirty(false),
dirty(false)
{ }
}
}
+ location_dirty = true;
dirty = true;
update_offset();
}
if(new_offset!=offset)
{
offset = new_offset;
+ location_dirty = true;
dirty = true;
- offset_changed();
}
if(next_in_buffer)
next_in_buffer->update_offset();
-
- /* Do not resize the buffer here, as more bufferables may be added before
- the buffer is actually used. */
+ else if(buffer && offset+get_data_size()>buffer->get_size())
+ {
+ location_dirty = true;
+ dirty = true;
+ }
}
bool Bufferable::resize_buffer() const
return false;
}
-void Bufferable::update_buffer() const
+void Bufferable::update_buffer_size() const
{
- Conditional<BindRestore> _bind(!ARB_direct_state_access, buffer, buffer->get_type());
-
if(resize_buffer())
{
+ Conditional<BindRestore> _bind(!ARB_direct_state_access, buffer, buffer->get_type());
+
/* Resizing the buffer invalidates its contents. Non-dirty data may
be in use, so reupload it. */
for(const Bufferable *b=prev_in_buffer; b; b=b->prev_in_buffer)
if(!b->dirty)
b->upload_data(0);
}
-
- upload_data(0);
}
void Bufferable::upload_data(char *target) const
{
+ unsigned data_size = get_data_size();
+ if(location_dirty)
+ {
+ update_buffer_size();
+ location_changed(buffer, offset, data_size);
+ location_dirty = false;
+ }
+
if(target)
{
const char *source = reinterpret_cast<const char *>(get_data_pointer());
- copy(source, source+get_data_size(), target);
+ copy(source, source+data_size, target);
}
else
- buffer->sub_data(offset, get_data_size(), get_data_pointer());
+ buffer->sub_data(offset, data_size, get_data_pointer());
dirty = false;
}
unsigned offset;
Bufferable *next_in_buffer;
Bufferable *prev_in_buffer;
+ mutable bool location_dirty;
protected:
mutable bool dirty;
void use_buffer(Buffer *buf, Bufferable *prev = 0);
/** Uploads new data into the buffer if necessary. */
- void refresh() const { if(buffer && dirty) update_buffer(); }
+ void refresh() const { if(buffer && dirty) upload_data(0); }
AsyncUpdater *refresh_async() const;
const Buffer *get_buffer() const { return buffer; }
protected:
- /** Returns the buffer in which the data is stored. */
- Buffer *get_mutable_buffer() const { return buffer; }
-
/** Returns the amount of data to be stored in the buffer, in bytes. */
virtual unsigned get_data_size() const = 0;
/** Returns the offset where the data should be uploaded. */
unsigned get_offset() const { return offset; }
- /** Called when the offset for the data has changed. */
- virtual void offset_changed() { }
+ /** Called when the target buffer or offset within it has changed. */
+ virtual void location_changed(Buffer *, unsigned, unsigned) const { }
private:
bool resize_buffer() const;
-protected:
- /** Resizes the buffer if necessary and calls upload_data(). */
- void update_buffer() const;
+ void update_buffer_size() const;
/** Uploads data to the buffer. Receives pointer to mapped buffer memory as
parameter. If null, buffer interface should be used instead. */
- virtual void upload_data(char *) const;
+ void upload_data(char *) const;
};
} // namespace GL
return BufferRange::get_uniform_buffer_alignment();
}
-void UniformBlock::offset_changed()
+void UniformBlock::location_changed(Buffer *buf, unsigned off, unsigned) const
{
delete buf_range;
- buf_range = 0;
-}
-
-void UniformBlock::upload_data(char *target) const
-{
- if(!buf_range)
- buf_range = new BufferRange(*get_mutable_buffer(), get_offset(), size);
-
- if(target)
- copy(data.begin(), data.end(), target);
- else
- buf_range->data(&data[0]);
- dirty = false;
+ buf_range = new BufferRange(*buf, off, size);
}
void UniformBlock::attach(int index, const Uniform &uni)
if(!get_buffer())
throw invalid_operation("UniformBlock::apply");
- if(dirty)
- update_buffer();
+ refresh();
buf_range->bind_to(UNIFORM_BUFFER, index);
}
else
virtual unsigned get_data_size() const { return size; }
virtual const void *get_data_pointer() const { return &data[0]; }
virtual unsigned get_alignment() const;
- virtual void offset_changed();
- virtual void upload_data(char *) const;
+ virtual void location_changed(Buffer *, unsigned, unsigned) const;
public:
void attach(int, const Uniform &);