update_offset();
}
+Bufferable::AsyncUpdater *Bufferable::refresh_async() const
+{
+ return dirty ? new AsyncUpdater(*this) : 0;
+}
+
void Bufferable::unlink_from_buffer()
{
if(prev_in_buffer)
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();
+ b->upload_data(0);
for(const Bufferable *b=next_in_buffer; b; b=b->next_in_buffer)
if(!b->dirty)
- b->upload_data();
+ b->upload_data(0);
}
- upload_data();
+ upload_data(0);
dirty = false;
}
-void Bufferable::upload_data() const
+void Bufferable::upload_data(char *target) const
+{
+ if(target)
+ {
+ const char *source = reinterpret_cast<const char *>(get_data_pointer());
+ copy(source, source+get_data_size(), target);
+ }
+ else
+ buffer->sub_data(offset, get_data_size(), get_data_pointer());
+}
+
+
+Bufferable::AsyncUpdater::AsyncUpdater(const Bufferable &b):
+ bufferable(b)
{
- buffer->sub_data(offset, get_data_size(), get_data_pointer());
+ buffer_resized = bufferable.resize_buffer();
+ mapped_address = reinterpret_cast<char *>(bufferable.buffer->map(WRITE_ONLY));
+}
+
+Bufferable::AsyncUpdater::~AsyncUpdater()
+{
+ bufferable.buffer->unmap();
+}
+
+void Bufferable::AsyncUpdater::upload_data()
+{
+ bufferable.upload_data(mapped_address+bufferable.offset);
+ // Update all bufferables in the same buffer at once
+ for(const Bufferable *b=bufferable.prev_in_buffer; b; b=b->prev_in_buffer)
+ if(b->dirty || buffer_resized)
+ {
+ b->upload_data(mapped_address+b->offset);
+ b->dirty = false;
+ }
+ for(const Bufferable *b=bufferable.next_in_buffer; b; b=b->next_in_buffer)
+ if(b->dirty || buffer_resized)
+ {
+ b->upload_data(mapped_address+b->offset);
+ b->dirty = false;
+ }
}
} // namespace GL
*/
class Bufferable
{
+public:
+ class AsyncUpdater
+ {
+ private:
+ const Bufferable &bufferable;
+ char *mapped_address;
+ bool buffer_resized;
+
+ public:
+ AsyncUpdater(const Bufferable &);
+ ~AsyncUpdater();
+
+ void upload_data();
+ };
+
private:
Buffer *buffer;
unsigned offset;
/** Uploads new data into the buffer if necessary. */
void refresh() const { if(dirty) update_buffer(); }
+ AsyncUpdater *refresh_async() const;
+
private:
void unlink_from_buffer();
/** Resizes the buffer if necessary and calls upload_data(). */
void update_buffer() const;
- /** Uploads data to the buffer. */
- virtual void upload_data() 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;
};
} // namespace GL
buf_range = 0;
}
-void UniformBlock::upload_data() const
+void UniformBlock::upload_data(char *target) const
{
if(!buf_range)
buf_range = new BufferRange(*get_buffer(), get_offset(), size);
- buf_range->data(&data[0]);
+
+ if(target)
+ copy(data.begin(), data.end(), target);
+ else
+ buf_range->data(&data[0]);
}
void UniformBlock::attach(int index, const Uniform &uni)
virtual const void *get_data_pointer() const { return &data[0]; }
virtual unsigned get_alignment() const;
virtual void offset_changed();
- virtual void upload_data() const;
+ virtual void upload_data(char *) const;
public:
void attach(int, const Uniform &);