Use std::string_view to construct sf::Shaders without allocations

This commit is contained in:
Chris Thrasher 2024-05-23 12:45:52 -06:00
parent eb4170796a
commit cc87ef7a3c
2 changed files with 52 additions and 44 deletions

View File

@ -36,6 +36,7 @@
#include <filesystem> #include <filesystem>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view>
#include <unordered_map> #include <unordered_map>
#include <cstddef> #include <cstddef>
@ -200,7 +201,7 @@ public:
/// \see loadFromFile, loadFromStream /// \see loadFromFile, loadFromStream
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> loadFromMemory(const std::string& shader, Type type); [[nodiscard]] static std::optional<Shader> loadFromMemory(std::string_view shader, Type type);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load both the vertex and fragment shaders from source codes in memory /// \brief Load both the vertex and fragment shaders from source codes in memory
@ -221,8 +222,7 @@ public:
/// \see loadFromFile, loadFromStream /// \see loadFromFile, loadFromStream
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> loadFromMemory(const std::string& vertexShader, [[nodiscard]] static std::optional<Shader> loadFromMemory(std::string_view vertexShader, std::string_view fragmentShader);
const std::string& fragmentShader);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry and fragment shaders from source codes in memory /// \brief Load the vertex, geometry and fragment shaders from source codes in memory
@ -244,9 +244,9 @@ public:
/// \see loadFromFile, loadFromStream /// \see loadFromFile, loadFromStream
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> loadFromMemory(const std::string& vertexShader, [[nodiscard]] static std::optional<Shader> loadFromMemory(std::string_view vertexShader,
const std::string& geometryShader, std::string_view geometryShader,
const std::string& fragmentShader); std::string_view fragmentShader);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry or fragment shader from a custom stream /// \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 /// \return Shader on success, `std::nullopt` if any error happened
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> compile(const char* vertexShaderCode, [[nodiscard]] static std::optional<Shader> compile(std::string_view vertexShaderCode,
const char* geometryShaderCode, std::string_view geometryShaderCode,
const char* fragmentShaderCode); std::string_view fragmentShaderCode);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Bind all the textures used by the shader /// \brief Bind all the textures used by the shader

View File

@ -281,11 +281,11 @@ std::optional<Shader> Shader::loadFromFile(const std::filesystem::path& filename
// Compile the shader program // Compile the shader program
if (type == Type::Vertex) if (type == Type::Vertex)
return compile(shader.data(), nullptr, nullptr); return compile(shader.data(), {}, {});
else if (type == Type::Geometry) else if (type == Type::Geometry)
return compile(nullptr, shader.data(), nullptr); return compile({}, shader.data(), {});
else else
return compile(nullptr, nullptr, shader.data()); return compile({}, {}, shader.data());
} }
@ -310,7 +310,7 @@ std::optional<Shader> Shader::loadFromFile(const std::filesystem::path& vertexSh
} }
// Compile the shader program // Compile the shader program
return compile(vertexShader.data(), nullptr, fragmentShader.data()); return compile(vertexShader.data(), {}, fragmentShader.data());
} }
@ -349,33 +349,33 @@ std::optional<Shader> Shader::loadFromFile(const std::filesystem::path& vertexSh
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& shader, Type type) std::optional<Shader> Shader::loadFromMemory(std::string_view shader, Type type)
{ {
// Compile the shader program // Compile the shader program
if (type == Type::Vertex) if (type == Type::Vertex)
return compile(shader.c_str(), nullptr, nullptr); return compile(shader, {}, {});
else if (type == Type::Geometry) else if (type == Type::Geometry)
return compile(nullptr, shader.c_str(), nullptr); return compile({}, shader, {});
else else
return compile(nullptr, nullptr, shader.c_str()); return compile({}, {}, shader);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader) std::optional<Shader> Shader::loadFromMemory(std::string_view vertexShader, std::string_view fragmentShader)
{ {
// Compile the shader program // Compile the shader program
return compile(vertexShader.c_str(), nullptr, fragmentShader.c_str()); return compile(vertexShader, {}, fragmentShader);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& vertexShader, std::optional<Shader> Shader::loadFromMemory(std::string_view vertexShader,
const std::string& geometryShader, std::string_view geometryShader,
const std::string& fragmentShader) std::string_view fragmentShader)
{ {
// Compile the shader program // 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> Shader::loadFromStream(InputStream& stream, Type type)
// Compile the shader program // Compile the shader program
if (type == Type::Vertex) if (type == Type::Vertex)
return compile(shader.data(), nullptr, nullptr); return compile(shader.data(), {}, {});
else if (type == Type::Geometry) else if (type == Type::Geometry)
return compile(nullptr, shader.data(), nullptr); return compile({}, shader.data(), {});
else else
return compile(nullptr, nullptr, shader.data()); return compile({}, {}, shader.data());
} }
@ -420,7 +420,7 @@ std::optional<Shader> Shader::loadFromStream(InputStream& vertexShaderStream, In
} }
// Compile the shader program // 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> Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) std::optional<Shader> Shader::compile(std::string_view vertexShaderCode,
std::string_view geometryShaderCode,
std::string_view fragmentShaderCode)
{ {
const TransientContextLock lock; const TransientContextLock lock;
@ -791,7 +793,7 @@ std::optional<Shader> Shader::compile(const char* vertexShaderCode, const char*
} }
// Make sure we can use geometry shaders // 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 " 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; << "(you should test Shader::isGeometryAvailable() before trying to use geometry shaders)" << std::endl;
@ -803,12 +805,14 @@ std::optional<Shader> Shader::compile(const char* vertexShaderCode, const char*
glCheck(shaderProgram = GLEXT_glCreateProgramObject()); glCheck(shaderProgram = GLEXT_glCreateProgramObject());
// Create the vertex shader if needed // Create the vertex shader if needed
if (vertexShaderCode) if (vertexShaderCode.data())
{ {
// Create and compile the shader // Create and compile the shader
GLEXT_GLhandle vertexShader{}; GLEXT_GLhandle vertexShader{};
glCheck(vertexShader = GLEXT_glCreateShaderObject(GLEXT_GL_VERTEX_SHADER)); 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<GLint>(vertexShaderCode.length());
glCheck(GLEXT_glShaderSource(vertexShader, 1, &sourceCode, &sourceCodeLength));
glCheck(GLEXT_glCompileShader(vertexShader)); glCheck(GLEXT_glCompileShader(vertexShader));
// Check the compile log // Check the compile log
@ -830,11 +834,13 @@ std::optional<Shader> Shader::compile(const char* vertexShaderCode, const char*
} }
// Create the geometry shader if needed // Create the geometry shader if needed
if (geometryShaderCode) if (geometryShaderCode.data())
{ {
// Create and compile the shader // Create and compile the shader
const GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER); const GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER);
glCheck(GLEXT_glShaderSource(geometryShader, 1, &geometryShaderCode, nullptr)); const GLcharARB* sourceCode = geometryShaderCode.data();
const auto sourceCodeLength = static_cast<GLint>(geometryShaderCode.length());
glCheck(GLEXT_glShaderSource(geometryShader, 1, &sourceCode, &sourceCodeLength));
glCheck(GLEXT_glCompileShader(geometryShader)); glCheck(GLEXT_glCompileShader(geometryShader));
// Check the compile log // Check the compile log
@ -856,12 +862,14 @@ std::optional<Shader> Shader::compile(const char* vertexShaderCode, const char*
} }
// Create the fragment shader if needed // Create the fragment shader if needed
if (fragmentShaderCode) if (fragmentShaderCode.data())
{ {
// Create and compile the shader // Create and compile the shader
GLEXT_GLhandle fragmentShader{}; GLEXT_GLhandle fragmentShader{};
glCheck(fragmentShader = GLEXT_glCreateShaderObject(GLEXT_GL_FRAGMENT_SHADER)); 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<GLint>(fragmentShaderCode.length());
glCheck(GLEXT_glShaderSource(fragmentShader, 1, &sourceCode, &sourceCodeLength));
glCheck(GLEXT_glCompileShader(fragmentShader)); glCheck(GLEXT_glCompileShader(fragmentShader));
// Check the compile log // Check the compile log
@ -990,23 +998,23 @@ std::optional<Shader> Shader::loadFromFile(const std::filesystem::path& /* verte
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& /* shader */, Type /* type */) std::optional<Shader> Shader::loadFromMemory(std::string_view /* shader */, Type /* type */)
{ {
return std::nullopt; return std::nullopt;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& /* vertexShader */, const std::string& /* fragmentShader */) std::optional<Shader> Shader::loadFromMemory(std::string_view /* vertexShader */, std::string_view /* fragmentShader */)
{ {
return std::nullopt; return std::nullopt;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& /* vertexShader */, std::optional<Shader> Shader::loadFromMemory(std::string_view /* vertexShader */,
const std::string& /* geometryShader */, std::string_view /* geometryShader */,
const std::string& /* fragmentShader */) std::string_view /* fragmentShader */)
{ {
return std::nullopt; return std::nullopt;
} }
@ -1201,9 +1209,9 @@ Shader::Shader(unsigned int shaderProgram) : m_shaderProgram(shaderProgram)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::optional<Shader> Shader::compile(const char* /* vertexShaderCode */, std::optional<Shader> Shader::compile(std::string_view /* vertexShaderCode */,
const char* /* geometryShaderCode */, std::string_view /* geometryShaderCode */,
const char* /* fragmentShaderCode */) std::string_view /* fragmentShaderCode */)
{ {
return std::nullopt; return std::nullopt;
} }