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 <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <cstddef>
@ -200,7 +201,7 @@ public:
/// \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
@ -221,8 +222,7 @@ public:
/// \see loadFromFile, loadFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> loadFromMemory(const std::string& vertexShader,
const std::string& fragmentShader);
[[nodiscard]] static std::optional<Shader> 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<Shader> loadFromMemory(const std::string& vertexShader,
const std::string& geometryShader,
const std::string& fragmentShader);
[[nodiscard]] static std::optional<Shader> 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<Shader> compile(const char* vertexShaderCode,
const char* geometryShaderCode,
const char* fragmentShaderCode);
[[nodiscard]] static std::optional<Shader> compile(std::string_view vertexShaderCode,
std::string_view geometryShaderCode,
std::string_view fragmentShaderCode);
////////////////////////////////////////////////////////////
/// \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
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> 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> 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
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> 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
return compile(vertexShader.c_str(), nullptr, fragmentShader.c_str());
return compile(vertexShader, {}, fragmentShader);
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& vertexShader,
const std::string& geometryShader,
const std::string& fragmentShader)
std::optional<Shader> 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> 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> 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> 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;
@ -791,7 +793,7 @@ std::optional<Shader> 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> 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<GLint>(vertexShaderCode.length());
glCheck(GLEXT_glShaderSource(vertexShader, 1, &sourceCode, &sourceCodeLength));
glCheck(GLEXT_glCompileShader(vertexShader));
// Check the compile log
@ -830,11 +834,13 @@ std::optional<Shader> 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<GLint>(geometryShaderCode.length());
glCheck(GLEXT_glShaderSource(geometryShader, 1, &sourceCode, &sourceCodeLength));
glCheck(GLEXT_glCompileShader(geometryShader));
// Check the compile log
@ -856,12 +862,14 @@ std::optional<Shader> 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<GLint>(fragmentShaderCode.length());
glCheck(GLEXT_glShaderSource(fragmentShader, 1, &sourceCode, &sourceCodeLength));
glCheck(GLEXT_glCompileShader(fragmentShader));
// 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;
}
////////////////////////////////////////////////////////////
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;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::loadFromMemory(const std::string& /* vertexShader */,
const std::string& /* geometryShader */,
const std::string& /* fragmentShader */)
std::optional<Shader> 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> 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 */)
{
return std::nullopt;
}