X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fcore%2Fbufferable.h;h=29acafe0f346c3e914bfe76d7ca4134e0c7822f6;hp=cbbde4e1b93f1e07266c097c150774f2b5621d3c;hb=HEAD;hpb=7aaec9a70b8d7733429bec043f8e33e02956f266 diff --git a/source/core/bufferable.h b/source/core/bufferable.h index cbbde4e1..29acafe0 100644 --- a/source/core/bufferable.h +++ b/source/core/bufferable.h @@ -1,63 +1,72 @@ #ifndef MSP_GL_BUFFERABLE_H_ #define MSP_GL_BUFFERABLE_H_ +#include +#include +#include "buffer.h" + namespace Msp { namespace GL { -class Buffer; - /** -Base class for things that can store data in buffers. Supports buffer sharing. -A dirty flag is provided for derived classes. It should be set when the data -in the buffer is considered out of date, and is cleared by Bufferable after -uploading fresh data to the buffer. +Base class for things that can store data in buffers. Multiple Bufferables +may be put in the same buffer. + +Derived classes should call mark_dirty() when the stored data has changed. */ -class Bufferable +class Bufferable: public NonCopyable { public: + /** + Uploads data to the buffer asynchronously, through a memory mapping. API + calls are done in the constructor and desctructor, so upload_data may be + called from a different thread. + */ class AsyncUpdater { private: const Bufferable &bufferable; - char *mapped_address; + Buffer::AsyncTransfer transfer; public: AsyncUpdater(const Bufferable &); - ~AsyncUpdater(); void upload_data(); }; private: - Buffer *buffer; - unsigned offset; - Bufferable *next_in_buffer; - Bufferable *prev_in_buffer; - mutable bool location_dirty; -protected: - mutable bool dirty; + Buffer *buffer = 0; + std::size_t offset = 0; + Bufferable *next_in_buffer = 0; + Bufferable *prev_in_buffer = 0; + mutable bool location_dirty = false; + mutable uint8_t dirty = 0; - Bufferable(); +protected: + Bufferable() = default; + Bufferable(Bufferable &&); public: virtual ~Bufferable(); /** Sets the buffer to use. If prev is not null, it must use the same - buffer, and this object is inserted after it. */ - void use_buffer(Buffer *buf, Bufferable *prev = 0); + buffer, and this object is inserted after it. + + Data is not uploaded immediately, but only when refresh() is called. */ + void use_buffer(Buffer *, Bufferable *prev = 0); /** Sets the buffer for the entire chain of objects. */ void change_buffer(Buffer *); /** Returns the total amount of storage required by this object and others - in the same chain, including any alignment between objects. */ - unsigned get_required_buffer_size() const; + in the same chain, including any padding required by object alignment. */ + std::size_t get_required_buffer_size(bool = false) const; /** Uploads new data into the buffer if necessary. */ - void refresh() const { if(buffer && dirty) upload_data(0); } + void refresh(unsigned f) const { if(dirty) upload_data(f, 0); } /** Returns an object which can be used to upload data to the buffer using - mapped memory. */ - AsyncUpdater *refresh_async() const; + mapped memory. If data is not dirty, returns null. */ + AsyncUpdater *refresh_async() const { return dirty ? create_async_updater() : 0; } private: void unlink_from_buffer(); @@ -66,32 +75,36 @@ public: /** Returns the buffer in which the data is stored. */ const Buffer *get_buffer() const { return buffer; } -protected: - /** Returns the amount of data to be stored in the buffer, in bytes. */ - virtual unsigned get_data_size() const = 0; + /** Returns the size of the data, in bytes. */ + virtual std::size_t get_data_size() const = 0; - /** Returns a pointer to the start of data in client memory. */ +protected: + /** Returns a pointer to the start of the data in client memory. */ virtual const void *get_data_pointer() const = 0; - /** Returns the alignment required for the data, in bytes. The offset is - guaranteed to be a multiple of this. */ - virtual unsigned get_alignment() const { return 1; } + /** Returns the alignment required for the data, in bytes. The offset + within the buffer is guaranteed to be a multiple of the alignment. */ + virtual std::size_t get_alignment() const { return 1; } /** Updates the offsets for the chain so that data from different objects does not overlap. Should be called if either data size or alignment changes. */ void update_offset(); - /** Returns the offset where the data should be uploaded. */ - unsigned get_offset() const { return offset; } + /* Indicates that the data of the bufferable has changed and should be + uploaded to the buffer again. */ + void mark_dirty(); - /** Called when the target buffer or offset within it has changed. */ - virtual void location_changed(Buffer *, unsigned, unsigned) const { } +public: + /** Returns the offset of the data from the beginning of the buffer. */ + std::size_t get_offset() const { return offset; } private: /** Uploads data to the buffer. Receives pointer to mapped buffer memory as parameter, or null to use the buffer upload interface. */ - void upload_data(char *) const; + void upload_data(unsigned, char *) const; + + AsyncUpdater *create_async_updater() const; }; } // namespace GL