virtual ~buffer_too_small() throw() { }
};
+enum BufferUsage
+{
+ STATIC,
+ STREAMING
+};
+
/**
Stores data in GPU memory.
then be modified either synchronously with the data() and sub_data() functions,
or asynchronously by memory-mapping the buffer.
+Buffers can have a static or streaming usage pattern. Streaming buffers can be
+memory mapped for less update overhead, but memory space is more limited. If
+the buffer is updated only rarely, static is recommended.
+
Applications normally don't need to deal with Buffers directly. They're
managed by other classes such as Mesh and ProgramData.
*/
{
friend BufferBackend;
+public:
+ /**
+ An RAII handle for asynchronously writing data into a buffer.
+ */
+ class AsyncTransfer: public NonCopyable
+ {
+ friend BufferBackend;
+ friend class Buffer;
+
+ private:
+ Buffer *buffer = 0;
+ std::size_t offset = 0;
+ std::size_t size = 0;
+ void *dest_addr = 0;
+
+ AsyncTransfer(Buffer &, std::size_t, std::size_t);
+ public:
+ AsyncTransfer() = default;
+ AsyncTransfer(AsyncTransfer &&);
+ AsyncTransfer &operator=(AsyncTransfer &&);
+ ~AsyncTransfer();
+
+ private:
+ void allocate();
+ void finalize();
+
+ public:
+ /** Returns an address for writing the data. It should not be used
+ beyond the lifetime of the object. */
+ void *get_address() { return dest_addr; }
+ };
+
private:
std::size_t size = 0;
+ BufferUsage usage = STATIC;
+ bool mapped = false;
public:
- /** Sets the storage size and allocates memory for the buffer. Size cannot
- be changed once set. */
- void storage(std::size_t);
+ /** Sets storage size and usage pattern and allocates memory for the buffer.
+ Size and usage cannot be changed once set. */
+ void storage(std::size_t, BufferUsage);
/** Replaces contents of the entire buffer. Allocated storage must exist.
The data must have size matching the defined storage. */
The range must be fully inside the buffer. */
void sub_data(std::size_t, std::size_t, const void *);
+ /** Creates an asynchronous transfer for writing data to a range of bytes in
+ the buffer. While the transfer is pending, the state of the buffer region
+ is indeterminate. */
+ AsyncTransfer sub_data_async(std::size_t, std::size_t);
+
+private:
+ void check_sub_data(std::size_t, std::size_t, const char *);
+
+public:
std::size_t get_size() const { return size; }
+ using BufferBackend::get_multiplicity;
+ std::size_t get_total_size() const { return size*get_multiplicity(); }
+ BufferUsage get_usage() const { return usage; }
void require_size(std::size_t) const;
- using BufferBackend::map;
- using BufferBackend::unmap;
+ void *map();
+ bool unmap();
using BufferBackend::set_debug_name;
};