mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Enable (when available) and improve performance of persistently mapped buffer path for the vertex/index buffers used with automatic batching.
--HG-- branch : minor
This commit is contained in:
+2
-2
@@ -542,10 +542,10 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
|
|||||||
set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
|
set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
|
||||||
src/modules/graphics/opengl/Buffer.cpp
|
src/modules/graphics/opengl/Buffer.cpp
|
||||||
src/modules/graphics/opengl/Buffer.h
|
src/modules/graphics/opengl/Buffer.h
|
||||||
src/modules/graphics/opengl/BufferSync.cpp
|
|
||||||
src/modules/graphics/opengl/BufferSync.h
|
|
||||||
src/modules/graphics/opengl/Canvas.cpp
|
src/modules/graphics/opengl/Canvas.cpp
|
||||||
src/modules/graphics/opengl/Canvas.h
|
src/modules/graphics/opengl/Canvas.h
|
||||||
|
src/modules/graphics/opengl/FenceSync.cpp
|
||||||
|
src/modules/graphics/opengl/FenceSync.h
|
||||||
src/modules/graphics/opengl/Graphics.cpp
|
src/modules/graphics/opengl/Graphics.cpp
|
||||||
src/modules/graphics/opengl/Graphics.h
|
src/modules/graphics/opengl/Graphics.h
|
||||||
src/modules/graphics/opengl/Image.cpp
|
src/modules/graphics/opengl/Image.cpp
|
||||||
|
|||||||
@@ -844,9 +844,9 @@
|
|||||||
FA27B3C11B4985BF008A9DCE /* wrap_VideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3B91B4985BF008A9DCE /* wrap_VideoStream.cpp */; };
|
FA27B3C11B4985BF008A9DCE /* wrap_VideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3B91B4985BF008A9DCE /* wrap_VideoStream.cpp */; };
|
||||||
FA27B3C21B4985BF008A9DCE /* wrap_VideoStream.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B3BA1B4985BF008A9DCE /* wrap_VideoStream.h */; };
|
FA27B3C21B4985BF008A9DCE /* wrap_VideoStream.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B3BA1B4985BF008A9DCE /* wrap_VideoStream.h */; };
|
||||||
FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3C81B498623008A9DCE /* Theora.framework */; };
|
FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3C81B498623008A9DCE /* Theora.framework */; };
|
||||||
FA28EBD51E352DB5003446F4 /* BufferSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA28EBD31E352DB5003446F4 /* BufferSync.cpp */; };
|
FA28EBD51E352DB5003446F4 /* FenceSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA28EBD31E352DB5003446F4 /* FenceSync.cpp */; };
|
||||||
FA28EBD61E352DB5003446F4 /* BufferSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA28EBD31E352DB5003446F4 /* BufferSync.cpp */; };
|
FA28EBD61E352DB5003446F4 /* FenceSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA28EBD31E352DB5003446F4 /* FenceSync.cpp */; };
|
||||||
FA28EBD71E352DB5003446F4 /* BufferSync.h in Headers */ = {isa = PBXBuildFile; fileRef = FA28EBD41E352DB5003446F4 /* BufferSync.h */; };
|
FA28EBD71E352DB5003446F4 /* FenceSync.h in Headers */ = {isa = PBXBuildFile; fileRef = FA28EBD41E352DB5003446F4 /* FenceSync.h */; };
|
||||||
FA29C0051E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
|
FA29C0051E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
|
||||||
FA29C0061E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
|
FA29C0061E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
|
||||||
FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; };
|
FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; };
|
||||||
@@ -1738,8 +1738,8 @@
|
|||||||
FA27B3C81B498623008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
|
FA27B3C81B498623008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
|
||||||
FA283EDC1B27CFAA00C70067 /* nogame.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = nogame.lua; sourceTree = "<group>"; };
|
FA283EDC1B27CFAA00C70067 /* nogame.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = nogame.lua; sourceTree = "<group>"; };
|
||||||
FA283EDD1B27CFAA00C70067 /* nogame.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nogame.lua.h; sourceTree = "<group>"; };
|
FA283EDD1B27CFAA00C70067 /* nogame.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nogame.lua.h; sourceTree = "<group>"; };
|
||||||
FA28EBD31E352DB5003446F4 /* BufferSync.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BufferSync.cpp; sourceTree = "<group>"; };
|
FA28EBD31E352DB5003446F4 /* FenceSync.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FenceSync.cpp; sourceTree = "<group>"; };
|
||||||
FA28EBD41E352DB5003446F4 /* BufferSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BufferSync.h; sourceTree = "<group>"; };
|
FA28EBD41E352DB5003446F4 /* FenceSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FenceSync.h; sourceTree = "<group>"; };
|
||||||
FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamBuffer.cpp; sourceTree = "<group>"; };
|
FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamBuffer.cpp; sourceTree = "<group>"; };
|
||||||
FA2AF6711DAC76FF0032B62C /* vertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vertex.h; sourceTree = "<group>"; };
|
FA2AF6711DAC76FF0032B62C /* vertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vertex.h; sourceTree = "<group>"; };
|
||||||
FA2AF6721DAD62710032B62C /* StreamBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = "<group>"; };
|
FA2AF6721DAD62710032B62C /* StreamBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = "<group>"; };
|
||||||
@@ -2733,10 +2733,10 @@
|
|||||||
children = (
|
children = (
|
||||||
FA0B7BA41A95902C000E1D17 /* Buffer.cpp */,
|
FA0B7BA41A95902C000E1D17 /* Buffer.cpp */,
|
||||||
FA0B7BA51A95902C000E1D17 /* Buffer.h */,
|
FA0B7BA51A95902C000E1D17 /* Buffer.h */,
|
||||||
FA28EBD31E352DB5003446F4 /* BufferSync.cpp */,
|
|
||||||
FA28EBD41E352DB5003446F4 /* BufferSync.h */,
|
|
||||||
FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */,
|
FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */,
|
||||||
FA0B7B8E1A95902C000E1D17 /* Canvas.h */,
|
FA0B7B8E1A95902C000E1D17 /* Canvas.h */,
|
||||||
|
FA28EBD31E352DB5003446F4 /* FenceSync.cpp */,
|
||||||
|
FA28EBD41E352DB5003446F4 /* FenceSync.h */,
|
||||||
FA0B7B911A95902C000E1D17 /* Graphics.cpp */,
|
FA0B7B911A95902C000E1D17 /* Graphics.cpp */,
|
||||||
FA0B7B921A95902C000E1D17 /* Graphics.h */,
|
FA0B7B921A95902C000E1D17 /* Graphics.h */,
|
||||||
FA0B7B931A95902C000E1D17 /* Image.cpp */,
|
FA0B7B931A95902C000E1D17 /* Image.cpp */,
|
||||||
@@ -3837,7 +3837,7 @@
|
|||||||
FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */,
|
FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */,
|
||||||
FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */,
|
FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */,
|
||||||
FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */,
|
FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */,
|
||||||
FA28EBD71E352DB5003446F4 /* BufferSync.h in Headers */,
|
FA28EBD71E352DB5003446F4 /* FenceSync.h in Headers */,
|
||||||
FADF542C1E3DAADA00012CC0 /* wrap_Mesh.h in Headers */,
|
FADF542C1E3DAADA00012CC0 /* wrap_Mesh.h in Headers */,
|
||||||
FAA3A9B01B7D465A00CED060 /* android.h in Headers */,
|
FAA3A9B01B7D465A00CED060 /* android.h in Headers */,
|
||||||
217DFBDE1D9F6D490055D849 /* compat.h in Headers */,
|
217DFBDE1D9F6D490055D849 /* compat.h in Headers */,
|
||||||
@@ -4253,7 +4253,7 @@
|
|||||||
FA57FB991AE1993600F2AD6D /* noise1234.cpp in Sources */,
|
FA57FB991AE1993600F2AD6D /* noise1234.cpp in Sources */,
|
||||||
FA0B7E221A95902C000E1D17 /* PolygonShape.cpp in Sources */,
|
FA0B7E221A95902C000E1D17 /* PolygonShape.cpp in Sources */,
|
||||||
FA0B7A651A958EA3000E1D17 /* b2Fixture.cpp in Sources */,
|
FA0B7A651A958EA3000E1D17 /* b2Fixture.cpp in Sources */,
|
||||||
FA28EBD61E352DB5003446F4 /* BufferSync.cpp in Sources */,
|
FA28EBD61E352DB5003446F4 /* FenceSync.cpp in Sources */,
|
||||||
FA0B7D521A95902C000E1D17 /* Text.cpp in Sources */,
|
FA0B7D521A95902C000E1D17 /* Text.cpp in Sources */,
|
||||||
FA0B7DA31A95902C000E1D17 /* PKMHandler.cpp in Sources */,
|
FA0B7DA31A95902C000E1D17 /* PKMHandler.cpp in Sources */,
|
||||||
FA0B7AB21A958EA3000E1D17 /* b2Rope.cpp in Sources */,
|
FA0B7AB21A958EA3000E1D17 /* b2Rope.cpp in Sources */,
|
||||||
@@ -4613,7 +4613,7 @@
|
|||||||
FA0B7EA61A95902C000E1D17 /* wrap_Decoder.cpp in Sources */,
|
FA0B7EA61A95902C000E1D17 /* wrap_Decoder.cpp in Sources */,
|
||||||
217DFBF21D9F6D490055D849 /* mime.c in Sources */,
|
217DFBF21D9F6D490055D849 /* mime.c in Sources */,
|
||||||
217DFBDF1D9F6D490055D849 /* except.c in Sources */,
|
217DFBDF1D9F6D490055D849 /* except.c in Sources */,
|
||||||
FA28EBD51E352DB5003446F4 /* BufferSync.cpp in Sources */,
|
FA28EBD51E352DB5003446F4 /* FenceSync.cpp in Sources */,
|
||||||
FA0B7E1B1A95902C000E1D17 /* MouseJoint.cpp in Sources */,
|
FA0B7E1B1A95902C000E1D17 /* MouseJoint.cpp in Sources */,
|
||||||
FA0B7CF41A95902C000E1D17 /* File.cpp in Sources */,
|
FA0B7CF41A95902C000E1D17 /* File.cpp in Sources */,
|
||||||
FA0B7E331A95902C000E1D17 /* WeldJoint.cpp in Sources */,
|
FA0B7E331A95902C000E1D17 /* WeldJoint.cpp in Sources */,
|
||||||
|
|||||||
@@ -798,7 +798,7 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawCommand &
|
|||||||
if (state.vbMap[i].data != nullptr && datasize > state.vbMap[i].size)
|
if (state.vbMap[i].data != nullptr && datasize > state.vbMap[i].size)
|
||||||
shouldflush = true;
|
shouldflush = true;
|
||||||
|
|
||||||
if (datasize > state.vb[i]->getSize())
|
if (datasize > state.vb[i]->getUsableSize())
|
||||||
{
|
{
|
||||||
buffersizes[i] = std::max(datasize, state.vb[i]->getSize() * 2);
|
buffersizes[i] = std::max(datasize, state.vb[i]->getSize() * 2);
|
||||||
shouldresize = true;
|
shouldresize = true;
|
||||||
@@ -814,7 +814,7 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawCommand &
|
|||||||
if (state.indexBufferMap.data != nullptr && datasize > state.indexBufferMap.size)
|
if (state.indexBufferMap.data != nullptr && datasize > state.indexBufferMap.size)
|
||||||
shouldflush = true;
|
shouldflush = true;
|
||||||
|
|
||||||
if (datasize > state.indexBuffer->getSize())
|
if (datasize > state.indexBuffer->getUsableSize())
|
||||||
{
|
{
|
||||||
buffersizes[2] = std::max(datasize, state.indexBuffer->getSize() * 2);
|
buffersizes[2] = std::max(datasize, state.indexBuffer->getSize() * 2);
|
||||||
shouldresize = true;
|
shouldresize = true;
|
||||||
|
|||||||
@@ -54,10 +54,13 @@ public:
|
|||||||
size_t getSize() const { return bufferSize; }
|
size_t getSize() const { return bufferSize; }
|
||||||
BufferType getMode() const { return mode; }
|
BufferType getMode() const { return mode; }
|
||||||
|
|
||||||
|
virtual size_t getUsableSize() const = 0;
|
||||||
virtual MapInfo map(size_t minsize) = 0;
|
virtual MapInfo map(size_t minsize) = 0;
|
||||||
virtual size_t unmap(size_t usedsize) = 0;
|
virtual size_t unmap(size_t usedsize) = 0;
|
||||||
virtual void markUsed(size_t usedsize) = 0;
|
virtual void markUsed(size_t usedsize) = 0;
|
||||||
|
|
||||||
|
virtual void nextFrame() {}
|
||||||
|
|
||||||
virtual ptrdiff_t getHandle() const = 0;
|
virtual ptrdiff_t getHandle() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
+54
-1
@@ -19,7 +19,7 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
||||||
#include "BufferSync.h"
|
#include "FenceSync.h"
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
@@ -28,6 +28,59 @@ namespace graphics
|
|||||||
namespace opengl
|
namespace opengl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
FenceSync::~FenceSync()
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FenceSync::fence()
|
||||||
|
{
|
||||||
|
bool wasActive = sync != 0;
|
||||||
|
|
||||||
|
if (wasActive)
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
|
||||||
|
return !wasActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FenceSync::cpuWait()
|
||||||
|
{
|
||||||
|
if (sync == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GLbitfield flags = 0;
|
||||||
|
GLuint64 duration = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
GLenum status = glClientWaitSync(sync, flags, duration);
|
||||||
|
|
||||||
|
if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (status == GL_WAIT_FAILED)
|
||||||
|
break;
|
||||||
|
|
||||||
|
flags = GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||||
|
duration = 1000000000; // 1 second in nanoseconds.
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FenceSync::cleanup()
|
||||||
|
{
|
||||||
|
if (sync != 0)
|
||||||
|
{
|
||||||
|
glDeleteSync(sync);
|
||||||
|
sync = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BufferSync::~BufferSync()
|
BufferSync::~BufferSync()
|
||||||
{
|
{
|
||||||
cleanup();
|
cleanup();
|
||||||
@@ -34,6 +34,22 @@ namespace graphics
|
|||||||
namespace opengl
|
namespace opengl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class FenceSync
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
~FenceSync();
|
||||||
|
|
||||||
|
bool fence();
|
||||||
|
bool cpuWait();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
GLsync sync;
|
||||||
|
|
||||||
|
}; // FenceSync
|
||||||
|
|
||||||
class BufferSync
|
class BufferSync
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -1004,6 +1004,10 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
glBindRenderbuffer(GL_RENDERBUFFER, info.info.uikit.colorbuffer);
|
glBindRenderbuffer(GL_RENDERBUFFER, info.info.uikit.colorbuffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
for (StreamBuffer *buffer : streamBufferState.vb)
|
||||||
|
buffer->nextFrame();
|
||||||
|
streamBufferState.indexBuffer->nextFrame();
|
||||||
|
|
||||||
auto window = getInstance<love::window::Window>(M_WINDOW);
|
auto window = getInstance<love::window::Window>(M_WINDOW);
|
||||||
if (window != nullptr)
|
if (window != nullptr)
|
||||||
window->swapBuffers();
|
window->swapBuffers();
|
||||||
|
|||||||
@@ -18,13 +18,15 @@
|
|||||||
* 3. This notice may not be removed or altered from any source distribution.
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
#include "common/config.h"
|
||||||
#include "StreamBuffer.h"
|
#include "StreamBuffer.h"
|
||||||
#include "OpenGL.h"
|
#include "OpenGL.h"
|
||||||
#include "BufferSync.h"
|
#include "FenceSync.h"
|
||||||
#include "graphics/Volatile.h"
|
#include "graphics/Volatile.h"
|
||||||
#include "common/Exception.h"
|
#include "common/Exception.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
@@ -33,7 +35,8 @@ namespace graphics
|
|||||||
namespace opengl
|
namespace opengl
|
||||||
{
|
{
|
||||||
|
|
||||||
static int BUFFER_FRAMES = 3;
|
static const int BUFFER_FRAMES = 3;
|
||||||
|
static const int MAX_SYNCS_PER_FRAME = 4;
|
||||||
|
|
||||||
class StreamBufferClientMemory final : public love::graphics::StreamBuffer
|
class StreamBufferClientMemory final : public love::graphics::StreamBuffer
|
||||||
{
|
{
|
||||||
@@ -58,6 +61,11 @@ public:
|
|||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t getUsableSize() const override
|
||||||
|
{
|
||||||
|
return bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
MapInfo map(size_t /*minsize*/) override
|
MapInfo map(size_t /*minsize*/) override
|
||||||
{
|
{
|
||||||
return MapInfo(data, bufferSize);
|
return MapInfo(data, bufferSize);
|
||||||
@@ -87,6 +95,7 @@ public:
|
|||||||
, glMode(OpenGL::getGLBufferType(mode))
|
, glMode(OpenGL::getGLBufferType(mode))
|
||||||
, data(nullptr)
|
, data(nullptr)
|
||||||
, offset(0)
|
, offset(0)
|
||||||
|
, frameOffset(0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -106,11 +115,17 @@ public:
|
|||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t getUsableSize() const override
|
||||||
|
{
|
||||||
|
return bufferSize - frameOffset;
|
||||||
|
}
|
||||||
|
|
||||||
MapInfo map(size_t minsize) override
|
MapInfo map(size_t minsize) override
|
||||||
{
|
{
|
||||||
if (offset + minsize > bufferSize)
|
if (offset + minsize > bufferSize)
|
||||||
{
|
{
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
frameOffset = 0;
|
||||||
gl.bindBuffer(mode, vbo);
|
gl.bindBuffer(mode, vbo);
|
||||||
glBufferData(glMode, bufferSize, nullptr, GL_STREAM_DRAW);
|
glBufferData(glMode, bufferSize, nullptr, GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
@@ -128,6 +143,12 @@ public:
|
|||||||
void markUsed(size_t usedsize) override
|
void markUsed(size_t usedsize) override
|
||||||
{
|
{
|
||||||
offset += usedsize;
|
offset += usedsize;
|
||||||
|
frameOffset += usedsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nextFrame() override
|
||||||
|
{
|
||||||
|
frameOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t getHandle() const override { return vbo; }
|
ptrdiff_t getHandle() const override { return vbo; }
|
||||||
@@ -142,6 +163,7 @@ public:
|
|||||||
glBufferData(glMode, bufferSize, nullptr, GL_STREAM_DRAW);
|
glBufferData(glMode, bufferSize, nullptr, GL_STREAM_DRAW);
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
frameOffset = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -163,17 +185,69 @@ protected:
|
|||||||
uint8 *data;
|
uint8 *data;
|
||||||
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
size_t frameOffset;
|
||||||
|
|
||||||
}; // StreamBufferSubDataOrphan
|
}; // StreamBufferSubDataOrphan
|
||||||
|
|
||||||
class StreamBufferMapSync final : public love::graphics::StreamBuffer, public Volatile
|
class StreamBufferSync : public love::graphics::StreamBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
StreamBufferSync(BufferType type, size_t size)
|
||||||
|
: love::graphics::StreamBuffer(type, size)
|
||||||
|
, syncSize((size + MAX_SYNCS_PER_FRAME - 1) / MAX_SYNCS_PER_FRAME)
|
||||||
|
, frameIndex(0)
|
||||||
|
, frameGPUReadOffset(0)
|
||||||
|
, syncs()
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~StreamBufferSync() {}
|
||||||
|
|
||||||
|
void nextFrame() override
|
||||||
|
{
|
||||||
|
getCurrentSync()->fence();
|
||||||
|
|
||||||
|
frameIndex = (frameIndex + 1) % BUFFER_FRAMES;
|
||||||
|
frameGPUReadOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void markUsed(size_t usedsize) override
|
||||||
|
{
|
||||||
|
int firstSyncIndex = frameGPUReadOffset / syncSize;
|
||||||
|
int lastSyncIndex = std::min((frameGPUReadOffset + usedsize), bufferSize - 1) / syncSize;
|
||||||
|
|
||||||
|
// Insert fences for all sync buckets completely filled by this section
|
||||||
|
// of the data. The last bucket before the end of the frame will also be
|
||||||
|
// handled by nextFrame().
|
||||||
|
for (int i = firstSyncIndex; i < lastSyncIndex; i++)
|
||||||
|
syncs[frameIndex * MAX_SYNCS_PER_FRAME + i].fence();
|
||||||
|
|
||||||
|
frameGPUReadOffset += usedsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
const size_t syncSize;
|
||||||
|
|
||||||
|
int frameIndex;
|
||||||
|
size_t frameGPUReadOffset;
|
||||||
|
|
||||||
|
FenceSync syncs[MAX_SYNCS_PER_FRAME * BUFFER_FRAMES];
|
||||||
|
|
||||||
|
FenceSync *getCurrentSync()
|
||||||
|
{
|
||||||
|
return &syncs[frameIndex * MAX_SYNCS_PER_FRAME + frameGPUReadOffset / syncSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // StreamBufferSync
|
||||||
|
|
||||||
|
class StreamBufferMapSync final : public StreamBufferSync, public Volatile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
StreamBufferMapSync(BufferType type, size_t size)
|
StreamBufferMapSync(BufferType type, size_t size)
|
||||||
: love::graphics::StreamBuffer(type, size)
|
: StreamBufferSync(type, size)
|
||||||
, vbo(0)
|
, vbo(0)
|
||||||
, gpuReadOffset(0)
|
|
||||||
, glMode(OpenGL::getGLBufferType(mode))
|
, glMode(OpenGL::getGLBufferType(mode))
|
||||||
{
|
{
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
@@ -184,21 +258,32 @@ public:
|
|||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
MapInfo map(size_t minsize) override
|
size_t getUsableSize() const override
|
||||||
|
{
|
||||||
|
return bufferSize - frameGPUReadOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapInfo map(size_t /*minsize*/) override
|
||||||
{
|
{
|
||||||
gl.bindBuffer(mode, vbo);
|
gl.bindBuffer(mode, vbo);
|
||||||
|
|
||||||
if (gpuReadOffset + minsize > bufferSize * BUFFER_FRAMES)
|
|
||||||
gpuReadOffset = 0;
|
|
||||||
|
|
||||||
MapInfo info;
|
MapInfo info;
|
||||||
info.size = bufferSize - (gpuReadOffset % bufferSize);
|
info.size = bufferSize - frameGPUReadOffset;
|
||||||
|
|
||||||
sync.wait(gpuReadOffset, info.size);
|
int firstSyncIndex = frameGPUReadOffset / syncSize;
|
||||||
|
int lastSyncIndex = (bufferSize - 1) / syncSize;
|
||||||
|
|
||||||
|
// We're mapping the full range of space left in the buffer, so we
|
||||||
|
// need to wait on all of it...
|
||||||
|
// FIXME: is it even worth it to have multiple sync objects per frame?
|
||||||
|
for (int i = firstSyncIndex; i <= lastSyncIndex; i++)
|
||||||
|
syncs[frameIndex * MAX_SYNCS_PER_FRAME + i].cpuWait();
|
||||||
|
|
||||||
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
|
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
|
||||||
|
|
||||||
info.data = (uint8 *) glMapBufferRange(glMode, gpuReadOffset, info.size, flags);
|
size_t mapoffset = (frameIndex * bufferSize) + frameGPUReadOffset;
|
||||||
|
info.data = (uint8 *) glMapBufferRange(glMode, mapoffset, info.size, flags);
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +293,7 @@ public:
|
|||||||
glFlushMappedBufferRange(glMode, 0, usedsize);
|
glFlushMappedBufferRange(glMode, 0, usedsize);
|
||||||
glUnmapBuffer(glMode);
|
glUnmapBuffer(glMode);
|
||||||
|
|
||||||
return gpuReadOffset;
|
return (frameIndex * bufferSize) + frameGPUReadOffset;
|
||||||
}
|
|
||||||
|
|
||||||
void markUsed(size_t usedsize) override
|
|
||||||
{
|
|
||||||
sync.lock(gpuReadOffset, usedsize);
|
|
||||||
gpuReadOffset += usedsize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t getHandle() const override { return vbo; }
|
ptrdiff_t getHandle() const override { return vbo; }
|
||||||
@@ -228,40 +307,38 @@ public:
|
|||||||
gl.bindBuffer(mode, vbo);
|
gl.bindBuffer(mode, vbo);
|
||||||
glBufferData(glMode, bufferSize * BUFFER_FRAMES, nullptr, GL_STREAM_DRAW);
|
glBufferData(glMode, bufferSize * BUFFER_FRAMES, nullptr, GL_STREAM_DRAW);
|
||||||
|
|
||||||
gpuReadOffset = 0;
|
frameGPUReadOffset = 0;
|
||||||
|
frameIndex = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadVolatile() override
|
void unloadVolatile() override
|
||||||
{
|
{
|
||||||
if (vbo == 0)
|
if (vbo != 0)
|
||||||
return;
|
{
|
||||||
|
gl.deleteBuffer(vbo);
|
||||||
|
vbo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
gl.deleteBuffer(vbo);
|
for (FenceSync &sync : syncs)
|
||||||
vbo = 0;
|
sync.cleanup();
|
||||||
|
|
||||||
sync.cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
GLuint vbo;
|
GLuint vbo;
|
||||||
size_t gpuReadOffset;
|
|
||||||
GLenum glMode;
|
GLenum glMode;
|
||||||
|
|
||||||
BufferSync sync;
|
|
||||||
|
|
||||||
}; // StreamBufferMapSync
|
}; // StreamBufferMapSync
|
||||||
|
|
||||||
class StreamBufferPersistentMapSync final : public love::graphics::StreamBuffer, public Volatile
|
class StreamBufferPersistentMapSync final : public StreamBufferSync, public Volatile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
StreamBufferPersistentMapSync(BufferType type, size_t size)
|
StreamBufferPersistentMapSync(BufferType type, size_t size)
|
||||||
: love::graphics::StreamBuffer(type, size)
|
: StreamBufferSync(type, size)
|
||||||
, vbo(0)
|
, vbo(0)
|
||||||
, gpuReadOffset(0)
|
|
||||||
, glMode(OpenGL::getGLBufferType(mode))
|
, glMode(OpenGL::getGLBufferType(mode))
|
||||||
, data(nullptr)
|
, data(nullptr)
|
||||||
{
|
{
|
||||||
@@ -273,32 +350,37 @@ public:
|
|||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
MapInfo map(size_t minsize) override
|
size_t getUsableSize() const override
|
||||||
{
|
{
|
||||||
if (gpuReadOffset + minsize > bufferSize * BUFFER_FRAMES)
|
return bufferSize - frameGPUReadOffset;
|
||||||
gpuReadOffset = 0;
|
}
|
||||||
|
|
||||||
|
MapInfo map(size_t /*minsize*/) override
|
||||||
|
{
|
||||||
MapInfo info;
|
MapInfo info;
|
||||||
info.size = bufferSize - (gpuReadOffset % bufferSize);
|
info.size = bufferSize - frameGPUReadOffset;
|
||||||
info.data = data + gpuReadOffset;
|
info.data = data + (frameIndex * bufferSize) + frameGPUReadOffset;
|
||||||
|
|
||||||
sync.wait(gpuReadOffset, info.size);
|
int firstSyncIndex = frameGPUReadOffset / syncSize;
|
||||||
|
int lastSyncIndex = (bufferSize - 1) / syncSize;
|
||||||
|
|
||||||
|
// We're mapping the full range of space left in the buffer, so we
|
||||||
|
// need to wait on all of it...
|
||||||
|
// FIXME: is it even worth it to have multiple sync objects per frame?
|
||||||
|
for (int i = firstSyncIndex; i <= lastSyncIndex; i++)
|
||||||
|
syncs[frameIndex * MAX_SYNCS_PER_FRAME + i].cpuWait();
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t unmap(size_t usedsize) override
|
size_t unmap(size_t usedsize) override
|
||||||
{
|
{
|
||||||
|
size_t offset = (frameIndex * bufferSize) + frameGPUReadOffset;
|
||||||
|
|
||||||
gl.bindBuffer(mode, vbo);
|
gl.bindBuffer(mode, vbo);
|
||||||
glFlushMappedBufferRange(glMode, gpuReadOffset, usedsize);
|
glFlushMappedBufferRange(glMode, offset, usedsize);
|
||||||
|
|
||||||
return gpuReadOffset;
|
return offset;
|
||||||
}
|
|
||||||
|
|
||||||
void markUsed(size_t usedsize) override
|
|
||||||
{
|
|
||||||
sync.lock(gpuReadOffset, usedsize);
|
|
||||||
gpuReadOffset += usedsize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t getHandle() const override { return vbo; }
|
ptrdiff_t getHandle() const override { return vbo; }
|
||||||
@@ -317,46 +399,41 @@ public:
|
|||||||
glBufferStorage(glMode, bufferSize * BUFFER_FRAMES, nullptr, storageflags);
|
glBufferStorage(glMode, bufferSize * BUFFER_FRAMES, nullptr, storageflags);
|
||||||
data = (uint8 *) glMapBufferRange(glMode, 0, bufferSize * BUFFER_FRAMES, mapflags);
|
data = (uint8 *) glMapBufferRange(glMode, 0, bufferSize * BUFFER_FRAMES, mapflags);
|
||||||
|
|
||||||
gpuReadOffset = 0;
|
frameGPUReadOffset = 0;
|
||||||
|
frameIndex = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadVolatile() override
|
void unloadVolatile() override
|
||||||
{
|
{
|
||||||
if (vbo == 0)
|
if (vbo != 0)
|
||||||
return;
|
{
|
||||||
|
gl.bindBuffer(mode, vbo);
|
||||||
|
glUnmapBuffer(glMode);
|
||||||
|
gl.deleteBuffer(vbo);
|
||||||
|
vbo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
gl.bindBuffer(mode, vbo);
|
for (FenceSync &sync : syncs)
|
||||||
glUnmapBuffer(glMode);
|
sync.cleanup();
|
||||||
gl.deleteBuffer(vbo);
|
|
||||||
vbo = 0;
|
|
||||||
|
|
||||||
sync.cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
GLuint vbo;
|
GLuint vbo;
|
||||||
size_t gpuReadOffset;
|
|
||||||
GLenum glMode;
|
GLenum glMode;
|
||||||
uint8 *data;
|
uint8 *data;
|
||||||
|
|
||||||
BufferSync sync;
|
|
||||||
|
|
||||||
}; // StreamBufferPersistentMapSync
|
}; // StreamBufferPersistentMapSync
|
||||||
|
|
||||||
love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size)
|
love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size)
|
||||||
{
|
{
|
||||||
if (gl.isCoreProfile())
|
if (gl.isCoreProfile())
|
||||||
{
|
{
|
||||||
// FIXME: This is disabled until more efficient manual syncing can be
|
|
||||||
// implemented.
|
|
||||||
#if 0
|
|
||||||
if (GLAD_VERSION_4_4 || GLAD_ARB_buffer_storage)
|
if (GLAD_VERSION_4_4 || GLAD_ARB_buffer_storage)
|
||||||
return new StreamBufferPersistentMapSync(mode, size);
|
return new StreamBufferPersistentMapSync(mode, size);
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
return new StreamBufferSubDataOrphan(mode, size);
|
return new StreamBufferSubDataOrphan(mode, size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user