It was possible for the buffer data to be updated without going through
the dirty check in UniformBlock::apply, leaving the UniformBlock with a
null buf_range and resulting in a segfault.
prev_in_buffer->next_in_buffer = this;
}
prev_in_buffer->next_in_buffer = this;
}
- update_buffer_offsets();
+ update_buffer_offset();
}
void Bufferable::unlink_from_buffer()
}
void Bufferable::unlink_from_buffer()
if(next_in_buffer)
{
next_in_buffer->prev_in_buffer = prev_in_buffer;
if(next_in_buffer)
{
next_in_buffer->prev_in_buffer = prev_in_buffer;
- next_in_buffer->update_buffer_offsets();
+ next_in_buffer->update_buffer_offset();
}
prev_in_buffer = 0;
next_in_buffer = 0;
}
}
prev_in_buffer = 0;
next_in_buffer = 0;
}
-void Bufferable::update_buffer_offsets()
+void Bufferable::update_buffer_offset()
{
unsigned offset = 0;
if(prev_in_buffer)
{
unsigned offset = 0;
if(prev_in_buffer)
{
buffer_offset = offset;
dirty = true;
{
buffer_offset = offset;
dirty = true;
- next_in_buffer->update_buffer_offsets();
+ next_in_buffer->update_buffer_offset();
+
+ /* Do not resize the buffer here, as the offsets may change multiple times
+ before the buffer is actually used */
}
void Bufferable::update_buffer_data() const
}
void Bufferable::update_buffer_data() const
for(const Bufferable *b=first; b; b=b->next_in_buffer)
total_size += b->get_data_size();
for(const Bufferable *b=first; b; b=b->next_in_buffer)
total_size += b->get_data_size();
- buffer->data(total_size, 0);
- for(const Bufferable *b=first; b; b=b->next_in_buffer)
+ if(total_size!=buffer->get_size())
- buffer->sub_data(b->buffer_offset, b->get_data_size(), b->get_data());
- b->dirty = false;
+ buffer->data(total_size, 0);
+ // Resizing the buffer invalidates its contents.
+ for(const Bufferable *b=first; b; b=b->next_in_buffer)
+ b->dirty = true;
+
+ upload_data();
+ dirty = false;
protected:
virtual unsigned get_data_size() const = 0;
protected:
virtual unsigned get_data_size() const = 0;
- virtual const void *get_data() const = 0;
- void update_buffer_offsets();
+ void update_buffer_offset();
+ virtual void offset_changed() { }
+
void update_buffer_data() const;
void update_buffer_data() const;
+ virtual void upload_data() const = 0;
+UniformBlock::~UniformBlock()
+{
+ delete buf_range;
+}
+
+void UniformBlock::offset_changed()
+{
+ delete buf_range;
+ buf_range = 0;
+}
+
+void UniformBlock::upload_data() const
+{
+ if(!buf_range)
+ buf_range = new BufferRange(*buffer, buffer_offset, size);
+ buf_range->data(&data[0]);
+}
+
void UniformBlock::attach(int index, const Uniform &uni)
{
uniforms[index] = &uni;
void UniformBlock::attach(int index, const Uniform &uni)
{
uniforms[index] = &uni;
- if(!buf_range)
- buf_range = new BufferRange(*buffer, buffer_offset, size);
- }
buf_range->bind_to(UNIFORM_BUFFER, index);
}
else
buf_range->bind_to(UNIFORM_BUFFER, index);
}
else
public:
UniformBlock();
UniformBlock(unsigned);
public:
UniformBlock();
UniformBlock(unsigned);
- virtual const void *get_data() const { return &data[0]; }
virtual unsigned get_data_size() const { return size; }
virtual unsigned get_data_size() const { return size; }
+ virtual void offset_changed();
+ virtual void upload_data() const;
public:
void attach(int, const Uniform &);
public:
void attach(int, const Uniform &);