From e2838131f236a5e7954e3a82410edfb9ba1d8254 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 17 Jan 2021 14:02:00 -0400 Subject: [PATCH] Add love.graphics.copyBuffer. --- src/common/Range.h | 5 +++++ src/modules/graphics/Buffer.cpp | 4 ++++ src/modules/graphics/Buffer.h | 7 ++++++ src/modules/graphics/Graphics.cpp | 27 ++++++++++++++++++++++++ src/modules/graphics/Graphics.h | 3 +++ src/modules/graphics/opengl/Buffer.cpp | 8 +++++++ src/modules/graphics/opengl/Buffer.h | 1 + src/modules/graphics/opengl/Graphics.cpp | 3 ++- src/modules/graphics/opengl/OpenGL.cpp | 5 +++++ src/modules/graphics/vertex.cpp | 2 ++ src/modules/graphics/vertex.h | 2 ++ src/modules/graphics/wrap_Graphics.cpp | 23 ++++++++++++++++++++ 12 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/common/Range.h b/src/common/Range.h index d150919f8..6dc892d5f 100644 --- a/src/common/Range.h +++ b/src/common/Range.h @@ -61,6 +61,11 @@ struct Range return first <= other.first && last >= other.last; } + bool intersects(const Range &other) + { + return !(first > other.last || last < other.first); + } + void encapsulate(size_t index) { first = std::min(first, index); diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp index aaf9b2228..6c34100f2 100644 --- a/src/modules/graphics/Buffer.cpp +++ b/src/modules/graphics/Buffer.cpp @@ -50,6 +50,7 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vectorgetTypeFlags() & Buffer::TYPEFLAG_COPY_SOURCE)) + throw love::Exception("Copy source buffer must be created with the copysource flag."); + + if (!(dest->getTypeFlags() & Buffer::TYPEFLAG_COPY_DEST)) + throw love::Exception("Copy destination buffer must be created with the copydest flag."); + + Range sourcerange(sourceoffset, size); + Range destrange(destoffset, size); + + if (sourcerange.getMax() >= source->getSize()) + throw love::Exception("Buffer copy source offset and size doesn't fit within the source Buffer's size."); + + if (destrange.getMax() >= dest->getSize()) + throw love::Exception("Buffer copy destination offset and size doesn't fit within the destination buffer's size."); + + if (source == dest && sourcerange.intersects(destrange)) + throw love::Exception("Copying a portion of a buffer to the same buffer requires non-overlapping source and destination offsets."); + + source->copyTo(dest, sourceoffset, destoffset, size); +} + Graphics::BatchedVertexData Graphics::requestBatchedDraw(const BatchedDrawCommand &cmd) { BatchedDrawState &state = batchedDrawState; @@ -1835,6 +1861,7 @@ STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, f { "glsl4", Graphics::FEATURE_GLSL4 }, { "instancing", Graphics::FEATURE_INSTANCING }, { "texelbuffer", Graphics::FEATURE_TEXEL_BUFFER }, + { "copybuffer", Graphics::FEATURE_COPY_BUFFER }, } STRINGMAP_CLASS_END(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index e7cc43a88..1bbdfff70 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -144,6 +144,7 @@ public: FEATURE_GLSL4, FEATURE_INSTANCING, FEATURE_TEXEL_BUFFER, + FEATURE_COPY_BUFFER, FEATURE_MAX_ENUM }; @@ -668,6 +669,8 @@ public: void captureScreenshot(const ScreenshotInfo &info); + void copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size); + void draw(Drawable *drawable, const Matrix4 &m); void draw(Texture *texture, Quad *quad, const Matrix4 &m); void drawLayer(Texture *texture, int layer, const Matrix4 &m); diff --git a/src/modules/graphics/opengl/Buffer.cpp b/src/modules/graphics/opengl/Buffer.cpp index a9e33c0f9..e6ace77ad 100644 --- a/src/modules/graphics/opengl/Buffer.cpp +++ b/src/modules/graphics/opengl/Buffer.cpp @@ -253,6 +253,14 @@ void Buffer::fill(size_t offset, size_t size, const void *data) } } +void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) +{ + gl.bindBuffer(BUFFERTYPE_COPY_SOURCE, buffer); + gl.bindBuffer(BUFFERTYPE_COPY_DEST, ((Buffer *) dest)->buffer); + + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, sourceoffset, destoffset, size); +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Buffer.h b/src/modules/graphics/opengl/Buffer.h index db0ae85fe..b875d862f 100644 --- a/src/modules/graphics/opengl/Buffer.h +++ b/src/modules/graphics/opengl/Buffer.h @@ -53,6 +53,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; + 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; }; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 9375e2161..1384fbd72 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1531,7 +1531,8 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3); capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported(); capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferTypeSupported(BUFFERTYPE_TEXEL); - static_assert(FEATURE_MAX_ENUM == 11, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + capabilities.features[FEATURE_COPY_BUFFER] = gl.isBufferTypeSupported(BUFFERTYPE_COPY_SOURCE); + static_assert(FEATURE_MAX_ENUM == 12, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize(); capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize(); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index d6522d6d5..e7d0ddb69 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -621,6 +621,8 @@ GLenum OpenGL::getGLBufferType(BufferType type) case BUFFERTYPE_INDEX: return GL_ELEMENT_ARRAY_BUFFER; case BUFFERTYPE_TEXEL: return GL_TEXTURE_BUFFER; case BUFFERTYPE_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER; + case BUFFERTYPE_COPY_SOURCE: return GL_COPY_READ_BUFFER; + case BUFFERTYPE_COPY_DEST: return GL_COPY_WRITE_BUFFER; case BUFFERTYPE_MAX_ENUM: return GL_ZERO; } @@ -1444,6 +1446,9 @@ bool OpenGL::isBufferTypeSupported(BufferType type) const return GLAD_VERSION_3_1; case BUFFERTYPE_SHADER_STORAGE: return (GLAD_VERSION_4_3 && isCoreProfile()) || GLAD_ES_VERSION_3_1; + case BUFFERTYPE_COPY_SOURCE: + case BUFFERTYPE_COPY_DEST: + return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0; case BUFFERTYPE_MAX_ENUM: return false; } diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index d448b9895..91c168edd 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -343,6 +343,8 @@ STRINGMAP_BEGIN(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName) { "index", BUFFERTYPE_INDEX }, { "texel", BUFFERTYPE_TEXEL }, { "shaderstorage", BUFFERTYPE_SHADER_STORAGE }, + { "copysource", BUFFERTYPE_COPY_SOURCE }, + { "copydest", BUFFERTYPE_COPY_DEST }, } STRINGMAP_END(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName) diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 21ff230ce..45e320ea9 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -60,6 +60,8 @@ enum BufferType BUFFERTYPE_INDEX, BUFFERTYPE_TEXEL, BUFFERTYPE_SHADER_STORAGE, + BUFFERTYPE_COPY_SOURCE, + BUFFERTYPE_COPY_DEST, BUFFERTYPE_MAX_ENUM }; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 713e5b5dd..3b2a45415 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -3255,6 +3255,27 @@ int w_polygon(lua_State *L) return 0; } +int w_copyBuffer(lua_State *L) +{ + Buffer *source = luax_checkbuffer(L, 1); + Buffer *dest = luax_checkbuffer(L, 2); + + ssize_t sourceoffset = luaL_optinteger(L, 3, 0); + ssize_t destoffset = luaL_optinteger(L, 4, 0); + + ssize_t size = std::min(source->getSize() - sourceoffset, dest->getSize() - destoffset); + if (!lua_isnoneornil(L, 5)) + size = luaL_checkinteger(L, 5); + + if (sourceoffset < 0 || destoffset < 0) + return luaL_error(L, "copyBuffer offsets cannot be negative."); + if (size <= 0) + return luaL_error(L, "copyBuffer size must be greater than 0."); + + luax_catchexcept(L, [&](){ instance()->copyBuffer(source, dest, sourceoffset, destoffset, size); }); + return 0; +} + int w_flushBatch(lua_State *) { instance()->flushBatchedDraws(); @@ -3451,6 +3472,8 @@ static const luaL_Reg functions[] = { "print", w_print }, { "printf", w_printf }, + { "copyBuffer", w_copyBuffer }, + { "isCreated", w_isCreated }, { "isActive", w_isActive }, { "isGammaCorrect", w_isGammaCorrect },