mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Replace internal 'staging' buffer data type with new 'readback' type.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ enum BufferDataUsage
|
||||
BUFFERDATAUSAGE_STREAM,
|
||||
BUFFERDATAUSAGE_DYNAMIC,
|
||||
BUFFERDATAUSAGE_STATIC,
|
||||
BUFFERDATAUSAGE_STAGING,
|
||||
BUFFERDATAUSAGE_READBACK,
|
||||
BUFFERDATAUSAGE_MAX_ENUM
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user