Replace internal 'staging' buffer data type with new 'readback' type.

This commit is contained in:
Alex Szpakowski
2022-05-30 21:43:25 -03:00
parent 7b66e50cfc
commit a533982cb4
10 changed files with 97 additions and 46 deletions
+3 -2
View File
@@ -36,6 +36,7 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
, usageFlags(settings.usageFlags)
, dataUsage(settings.dataUsage)
, mapped(false)
, mappedType(MAP_WRITE_INVALIDATE)
, immutable(false)
{
if (size == 0 && arraylength == 0)
@@ -61,8 +62,8 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
if (storagebuffer && dataUsage == BUFFERDATAUSAGE_STREAM)
throw love::Exception("Buffers created with 'stream' data usage cannot be used as a shader storage buffer.");
if (dataUsage == BUFFERDATAUSAGE_STAGING && (indexbuffer || vertexbuffer || texelbuffer || storagebuffer))
throw love::Exception("Buffers created with 'staging' data usage cannot be index, vertex, texel, or shaderstorage buffer types.");
if (dataUsage == BUFFERDATAUSAGE_READBACK && (indexbuffer || vertexbuffer || texelbuffer || storagebuffer))
throw love::Exception("Buffers created with 'readback' data usage cannot be index, vertex, texel, or shaderstorage buffer types.");
size_t offset = 0;
size_t stride = 0;
+5 -4
View File
@@ -53,6 +53,7 @@ public:
enum MapType
{
MAP_WRITE_INVALIDATE,
MAP_READ_ONLY,
};
struct DataDeclaration
@@ -128,7 +129,7 @@ public:
/**
* Fill a portion of the buffer with data.
*/
virtual void fill(size_t offset, size_t size, const void *data) = 0;
virtual bool fill(size_t offset, size_t size, const void *data) = 0;
/**
* Copy a portion of this Buffer's data to another buffer, using the GPU.
@@ -147,10 +148,10 @@ public:
{
public:
Mapper(Buffer &buffer)
Mapper(Buffer &buffer, MapType maptype = MAP_WRITE_INVALIDATE)
: buffer(buffer)
{
data = buffer.map(MAP_WRITE_INVALIDATE, 0, buffer.getSize());
data = buffer.map(maptype, 0, buffer.getSize());
}
~Mapper()
@@ -179,7 +180,7 @@ protected:
BufferDataUsage dataUsage;
bool mapped;
MapType mappedType;
bool immutable;
}; // Buffer
+6
View File
@@ -1181,6 +1181,9 @@ void Graphics::copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, siz
if (dest->getDataUsage() == BUFFERDATAUSAGE_STREAM)
throw love::Exception("Buffers created with 'stream' data usage cannot be used as a copy destination.");
if (source->getDataUsage() == BUFFERDATAUSAGE_READBACK)
throw love::Exception("Buffers created with 'readback' data usage cannot be used as a copy source.");
if (sourcerange.getMax() >= source->getSize())
throw love::Exception("Buffer copy source offset and size doesn't fit within the source Buffer's size.");
@@ -1290,6 +1293,9 @@ void Graphics::copyBufferToTexture(Buffer *source, Texture *dest, size_t sourceo
if (!capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE])
throw love::Exception("Copying a Buffer to a Texture is not supported on this system.");
if (source->getDataUsage() == BUFFERDATAUSAGE_READBACK)
throw love::Exception("Buffers created with 'readback' data usage cannot be used as a copy source.");
PixelFormat format = dest->getPixelFormat();
if (isPixelFormatDepthStencil(format))
+1 -1
View File
@@ -40,7 +40,7 @@ public:
void *map(MapType map, size_t offset, size_t size) override;
void unmap(size_t usedoffset, size_t usedsize) override;
void fill(size_t offset, size_t size, const void *data) override;
bool fill(size_t offset, size_t size, const void *data) override;
void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override;
ptrdiff_t getHandle() const override { return (ptrdiff_t) buffer; }
+38 -24
View File
@@ -18,7 +18,7 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
#import "Buffer.h"
#include "Buffer.h"
#include "Graphics.h"
namespace love
@@ -65,11 +65,16 @@ Buffer::Buffer(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settin
size = getSize();
arraylength = getArrayLength();
MTLResourceOptions opts = MTLResourceStorageModePrivate;
MTLResourceOptions opts = 0;
if (settings.dataUsage == BUFFERDATAUSAGE_READBACK)
opts |= MTLResourceStorageModeShared;
else
opts |= MTLResourceStorageModePrivate;
buffer = [device newBufferWithLength:size options:opts];
if (buffer == nil)
throw love::Exception("Could not create buffer (out of VRAM?)");
throw love::Exception("Could not create buffer with %d bytes (out of VRAM?)", size);
if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
{
@@ -109,16 +114,30 @@ Buffer::~Buffer()
texture = nil;
}}
void *Buffer::map(MapType /*map*/, size_t offset, size_t size)
void *Buffer::map(MapType map, size_t offset, size_t size)
{ @autoreleasepool {
if (size == 0 || isImmutable())
if (size == 0)
return nullptr;
if (map == MAP_WRITE_INVALIDATE && (isImmutable() || dataUsage == BUFFERDATAUSAGE_READBACK))
return nullptr;
if (map == MAP_READ_ONLY && dataUsage != BUFFERDATAUSAGE_READBACK)
return nullptr;
Range r(offset, size);
if (!Range(0, getSize()).contains(r))
return nullptr;
if (map == MAP_READ_ONLY)
{
mappedRange = r;
mapped = true;
mappedType = map;
return (char *) buffer.contents + offset;
}
auto gfx = Graphics::getInstance();
// TODO: Don't create a new buffer every time, also do something for stream
@@ -129,6 +148,7 @@ void *Buffer::map(MapType /*map*/, size_t offset, size_t size)
{
mappedRange = r;
mapped = true;
mappedType = map;
return mapBuffer.contents;
}
@@ -137,6 +157,12 @@ void *Buffer::map(MapType /*map*/, size_t offset, size_t size)
void Buffer::unmap(size_t usedoffset, size_t usedsize)
{ @autoreleasepool {
if (mappedType == MAP_READ_ONLY)
{
mapped = false;
return;
}
if (mapBuffer == nil)
return;
@@ -158,29 +184,17 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
mapped = false;
}}
void Buffer::fill(size_t offset, size_t size, const void *data)
bool Buffer::fill(size_t offset, size_t size, const void *data)
{ @autoreleasepool {
if (size == 0 || isImmutable())
return;
void *dest = map(MAP_WRITE_INVALIDATE, offset, size);
size_t buffersize = getSize();
if (dest == nullptr)
return false;
if (!Range(0, buffersize).contains(Range(offset, size)))
return;
memcpy(dest, data, size);
// TODO: Don't create a new buffer every time, also do something for stream
// buffers.
auto gfx = Graphics::getInstance();
auto encoder = gfx->useBlitEncoder();
auto tempbuffer = [gfx->device newBufferWithLength:size options:MTLResourceStorageModeShared];
memcpy(tempbuffer.contents, data, size);
[encoder copyFromBuffer:tempbuffer
sourceOffset:0
toBuffer:buffer
destinationOffset:offset
size:size];
unmap(offset, size);
return true;
}}
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
+35 -8
View File
@@ -103,7 +103,7 @@ Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const st
if (!load(data))
{
unloadVolatile();
throw love::Exception("Could not create buffer (out of VRAM?)");
throw love::Exception("Could not create buffer with %d bytes (out of VRAM?)", size);
}
}
@@ -164,11 +164,17 @@ bool Buffer::supportsOrphan() const
return dataUsage == BUFFERDATAUSAGE_STREAM || dataUsage == BUFFERDATAUSAGE_DYNAMIC;
}
void *Buffer::map(MapType /*map*/, size_t offset, size_t size)
void *Buffer::map(MapType map, size_t offset, size_t size)
{
if (size == 0 || isImmutable())
if (size == 0)
return nullptr;
if (map == MAP_WRITE_INVALIDATE && (isImmutable() || dataUsage == BUFFERDATAUSAGE_READBACK))
return nullptr;
if (map == MAP_READ_ONLY && dataUsage != BUFFERDATAUSAGE_READBACK)
return nullptr;
Range r(offset, size);
if (!Range(0, getSize()).contains(r))
@@ -176,7 +182,16 @@ void *Buffer::map(MapType /*map*/, size_t offset, size_t size)
char *data = nullptr;
if (ownsMemoryMap)
if (map == MAP_READ_ONLY)
{
gl.bindBuffer(mapUsage, buffer);
if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0)
data = (char *) glMapBufferRange(target, offset, size, GL_MAP_READ_BIT);
else if (GLAD_VERSION_1_1)
data = (char *) glMapBuffer(target, GL_READ_ONLY) + offset;
}
else if (ownsMemoryMap)
{
if (memoryMap == nullptr)
memoryMap = (char *) malloc(getSize());
@@ -191,6 +206,7 @@ void *Buffer::map(MapType /*map*/, size_t offset, size_t size)
if (data != nullptr)
{
mapped = true;
mappedType = map;
mappedRange = r;
if (!ownsMemoryMap)
memoryMap = data;
@@ -208,6 +224,15 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
mapped = false;
if (mappedType == MAP_READ_ONLY)
{
gl.bindBuffer(mapUsage, buffer);
glUnmapBuffer(target);
if (!ownsMemoryMap)
memoryMap = nullptr;
return;
}
// Orphan optimization - see fill().
if (supportsOrphan() && mappedRange.first == 0 && mappedRange.getSize() == getSize())
{
@@ -227,15 +252,15 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
}
}
void Buffer::fill(size_t offset, size_t size, const void *data)
bool Buffer::fill(size_t offset, size_t size, const void *data)
{
if (size == 0 || isImmutable())
return;
if (size == 0 || isImmutable() || dataUsage == BUFFERDATAUSAGE_READBACK)
return false;
size_t buffersize = getSize();
if (!Range(0, buffersize).contains(Range(offset, size)))
return;
return false;
GLenum gldatausage = OpenGL::getGLBufferDataUsage(dataUsage);
@@ -259,6 +284,8 @@ void Buffer::fill(size_t offset, size_t size, const void *data)
{
glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, data);
}
return true;
}
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
+3 -1
View File
@@ -52,12 +52,14 @@ public:
void *map(MapType map, size_t offset, size_t size) override;
void unmap(size_t usedoffset, size_t usedsize) override;
void fill(size_t offset, size_t size, const void *data) override;
bool fill(size_t offset, size_t size, const void *data) override;
void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override;
ptrdiff_t getHandle() const override { return buffer; };
ptrdiff_t getTexelBufferHandle() const override { return texture; };
BufferUsage getMapUsage() const { return mapUsage; }
private:
bool load(const void *initialdata);
+1 -1
View File
@@ -843,7 +843,7 @@ GLenum OpenGL::getGLBufferDataUsage(BufferDataUsage usage)
case BUFFERDATAUSAGE_STREAM: return GL_STREAM_DRAW;
case BUFFERDATAUSAGE_DYNAMIC: return GL_DYNAMIC_DRAW;
case BUFFERDATAUSAGE_STATIC: return GL_STATIC_DRAW;
case BUFFERDATAUSAGE_STAGING:
case BUFFERDATAUSAGE_READBACK:
return (GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0) ? GL_STREAM_READ : GL_STREAM_DRAW;
default: return 0;
}
+4 -4
View File
@@ -383,10 +383,10 @@ STRINGMAP_END(IndexDataType, INDEX_MAX_ENUM, indexType)
STRINGMAP_BEGIN(BufferDataUsage, BUFFERDATAUSAGE_MAX_ENUM, bufferDataUsage)
{
{ "stream", BUFFERDATAUSAGE_STREAM },
{ "dynamic", BUFFERDATAUSAGE_DYNAMIC },
{ "static", BUFFERDATAUSAGE_STATIC },
{ "staging", BUFFERDATAUSAGE_STAGING },
{ "stream", BUFFERDATAUSAGE_STREAM },
{ "dynamic", BUFFERDATAUSAGE_DYNAMIC },
{ "static", BUFFERDATAUSAGE_STATIC },
{ "readback", BUFFERDATAUSAGE_READBACK },
}
STRINGMAP_END(BufferDataUsage, BUFFERDATAUSAGE_MAX_ENUM, bufferDataUsage)
+1 -1
View File
@@ -110,7 +110,7 @@ enum BufferDataUsage
BUFFERDATAUSAGE_STREAM,
BUFFERDATAUSAGE_DYNAMIC,
BUFFERDATAUSAGE_STATIC,
BUFFERDATAUSAGE_STAGING,
BUFFERDATAUSAGE_READBACK,
BUFFERDATAUSAGE_MAX_ENUM
};