From d990044288438ff51f88f8df3dfbb41762c64aea Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 28 Jan 2017 19:26:57 -0400 Subject: [PATCH] love.graphics internal Buffer objects are no longer OpenGL-specific. --HG-- branch : minor --- CMakeLists.txt | 6 +- .../xcode/liblove.xcodeproj/project.pbxproj | 30 ++- src/modules/graphics/Buffer.cpp | 177 +++++++++++++++ .../graphics/{opengl/GLBuffer.h => Buffer.h} | 206 +++++------------- src/modules/graphics/Graphics.cpp | 1 + src/modules/graphics/Graphics.h | 4 + src/modules/graphics/ParticleSystem.cpp | 68 +++++- src/modules/graphics/ParticleSystem.h | 12 +- src/modules/graphics/Shader.cpp | 1 + src/modules/graphics/Shader.h | 17 ++ .../opengl/{GLBuffer.cpp => Buffer.cpp} | 201 +++-------------- src/modules/graphics/opengl/Buffer.h | 80 +++++++ src/modules/graphics/opengl/Graphics.cpp | 26 ++- src/modules/graphics/opengl/Graphics.h | 2 + src/modules/graphics/opengl/Mesh.cpp | 57 +++-- src/modules/graphics/opengl/Mesh.h | 20 +- .../graphics/opengl/ParticleSystem.cpp | 86 +------- src/modules/graphics/opengl/ParticleSystem.h | 19 +- src/modules/graphics/opengl/Shader.cpp | 5 + src/modules/graphics/opengl/Shader.h | 6 +- src/modules/graphics/opengl/SpriteBatch.cpp | 40 ++-- src/modules/graphics/opengl/SpriteBatch.h | 7 +- src/modules/graphics/opengl/Text.cpp | 38 ++-- src/modules/graphics/opengl/Text.h | 9 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 1 - src/modules/graphics/vertex.cpp | 6 + src/modules/graphics/vertex.h | 1 + 27 files changed, 594 insertions(+), 532 deletions(-) create mode 100644 src/modules/graphics/Buffer.cpp rename src/modules/graphics/{opengl/GLBuffer.h => Buffer.h} (53%) rename src/modules/graphics/opengl/{GLBuffer.cpp => Buffer.cpp} (51%) create mode 100644 src/modules/graphics/opengl/Buffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 74324810c..a231a611a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -465,6 +465,8 @@ source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE}) # set(LOVE_SRC_MODULE_GRAPHICS_ROOT + src/modules/graphics/Buffer.cpp + src/modules/graphics/Buffer.h src/modules/graphics/Canvas.cpp src/modules/graphics/Canvas.h src/modules/graphics/Color.h @@ -503,14 +505,14 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT ) set(LOVE_SRC_MODULE_GRAPHICS_OPENGL + src/modules/graphics/opengl/Buffer.cpp + 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.h src/modules/graphics/opengl/Font.cpp src/modules/graphics/opengl/Font.h - src/modules/graphics/opengl/GLBuffer.cpp - src/modules/graphics/opengl/GLBuffer.h src/modules/graphics/opengl/Graphics.cpp src/modules/graphics/opengl/Graphics.h src/modules/graphics/opengl/Image.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 053512776..855ea57dc 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -453,9 +453,9 @@ FA0B7D511A95902C000E1D17 /* Text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA11A95902C000E1D17 /* Text.cpp */; }; FA0B7D521A95902C000E1D17 /* Text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA11A95902C000E1D17 /* Text.cpp */; }; FA0B7D531A95902C000E1D17 /* Text.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BA21A95902C000E1D17 /* Text.h */; }; - FA0B7D551A95902C000E1D17 /* GLBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */; }; - FA0B7D561A95902C000E1D17 /* GLBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */; }; - FA0B7D571A95902C000E1D17 /* GLBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BA51A95902C000E1D17 /* GLBuffer.h */; }; + FA0B7D551A95902C000E1D17 /* Buffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA41A95902C000E1D17 /* Buffer.cpp */; }; + FA0B7D561A95902C000E1D17 /* Buffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA41A95902C000E1D17 /* Buffer.cpp */; }; + FA0B7D571A95902C000E1D17 /* Buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BA51A95902C000E1D17 /* Buffer.h */; }; FA0B7D5E1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */; }; FA0B7D5F1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */; }; FA0B7D601A95902C000E1D17 /* wrap_Graphics.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BAB1A95902C000E1D17 /* wrap_Graphics.h */; }; @@ -1011,6 +1011,9 @@ FAB2D5AA1AABDD8A008224A4 /* TrueTypeRasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB2D5A81AABDD8A008224A4 /* TrueTypeRasterizer.cpp */; }; FAB2D5AB1AABDD8A008224A4 /* TrueTypeRasterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB2D5A81AABDD8A008224A4 /* TrueTypeRasterizer.cpp */; }; FAB2D5AC1AABDD8A008224A4 /* TrueTypeRasterizer.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB2D5A91AABDD8A008224A4 /* TrueTypeRasterizer.h */; }; + FADF53F81E3C7ACD00012CC0 /* Buffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF53F61E3C7ACD00012CC0 /* Buffer.cpp */; }; + FADF53F91E3C7ACD00012CC0 /* Buffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADF53F61E3C7ACD00012CC0 /* Buffer.cpp */; }; + FADF53FA1E3C7ACD00012CC0 /* Buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FADF53F71E3C7ACD00012CC0 /* Buffer.h */; }; FAE272521C05A15B00A67640 /* ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE272501C05A15B00A67640 /* ParticleSystem.cpp */; }; FAE272531C05A15B00A67640 /* ParticleSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE272511C05A15B00A67640 /* ParticleSystem.h */; }; FAF140531E20934C00F898D2 /* CodeGen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF13FC21E20934C00F898D2 /* CodeGen.cpp */; }; @@ -1450,8 +1453,8 @@ FA0B7BA01A95902C000E1D17 /* SpriteBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatch.h; sourceTree = ""; }; FA0B7BA11A95902C000E1D17 /* Text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Text.cpp; sourceTree = ""; }; FA0B7BA21A95902C000E1D17 /* Text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Text.h; sourceTree = ""; }; - FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GLBuffer.cpp; sourceTree = ""; }; - FA0B7BA51A95902C000E1D17 /* GLBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLBuffer.h; sourceTree = ""; }; + FA0B7BA41A95902C000E1D17 /* Buffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Buffer.cpp; sourceTree = ""; }; + FA0B7BA51A95902C000E1D17 /* Buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = ""; }; FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Graphics.cpp; sourceTree = ""; }; FA0B7BAB1A95902C000E1D17 /* wrap_Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Graphics.h; sourceTree = ""; }; FA0B7BAC1A95902C000E1D17 /* wrap_Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Image.cpp; sourceTree = ""; }; @@ -1833,6 +1836,8 @@ FAB2D5A91AABDD8A008224A4 /* TrueTypeRasterizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrueTypeRasterizer.h; sourceTree = ""; }; FAC734C11B2E021A00AB460A /* wrap_SoundData.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_SoundData.lua; sourceTree = ""; }; FAC734C21B2E628700AB460A /* wrap_ImageData.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_ImageData.lua; sourceTree = ""; }; + FADF53F61E3C7ACD00012CC0 /* Buffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Buffer.cpp; sourceTree = ""; }; + FADF53F71E3C7ACD00012CC0 /* Buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = ""; }; FAE272501C05A15B00A67640 /* ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParticleSystem.cpp; sourceTree = ""; }; FAE272511C05A15B00A67640 /* ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleSystem.h; sourceTree = ""; }; FAF13FC21E20934C00F898D2 /* CodeGen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGen.cpp; sourceTree = ""; }; @@ -2615,6 +2620,8 @@ FA0B7B871A95902C000E1D17 /* graphics */ = { isa = PBXGroup; children = ( + FADF53F61E3C7ACD00012CC0 /* Buffer.cpp */, + FADF53F71E3C7ACD00012CC0 /* Buffer.h */, FA1BA0A51E16F20600AA2803 /* Canvas.cpp */, FA1BA0A61E16F20600AA2803 /* Canvas.h */, FA0B7B881A95902C000E1D17 /* Color.h */, @@ -2658,14 +2665,14 @@ FA0B7B8C1A95902C000E1D17 /* opengl */ = { isa = PBXGroup; children = ( + FA0B7BA41A95902C000E1D17 /* Buffer.cpp */, + FA0B7BA51A95902C000E1D17 /* Buffer.h */, FA28EBD31E352DB5003446F4 /* BufferSync.cpp */, FA28EBD41E352DB5003446F4 /* BufferSync.h */, FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */, FA0B7B8E1A95902C000E1D17 /* Canvas.h */, FA0B7B8F1A95902C000E1D17 /* Font.cpp */, FA0B7B901A95902C000E1D17 /* Font.h */, - FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */, - FA0B7BA51A95902C000E1D17 /* GLBuffer.h */, FA0B7B911A95902C000E1D17 /* Graphics.cpp */, FA0B7B921A95902C000E1D17 /* Graphics.h */, FA0B7B931A95902C000E1D17 /* Image.cpp */, @@ -3533,7 +3540,7 @@ FAF140571E20934C00F898D2 /* arrays.h in Headers */, FA0B7A371A958EA3000E1D17 /* b2Distance.h in Headers */, FA0B7E681A95902C000E1D17 /* wrap_PrismaticJoint.h in Headers */, - FA0B7D571A95902C000E1D17 /* GLBuffer.h in Headers */, + FA0B7D571A95902C000E1D17 /* Buffer.h in Headers */, FAF140AB1E20934C00F898D2 /* SymbolTable.h in Headers */, FA27B3C71B4985D8008A9DCE /* Video.h in Headers */, FA0B7ED71A95902D000E1D17 /* Timer.h in Headers */, @@ -3628,6 +3635,7 @@ FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */, FA0B7A401A958EA3000E1D17 /* b2ChainShape.h in Headers */, 217DFBE81D9F6D490055D849 /* inet.h in Headers */, + FADF53FA1E3C7ACD00012CC0 /* Buffer.h in Headers */, FA0B7AA61A958EA3000E1D17 /* b2RevoluteJoint.h in Headers */, FA0B7EEA1A95902D000E1D17 /* wrap_Window.h in Headers */, FA1557C01CE90A2C00AFF582 /* tinyexr.h in Headers */, @@ -4084,6 +4092,7 @@ FA0B7D161A95902C000E1D17 /* Font.cpp in Sources */, FA0B7EB61A95902C000E1D17 /* wrap_System.cpp in Sources */, FA0B7DAC1A95902C000E1D17 /* STBHandler.cpp in Sources */, + FADF53F91E3C7ACD00012CC0 /* Buffer.cpp in Sources */, FA0B79301A958E3B000E1D17 /* Module.cpp in Sources */, FAF1409B1E20934C00F898D2 /* propagateNoContraction.cpp in Sources */, FA0B7DDA1A95902C000E1D17 /* RandomGenerator.cpp in Sources */, @@ -4187,7 +4196,7 @@ FA0B7DF51A95902C000E1D17 /* wrap_Mouse.cpp in Sources */, FA0B7E861A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */, FA0B7E761A95902C000E1D17 /* wrap_WeldJoint.cpp in Sources */, - FA0B7D561A95902C000E1D17 /* GLBuffer.cpp in Sources */, + FA0B7D561A95902C000E1D17 /* Buffer.cpp in Sources */, FA0B7A6C1A958EA3000E1D17 /* b2World.cpp in Sources */, FA1557C51CE90BD900AFF582 /* EXRHandler.cpp in Sources */, FA57FB991AE1993600F2AD6D /* noise1234.cpp in Sources */, @@ -4437,6 +4446,7 @@ FA0B7EB51A95902C000E1D17 /* wrap_System.cpp in Sources */, FA0B7DAB1A95902C000E1D17 /* STBHandler.cpp in Sources */, FA0B7AB81A958EA3000E1D17 /* enet.cpp in Sources */, + FADF53F81E3C7ACD00012CC0 /* Buffer.cpp in Sources */, FA0B7DD91A95902C000E1D17 /* RandomGenerator.cpp in Sources */, FAF1409A1E20934C00F898D2 /* propagateNoContraction.cpp in Sources */, FA0B7A9B1A958EA3000E1D17 /* b2MouseJoint.cpp in Sources */, @@ -4536,7 +4546,7 @@ FA0B7E851A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */, FA0B7E751A95902C000E1D17 /* wrap_WeldJoint.cpp in Sources */, FAF140951E20934C00F898D2 /* PpSymbols.cpp in Sources */, - FA0B7D551A95902C000E1D17 /* GLBuffer.cpp in Sources */, + FA0B7D551A95902C000E1D17 /* Buffer.cpp in Sources */, FA57FB981AE1993600F2AD6D /* noise1234.cpp in Sources */, FA0B7E211A95902C000E1D17 /* PolygonShape.cpp in Sources */, FA0B7D511A95902C000E1D17 /* Text.cpp in Sources */, diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp new file mode 100644 index 000000000..4ad7377d6 --- /dev/null +++ b/src/modules/graphics/Buffer.cpp @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "Buffer.h" +#include "Graphics.h" +#include "common/Exception.h" + +namespace love +{ +namespace graphics +{ + +Buffer::Buffer(size_t size, BufferType type, vertex::Usage usage, uint32 mapflags) + : size(size) + , type(type) + , usage(usage) + , map_flags(mapflags) + , is_mapped(false) +{ +} + +Buffer::~Buffer() +{ +} + +// QuadIndices + +size_t QuadIndices::maxSize = 0; +size_t QuadIndices::elementSize = 0; +size_t QuadIndices::objectCount = 0; + +Buffer *QuadIndices::indexBuffer = nullptr; +char *QuadIndices::indices = nullptr; + +QuadIndices::QuadIndices(Graphics *gfx, size_t size) +: size(size) +{ + // The upper limit is the maximum of uint32 divided by six (the number + // of indices per size) and divided by the size of uint32. This guarantees + // no overflows when calculating the array size in bytes. + if (size == 0 || size > ((uint32) -1) / 6 / sizeof(uint32)) + throw love::Exception("Invalid number of quads."); + + // Create a new / larger buffer if needed. + if (indexBuffer == nullptr || size > maxSize) + { + Buffer *newbuffer = nullptr; + char *newindices = nullptr; + + // Depending on the size, a switch to int and more memory is needed. + IndexDataType targettype = getType(size); + size_t elemsize = vertex::getIndexDataSize(targettype); + + size_t buffersize = elemsize * 6 * size; + + try + { + newbuffer = gfx->newBuffer(buffersize, nullptr, BUFFER_INDEX, vertex::USAGE_STATIC, 0); + newindices = new char[buffersize]; + } + catch (std::bad_alloc &) + { + delete newbuffer; + delete[] newindices; + throw love::Exception("Out of memory."); + } + + // Allocation of the new Buffer succeeded. + // The old Buffer can now be deleted. + delete indexBuffer; + indexBuffer = newbuffer; + + delete[] indices; + indices = newindices; + + maxSize = size; + elementSize = elemsize; + + switch (targettype) + { + case INDEX_UINT16: + fill(); + break; + case INDEX_UINT32: + fill(); + break; + case INDEX_MAX_ENUM: + break; + } + } + + objectCount++; +} + +QuadIndices::QuadIndices(const QuadIndices &other) +: size(other.size) +{ + objectCount++; +} + +QuadIndices &QuadIndices::operator = (const QuadIndices &other) +{ + size = other.size; + return *this; +} + +QuadIndices::~QuadIndices() +{ + --objectCount; + + // Delete the buffer if we were the last living QuadIndices object. + if (objectCount <= 0) + { + delete indexBuffer; + indexBuffer = nullptr; + + delete[] indices; + indices = nullptr; + } +} + +size_t QuadIndices::getSize() const +{ + return size; +} + +size_t QuadIndices::getIndexCount(size_t elements) const +{ + return elements * 6; +} + +IndexDataType QuadIndices::getType(size_t s) const +{ + return vertex::getIndexDataTypeFromMax(s); +} + +size_t QuadIndices::getElementSize() +{ + return elementSize; +} + +Buffer *QuadIndices::getBuffer() const +{ + return indexBuffer; +} + +const void *QuadIndices::getIndices(size_t offset) const +{ + return indices + offset; +} + +template +void QuadIndices::fill() +{ + vertex::fillIndices(vertex::TriangleIndexMode::QUADS, 0, maxSize * 4, (T *) indices); + indexBuffer->fill(0, indexBuffer->getSize(), indices); +} + +} // graphics +} // love diff --git a/src/modules/graphics/opengl/GLBuffer.h b/src/modules/graphics/Buffer.h similarity index 53% rename from src/modules/graphics/opengl/GLBuffer.h rename to src/modules/graphics/Buffer.h index dc25781fd..38493b2be 100644 --- a/src/modules/graphics/opengl/GLBuffer.h +++ b/src/modules/graphics/Buffer.h @@ -18,17 +18,12 @@ * 3. This notice may not be removed or altered from any source distribution. **/ - -#ifndef LOVE_GRAPHICS_OPENGL_GL_BUFFER_H -#define LOVE_GRAPHICS_OPENGL_GL_BUFFER_H +#pragma once // LOVE #include "common/config.h" -#include "graphics/Volatile.h" -#include "graphics/vertex.h" - -// OpenGL -#include "OpenGL.h" +#include "common/int.h" +#include "vertex.h" // C #include @@ -37,57 +32,35 @@ namespace love { namespace graphics { -namespace opengl -{ + +class Graphics; /** - * GLBuffer is a thin abstraction over OpenGL's Buffer Objects. - * The class is meant for internal use. - */ -class GLBuffer : public Volatile + * A block of GPU-owned memory. Currently meant for internal use. + **/ +class Buffer { public: enum MapFlags { - MAP_EXPLICIT_RANGE_MODIFY = 0x01, // see setMappedRangeModified. + MAP_EXPLICIT_RANGE_MODIFY = (1 << 0), // see setMappedRangeModified. + MAP_READ = (1 << 1), }; - /** - * Constructor. - * - * @param size The size of the GLBuffer in bytes. - * @param type The type of the buffer object. - * @param usage Usage hint. - */ - GLBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags = 0); + Buffer(size_t size, BufferType type, vertex::Usage usage, uint32 mapflags); + virtual ~Buffer(); - /** - * Destructor. - */ - virtual ~GLBuffer(); - - /** - * Get the size of the GLBuffer, in bytes. - * - * @return The size of the GLBuffer. - */ size_t getSize() const { return size; } - /** - * Get the type of the buffer object. - */ BufferType getType() const { return type; } - /** - * Get the usage hint for this GLBuffer. - */ vertex::Usage getUsage() const { return usage; @@ -99,32 +72,29 @@ public: } /** - * Map the GLBuffer to client memory. + * Map the Buffer to client memory. * * This can be faster for large changes to the buffer. For smaller * changes, see fill(). - * - * @return A pointer to memory which represents the buffer. */ - void *map(); + virtual void *map() = 0; /** - * Unmap a previously mapped GLBuffer. The buffer must be unmapped - * when used to draw elements. + * Unmap a previously mapped Buffer. The buffer must be unmapped when used + * to draw. */ - void unmap(); + virtual void unmap() = 0; /** * Marks a range of mapped data as modified. - * NOTE: GLBuffer::fill calls this internally for you. + * NOTE: Buffer::fill calls this internally for you. **/ - void setMappedRangeModified(size_t offset, size_t size); + virtual void setMappedRangeModified(size_t offset, size_t size) = 0; /** - * Bind the GLBuffer to its specified target. - * (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, etc). - */ - void bind(); + * Gets the backend-specific handle for this Buffer. + **/ + virtual ptrdiff_t getHandle() const = 0; /** * Fill a portion of the buffer with data and marks the range as modified. @@ -133,34 +103,27 @@ public: * @param size The size of the incoming data. * @param data Pointer to memory to copy data from. */ - void fill(size_t offset, size_t size, const void *data); + virtual void fill(size_t offset, size_t size, const void *data) = 0; /** - * Get a pointer which represents the specified byte offset. - * - * @param offset The byte offset. (0 is first byte). - * @return A pointer which represents the offset. - */ - const void *getPointer(size_t offset) const; + * Copy the contents of this Buffer to another Buffer object. + **/ + virtual void copyTo(size_t offset, size_t size, Buffer *other, size_t otheroffset) = 0; uint32 getMapFlags() const { return map_flags; } - // Implements Volatile. - bool loadVolatile() override; - void unloadVolatile() override; - class Mapper { public: /** - * Memory-maps a GLBuffer. + * Memory-maps a Buffer. */ - Mapper(GLBuffer &buffer) - : buf(buffer) + Mapper(Buffer &buffer) + : buf(buffer) { elems = buf.map(); } @@ -183,57 +146,33 @@ public: private: - GLBuffer &buf; + Buffer &buf; void *elems; }; // Mapper -private: - - /** - * Creates the VBO, and optionally restores data we saved earlier. - * - * @param restore True to restore data previously saved with 'unload'. - * @return True on success, false otherwise. - */ - bool load(bool restore); - void unload(); - - void unmapStatic(size_t offset, size_t size); - void unmapStream(); - - // Whether the buffer is currently mapped to main memory. - bool is_mapped; +protected: // The size of the buffer, in bytes. size_t size; // The type of the buffer object. BufferType type; - GLenum target; // Usage hint. GL_[DYNAMIC, STATIC, STREAM]_DRAW. vertex::Usage usage; - - // The VBO identifier. Assigned by OpenGL. - GLuint vbo; - - // A pointer to mapped memory. - char *memory_map; - - size_t modified_offset; - size_t modified_size; - + uint32 map_flags; -}; // GLBuffer - + bool is_mapped; + +}; // Buffer /** - * QuadIndices manages one shared GLBuffer that stores the indices for an - * element array. Vertex arrays using the vertex structure (or anything else - * that can use the pattern below) can request a size and use it for the - * drawElements call. + * QuadIndices manages one shared Buffer that stores the indices for an element + * array. Vertex arrays using the vertex structure (or anything else that can + * use the pattern below) can request a size and use it for the indexed draw + * call. * * indices[i*6 + 0] = i*4 + 0; * indices[i*6 + 1] = i*4 + 1; @@ -243,25 +182,23 @@ private: * indices[i*6 + 4] = i*4 + 1; * indices[i*6 + 5] = i*4 + 3; * - * There will always be a large enough GLBuffer around until all - * QuadIndices instances have been deleted. + * There will always be a large enough Buffer around until all QuadIndices + * instances have been deleted. * * Q: Why have something like QuadIndices? - * A: The indices for the SpriteBatch do not change, only the array size - * varies. Using one GLBuffer for all element arrays removes this - * duplicated data and saves some memory. + * A: The indices for the SpriteBatch do not change, only the array size varies. + * Using one Buffer for all element arrays removes this duplicated data and + * saves some memory. */ class QuadIndices { public: /** - * Adds an entry to the list of sizes and resizes the GLBuffer + * Adds an entry to the list of sizes and resizes the Buffer * if needed. A size of 1 allocates a group of 6 indices for 4 vertices * creating 1 face. - * - * @param size The requested size in groups of 6 indices. */ - QuadIndices(size_t size); + QuadIndices(Graphics *gfx, size_t size); QuadIndices(const QuadIndices &other); QuadIndices &operator = (const QuadIndices &other); @@ -275,8 +212,6 @@ public: /** * Returns the number of index groups. * This can be used for getIndexCount to get the full count of indices. - * - * @return The number of index groups. */ size_t getSize() const; @@ -284,9 +219,6 @@ public: * Returns the number of indices that the passed element count will have. * Use QuadIndices::getSize to get the full index count for that * QuadIndices instance. - * - * @param elements The number of elements to calculate the index count for. - * @return The index count. */ size_t getIndexCount(size_t elements) const; @@ -294,12 +226,9 @@ public: * Returns the integer type of the element array. * If an optional nonzero size argument is passed, the function returns * the integer type of the element array of that size. - * - * @param s The size of the array to calculated the integer type of. - * @return The element array integer type. */ - GLenum getType(size_t s) const; - inline GLenum getType() const + IndexDataType getType(size_t s) const; + inline IndexDataType getType() const { return getType(maxSize); } @@ -308,28 +237,16 @@ public: * Returns the size in bytes of an element in the element array. * Can be used with getPointer to calculate an offset into the array based * on a number of elements. - * - * @return The size of an element in bytes. **/ size_t getElementSize(); /** - * Returns the pointer to the GLBuffer. - * The pointer will change if a new size request or removal causes - * a GLBuffer resize. It is recommended to retrieve the pointer - * value directly before the drawing call. - * - * @return The pointer to the GLBuffer. + * Returns the pointer to the Buffer. + * The pointer will change if a new size request or removal causes a Buffer + * resize. It is recommended to retrieve the pointer value directly before + * the drawing call. */ - GLBuffer *getBuffer() const; - - /** - * Returns a pointer which represents the specified byte offset. - * - * @param offset The offset in bytes. - * @return A pointer which represents the offset. - */ - const void *getPointer(size_t offset) const; + Buffer *getBuffer() const; /** * Returns a direct pointer to the index data. @@ -339,9 +256,6 @@ public: * the index data came from an Index Buffer. * So the direct pointer to the index buffer should be used instead of the * index buffer when rendering using client-side vertex arrays. - * - * @param offset An offset in bytes into the index data. - * @return A direct pointer to the index data at the specified offset. **/ const void *getIndices(size_t offset) const; @@ -360,20 +274,18 @@ private: // The size in bytes of an element in the element array. static size_t elementSize; - // The current GLBuffer size. 0 means no GLBuffer. + // The current GLBuffer size. 0 means no Buffer. static size_t maxSize; static size_t objectCount; - // The GLBuffer for the element array. Can be null. - static GLBuffer *indexBuffer; - + // The Buffer for the element array. Can be null. + static Buffer *indexBuffer; + // The array of indices that will also be stored in the index buffer. static char *indices; -}; -} // opengl +}; // QuadIndices + } // graphics } // love - -#endif // LOVE_GRAPHICS_OPENGL_GL_BUFFER_H diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index b0d8b928a..89d94b075 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -20,6 +20,7 @@ // LOVE #include "Graphics.h" +#include "Buffer.h" #include "math/MathModule.h" #include "Polyline.h" #include "font/Font.h" diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index d6481ceb5..bb681bfd4 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -49,6 +49,8 @@ class Reference; namespace graphics { +class Buffer; + const int MAX_COLOR_RENDER_TARGETS = 8; /** @@ -315,6 +317,8 @@ public: virtual Shader *newShader(const Shader::ShaderSource &source) = 0; + virtual Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) = 0; + bool validateShader(bool gles, const Shader::ShaderSource &source, std::string &err); /** diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index c4a901b38..6bd28208d 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -21,6 +21,7 @@ //LOVE #include "common/config.h" #include "ParticleSystem.h" +#include "Graphics.h" #include "common/math.h" #include "modules/math/RandomGenerator.h" @@ -52,7 +53,7 @@ float calculate_variation(float inner, float outer, float var) love::Type ParticleSystem::type("ParticleSystem", &Drawable::type); -ParticleSystem::ParticleSystem(Texture *texture, uint32 size) +ParticleSystem::ParticleSystem(Graphics *gfx, Texture *texture, uint32 size) : pMem(nullptr) , pFree(nullptr) , pHead(nullptr) @@ -90,12 +91,15 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size) , offset(float(texture->getWidth())*0.5f, float(texture->getHeight())*0.5f) , defaultOffset(true) , relativeRotation(false) + , buffer(nullptr) + , quadIndices(gfx, size) { if (size == 0 || size > MAX_PARTICLES) throw love::Exception("Invalid ParticleSystem size."); sizes.push_back(1.0f); colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); + setBufferSize(size); } @@ -143,6 +147,8 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , colors(p.colors) , quads(p.quads) , relativeRotation(p.relativeRotation) + , buffer(nullptr) + , quadIndices(p.quadIndices) { setBufferSize(maxParticles); } @@ -169,6 +175,13 @@ void ParticleSystem::createBuffers(size_t size) { pFree = pMem = new Particle[size]; maxParticles = (uint32) size; + + auto gfx = Module::getInstance(Module::M_GRAPHICS); + + size_t bytes = sizeof(Vertex) * size * 4; + buffer = gfx->newBuffer(bytes, nullptr, BUFFER_VERTEX, vertex::USAGE_STREAM, 0); + + quadIndices = QuadIndices(gfx, size); } catch (std::bad_alloc &) { @@ -179,10 +192,11 @@ void ParticleSystem::createBuffers(size_t size) void ParticleSystem::deleteBuffers() { - // Clean up for great gracefulness! delete[] pMem; + delete buffer; pMem = nullptr; + buffer = nullptr; maxParticles = 0; activeParticles = 0; } @@ -933,6 +947,56 @@ void ParticleSystem::update(float dt) prevPosition = position; } +bool ParticleSystem::prepareDraw(Graphics *gfx, const Matrix4 &m) +{ + uint32 pCount = getCount(); + + if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || buffer == nullptr) + return false; + + gfx->flushStreamDraws(); + + Graphics::TempTransform transform(gfx, m); + + const Vertex *textureVerts = texture->getVertices(); + Vertex *pVerts = (Vertex *) buffer->map(); + Particle *p = pHead; + + bool useQuads = !quads.empty(); + + Matrix3 t; + + // set the vertex data for each particle (transformation, texcoords, color) + while (p) + { + if (useQuads) + textureVerts = quads[p->quadIndex]->getVertices(); + + // particle vertices are image vertices transformed by particle info + t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f); + t.transform(pVerts, textureVerts, 4); + + // Particle colors are stored as floats (0-1) but vertex colors are + // unsigned bytes (0-255). + Color c = toColor(p->color); + + // set the texture coordinate and color data for particle vertices + for (int v = 0; v < 4; v++) + { + pVerts[v].s = textureVerts[v].s; + pVerts[v].t = textureVerts[v].t; + pVerts[v].color = c; + } + + pVerts += 4; + p = p->next; + } + + buffer->unmap(); + + return true; +} + bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out) { return distributions.find(in, out); diff --git a/src/modules/graphics/ParticleSystem.h b/src/modules/graphics/ParticleSystem.h index 4a51950ef..3b8a78f7e 100644 --- a/src/modules/graphics/ParticleSystem.h +++ b/src/modules/graphics/ParticleSystem.h @@ -29,6 +29,7 @@ #include "Color.h" #include "Quad.h" #include "Texture.h" +#include "Buffer.h" // STL #include @@ -38,6 +39,8 @@ namespace love namespace graphics { +class Graphics; + /** * A class for creating, moving and drawing particles. * A big thanks to bobthebloke.org @@ -81,7 +84,7 @@ public: /** * Creates a particle system with the specified buffer size and texture. **/ - ParticleSystem(Texture *texture, uint32 buffer); + ParticleSystem(Graphics *gfx, Texture *texture, uint32 buffer); ParticleSystem(const ParticleSystem &p); /** @@ -548,6 +551,8 @@ protected: int quadIndex; }; + bool prepareDraw(Graphics *gfx, const Matrix4 &m); + // Pointer to the beginning of the allocated memory. Particle *pMem; @@ -647,6 +652,11 @@ protected: bool relativeRotation; + Buffer *buffer; + + // Vertex index buffer. + QuadIndices quadIndices; + private: void resetOffset(); diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index c450d20f2..291d9fed5 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -21,6 +21,7 @@ // LOVE #include "Shader.h" #include "Graphics.h" +#include "math/MathModule.h" // glslang #include "libraries/glslang/glslang/Public/ShaderLang.h" diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 85f30bd35..66efe8744 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -31,6 +31,11 @@ #include #include +namespace glslang +{ +class TShader; +} + namespace love { namespace graphics @@ -171,6 +176,8 @@ public: **/ virtual void setVideoTextures(ptrdiff_t ytexture, ptrdiff_t cbtexture, ptrdiff_t crtexture) = 0; + virtual ptrdiff_t getHandle() const = 0; + static bool validate(Graphics *gfx, bool gles, const ShaderSource &source, bool checkWithDefaults, std::string &err); static bool initialize(); @@ -187,9 +194,19 @@ public: protected: + struct CachedShaderStage + { + int referenceCount; + ShaderStage stage; + glslang::TShader *glslangShader; + ptrdiff_t handle; + }; + // Source code used for this Shader. ShaderSource shaderSource; + static std::map cachedShaders; + private: static StringMap::Entry languageEntries[]; diff --git a/src/modules/graphics/opengl/GLBuffer.cpp b/src/modules/graphics/opengl/Buffer.cpp similarity index 51% rename from src/modules/graphics/opengl/GLBuffer.cpp rename to src/modules/graphics/opengl/Buffer.cpp index 9ba3a7ce1..b79ea0fcd 100644 --- a/src/modules/graphics/opengl/GLBuffer.cpp +++ b/src/modules/graphics/opengl/Buffer.cpp @@ -18,7 +18,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "GLBuffer.h" +#include "Buffer.h" #include "common/Exception.h" #include "graphics/vertex.h" @@ -35,16 +35,12 @@ namespace graphics namespace opengl { -GLBuffer::GLBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) - : is_mapped(false) - , size(size) - , type(type) - , usage(usage) +Buffer::Buffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) + : love::graphics::Buffer(size, type, usage, mapflags) , vbo(0) , memory_map(nullptr) , modified_offset(0) , modified_size(0) - , map_flags(mapflags) { target = OpenGL::getGLBufferType(type); @@ -67,7 +63,7 @@ GLBuffer::GLBuffer(size_t size, const void *data, BufferType type, vertex::Usage } } -GLBuffer::~GLBuffer() +Buffer::~Buffer() { if (vbo != 0) unload(); @@ -75,7 +71,7 @@ GLBuffer::~GLBuffer() delete[] memory_map; } -void *GLBuffer::map() +void *Buffer::map() { if (is_mapped) return memory_map; @@ -88,7 +84,7 @@ void *GLBuffer::map() return memory_map; } -void GLBuffer::unmapStatic(size_t offset, size_t size) +void Buffer::unmapStatic(size_t offset, size_t size) { if (size == 0) return; @@ -98,7 +94,7 @@ void GLBuffer::unmapStatic(size_t offset, size_t size) glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, memory_map + offset); } -void GLBuffer::unmapStream() +void Buffer::unmapStream() { GLenum glusage = OpenGL::getGLBufferUsage(getUsage()); @@ -109,7 +105,7 @@ void GLBuffer::unmapStream() glBufferData(target, (GLsizeiptr) getSize(), memory_map, glusage); } -void GLBuffer::unmap() +void Buffer::unmap() { if (!is_mapped) return; @@ -127,15 +123,15 @@ void GLBuffer::unmap() if (modified_size > 0) { - switch (OpenGL::getGLBufferUsage(getUsage())) + switch (getUsage()) { - case GL_STATIC_DRAW: + case vertex::USAGE_STATIC: unmapStatic(modified_offset, modified_size); break; - case GL_STREAM_DRAW: + case vertex::USAGE_STREAM: unmapStream(); break; - case GL_DYNAMIC_DRAW: + case vertex::USAGE_DYNAMIC: default: // It's probably more efficient to treat it like a streaming buffer if // at least a third of its contents have been modified during the map(). @@ -153,7 +149,7 @@ void GLBuffer::unmap() is_mapped = false; } -void GLBuffer::setMappedRangeModified(size_t offset, size_t modifiedsize) +void Buffer::setMappedRangeModified(size_t offset, size_t modifiedsize) { if (!is_mapped || !(map_flags & MAP_EXPLICIT_RANGE_MODIFY)) return; @@ -169,12 +165,7 @@ void GLBuffer::setMappedRangeModified(size_t offset, size_t modifiedsize) modified_size = new_range_end - modified_offset; } -void GLBuffer::bind() -{ - gl.bindBuffer(getType(), vbo); -} - -void GLBuffer::fill(size_t offset, size_t size, const void *data) +void Buffer::fill(size_t offset, size_t size, const void *data) { memcpy(memory_map + offset, data, size); @@ -187,26 +178,30 @@ void GLBuffer::fill(size_t offset, size_t size, const void *data) } } -const void *GLBuffer::getPointer(size_t offset) const +ptrdiff_t Buffer::getHandle() const { - return BUFFER_OFFSET(offset); + return vbo; } -bool GLBuffer::loadVolatile() +void Buffer::copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset) +{ + other->fill(otheroffset, size, memory_map + offset); +} + +bool Buffer::loadVolatile() { return load(true); } -void GLBuffer::unloadVolatile() +void Buffer::unloadVolatile() { unload(); } -bool GLBuffer::load(bool restore) +bool Buffer::load(bool restore) { glGenBuffers(1, &vbo); - - bind(); + gl.bindBuffer(type, vbo); while (glGetError() != GL_NO_ERROR) /* Clear the error buffer. */; @@ -220,157 +215,13 @@ bool GLBuffer::load(bool restore) return (glGetError() == GL_NO_ERROR); } -void GLBuffer::unload() +void Buffer::unload() { is_mapped = false; gl.deleteBuffer(vbo); vbo = 0; } - -// QuadIndices - -size_t QuadIndices::maxSize = 0; -size_t QuadIndices::elementSize = 0; -size_t QuadIndices::objectCount = 0; - -GLBuffer *QuadIndices::indexBuffer = nullptr; -char *QuadIndices::indices = nullptr; - -QuadIndices::QuadIndices(size_t size) - : size(size) -{ - // The upper limit is the maximum of GLuint divided by six (the number - // of indices per size) and divided by the size of GLuint. This guarantees - // no overflows when calculating the array size in bytes. - if (size == 0 || size > ((GLuint) -1) / 6 / sizeof(GLuint)) - throw love::Exception("Invalid number of quads."); - - // Create a new / larger buffer if needed. - if (indexBuffer == nullptr || size > maxSize) - { - GLBuffer *newbuffer = nullptr; - char *newindices = nullptr; - - // Depending on the size, a switch to int and more memory is needed. - GLenum targettype = getType(size); - size_t elemsize = (targettype == GL_UNSIGNED_SHORT) ? sizeof(GLushort) : sizeof(GLuint); - - size_t buffersize = elemsize * 6 * size; - - // Create may throw out-of-memory exceptions. - // QuadIndices will propagate the exception and keep the old GLBuffer. - try - { - newbuffer = new GLBuffer(buffersize, nullptr, BUFFER_INDEX, vertex::USAGE_STATIC); - newindices = new char[buffersize]; - } - catch (std::bad_alloc &) - { - delete newbuffer; - delete[] newindices; - throw love::Exception("Out of memory."); - } - - // Allocation of the new GLBuffer succeeded. - // The old GLBuffer can now be deleted. - delete indexBuffer; - indexBuffer = newbuffer; - - delete[] indices; - indices = newindices; - - maxSize = size; - elementSize = elemsize; - - switch (targettype) - { - case GL_UNSIGNED_SHORT: - fill(); - break; - case GL_UNSIGNED_INT: - fill(); - break; - } - } - - objectCount++; -} - -QuadIndices::QuadIndices(const QuadIndices &other) - : size(other.size) -{ - objectCount++; -} - -QuadIndices &QuadIndices::operator = (const QuadIndices &other) -{ - size = other.size; - return *this; -} - -QuadIndices::~QuadIndices() -{ - --objectCount; - - // Delete the buffer if we were the last living QuadIndices object. - if (objectCount <= 0) - { - delete indexBuffer; - indexBuffer = nullptr; - - delete[] indices; - indices = nullptr; - } -} - -size_t QuadIndices::getSize() const -{ - return size; -} - -size_t QuadIndices::getIndexCount(size_t elements) const -{ - return elements * 6; -} - -GLenum QuadIndices::getType(size_t s) const -{ - // Calculates if unsigned short is big enough to hold all the vertex indices. - static const GLenum types[] = {GL_UNSIGNED_SHORT, GL_UNSIGNED_INT}; - return types[s * 4 > std::numeric_limits::max()]; - // if buffer-size > max(GLushort) then GL_UNSIGNED_INT else GL_UNSIGNED_SHORT -} - -size_t QuadIndices::getElementSize() -{ - return elementSize; -} - -GLBuffer *QuadIndices::getBuffer() const -{ - return indexBuffer; -} - -const void *QuadIndices::getPointer(size_t offset) const -{ - return indexBuffer->getPointer(offset); -} - -const void *QuadIndices::getIndices(size_t offset) const -{ - return indices + offset; -} - -template -void QuadIndices::fill() -{ - using namespace love::graphics::vertex; - - fillIndices(TriangleIndexMode::QUADS, 0, maxSize * 4, (T *) indices); - indexBuffer->fill(0, indexBuffer->getSize(), indices); -} - } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Buffer.h b/src/modules/graphics/opengl/Buffer.h new file mode 100644 index 000000000..bfd931227 --- /dev/null +++ b/src/modules/graphics/opengl/Buffer.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +// LOVE +#include "common/config.h" +#include "graphics/Buffer.h" +#include "graphics/Volatile.h" + +// OpenGL +#include "OpenGL.h" + +namespace love +{ +namespace graphics +{ +namespace opengl +{ + +class Buffer final : public love::graphics::Buffer, public Volatile +{ +public: + + Buffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags); + virtual ~Buffer(); + + void *map() override; + void unmap() override; + void setMappedRangeModified(size_t offset, size_t size) override; + void fill(size_t offset, size_t size, const void *data) override; + ptrdiff_t getHandle() const override; + + void copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset) override; + + // Implements Volatile. + bool loadVolatile() override; + void unloadVolatile() override; + +private: + + bool load(bool restore); + void unload(); + + void unmapStatic(size_t offset, size_t size); + void unmapStream(); + + GLenum target; + + // The VBO identifier. Assigned by OpenGL. + GLuint vbo; + + // A pointer to mapped memory. + char *memory_map; + + size_t modified_offset; + size_t modified_size; + +}; // Buffer + +} // opengl +} // graphics +} // love diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 69e29b1f3..86e662bc4 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -29,6 +29,7 @@ #include "StreamBuffer.h" #include "math/MathModule.h" #include "window/Window.h" +#include "Buffer.h" #include "libraries/xxHash/xxhash.h" @@ -117,12 +118,12 @@ graphics::Font *Graphics::newFont(love::font::Rasterizer *r, const Texture::Filt SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, vertex::Usage usage) { - return new SpriteBatch(texture, size, usage); + return new SpriteBatch(this, texture, size, usage); } ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size) { - return new ParticleSystem(texture, size); + return new ParticleSystem(this, texture, size); } love::graphics::Canvas *Graphics::newCanvas(int width, int height, const Canvas::Settings &settings) @@ -159,29 +160,34 @@ love::graphics::Shader *Graphics::newShader(const Shader::ShaderSource &source) return new Shader(source); } +love::graphics::Buffer *Graphics::newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) +{ + return new Buffer(size, data, type, usage, mapflags); +} + Mesh *Graphics::newMesh(const std::vector &vertices, Mesh::DrawMode drawmode, vertex::Usage usage) { - return new Mesh(vertices, drawmode, usage); + return new Mesh(this, vertices, drawmode, usage); } Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) { - return new Mesh(vertexcount, drawmode, usage); + return new Mesh(this, vertexcount, drawmode, usage); } Mesh *Graphics::newMesh(const std::vector &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) { - return new Mesh(vertexformat, vertexcount, drawmode, usage); + return new Mesh(this, vertexformat, vertexcount, drawmode, usage); } Mesh *Graphics::newMesh(const std::vector &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage) { - return new Mesh(vertexformat, data, datasize, drawmode, usage); + return new Mesh(this, vertexformat, data, datasize, drawmode, usage); } Text *Graphics::newText(graphics::Font *font, const std::vector &text) { - return new Text(font, text); + return new Text(this, font, text); } Video *Graphics::newVideo(love::video::VideoStream *stream, float pixeldensity) @@ -295,7 +301,7 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b // index buffer objects, since the shared index buffer used by QuadIndices // objects is destroyed when the last object is destroyed. if (quadIndices == nullptr) - quadIndices = new QuadIndices(20); + quadIndices = new QuadIndices(this, 20); // Restore the graphics state. restoreState(states.back()); @@ -726,7 +732,7 @@ void Graphics::clear(Colorf c) // This seems to be enough to fix the bug for me. Other methods I've // tried (e.g. dummy draws) don't work in all cases. gl.useProgram(0); - gl.useProgram(((Shader *)Shader::current)->getProgram()); + gl.useProgram((GLuint) Shader::current->getHandle()); } } @@ -792,7 +798,7 @@ void Graphics::clear(const std::vector &colors) // This seems to be enough to fix the bug for me. Other methods I've // tried (e.g. dummy draws) don't work in all cases. gl.useProgram(0); - gl.useProgram(((Shader *)Shader::current)->getProgram()); + gl.useProgram((GLuint) Shader::current->getHandle()); } } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index e7af45807..d35a80225 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -78,6 +78,8 @@ public: love::graphics::Shader *newShader(const Shader::ShaderSource &source) override; + love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; + Mesh *newMesh(const std::vector &vertices, Mesh::DrawMode drawmode, vertex::Usage usage); Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage); diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 01b45d6cf..800820a87 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -61,7 +61,7 @@ static std::vector getDefaultVertexFormat() love::Type Mesh::type("Mesh", &Drawable::type); -Mesh::Mesh(const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage) : vertexFormat(vertexformat) , vbo(nullptr) , vertexCount(0) @@ -78,17 +78,17 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size calculateAttributeSizes(); vertexCount = datasize / vertexStride; - elementDataType = getIndexTypeFromMax(vertexCount); + elementDataType = vertex::getIndexDataTypeFromMax(vertexCount); if (vertexCount == 0) throw love::Exception("Data size is too small for specified vertex attribute formats."); - vbo = new GLBuffer(datasize, data, BUFFER_VERTEX, usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); + vbo = gfx->newBuffer(datasize, data, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY | Buffer::MAP_READ); vertexScratchBuffer = new char[vertexStride]; } -Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage) : vertexFormat(vertexformat) , vbo(nullptr) , vertexCount((size_t) vertexcount) @@ -96,7 +96,7 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM , ibo(nullptr) , useIndexBuffer(false) , elementCount(0) - , elementDataType(getIndexTypeFromMax(vertexcount)) + , elementDataType(vertex::getIndexDataTypeFromMax(vertexcount)) , drawMode(drawmode) , rangeStart(-1) , rangeCount(-1) @@ -109,7 +109,7 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM size_t buffersize = vertexCount * vertexStride; - vbo = new GLBuffer(buffersize, nullptr, BUFFER_VERTEX, usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); + vbo = gfx->newBuffer(buffersize, nullptr, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY | Buffer::MAP_READ); // Initialize the buffer's contents to 0. memset(vbo->map(), 0, buffersize); @@ -119,13 +119,13 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM vertexScratchBuffer = new char[vertexStride]; } -Mesh::Mesh(const std::vector &vertices, DrawMode drawmode, vertex::Usage usage) - : Mesh(getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertices, DrawMode drawmode, vertex::Usage usage) + : Mesh(gfx, getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage) { } -Mesh::Mesh(int vertexcount, DrawMode drawmode, vertex::Usage usage) - : Mesh(getDefaultVertexFormat(), vertexcount, drawmode, usage) +Mesh::Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage) + : Mesh(gfx, getDefaultVertexFormat(), vertexcount, drawmode, usage) { } @@ -393,7 +393,7 @@ void Mesh::flush() * Copies index data from a vector to a mapped index buffer. **/ template -static void copyToIndexBuffer(const std::vector &indices, GLBuffer::Mapper &buffermap, size_t maxval) +static void copyToIndexBuffer(const std::vector &indices, Buffer::Mapper &buffermap, size_t maxval) { T *elems = (T *) buffermap.get(); @@ -410,7 +410,7 @@ void Mesh::setVertexMap(const std::vector &map) { size_t maxval = getVertexCount(); - IndexDataType datatype = getIndexTypeFromMax(maxval); + IndexDataType datatype = vertex::getIndexDataTypeFromMax(maxval); // Calculate the size in bytes of the index buffer data. size_t size = map.size() * vertex::getIndexDataSize(datatype); @@ -422,7 +422,10 @@ void Mesh::setVertexMap(const std::vector &map) } if (!ibo && size > 0) - ibo = new GLBuffer(size, nullptr, BUFFER_INDEX, vbo->getUsage()); + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + ibo = gfx->newBuffer(size, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ); + } useIndexBuffer = true; elementCount = map.size(); @@ -430,7 +433,7 @@ void Mesh::setVertexMap(const std::vector &map) if (!ibo || elementCount == 0) return; - GLBuffer::Mapper ibomap(*ibo); + Buffer::Mapper ibomap(*ibo); // Fill the buffer with the index values from the vector. switch (datatype) @@ -456,14 +459,17 @@ void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasiz } if (!ibo && datasize > 0) - ibo = new GLBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage()); + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + ibo = gfx->newBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ); + } elementCount = datasize / vertex::getIndexDataSize(datatype); if (!ibo || elementCount == 0) return; - GLBuffer::Mapper ibomap(*ibo); + Buffer::Mapper ibomap(*ibo); memcpy(ibomap.get(), data, datasize); useIndexBuffer = true; @@ -587,13 +593,12 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu if (attriblocation < 0) return attriblocation; - // Needed for glVertexAttribPointer. - vbo->bind(); - // Make sure the buffer isn't mapped (sends data to GPU if needed.) vbo->unmap(); - const void *gloffset = vbo->getPointer(getAttributeOffset(attributeindex)); + gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle()); + + const void *gloffset = BUFFER_OFFSET(getAttributeOffset(attributeindex)); GLenum datatype = getGLDataType(format.type); GLboolean normalized = (datatype == GL_UNSIGNED_BYTE); @@ -651,7 +656,7 @@ void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m, if (useIndexBuffer && ibo && elementCount > 0) { // Use the custom vertex map (index buffer) to draw the vertices. - ibo->bind(); + gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle()); // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); @@ -665,7 +670,7 @@ void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m, count = std::min(count, (int) elementCount - start); size_t elementsize = vertex::getIndexDataSize(elementDataType); - const void *indices = ibo->getPointer(start * elementsize); + const void *indices = BUFFER_OFFSET(start * elementsize); GLenum type = OpenGL::getGLIndexDataType(elementDataType); if (count > 0) @@ -734,14 +739,6 @@ GLenum Mesh::getGLDataType(DataType type) } } -IndexDataType Mesh::getIndexTypeFromMax(size_t maxvalue) -{ - if (maxvalue > LOVE_UINT16_MAX) - return INDEX_UINT32; - else - return INDEX_UINT16; -} - bool Mesh::getConstant(const char *in, Mesh::DrawMode &out) { return drawModes.find(in, out); diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index c103da590..15e425105 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -29,7 +29,8 @@ #include "graphics/Drawable.h" #include "graphics/Texture.h" #include "graphics/vertex.h" -#include "GLBuffer.h" +#include "graphics/Buffer.h" +#include "OpenGL.h" // C++ #include @@ -39,6 +40,9 @@ namespace love { namespace graphics { + +class Graphics; + namespace opengl { @@ -86,11 +90,11 @@ public: int components; // max 4 }; - Mesh(const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage); - Mesh(const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage); + Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage); + Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage); - Mesh(const std::vector &vertices, DrawMode drawmode, vertex::Usage usage); - Mesh(int vertexcount, DrawMode drawmode, vertex::Usage usage); + Mesh(graphics::Graphics *gfx, const std::vector &vertices, DrawMode drawmode, vertex::Usage usage); + Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage); virtual ~Mesh(); @@ -229,8 +233,6 @@ private: static size_t getAttribFormatSize(const AttribFormat &format); - static IndexDataType getIndexTypeFromMax(size_t maxvalue); - static GLenum getGLDrawMode(DrawMode mode); static GLenum getGLDataType(DataType type); @@ -240,7 +242,7 @@ private: std::unordered_map attachedAttributes; // Vertex buffer, for the vertex data. - GLBuffer *vbo; + Buffer *vbo; size_t vertexCount; size_t vertexStride; @@ -249,7 +251,7 @@ private: char *vertexScratchBuffer; // Element (vertex index) buffer, for the vertex map. - GLBuffer *ibo; + Buffer *ibo; bool useIndexBuffer; size_t elementCount; IndexDataType elementDataType; diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 2613316ae..9fc066c77 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -19,17 +19,11 @@ **/ //LOVE -#include "common/config.h" #include "ParticleSystem.h" #include "graphics/Graphics.h" #include "OpenGL.h" -// STD -#include -#include -#include - namespace love { namespace graphics @@ -37,32 +31,18 @@ namespace graphics namespace opengl { -ParticleSystem::ParticleSystem(Texture *texture, uint32 size) - : love::graphics::ParticleSystem(texture, size) - , buffer(nullptr) - , quadIndices(size) +ParticleSystem::ParticleSystem(Graphics *gfx, Texture *texture, uint32 size) + : love::graphics::ParticleSystem(gfx, texture, size) { - createVertices(size); } ParticleSystem::ParticleSystem(const ParticleSystem &p) : love::graphics::ParticleSystem(p) - , quadIndices(p.quadIndices) { - createVertices(maxParticles); } ParticleSystem::~ParticleSystem() { - delete buffer; -} - -void ParticleSystem::createVertices(size_t numparticles) -{ - size_t size = sizeof(Vertex) * numparticles * 4; - GLBuffer *newbuffer = new GLBuffer(size, nullptr, BUFFER_VERTEX, vertex::USAGE_STREAM, 0); - delete buffer; - buffer = newbuffer; } ParticleSystem *ParticleSystem::clone() @@ -70,78 +50,28 @@ ParticleSystem *ParticleSystem::clone() return new ParticleSystem(*this); } -void ParticleSystem::setBufferSize(uint32 size) -{ - love::graphics::ParticleSystem::setBufferSize(size); - - quadIndices = QuadIndices(size); - createVertices(size); -} - void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m) { - uint32 pCount = getCount(); - - if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || buffer == nullptr) + if (!prepareDraw(gfx, m)) return; - gfx->flushStreamDraws(); - OpenGL::TempDebugGroup debuggroup("ParticleSystem draw"); - Graphics::TempTransform transform(gfx, m); - - const Vertex *textureVerts = texture->getVertices(); - Vertex *pVerts = (Vertex *) buffer->map(); - Particle *p = pHead; - - bool useQuads = !quads.empty(); - - Matrix3 t; - - // set the vertex data for each particle (transformation, texcoords, color) - while (p) - { - if (useQuads) - textureVerts = quads[p->quadIndex]->getVertices(); - - // particle vertices are image vertices transformed by particle info - t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f); - t.transform(pVerts, textureVerts, 4); - - // Particle colors are stored as floats (0-1) but vertex colors are - // unsigned bytes (0-255). - Color c = toColor(p->color); - - // set the texture coordinate and color data for particle vertices - for (int v = 0; v < 4; v++) - { - pVerts[v].s = textureVerts[v].s; - pVerts[v].t = textureVerts[v].t; - pVerts[v].color = c; - } - - pVerts += 4; - p = p->next; - } - - buffer->unmap(); - gl.bindTextureToUnit(texture, 0, false); gl.prepareDraw(); gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR); - buffer->bind(); + gl.bindBuffer(BUFFER_VERTEX, (GLuint) buffer->getHandle()); glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, color.r))); glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, x))); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, s))); - GLsizei count = (GLsizei) quadIndices.getIndexCount(pCount); - GLenum gltype = quadIndices.getType(); + GLsizei count = (GLsizei) quadIndices.getIndexCount(getCount()); + GLenum gltype = OpenGL::getGLIndexDataType(quadIndices.getType()); - quadIndices.getBuffer()->bind(); - gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getPointer(0)); + gl.bindBuffer(BUFFER_INDEX, (GLuint) quadIndices.getBuffer()->getHandle()); + gl.drawElements(GL_TRIANGLES, count, gltype, BUFFER_OFFSET(0)); } } // opengl diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 2c77b67ca..04d385995 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -23,37 +23,30 @@ // LOVE #include "graphics/ParticleSystem.h" -#include "GLBuffer.h" namespace love { namespace graphics { + +class Graphics; + namespace opengl { -class ParticleSystem : public love::graphics::ParticleSystem +class ParticleSystem final : public love::graphics::ParticleSystem { public: - ParticleSystem(Texture *texture, uint32 buffer); + ParticleSystem(Graphics *gfx, Texture *texture, uint32 buffer); ParticleSystem(const ParticleSystem &p); virtual ~ParticleSystem(); ParticleSystem *clone() override; - void setBufferSize(uint32 size) override; void draw(Graphics *gfx, const Matrix4 &m) override; -private: - - void createVertices(size_t numparticles); - - GLBuffer *buffer; - - // Vertex index buffer. - QuadIndices quadIndices; -}; +}; // ParticleSystem } // opengl } // graphics diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 64738ac8a..967315d04 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -726,6 +726,11 @@ bool Shader::hasUniform(const std::string &name) const return uniforms.find(name) != uniforms.end(); } +ptrdiff_t Shader::getHandle() const +{ + return program; +} + GLint Shader::getAttribLocation(const std::string &name) { auto it = attributes.find(name); diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 2f2e95bd1..826eb57df 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -62,6 +62,7 @@ public: void updateUniform(const UniformInfo *info, int count, bool internalUpdate = false) override; void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate = false) override; bool hasUniform(const std::string &name) const override; + ptrdiff_t getHandle() const override; void setVideoTextures(ptrdiff_t ytexture, ptrdiff_t cbtexture, ptrdiff_t crtexture) override; GLint getAttribLocation(const std::string &name); @@ -70,11 +71,6 @@ public: void updatePointSize(float size); void updateBuiltinUniforms(); - GLuint getProgram() const - { - return program; - } - static std::string getGLSLVersion(); static bool isSupported(); diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 1fe94e0e8..6dc503d6c 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -25,7 +25,6 @@ #include "OpenGL.h" // LOVE -#include "GLBuffer.h" #include "graphics/Texture.h" #include "graphics/Graphics.h" @@ -44,13 +43,13 @@ namespace opengl love::Type SpriteBatch::type("SpriteBatch", &Drawable::type); -SpriteBatch::SpriteBatch(Texture *texture, int size, vertex::Usage usage) +SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usage usage) : texture(texture) , size(size) , next(0) , color(0) , array_buf(nullptr) - , quad_indices(size) + , quad_indices(gfx, size) , range_start(-1) , range_count(-1) { @@ -59,7 +58,7 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, vertex::Usage usage) size_t vertex_size = sizeof(Vertex) * 4 * size; - array_buf = new GLBuffer(vertex_size, nullptr, BUFFER_VERTEX, usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); + array_buf = gfx->newBuffer(vertex_size, nullptr, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY); } SpriteBatch::~SpriteBatch() @@ -155,24 +154,21 @@ void SpriteBatch::setBufferSize(int newsize) if (newsize == size) return; - // Map the old GLBuffer to get a pointer to its data. - void *old_data = array_buf->map(); - size_t vertex_size = sizeof(Vertex) * 4 * newsize; - GLBuffer *new_array_buf = nullptr; + love::graphics::Buffer *new_array_buf = nullptr; int new_next = std::min(next, newsize); try { - new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getType(), array_buf->getUsage(), array_buf->getMapFlags()); + auto gfx = Module::getInstance(Module::M_GRAPHICS); + new_array_buf = gfx->newBuffer(vertex_size, nullptr, array_buf->getType(), array_buf->getUsage(), array_buf->getMapFlags()); // Copy as much of the old data into the new GLBuffer as can fit. size_t copy_size = sizeof(Vertex) * 4 * new_next; - memcpy(new_array_buf->map(), old_data, copy_size); - new_array_buf->setMappedRangeModified(0, copy_size); + array_buf->copyTo(0, copy_size, new_array_buf, 0); - quad_indices = QuadIndices(newsize); + quad_indices = QuadIndices(gfx, newsize); } catch (love::Exception &) { @@ -262,17 +258,17 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) array_buf->unmap(); - array_buf->bind(); + gl.bindBuffer(BUFFER_VERTEX, (GLuint) array_buf->getHandle()); // Apply per-sprite color, if a color is set. if (color) { enabledattribs |= ATTRIBFLAG_COLOR; - glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), array_buf->getPointer(color_offset)); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), BUFFER_OFFSET(color_offset)); } - glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(pos_offset)); - glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(texel_offset)); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(pos_offset)); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(texel_offset)); for (const auto &it : attached_attributes) { @@ -301,11 +297,15 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) count = std::min(count, next - start); - quad_indices.getBuffer()->bind(); - const void *indices = quad_indices.getPointer(start * quad_indices.getElementSize()); - if (count > 0) - gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(count), quad_indices.getType(), indices); + { + gl.bindBuffer(BUFFER_INDEX, (GLuint) quad_indices.getBuffer()->getHandle()); + + const void *indices = BUFFER_OFFSET(start * quad_indices.getElementSize()); + GLenum gltype = OpenGL::getGLIndexDataType(quad_indices.getType()); + + gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(count), gltype, indices); + } } void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index) diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index 63299124d..81c0f640f 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -34,7 +34,7 @@ #include "graphics/Volatile.h" #include "graphics/Color.h" #include "graphics/Quad.h" -#include "GLBuffer.h" +#include "graphics/Buffer.h" #include "Mesh.h" namespace love @@ -44,6 +44,7 @@ namespace graphics // Forward declarations. class Texture; +class Graphics; namespace opengl { @@ -54,7 +55,7 @@ public: static love::Type type; - SpriteBatch(Texture *texture, int size, vertex::Usage usage); + SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usage usage); virtual ~SpriteBatch(); int add(const Matrix4 &m, int index = -1); @@ -138,7 +139,7 @@ private: // added sprite. Color *color; - GLBuffer *array_buf; + love::graphics::Buffer *array_buf; QuadIndices quad_indices; std::unordered_map attached_attributes; diff --git a/src/modules/graphics/opengl/Text.cpp b/src/modules/graphics/opengl/Text.cpp index a38bcd4b3..4c9ad0524 100644 --- a/src/modules/graphics/opengl/Text.cpp +++ b/src/modules/graphics/opengl/Text.cpp @@ -21,6 +21,7 @@ #include "Text.h" #include "common/Matrix.h" #include "graphics/Graphics.h" +#include "OpenGL.h" #include @@ -33,10 +34,10 @@ namespace opengl love::Type Text::type("Text", &Drawable::type); -Text::Text(love::graphics::Font *font, const std::vector &text) +Text::Text(love::graphics::Graphics *gfx, love::graphics::Font *font, const std::vector &text) : font(font) , vbo(nullptr) - , quadIndices(20) + , quadIndices(gfx, 20) , vert_offset(0) , texture_cache_id((uint32) -1) { @@ -59,25 +60,15 @@ void Text::uploadVertices(const std::vector &vertices, size_t { // Make it bigger than necessary to reduce potential future allocations. size_t newsize = size_t((offset + datasize) * 1.5); + if (vbo != nullptr) newsize = std::max(size_t(vbo->getSize() * 1.5), newsize); - GLBuffer *new_vbo = new GLBuffer(newsize, nullptr, BUFFER_VERTEX, vertex::USAGE_DYNAMIC); + auto gfx = Module::getInstance(Module::M_GRAPHICS); + Buffer *new_vbo = gfx->newBuffer(newsize, nullptr, BUFFER_VERTEX, vertex::USAGE_DYNAMIC, 0); if (vbo != nullptr) - { - try - { - vbodata = (uint8 *) vbo->map(); - } - catch (love::Exception &) - { - delete new_vbo; - throw; - } - - new_vbo->fill(0, vbo->getSize(), vbodata); - } + vbo->copyTo(0, vbo->getSize(), new_vbo, 0); delete vbo; vbo = new_vbo; @@ -229,7 +220,7 @@ void Text::draw(Graphics *gfx, const Matrix4 &m) totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts); if ((size_t) totalverts / 4 > quadIndices.getSize()) - quadIndices = QuadIndices((size_t) totalverts / 4); + quadIndices = QuadIndices(gfx, (size_t) totalverts / 4); const size_t pos_offset = offsetof(Font::GlyphVertex, x); const size_t tex_offset = offsetof(Font::GlyphVertex, s); @@ -243,16 +234,17 @@ void Text::draw(Graphics *gfx, const Matrix4 &m) gl.prepareDraw(); - vbo->bind(); vbo->unmap(); // Make sure all pending data is flushed to the GPU. - glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(pos_offset)); - glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, vbo->getPointer(tex_offset)); - glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, vbo->getPointer(color_offset)); + gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle()); + + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(pos_offset)); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, BUFFER_OFFSET(tex_offset)); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(color_offset)); gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR); - quadIndices.getBuffer()->bind(); + gl.bindBuffer(BUFFER_INDEX, (GLuint) quadIndices.getBuffer()->getHandle()); // We need a separate draw call for every section of the text which uses a // different texture than the previous section. @@ -264,7 +256,7 @@ void Text::draw(Graphics *gfx, const Matrix4 &m) // TODO: Use glDrawElementsBaseVertex when supported? gl.bindTextureToUnit((GLuint) cmd.texture, 0, false); - gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getPointer(offset)); + gl.drawElements(GL_TRIANGLES, count, gltype, BUFFER_OFFSET(offset)); } } diff --git a/src/modules/graphics/opengl/Text.h b/src/modules/graphics/opengl/Text.h index a5e0c907b..709e48e87 100644 --- a/src/modules/graphics/opengl/Text.h +++ b/src/modules/graphics/opengl/Text.h @@ -25,12 +25,15 @@ #include "common/config.h" #include "graphics/Drawable.h" #include "graphics/Font.h" -#include "GLBuffer.h" +#include "graphics/Buffer.h" namespace love { namespace graphics { + +class Graphics; + namespace opengl { @@ -40,7 +43,7 @@ public: static love::Type type; - Text(love::graphics::Font *font, const std::vector &text = {}); + Text(love::graphics::Graphics *gfx, love::graphics::Font *font, const std::vector &text = {}); virtual ~Text(); void set(const std::vector &text); @@ -85,7 +88,7 @@ private: void addTextData(const TextData &s); StrongRef font; - GLBuffer *vbo; + Buffer *vbo; QuadIndices quadIndices; std::vector draw_commands; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 0f3490e6b..fb93622ee 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -19,7 +19,6 @@ **/ #include "wrap_Graphics.h" -#include "OpenGL.h" #include "graphics/Texture.h" #include "image/ImageData.h" #include "image/Image.h" diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index 65744b28e..2395e1c80 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -66,6 +66,12 @@ size_t getIndexDataSize(IndexDataType type) } } +IndexDataType getIndexDataTypeFromMax(size_t maxvalue) +{ + IndexDataType types[] = {INDEX_UINT16, INDEX_UINT32}; + return types[maxvalue > LOVE_UINT16_MAX ? 1 : 0]; +} + int getIndexCount(TriangleIndexMode mode, int vertexCount) { switch (mode) diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 62d12fbed..7f289a300 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -123,6 +123,7 @@ struct XYf_STus_RGBAub size_t getFormatStride(CommonFormat format); size_t getIndexDataSize(IndexDataType type); +IndexDataType getIndexDataTypeFromMax(size_t maxvalue); int getIndexCount(TriangleIndexMode mode, int vertexCount);