From 03b1065b06e5a3b07977f70d17ceb841401b02b1 Mon Sep 17 00:00:00 2001 From: gaalve Date: Fri, 13 Jun 2025 17:41:03 +0200 Subject: [PATCH 01/10] added ignore item for visual studio development --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b98dc456f..ee08d9f77 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ compile_commands.json *.exe *.out *.app +/.vs From ccfd88c3ad57fbb7fc891974c341fddb6798b9e2 Mon Sep 17 00:00:00 2001 From: gaalve Date: Fri, 13 Jun 2025 17:44:11 +0200 Subject: [PATCH 02/10] added instance vertex count for more granular instanced rendering command --- include/polyscope/render/engine.h | 2 ++ include/polyscope/render/mock_opengl/mock_gl_engine.h | 3 ++- include/polyscope/render/opengl/gl_engine.h | 1 + src/render/mock_opengl/mock_gl_engine.cpp | 4 ++++ src/render/opengl/gl_engine.cpp | 8 ++++++-- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index 48a7493cc..8bd3c9c2d 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -401,6 +401,7 @@ class ShaderProgram { // Indices virtual void setInstanceCount(uint32_t instanceCount) = 0; + virtual void setInstanceVertexCount(uint32_t instanceVertexCount) = 0; // Call once to initialize GLSL code used by multiple shaders static void initCommonShaders(); // TODO @@ -432,6 +433,7 @@ class ShaderProgram { // instancing uint32_t instanceCount = INVALID_IND_32; + uint32_t instanceVertexCount = INVALID_IND_32; }; diff --git a/include/polyscope/render/mock_opengl/mock_gl_engine.h b/include/polyscope/render/mock_opengl/mock_gl_engine.h index bcdb7e3e4..4072cc953 100644 --- a/include/polyscope/render/mock_opengl/mock_gl_engine.h +++ b/include/polyscope/render/mock_opengl/mock_gl_engine.h @@ -280,8 +280,9 @@ class GLShaderProgram : public ShaderProgram { void setIndex(std::shared_ptr externalBuffer) override; void setPrimitiveRestartIndex(unsigned int restartIndex) override; - // Indices + // Instancing void setInstanceCount(uint32_t instanceCount) override; + void setInstanceVertexCount(uint32_t instanceVertexCount) override; // Textures bool hasTexture(std::string name) override; diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index ba57b9bd1..629bb0ad8 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -326,6 +326,7 @@ class GLShaderProgram : public ShaderProgram { // Instancing void setInstanceCount(uint32_t instanceCount) override; + void setInstanceVertexCount(uint32_t instanceVertexCount) override; // Textures bool hasTexture(std::string name) override; diff --git a/src/render/mock_opengl/mock_gl_engine.cpp b/src/render/mock_opengl/mock_gl_engine.cpp index 405c8366f..37033e38b 100644 --- a/src/render/mock_opengl/mock_gl_engine.cpp +++ b/src/render/mock_opengl/mock_gl_engine.cpp @@ -1481,6 +1481,9 @@ void GLShaderProgram::validateData() { if (instanceCount == INVALID_IND_32) { throw std::invalid_argument("Must set instance count to use instanced drawing"); } + if (instanceVertexCount == INVALID_IND_32) { + throw std::invalid_argument("Must set instance vertex count to use instanced drawing"); + } } } @@ -1493,6 +1496,7 @@ void GLShaderProgram::setPrimitiveRestartIndex(unsigned int restartIndex_) { } void GLShaderProgram::setInstanceCount(uint32_t instanceCount_) { instanceCount = instanceCount_; } +void GLShaderProgram::setInstanceVertexCount(uint32_t instanceVertexCount_) { instanceVertexCount = instanceVertexCount_; } void GLShaderProgram::activateTextures() { for (GLShaderTexture& t : textures) { diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index eff222853..2845e1e9a 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -2019,6 +2019,9 @@ void GLShaderProgram::validateData() { if (instanceCount == INVALID_IND_32) { throw std::invalid_argument("Must set instance count to use instanced drawing"); } + if (instanceVertexCount == INVALID_IND_32) { + throw std::invalid_argument("Must set instance vertex count to use instanced drawing"); + } } } @@ -2031,6 +2034,7 @@ void GLShaderProgram::setPrimitiveRestartIndex(unsigned int restartIndex_) { } void GLShaderProgram::setInstanceCount(uint32_t instanceCount_) { instanceCount = instanceCount_; } +void GLShaderProgram::setInstanceVertexCount(uint32_t instanceVertexCount_) { instanceVertexCount = instanceVertexCount_; } void GLShaderProgram::activateTextures() { for (GLShaderTexture& t : textures) { @@ -2092,10 +2096,10 @@ void GLShaderProgram::draw() { glDrawElements(GL_TRIANGLES, drawDataLength, GL_UNSIGNED_INT, 0); break; case DrawMode::TrianglesInstanced: - glDrawArraysInstanced(GL_TRIANGLES, 0, drawDataLength, instanceCount); + glDrawArraysInstanced(GL_TRIANGLES, 0, instanceVertexCount, instanceCount); break; case DrawMode::TriangleStripInstanced: - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, drawDataLength, instanceCount); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, instanceVertexCount, instanceCount); break; } From eaea0ae6c3f345d40ad9529c1d673aa42f9c24eb Mon Sep 17 00:00:00 2001 From: gaalve Date: Fri, 13 Jun 2025 17:45:23 +0200 Subject: [PATCH 03/10] fixed: integer types were previously implicitly cast to floating point types on gpu --- src/render/opengl/gl_engine.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index 2845e1e9a..704004017 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -1299,11 +1299,11 @@ void GLShaderProgram::assignBufferToVAO(GLShaderAttribute& a) { reinterpret_cast(sizeof(float) * 1 * iArrInd)); break; case RenderDataType::Int: - glVertexAttribPointer(a.location + iArrInd, 1, GL_INT, GL_FALSE, sizeof(int) * 1 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 1, GL_INT, sizeof(int) * 1 * a.arrayCount, reinterpret_cast(sizeof(int) * 1 * iArrInd)); break; case RenderDataType::UInt: - glVertexAttribPointer(a.location + iArrInd, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 1 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 1, GL_UNSIGNED_INT, sizeof(uint32_t) * 1 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 1 * iArrInd)); break; case RenderDataType::Vector2Float: @@ -1319,15 +1319,15 @@ void GLShaderProgram::assignBufferToVAO(GLShaderAttribute& a) { reinterpret_cast(sizeof(float) * 4 * iArrInd)); break; case RenderDataType::Vector2UInt: - glVertexAttribPointer(a.location + iArrInd, 2, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 2 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 2, GL_UNSIGNED_INT, sizeof(uint32_t) * 2 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 2 * iArrInd)); break; case RenderDataType::Vector3UInt: - glVertexAttribPointer(a.location + iArrInd, 3, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 3 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 3, GL_UNSIGNED_INT, sizeof(uint32_t) * 3 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 3 * iArrInd)); break; case RenderDataType::Vector4UInt: - glVertexAttribPointer(a.location + iArrInd, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 4 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 4, GL_UNSIGNED_INT, sizeof(uint32_t) * 4 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 4 * iArrInd)); break; default: From 3cdd548dd4b6ef80ee084c9d50509ee08b2727ed Mon Sep 17 00:00:00 2001 From: gaalve Date: Fri, 13 Jun 2025 17:45:46 +0200 Subject: [PATCH 04/10] added attribute divisor for instanced rendering --- include/polyscope/render/engine.h | 8 +++++--- include/polyscope/render/opengl/gl_engine.h | 1 + src/render/opengl/gl_engine.cpp | 7 ++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index 8bd3c9c2d..bbe5c4624 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -291,12 +291,14 @@ struct ShaderSpecUniform { const RenderDataType type; }; struct ShaderSpecAttribute { - ShaderSpecAttribute(std::string name_, RenderDataType type_) : name(name_), type(type_), arrayCount(1) {} - ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_) - : name(name_), type(type_), arrayCount(arrayCount_) {} + ShaderSpecAttribute(std::string name_, RenderDataType type_, int attribDivisor = 0) + : name(name_), type(type_), arrayCount(1), attribDivisor(attribDivisor) {} + ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_, int attribDivisor = 0) + : name(name_), type(type_), arrayCount(arrayCount_), attribDivisor(attribDivisor) {} const std::string name; const RenderDataType type; const int arrayCount; // number of times this element is repeated in an array + const int attribDivisor; }; struct ShaderSpecTexture { const std::string name; diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index 629bb0ad8..718a04431 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -237,6 +237,7 @@ struct GLShaderAttribute { std::string name; RenderDataType type; int arrayCount; + int attribDivisor; AttributeLocation location; // -1 means "no location", usually because it was optimized out std::shared_ptr buff; // the buffer that we will actually use }; diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index 704004017..d3ad3d60d 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -1174,7 +1174,7 @@ void GLCompiledProgram::addUniqueAttribute(ShaderSpecAttribute newAttribute) { return; } } - attributes.push_back(GLShaderAttribute{newAttribute.name, newAttribute.type, newAttribute.arrayCount, -1, nullptr}); + attributes.push_back(GLShaderAttribute{newAttribute.name, newAttribute.type, newAttribute.arrayCount, newAttribute.attribDivisor, -1, nullptr}); } void GLCompiledProgram::addUniqueUniform(ShaderSpecUniform newUniform) { @@ -1334,6 +1334,11 @@ void GLShaderProgram::assignBufferToVAO(GLShaderAttribute& a) { throw std::invalid_argument("Unrecognized GLShaderAttribute type"); break; } + + if (a.attribDivisor > 0) { + glVertexAttribDivisor(a.location + iArrInd, a.attribDivisor); + } + } checkGLError(); From 75a06c34b45c3421e36f9f330418f9da2e4102bc Mon Sep 17 00:00:00 2001 From: gaalve Date: Fri, 13 Jun 2025 18:09:51 +0200 Subject: [PATCH 05/10] fixed shader spec attribute constructor ambigous --- include/polyscope/render/engine.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index bbe5c4624..6539f030b 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "polyscope/render/color_maps.h" @@ -291,10 +292,8 @@ struct ShaderSpecUniform { const RenderDataType type; }; struct ShaderSpecAttribute { - ShaderSpecAttribute(std::string name_, RenderDataType type_, int attribDivisor = 0) - : name(name_), type(type_), arrayCount(1), attribDivisor(attribDivisor) {} - ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_, int attribDivisor = 0) - : name(name_), type(type_), arrayCount(arrayCount_), attribDivisor(attribDivisor) {} + ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_ = 1, int attribDivisor = 0) + : name(std::move(name_)), type(type_), arrayCount(arrayCount_), attribDivisor(attribDivisor) {} const std::string name; const RenderDataType type; const int arrayCount; // number of times this element is repeated in an array From 2fe80c4325d4ce1383e3b80a824a6c9674141d1b Mon Sep 17 00:00:00 2001 From: gaalve Date: Sun, 15 Jun 2025 21:14:30 +0200 Subject: [PATCH 06/10] reverting unintentional change --- include/polyscope/render/engine.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index 6539f030b..46dd2ac7b 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "polyscope/render/color_maps.h" @@ -293,7 +292,7 @@ struct ShaderSpecUniform { }; struct ShaderSpecAttribute { ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_ = 1, int attribDivisor = 0) - : name(std::move(name_)), type(type_), arrayCount(arrayCount_), attribDivisor(attribDivisor) {} + : name(name_), type(type_), arrayCount(arrayCount_), attribDivisor(attribDivisor) {} const std::string name; const RenderDataType type; const int arrayCount; // number of times this element is repeated in an array From dcbcb866e37a44c272e4f49fa94bd7968ddec183 Mon Sep 17 00:00:00 2001 From: gaalve Date: Mon, 16 Jun 2025 02:54:37 +0200 Subject: [PATCH 07/10] added texture buffer support --- include/polyscope/render/opengl/gl_engine.h | 39 +++++++ src/render/opengl/gl_engine.cpp | 108 ++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index 718a04431..6ccd4627f 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -30,6 +30,7 @@ namespace backend_openGL3 { // Some very nice typdefs typedef GLuint TextureBufferHandle; +typedef GLuint TextureStorageBufferHandle; typedef GLuint RenderBufferHandle; typedef GLuint FrameBufferHandle; typedef GLuint ShaderHandle; @@ -173,6 +174,44 @@ class GLTextureBuffer : public TextureBuffer { protected: TextureBufferHandle handle; + + static GLTextureBuffer createUnintializedTextureBuffer(TextureFormat format, unsigned int size1D); + +private: + GLTextureBuffer(): TextureBuffer(1, TextureFormat::RGB8, 0), handle{0} {} +}; + +class GLStorageTextureBuffer : public GLTextureBuffer { +public: + ~GLStorageTextureBuffer() override; + void resize(unsigned newLen) override; + void resize(unsigned newX, unsigned newY) override; + void resize(unsigned newX, unsigned newY, unsigned newZ) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setFilterMode(FilterMode newMode) override; + void* getNativeHandle() override; + uint32_t getNativeBufferID() override; + std::vector getDataScalar() override; + std::vector getDataVector2() override; + std::vector getDataVector3() override; + + // Note: underlying buffer uses R32F as the internal format + // to support other formats here resizing, setData and getData need new logic + GLStorageTextureBuffer(unsigned int size1D, float* data); +protected: + TextureStorageBufferHandle bufferHandle; }; class GLRenderBuffer : public RenderBuffer { diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index d3ad3d60d..1fcc0b9cc 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -770,6 +770,114 @@ void GLTextureBuffer::bind() { checkGLError(); } +GLTextureBuffer GLTextureBuffer::createUnintializedTextureBuffer(TextureFormat format, unsigned int size1D) { + GLTextureBuffer buffer = {}; + buffer.format = format; + buffer.sizeX = size1D; + return buffer; +} + +// ============================================================= +// ===================== Storage Texture buffer ========================= +// ============================================================= + + + +GLStorageTextureBuffer::~GLStorageTextureBuffer() { + glDeleteBuffers(1, &bufferHandle); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + if (data.size() != getTotalSize()) { + exception("OpenGL error: texture buffer data is not the right size."); + } + + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glBufferSubData(GL_TEXTURE_BUFFER, 0, getSizeInBytes(), &data.front()); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); +} + +void GLStorageTextureBuffer::resize(unsigned newLen) { + + // intentionally skipping the logic of GLTextureBuffer::resize here + TextureBuffer::resize(newLen); // NOLINT(bugprone-parent-virtual-call) + + glDeleteBuffers(1, &bufferHandle); + + glGenBuffers(1, &bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glBufferData(GL_TEXTURE_BUFFER, getSizeInBytes(), nullptr, GL_DYNAMIC_DRAW); + + glBindTexture(GL_TEXTURE_BUFFER, handle); + glTexBuffer(GL_TEXTURE_BUFFER, internalFormat(format), bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); +} +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY) { exception("buffer textures only support 1 dimension"); } +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY, unsigned newZ) { exception("buffer textures only support 1 dimension"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } + +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector>& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector>& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector>& data) { exception("not implemented"); } + +void GLStorageTextureBuffer::setFilterMode(FilterMode newMode) { + // no op - gsampleBuffer does not have a filter mode +} + +void* GLStorageTextureBuffer::getNativeHandle() { + return GLTextureBuffer::getNativeHandle(); +} + +uint32_t GLStorageTextureBuffer::getNativeBufferID() { + return GLTextureBuffer::getNativeBufferID(); +} + +std::vector GLStorageTextureBuffer::getDataScalar() { + + std::vector outData; + outData.resize(getTotalSize()); + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glGetBufferSubData(GL_TEXTURE_BUFFER, 0, getSizeInBytes(), &outData.front()); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); + + return outData; +} +std::vector GLStorageTextureBuffer::getDataVector2() { + exception("not implemented"); + return {}; +} +std::vector GLStorageTextureBuffer::getDataVector3() { + exception("not implemented"); + return {}; +} + +GLStorageTextureBuffer::GLStorageTextureBuffer(unsigned int size1D, float* data) : GLTextureBuffer{createUnintializedTextureBuffer(TextureFormat::R32F, size1D)}{ + glGenBuffers(1, &bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glBufferData(GL_TEXTURE_BUFFER, getSizeInBytes(), data, GL_DYNAMIC_DRAW); + + glGenTextures(1, &handle); + glBindTexture(GL_TEXTURE_BUFFER, handle); + glTexBuffer(GL_TEXTURE_BUFFER, internalFormat(format), bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); +} + // ============================================================= // ===================== Render buffer ========================= // ============================================================= From f252b0b5fbf7b05b978be5898da78767f5de592b Mon Sep 17 00:00:00 2001 From: gaalve Date: Mon, 16 Jun 2025 12:39:21 +0200 Subject: [PATCH 08/10] added mock gl implementation of buffer texture + convenience method --- include/polyscope/render/engine.h | 3 + .../render/mock_opengl/mock_gl_engine.h | 35 ++++++ include/polyscope/render/opengl/gl_engine.h | 3 + src/render/mock_opengl/mock_gl_engine.cpp | 113 ++++++++++++++++++ src/render/opengl/gl_engine.cpp | 13 +- 5 files changed, 163 insertions(+), 4 deletions(-) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index 46dd2ac7b..f6ba2188d 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -551,6 +551,9 @@ class Engine { unsigned int sizeY_, unsigned int sizeZ_, const float* data) = 0; // 3d + // create buffer texture + virtual std::shared_ptr generateStorageTextureBuffer(unsigned int size1D, float* data) = 0; + // create render buffers virtual std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) = 0; diff --git a/include/polyscope/render/mock_opengl/mock_gl_engine.h b/include/polyscope/render/mock_opengl/mock_gl_engine.h index 4072cc953..ebbcfd4e4 100644 --- a/include/polyscope/render/mock_opengl/mock_gl_engine.h +++ b/include/polyscope/render/mock_opengl/mock_gl_engine.h @@ -139,6 +139,38 @@ class GLTextureBuffer : public TextureBuffer { protected: }; +class GLStorageTextureBuffer : public GLTextureBuffer { +public: + ~GLStorageTextureBuffer() override; + void resize(unsigned newLen) override; + void resize(unsigned newX, unsigned newY) override; + void resize(unsigned newX, unsigned newY, unsigned newZ) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setFilterMode(FilterMode newMode) override; + void* getNativeHandle() override; + uint32_t getNativeBufferID() override; + std::vector getDataScalar() override; + std::vector getDataVector2() override; + std::vector getDataVector3() override; + + // Note: underlying buffer uses R32F as the internal format + // to support other formats here resizing, setData and getData need new logic + GLStorageTextureBuffer(unsigned int size1D, float* data); +protected: +}; + class GLRenderBuffer : public RenderBuffer { public: GLRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_); @@ -385,6 +417,9 @@ class MockGLEngine : public Engine { unsigned int sizeZ_, const float* data) override; // 3d + // create buffer texture + std::shared_ptr generateStorageTextureBuffer(unsigned int size1D, float* data) override; + // create render buffers std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) override; diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index 6ccd4627f..7e526d2c4 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -444,6 +444,9 @@ class GLEngine : public Engine { unsigned int sizeZ_, const float* data) override; // 3d + // create buffer texture + std::shared_ptr generateStorageTextureBuffer(unsigned int size1D, float* data) override; + // create render buffers std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) override; diff --git a/src/render/mock_opengl/mock_gl_engine.cpp b/src/render/mock_opengl/mock_gl_engine.cpp index 37033e38b..19b1b1ab6 100644 --- a/src/render/mock_opengl/mock_gl_engine.cpp +++ b/src/render/mock_opengl/mock_gl_engine.cpp @@ -519,6 +519,115 @@ void GLTextureBuffer::bind() { checkGLError(); } +GLStorageTextureBuffer::~GLStorageTextureBuffer() {} + +void GLStorageTextureBuffer::resize(unsigned newLen) { + // intentionally skipping the logic of GLTextureBuffer::resize here + TextureBuffer::resize(newLen); // NOLINT(bugprone-parent-virtual-call) + + checkGLError(); +} + +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY) { + exception("buffer textures only support 1 dimension"); +} + +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY, unsigned newZ) { + exception("buffer textures only support 1 dimension"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + if (data.size() != getTotalSize()) { + exception("OpenGL error: texture buffer data is not the right size."); + } + + checkGLError(); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector>& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector>& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector>& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setFilterMode(FilterMode newMode) { + // no-op +} + +void* GLStorageTextureBuffer::getNativeHandle() { + return GLTextureBuffer::getNativeHandle(); +} + +uint32_t GLStorageTextureBuffer::getNativeBufferID() { + return GLTextureBuffer::getNativeBufferID(); +} + +std::vector GLStorageTextureBuffer::getDataScalar() { + std::vector outData; + outData.resize(getTotalSize()); + + return outData; +} + +std::vector GLStorageTextureBuffer::getDataVector2() { + std::vector outData; + outData.resize(getTotalSize()); + exception("not implemented"); + return outData; +} + +std::vector GLStorageTextureBuffer::getDataVector3() { + std::vector outData; + outData.resize(getTotalSize()); + exception("not implemented"); + return outData; +} + +GLStorageTextureBuffer::GLStorageTextureBuffer(unsigned int size1D, float* data): GLTextureBuffer{TextureFormat::R32F, size1D} { +} + // ============================================================= // ===================== Render buffer ========================= // ============================================================= @@ -1746,6 +1855,10 @@ std::shared_ptr MockGLEngine::generateTextureBuffer(TextureFormat return std::shared_ptr(newT); } +std::shared_ptr MockGLEngine::generateStorageTextureBuffer(unsigned int size1D, float* data) { + throw std::logic_error("Not implemented"); +} + std::shared_ptr MockGLEngine::generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) { diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index 1fcc0b9cc..0d6f7ae81 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -778,7 +778,7 @@ GLTextureBuffer GLTextureBuffer::createUnintializedTextureBuffer(TextureFormat f } // ============================================================= -// ===================== Storage Texture buffer ========================= +// =================== Storage Texture buffer ================== // ============================================================= @@ -788,9 +788,9 @@ GLStorageTextureBuffer::~GLStorageTextureBuffer() { } void GLStorageTextureBuffer::setData(const std::vector& data) { - if (data.size() != getTotalSize()) { - exception("OpenGL error: texture buffer data is not the right size."); - } + if (data.size() != getTotalSize()) { + exception("OpenGL error: texture buffer data is not the right size."); + } glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); glBufferSubData(GL_TEXTURE_BUFFER, 0, getSizeInBytes(), &data.front()); @@ -2405,6 +2405,11 @@ std::shared_ptr GLEngine::generateTextureBuffer(TextureFormat for return std::shared_ptr(newT); } +std::shared_ptr GLEngine::generateStorageTextureBuffer(unsigned int size1D, float* data) { + GLStorageTextureBuffer* newT = new GLStorageTextureBuffer(size1D, data); + return std::shared_ptr(newT); +} + std::shared_ptr GLEngine::generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) { GLRenderBuffer* newR = new GLRenderBuffer(type, sizeX_, sizeY_); From 42f4e2bf8d4723e2ca262d390cb7879d12d78adf Mon Sep 17 00:00:00 2001 From: gaalve Date: Wed, 18 Jun 2025 21:56:44 +0200 Subject: [PATCH 09/10] added support for texture buffers with integer data format --- include/polyscope/render/engine.h | 4 ++-- .../render/mock_opengl/mock_gl_engine.h | 4 ++-- include/polyscope/render/opengl/gl_engine.h | 6 +++--- src/render/engine.cpp | 4 ++++ src/render/mock_opengl/mock_gl_engine.cpp | 8 +++++--- src/render/opengl/gl_engine.cpp | 16 +++++++++++++--- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index f6ba2188d..6020aeac7 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -36,7 +36,7 @@ enum class DrawMode { TriangleStripInstanced, }; -enum class TextureFormat { RGB8 = 0, RGBA8, RG16F, RGB16F, RGBA16F, RGBA32F, RGB32F, R32F, R16F, DEPTH24 }; +enum class TextureFormat { RGB8 = 0, RGBA8, RG16F, RGB16F, RGBA16F, RGBA32F, RGB32F, R32F, R16F, DEPTH24, R32UI, R32I }; enum class RenderBufferType { Color, ColorAlpha, Depth, Float4 }; enum class DepthMode { Less, LEqual, LEqualReadOnly, Greater, Disable, PassReadOnly }; enum class BlendMode { AlphaOver, OverNoWrite, AlphaUnder, Zero, WeightedAdd, Add, Source, Disable }; @@ -552,7 +552,7 @@ class Engine { const float* data) = 0; // 3d // create buffer texture - virtual std::shared_ptr generateStorageTextureBuffer(unsigned int size1D, float* data) = 0; + virtual std::shared_ptr generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) = 0; // create render buffers virtual std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, diff --git a/include/polyscope/render/mock_opengl/mock_gl_engine.h b/include/polyscope/render/mock_opengl/mock_gl_engine.h index ebbcfd4e4..7acd96ed5 100644 --- a/include/polyscope/render/mock_opengl/mock_gl_engine.h +++ b/include/polyscope/render/mock_opengl/mock_gl_engine.h @@ -167,7 +167,7 @@ class GLStorageTextureBuffer : public GLTextureBuffer { // Note: underlying buffer uses R32F as the internal format // to support other formats here resizing, setData and getData need new logic - GLStorageTextureBuffer(unsigned int size1D, float* data); + GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data); protected: }; @@ -418,7 +418,7 @@ class MockGLEngine : public Engine { const float* data) override; // 3d // create buffer texture - std::shared_ptr generateStorageTextureBuffer(unsigned int size1D, float* data) override; + std::shared_ptr generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) override; // create render buffers std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index 7e526d2c4..339c86882 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -207,9 +207,9 @@ class GLStorageTextureBuffer : public GLTextureBuffer { std::vector getDataVector2() override; std::vector getDataVector3() override; - // Note: underlying buffer uses R32F as the internal format + // Note: underlying buffer expects a type with 4 bytes and 1 dimension as the internal format // to support other formats here resizing, setData and getData need new logic - GLStorageTextureBuffer(unsigned int size1D, float* data); + GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data); protected: TextureStorageBufferHandle bufferHandle; }; @@ -445,7 +445,7 @@ class GLEngine : public Engine { const float* data) override; // 3d // create buffer texture - std::shared_ptr generateStorageTextureBuffer(unsigned int size1D, float* data) override; + std::shared_ptr generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) override; // create render buffers std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, diff --git a/src/render/engine.cpp b/src/render/engine.cpp index c959a2628..a0754afac 100644 --- a/src/render/engine.cpp +++ b/src/render/engine.cpp @@ -25,6 +25,8 @@ int dimension(const TextureFormat& x) { case TextureFormat::RGB32F: return 3; case TextureFormat::RGBA32F: return 4; case TextureFormat::DEPTH24: return 1; + case TextureFormat::R32UI: return 1; + case TextureFormat::R32I: return 1; } // clang-format on exception("bad enum"); @@ -44,6 +46,8 @@ int sizeInBytes(const TextureFormat& f) { case TextureFormat::RGB32F: return 3*4; case TextureFormat::RGBA32F: return 4*4; case TextureFormat::DEPTH24: return 1*3; + case TextureFormat::R32UI: return 1*4; + case TextureFormat::R32I: return 1*4; } // clang-format on return -1; diff --git a/src/render/mock_opengl/mock_gl_engine.cpp b/src/render/mock_opengl/mock_gl_engine.cpp index 19b1b1ab6..ebdf9c803 100644 --- a/src/render/mock_opengl/mock_gl_engine.cpp +++ b/src/render/mock_opengl/mock_gl_engine.cpp @@ -625,7 +625,8 @@ std::vector GLStorageTextureBuffer::getDataVector3() { return outData; } -GLStorageTextureBuffer::GLStorageTextureBuffer(unsigned int size1D, float* data): GLTextureBuffer{TextureFormat::R32F, size1D} { +GLStorageTextureBuffer::GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data): GLTextureBuffer{format, size1D} { + if (sizeInBytes(format) != 4 && dimension(format) != 1) exception("Unsupported format specified. Format with 1 dimesnion and 4 bytes expected."); } // ============================================================= @@ -1855,8 +1856,9 @@ std::shared_ptr MockGLEngine::generateTextureBuffer(TextureFormat return std::shared_ptr(newT); } -std::shared_ptr MockGLEngine::generateStorageTextureBuffer(unsigned int size1D, float* data) { - throw std::logic_error("Not implemented"); +std::shared_ptr MockGLEngine::generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) { + GLStorageTextureBuffer* newT = new GLStorageTextureBuffer(format, size1D, data); + return std::shared_ptr(newT); } diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index 0d6f7ae81..f21a9cb1f 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -54,6 +54,9 @@ inline GLenum internalFormat(const TextureFormat& x) { case TextureFormat::RGB32F: return GL_RGBA32F; case TextureFormat::RGBA32F: return GL_RGBA32F; case TextureFormat::DEPTH24: return GL_DEPTH_COMPONENT24; + case TextureFormat::R32UI: return GL_R32UI; + case TextureFormat::R32I: return GL_R32I; + break; } exception("bad enum"); return GL_RGB8; @@ -71,6 +74,8 @@ inline GLenum formatF(const TextureFormat& x) { case TextureFormat::RGB32F: return GL_RGB; case TextureFormat::RGBA32F: return GL_RGBA; case TextureFormat::DEPTH24: return GL_DEPTH_COMPONENT; + case TextureFormat::R32UI: return GL_RED; + case TextureFormat::R32I: return GL_RED; } exception("bad enum"); return GL_RGB; @@ -88,6 +93,8 @@ inline GLenum type(const TextureFormat& x) { case TextureFormat::RGB32F: return GL_FLOAT; case TextureFormat::RGBA32F: return GL_FLOAT; case TextureFormat::DEPTH24: return GL_FLOAT; + case TextureFormat::R32UI: return GL_UNSIGNED_INT; + case TextureFormat::R32I: return GL_INT; } exception("bad enum"); return GL_UNSIGNED_BYTE; @@ -865,7 +872,10 @@ std::vector GLStorageTextureBuffer::getDataVector3() { return {}; } -GLStorageTextureBuffer::GLStorageTextureBuffer(unsigned int size1D, float* data) : GLTextureBuffer{createUnintializedTextureBuffer(TextureFormat::R32F, size1D)}{ +GLStorageTextureBuffer::GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) : GLTextureBuffer{createUnintializedTextureBuffer(format, size1D)}{ + + if (sizeInBytes(format) != 4 && dimension(format) != 1) exception("Unsupported format specified. Format with 1 dimesnion and 4 bytes expected."); + glGenBuffers(1, &bufferHandle); glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); glBufferData(GL_TEXTURE_BUFFER, getSizeInBytes(), data, GL_DYNAMIC_DRAW); @@ -2405,8 +2415,8 @@ std::shared_ptr GLEngine::generateTextureBuffer(TextureFormat for return std::shared_ptr(newT); } -std::shared_ptr GLEngine::generateStorageTextureBuffer(unsigned int size1D, float* data) { - GLStorageTextureBuffer* newT = new GLStorageTextureBuffer(size1D, data); +std::shared_ptr GLEngine::generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) { + GLStorageTextureBuffer* newT = new GLStorageTextureBuffer(format, size1D, data); return std::shared_ptr(newT); } From 2ef918a6406d25a8dd7c5d3e20aee2b0f54ec152 Mon Sep 17 00:00:00 2001 From: gaalve Date: Wed, 18 Jun 2025 22:38:23 +0200 Subject: [PATCH 10/10] fixed used wrong target when binding texture buffers --- include/polyscope/render/opengl/gl_engine.h | 4 +++- src/render/opengl/gl_engine.cpp | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index 339c86882..185641fd8 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -168,7 +168,7 @@ class GLTextureBuffer : public TextureBuffer { std::vector getDataVector3() override; void bind(); - GLenum textureType(); + virtual GLenum textureType(); TextureBufferHandle getHandle() const { return handle; } @@ -207,6 +207,8 @@ class GLStorageTextureBuffer : public GLTextureBuffer { std::vector getDataVector2() override; std::vector getDataVector3() override; + GLenum textureType() override; + // Note: underlying buffer expects a type with 4 bytes and 1 dimension as the internal format // to support other formats here resizing, setData and getData need new logic GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data); diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index f21a9cb1f..efb60a89f 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -872,6 +872,10 @@ std::vector GLStorageTextureBuffer::getDataVector3() { return {}; } +GLenum GLStorageTextureBuffer::textureType() { + return GL_TEXTURE_BUFFER; +} + GLStorageTextureBuffer::GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) : GLTextureBuffer{createUnintializedTextureBuffer(format, size1D)}{ if (sizeInBytes(format) != 4 && dimension(format) != 1) exception("Unsupported format specified. Format with 1 dimesnion and 4 bytes expected.");