From cc87ef7a3c73669bcaeea7873f68f39adc43b718 Mon Sep 17 00:00:00 2001 From: Chris Thrasher Date: Thu, 23 May 2024 12:45:52 -0600 Subject: [PATCH] Use `std::string_view` to construct `sf::Shader`s without allocations --- include/SFML/Graphics/Shader.hpp | 18 ++++---- src/SFML/Graphics/Shader.cpp | 78 ++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/include/SFML/Graphics/Shader.hpp b/include/SFML/Graphics/Shader.hpp index bb4914a99..3aef99703 100644 --- a/include/SFML/Graphics/Shader.hpp +++ b/include/SFML/Graphics/Shader.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -200,7 +201,7 @@ public: /// \see loadFromFile, loadFromStream /// //////////////////////////////////////////////////////////// - [[nodiscard]] static std::optional loadFromMemory(const std::string& shader, Type type); + [[nodiscard]] static std::optional loadFromMemory(std::string_view shader, Type type); //////////////////////////////////////////////////////////// /// \brief Load both the vertex and fragment shaders from source codes in memory @@ -221,8 +222,7 @@ public: /// \see loadFromFile, loadFromStream /// //////////////////////////////////////////////////////////// - [[nodiscard]] static std::optional loadFromMemory(const std::string& vertexShader, - const std::string& fragmentShader); + [[nodiscard]] static std::optional loadFromMemory(std::string_view vertexShader, std::string_view fragmentShader); //////////////////////////////////////////////////////////// /// \brief Load the vertex, geometry and fragment shaders from source codes in memory @@ -244,9 +244,9 @@ public: /// \see loadFromFile, loadFromStream /// //////////////////////////////////////////////////////////// - [[nodiscard]] static std::optional loadFromMemory(const std::string& vertexShader, - const std::string& geometryShader, - const std::string& fragmentShader); + [[nodiscard]] static std::optional loadFromMemory(std::string_view vertexShader, + std::string_view geometryShader, + std::string_view fragmentShader); //////////////////////////////////////////////////////////// /// \brief Load the vertex, geometry or fragment shader from a custom stream @@ -664,9 +664,9 @@ private: /// \return Shader on success, `std::nullopt` if any error happened /// //////////////////////////////////////////////////////////// - [[nodiscard]] static std::optional compile(const char* vertexShaderCode, - const char* geometryShaderCode, - const char* fragmentShaderCode); + [[nodiscard]] static std::optional compile(std::string_view vertexShaderCode, + std::string_view geometryShaderCode, + std::string_view fragmentShaderCode); //////////////////////////////////////////////////////////// /// \brief Bind all the textures used by the shader diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp index 4bd99fdab..e06f2e00d 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -281,11 +281,11 @@ std::optional Shader::loadFromFile(const std::filesystem::path& filename // Compile the shader program if (type == Type::Vertex) - return compile(shader.data(), nullptr, nullptr); + return compile(shader.data(), {}, {}); else if (type == Type::Geometry) - return compile(nullptr, shader.data(), nullptr); + return compile({}, shader.data(), {}); else - return compile(nullptr, nullptr, shader.data()); + return compile({}, {}, shader.data()); } @@ -310,7 +310,7 @@ std::optional Shader::loadFromFile(const std::filesystem::path& vertexSh } // Compile the shader program - return compile(vertexShader.data(), nullptr, fragmentShader.data()); + return compile(vertexShader.data(), {}, fragmentShader.data()); } @@ -349,33 +349,33 @@ std::optional Shader::loadFromFile(const std::filesystem::path& vertexSh //////////////////////////////////////////////////////////// -std::optional Shader::loadFromMemory(const std::string& shader, Type type) +std::optional Shader::loadFromMemory(std::string_view shader, Type type) { // Compile the shader program if (type == Type::Vertex) - return compile(shader.c_str(), nullptr, nullptr); + return compile(shader, {}, {}); else if (type == Type::Geometry) - return compile(nullptr, shader.c_str(), nullptr); + return compile({}, shader, {}); else - return compile(nullptr, nullptr, shader.c_str()); + return compile({}, {}, shader); } //////////////////////////////////////////////////////////// -std::optional Shader::loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader) +std::optional Shader::loadFromMemory(std::string_view vertexShader, std::string_view fragmentShader) { // Compile the shader program - return compile(vertexShader.c_str(), nullptr, fragmentShader.c_str()); + return compile(vertexShader, {}, fragmentShader); } //////////////////////////////////////////////////////////// -std::optional Shader::loadFromMemory(const std::string& vertexShader, - const std::string& geometryShader, - const std::string& fragmentShader) +std::optional Shader::loadFromMemory(std::string_view vertexShader, + std::string_view geometryShader, + std::string_view fragmentShader) { // Compile the shader program - return compile(vertexShader.c_str(), geometryShader.c_str(), fragmentShader.c_str()); + return compile(vertexShader, geometryShader, fragmentShader); } @@ -392,11 +392,11 @@ std::optional Shader::loadFromStream(InputStream& stream, Type type) // Compile the shader program if (type == Type::Vertex) - return compile(shader.data(), nullptr, nullptr); + return compile(shader.data(), {}, {}); else if (type == Type::Geometry) - return compile(nullptr, shader.data(), nullptr); + return compile({}, shader.data(), {}); else - return compile(nullptr, nullptr, shader.data()); + return compile({}, {}, shader.data()); } @@ -420,7 +420,7 @@ std::optional Shader::loadFromStream(InputStream& vertexShaderStream, In } // Compile the shader program - return compile(vertexShader.data(), nullptr, fragmentShader.data()); + return compile(vertexShader.data(), {}, fragmentShader.data()); } @@ -778,7 +778,9 @@ Shader::Shader(unsigned int shaderProgram) : m_shaderProgram(shaderProgram) //////////////////////////////////////////////////////////// -std::optional Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) +std::optional Shader::compile(std::string_view vertexShaderCode, + std::string_view geometryShaderCode, + std::string_view fragmentShaderCode) { const TransientContextLock lock; @@ -791,7 +793,7 @@ std::optional Shader::compile(const char* vertexShaderCode, const char* } // Make sure we can use geometry shaders - if (geometryShaderCode && !isGeometryAvailable()) + if (geometryShaderCode.data() && !isGeometryAvailable()) { err() << "Failed to create a shader: your system doesn't support geometry shaders " << "(you should test Shader::isGeometryAvailable() before trying to use geometry shaders)" << std::endl; @@ -803,12 +805,14 @@ std::optional Shader::compile(const char* vertexShaderCode, const char* glCheck(shaderProgram = GLEXT_glCreateProgramObject()); // Create the vertex shader if needed - if (vertexShaderCode) + if (vertexShaderCode.data()) { // Create and compile the shader GLEXT_GLhandle vertexShader{}; glCheck(vertexShader = GLEXT_glCreateShaderObject(GLEXT_GL_VERTEX_SHADER)); - glCheck(GLEXT_glShaderSource(vertexShader, 1, &vertexShaderCode, nullptr)); + const GLcharARB* sourceCode = vertexShaderCode.data(); + const auto sourceCodeLength = static_cast(vertexShaderCode.length()); + glCheck(GLEXT_glShaderSource(vertexShader, 1, &sourceCode, &sourceCodeLength)); glCheck(GLEXT_glCompileShader(vertexShader)); // Check the compile log @@ -830,11 +834,13 @@ std::optional Shader::compile(const char* vertexShaderCode, const char* } // Create the geometry shader if needed - if (geometryShaderCode) + if (geometryShaderCode.data()) { // Create and compile the shader - const GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER); - glCheck(GLEXT_glShaderSource(geometryShader, 1, &geometryShaderCode, nullptr)); + const GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER); + const GLcharARB* sourceCode = geometryShaderCode.data(); + const auto sourceCodeLength = static_cast(geometryShaderCode.length()); + glCheck(GLEXT_glShaderSource(geometryShader, 1, &sourceCode, &sourceCodeLength)); glCheck(GLEXT_glCompileShader(geometryShader)); // Check the compile log @@ -856,12 +862,14 @@ std::optional Shader::compile(const char* vertexShaderCode, const char* } // Create the fragment shader if needed - if (fragmentShaderCode) + if (fragmentShaderCode.data()) { // Create and compile the shader GLEXT_GLhandle fragmentShader{}; glCheck(fragmentShader = GLEXT_glCreateShaderObject(GLEXT_GL_FRAGMENT_SHADER)); - glCheck(GLEXT_glShaderSource(fragmentShader, 1, &fragmentShaderCode, nullptr)); + const GLcharARB* sourceCode = fragmentShaderCode.data(); + const auto sourceCodeLength = static_cast(fragmentShaderCode.length()); + glCheck(GLEXT_glShaderSource(fragmentShader, 1, &sourceCode, &sourceCodeLength)); glCheck(GLEXT_glCompileShader(fragmentShader)); // Check the compile log @@ -990,23 +998,23 @@ std::optional Shader::loadFromFile(const std::filesystem::path& /* verte //////////////////////////////////////////////////////////// -std::optional Shader::loadFromMemory(const std::string& /* shader */, Type /* type */) +std::optional Shader::loadFromMemory(std::string_view /* shader */, Type /* type */) { return std::nullopt; } //////////////////////////////////////////////////////////// -std::optional Shader::loadFromMemory(const std::string& /* vertexShader */, const std::string& /* fragmentShader */) +std::optional Shader::loadFromMemory(std::string_view /* vertexShader */, std::string_view /* fragmentShader */) { return std::nullopt; } //////////////////////////////////////////////////////////// -std::optional Shader::loadFromMemory(const std::string& /* vertexShader */, - const std::string& /* geometryShader */, - const std::string& /* fragmentShader */) +std::optional Shader::loadFromMemory(std::string_view /* vertexShader */, + std::string_view /* geometryShader */, + std::string_view /* fragmentShader */) { return std::nullopt; } @@ -1201,9 +1209,9 @@ Shader::Shader(unsigned int shaderProgram) : m_shaderProgram(shaderProgram) //////////////////////////////////////////////////////////// -std::optional Shader::compile(const char* /* vertexShaderCode */, - const char* /* geometryShaderCode */, - const char* /* fragmentShaderCode */) +std::optional Shader::compile(std::string_view /* vertexShaderCode */, + std::string_view /* geometryShaderCode */, + std::string_view /* fragmentShaderCode */) { return std::nullopt; }