refactor(shader): 合并GLShaderNew到GLShader并优化着色器缓存逻辑

- 删除GLShaderNew类,将其功能合并到GLShader中
- 增加着色器缓存保存时的空二进制检查
- 添加更多调试日志信息
- 优化二进制数据获取的错误处理
This commit is contained in:
ChestnutYueyue 2026-02-15 16:24:35 +08:00
parent 78680138c2
commit 867013f6eb
7 changed files with 451 additions and 672 deletions

View File

@ -1,55 +1,196 @@
#pragma once #pragma once
#include <extra2d/core/color.h>
#include <extra2d/graphics/shader_interface.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <glm/mat4x4.hpp> #include <vector>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
namespace extra2d { namespace extra2d {
// ============================================================================ class GLShader : public IShader {
// OpenGL Shader 程序
// ============================================================================
class GLShader {
public: public:
/**
* @brief
*/
GLShader(); GLShader();
~GLShader();
// 从源码编译 /**
* @brief
*/
~GLShader() override;
/**
* @brief Shader程序
*/
void bind() const override;
/**
* @brief Shader程序
*/
void unbind() const override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setBool(const std::string& name, bool value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setInt(const std::string& name, int value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setFloat(const std::string& name, float value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec2(const std::string& name, const glm::vec2& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec3(const std::string& name, const glm::vec3& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec4(const std::string& name, const glm::vec4& value) override;
/**
* @brief 4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
void setMat4(const std::string& name, const glm::mat4& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param color
*/
void setColor(const std::string& name, const Color& color) override;
/**
* @brief Shader是否有效
* @return truefalse
*/
bool isValid() const override { return programID_ != 0; }
/**
* @brief OpenGL程序ID
* @return OpenGL程序ID
*/
uint32_t getNativeHandle() const override { return programID_; }
/**
* @brief Shader名称
* @return Shader名称
*/
const std::string& getName() const override { return name_; }
/**
* @brief Shader名称
* @param name Shader名称
*/
void setName(const std::string& name) override { name_ = name; }
/**
* @brief Shader
* @param vertexSource
* @param fragmentSource
* @return truefalse
*/
bool compileFromSource(const char* vertexSource, const char* fragmentSource); bool compileFromSource(const char* vertexSource, const char* fragmentSource);
// 从文件加载并编译 /**
bool compileFromFile(const std::string& vertexPath, const std::string& fragmentPath); * @brief Shader
* @param binary
* @return truefalse
*/
bool compileFromBinary(const std::vector<uint8_t>& binary);
// 使用/激活 /**
void bind() const; * @brief Shader二进制数据
void unbind() const; * @param outBinary
* @return truefalse
*/
bool getBinary(std::vector<uint8_t>& outBinary);
// Uniform 设置 /**
void setBool(const std::string& name, bool value); * @brief OpenGL程序ID
void setInt(const std::string& name, int value); * @return OpenGL程序ID
void setFloat(const std::string& name, float value); */
void setVec2(const std::string& name, const glm::vec2& value);
void setVec3(const std::string& name, const glm::vec3& value);
void setVec4(const std::string& name, const glm::vec4& value);
void setMat4(const std::string& name, const glm::mat4& value);
// 获取程序 ID
GLuint getProgramID() const { return programID_; } GLuint getProgramID() const { return programID_; }
// 检查是否有效
bool isValid() const { return programID_ != 0; }
private: private:
GLuint programID_; GLuint programID_ = 0;
std::string name_;
std::unordered_map<std::string, GLint> uniformCache_; std::unordered_map<std::string, GLint> uniformCache_;
/**
* @brief
* @param type
* @param source
* @return ID0
*/
GLuint compileShader(GLenum type, const char* source); GLuint compileShader(GLenum type, const char* source);
/**
* @brief uniform位置
* @param name uniform变量名
* @return uniform位置
*/
GLint getUniformLocation(const std::string& name); GLint getUniformLocation(const std::string& name);
}; };
class GLShaderFactory : public IShaderFactory {
public:
/**
* @brief Shader
* @param name Shader名称
* @param vertSource
* @param fragSource
* @return Shader实例
*/
Ptr<IShader> createFromSource(
const std::string& name,
const std::string& vertSource,
const std::string& fragSource) override;
/**
* @brief Shader
* @param name Shader名称
* @param binary
* @return Shader实例
*/
Ptr<IShader> createFromBinary(
const std::string& name,
const std::vector<uint8_t>& binary) override;
/**
* @brief Shader的二进制数据
* @param shader Shader实例
* @param outBinary
* @return truefalse
*/
bool getShaderBinary(const IShader& shader,
std::vector<uint8_t>& outBinary) override;
};
} // namespace extra2d } // namespace extra2d

View File

@ -1,202 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/graphics/shader_interface.h>
#include <glad/glad.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// OpenGL Shader实现
// ============================================================================
class GLShaderNew : public IShader {
public:
/**
* @brief
*/
GLShaderNew();
/**
* @brief
*/
~GLShaderNew() override;
/**
* @brief Shader程序
*/
void bind() const override;
/**
* @brief Shader程序
*/
void unbind() const override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setBool(const std::string& name, bool value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setInt(const std::string& name, int value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setFloat(const std::string& name, float value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec2(const std::string& name, const glm::vec2& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec3(const std::string& name, const glm::vec3& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void setVec4(const std::string& name, const glm::vec4& value) override;
/**
* @brief 4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
void setMat4(const std::string& name, const glm::mat4& value) override;
/**
* @brief uniform变量
* @param name uniform变量名
* @param color
*/
void setColor(const std::string& name, const Color& color) override;
/**
* @brief Shader是否有效
* @return truefalse
*/
bool isValid() const override { return programID_ != 0; }
/**
* @brief OpenGL程序ID
* @return OpenGL程序ID
*/
uint32_t getNativeHandle() const override { return programID_; }
/**
* @brief Shader名称
* @return Shader名称
*/
const std::string& getName() const override { return name_; }
/**
* @brief Shader名称
* @param name Shader名称
*/
void setName(const std::string& name) override { name_ = name; }
/**
* @brief Shader
* @param vertexSource
* @param fragmentSource
* @return truefalse
*/
bool compileFromSource(const char* vertexSource, const char* fragmentSource);
/**
* @brief Shader
* @param binary
* @return truefalse
*/
bool compileFromBinary(const std::vector<uint8_t>& binary);
/**
* @brief Shader二进制数据
* @param outBinary
* @return truefalse
*/
bool getBinary(std::vector<uint8_t>& outBinary);
/**
* @brief OpenGL程序ID
* @return OpenGL程序ID
*/
GLuint getProgramID() const { return programID_; }
private:
GLuint programID_ = 0;
std::string name_;
std::unordered_map<std::string, GLint> uniformCache_;
/**
* @brief
* @param type
* @param source
* @return ID0
*/
GLuint compileShader(GLenum type, const char* source);
/**
* @brief uniform位置
* @param name uniform变量名
* @return uniform位置
*/
GLint getUniformLocation(const std::string& name);
};
// ============================================================================
// OpenGL Shader工厂
// ============================================================================
class GLShaderFactory : public IShaderFactory {
public:
/**
* @brief Shader
* @param name Shader名称
* @param vertSource
* @param fragSource
* @return Shader实例
*/
Ptr<IShader> createFromSource(
const std::string& name,
const std::string& vertSource,
const std::string& fragSource) override;
/**
* @brief Shader
* @param name Shader名称
* @param binary
* @return Shader实例
*/
Ptr<IShader> createFromBinary(
const std::string& name,
const std::vector<uint8_t>& binary) override;
/**
* @brief Shader的二进制数据
* @param shader Shader实例
* @param outBinary
* @return truefalse
*/
bool getShaderBinary(const IShader& shader,
std::vector<uint8_t>& outBinary) override;
};
} // namespace extra2d

View File

@ -1,14 +1,13 @@
#include <extra2d/graphics/opengl/gl_shader.h> #include <extra2d/graphics/opengl/gl_shader.h>
#include <extra2d/utils/logger.h> #include <extra2d/utils/logger.h>
#include <fstream>
#include <sstream>
namespace extra2d { namespace extra2d {
/** /**
* @brief ID为0 * @brief ID为0
*/ */
GLShader::GLShader() : programID_(0) {} GLShader::GLShader() : programID_(0) {
}
/** /**
* @brief OpenGL着色器程序 * @brief OpenGL着色器程序
@ -16,82 +15,23 @@ GLShader::GLShader() : programID_(0) {}
GLShader::~GLShader() { GLShader::~GLShader() {
if (programID_ != 0) { if (programID_ != 0) {
glDeleteProgram(programID_); glDeleteProgram(programID_);
}
}
/**
* @brief
* @param vertexSource
* @param fragmentSource
* @return truefalse
*/
bool GLShader::compileFromSource(const char *vertexSource,
const char *fragmentSource) {
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0)
return false;
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShader == 0) {
glDeleteShader(vertexShader);
return false;
}
programID_ = glCreateProgram();
glAttachShader(programID_, vertexShader);
glAttachShader(programID_, fragmentShader);
glLinkProgram(programID_);
GLint success;
glGetProgramiv(programID_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Shader program linking failed: {}", infoLog);
glDeleteProgram(programID_);
programID_ = 0; programID_ = 0;
} }
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return success == GL_TRUE;
} }
/** /**
* @brief * @brief Shader程序
* @param vertexPath
* @param fragmentPath
* @return truefalse
*/ */
bool GLShader::compileFromFile(const std::string &vertexPath, void GLShader::bind() const {
const std::string &fragmentPath) { glUseProgram(programID_);
std::ifstream vShaderFile(vertexPath);
std::ifstream fShaderFile(fragmentPath);
if (!vShaderFile.is_open() || !fShaderFile.is_open()) {
E2D_LOG_ERROR("Failed to open shader files: {}, {}", vertexPath,
fragmentPath);
return false;
}
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
return compileFromSource(vShaderStream.str().c_str(),
fShaderStream.str().c_str());
} }
/** /**
* @brief 使 * @brief Shader程序
*/ */
void GLShader::bind() const { glUseProgram(programID_); } void GLShader::unbind() const {
glUseProgram(0);
/** }
* @brief
*/
void GLShader::unbind() const { glUseProgram(0); }
/** /**
* @brief uniform变量 * @brief uniform变量
@ -156,11 +96,156 @@ void GLShader::setMat4(const std::string &name, const glm::mat4 &value) {
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]);
} }
/**
* @brief uniform变量
* @param name uniform变量名
* @param color
*/
void GLShader::setColor(const std::string& name, const Color& color) {
glUniform4f(getUniformLocation(name), color.r, color.g, color.b, color.a);
}
/**
* @brief Shader
* @param vertexSource
* @param fragmentSource
* @return truefalse
*/
bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentSource) {
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return false;
}
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShader == 0) {
glDeleteShader(vertexShader);
return false;
}
if (programID_ != 0) {
glDeleteProgram(programID_);
uniformCache_.clear();
}
programID_ = glCreateProgram();
glAttachShader(programID_, vertexShader);
glAttachShader(programID_, fragmentShader);
glLinkProgram(programID_);
GLint success;
glGetProgramiv(programID_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Shader program linking failed: {}", infoLog);
glDeleteProgram(programID_);
programID_ = 0;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return success == GL_TRUE;
}
/**
* @brief Shader
* @param binary
* @return truefalse
*/
bool GLShader::compileFromBinary(const std::vector<uint8_t>& binary) {
if (binary.empty()) {
E2D_LOG_ERROR("Binary data is empty");
return false;
}
GLint numFormats = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats);
if (numFormats == 0) {
E2D_LOG_ERROR("Program binary formats not supported");
return false;
}
if (programID_ != 0) {
glDeleteProgram(programID_);
uniformCache_.clear();
}
programID_ = glCreateProgram();
GLenum binaryFormat = 0;
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, reinterpret_cast<GLint*>(&binaryFormat));
glProgramBinary(programID_, binaryFormat, binary.data(), static_cast<GLsizei>(binary.size()));
GLint success = 0;
glGetProgramiv(programID_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Failed to load shader from binary: {}", infoLog);
glDeleteProgram(programID_);
programID_ = 0;
return false;
}
return true;
}
/**
* @brief Shader二进制数据
* @param outBinary
* @return truefalse
*/
bool GLShader::getBinary(std::vector<uint8_t>& outBinary) {
if (programID_ == 0) {
E2D_LOG_WARN("Cannot get binary: shader program is 0");
return false;
}
GLint binaryLength = 0;
glGetProgramiv(programID_, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
E2D_LOG_DEBUG("Shader binary length: {}", binaryLength);
if (binaryLength <= 0) {
E2D_LOG_WARN("Shader binary length is 0 or negative");
return false;
}
outBinary.resize(binaryLength);
GLenum binaryFormat = 0;
GLsizei actualLength = 0;
glGetProgramBinary(programID_, binaryLength, &actualLength, &binaryFormat, outBinary.data());
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
E2D_LOG_ERROR("glGetProgramBinary failed with error: {}", err);
outBinary.clear();
return false;
}
if (actualLength == 0) {
E2D_LOG_WARN("glGetProgramBinary returned 0 bytes");
outBinary.clear();
return false;
}
if (actualLength != binaryLength) {
outBinary.resize(actualLength);
}
E2D_LOG_DEBUG("Shader binary retrieved: {} bytes, format: {}", actualLength, binaryFormat);
return true;
}
/** /**
* @brief * @brief
* @param type GL_VERTEX_SHADER或GL_FRAGMENT_SHADER * @param type
* @param source * @param source
* @return ID0 * @return ID0
*/ */
GLuint GLShader::compileShader(GLenum type, const char* source) { GLuint GLShader::compileShader(GLenum type, const char* source) {
GLuint shader = glCreateShader(type); GLuint shader = glCreateShader(type);
@ -181,7 +266,7 @@ GLuint GLShader::compileShader(GLenum type, const char *source) {
} }
/** /**
* @brief uniform变量位置使 * @brief uniform位置
* @param name uniform变量名 * @param name uniform变量名
* @return uniform位置 * @return uniform位置
*/ */
@ -196,4 +281,68 @@ GLint GLShader::getUniformLocation(const std::string &name) {
return location; return location;
} }
// ============================================================================
// GLShaderFactory 实现
// ============================================================================
/**
* @brief Shader
* @param name Shader名称
* @param vertSource
* @param fragSource
* @return Shader实例
*/
Ptr<IShader> GLShaderFactory::createFromSource(
const std::string& name,
const std::string& vertSource,
const std::string& fragSource) {
auto shader = std::make_shared<GLShader>();
shader->setName(name);
if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) {
E2D_LOG_ERROR("Failed to compile shader from source: {}", name);
return nullptr;
}
return shader;
}
/**
* @brief Shader
* @param name Shader名称
* @param binary
* @return Shader实例
*/
Ptr<IShader> GLShaderFactory::createFromBinary(
const std::string& name,
const std::vector<uint8_t>& binary) {
auto shader = std::make_shared<GLShader>();
shader->setName(name);
if (!shader->compileFromBinary(binary)) {
E2D_LOG_ERROR("Failed to create shader from binary: {}", name);
return nullptr;
}
return shader;
}
/**
* @brief Shader的二进制数据
* @param shader Shader实例
* @param outBinary
* @return truefalse
*/
bool GLShaderFactory::getShaderBinary(const IShader& shader, std::vector<uint8_t>& outBinary) {
const GLShader* glShader = dynamic_cast<const GLShader*>(&shader);
if (!glShader) {
E2D_LOG_ERROR("Shader is not a GLShader instance");
return false;
}
return const_cast<GLShader*>(glShader)->getBinary(outBinary);
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,325 +0,0 @@
#include <extra2d/graphics/opengl/gl_shader_new.h>
#include <extra2d/utils/logger.h>
namespace extra2d {
/**
* @brief ID为0
*/
GLShaderNew::GLShaderNew() : programID_(0) {
}
/**
* @brief OpenGL着色器程序
*/
GLShaderNew::~GLShaderNew() {
if (programID_ != 0) {
glDeleteProgram(programID_);
programID_ = 0;
}
}
/**
* @brief Shader程序
*/
void GLShaderNew::bind() const {
glUseProgram(programID_);
}
/**
* @brief Shader程序
*/
void GLShaderNew::unbind() const {
glUseProgram(0);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShaderNew::setBool(const std::string& name, bool value) {
glUniform1i(getUniformLocation(name), value ? 1 : 0);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShaderNew::setInt(const std::string& name, int value) {
glUniform1i(getUniformLocation(name), value);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShaderNew::setFloat(const std::string& name, float value) {
glUniform1f(getUniformLocation(name), value);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShaderNew::setVec2(const std::string& name, const glm::vec2& value) {
glUniform2fv(getUniformLocation(name), 1, &value[0]);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShaderNew::setVec3(const std::string& name, const glm::vec3& value) {
glUniform3fv(getUniformLocation(name), 1, &value[0]);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param value
*/
void GLShaderNew::setVec4(const std::string& name, const glm::vec4& value) {
glUniform4fv(getUniformLocation(name), 1, &value[0]);
}
/**
* @brief 4x4矩阵类型uniform变量
* @param name uniform变量名
* @param value 4x4矩阵值
*/
void GLShaderNew::setMat4(const std::string& name, const glm::mat4& value) {
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]);
}
/**
* @brief uniform变量
* @param name uniform变量名
* @param color
*/
void GLShaderNew::setColor(const std::string& name, const Color& color) {
glUniform4f(getUniformLocation(name), color.r, color.g, color.b, color.a);
}
/**
* @brief Shader
* @param vertexSource
* @param fragmentSource
* @return truefalse
*/
bool GLShaderNew::compileFromSource(const char* vertexSource, const char* fragmentSource) {
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return false;
}
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShader == 0) {
glDeleteShader(vertexShader);
return false;
}
if (programID_ != 0) {
glDeleteProgram(programID_);
uniformCache_.clear();
}
programID_ = glCreateProgram();
glAttachShader(programID_, vertexShader);
glAttachShader(programID_, fragmentShader);
glLinkProgram(programID_);
GLint success;
glGetProgramiv(programID_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Shader program linking failed: {}", infoLog);
glDeleteProgram(programID_);
programID_ = 0;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return success == GL_TRUE;
}
/**
* @brief Shader
* @param binary
* @return truefalse
*/
bool GLShaderNew::compileFromBinary(const std::vector<uint8_t>& binary) {
if (binary.empty()) {
E2D_LOG_ERROR("Binary data is empty");
return false;
}
GLint numFormats = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats);
if (numFormats == 0) {
E2D_LOG_ERROR("Program binary formats not supported");
return false;
}
if (programID_ != 0) {
glDeleteProgram(programID_);
uniformCache_.clear();
}
programID_ = glCreateProgram();
GLenum binaryFormat = 0;
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, reinterpret_cast<GLint*>(&binaryFormat));
glProgramBinary(programID_, binaryFormat, binary.data(), static_cast<GLsizei>(binary.size()));
GLint success = 0;
glGetProgramiv(programID_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(programID_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Failed to load shader from binary: {}", infoLog);
glDeleteProgram(programID_);
programID_ = 0;
return false;
}
return true;
}
/**
* @brief Shader二进制数据
* @param outBinary
* @return truefalse
*/
bool GLShaderNew::getBinary(std::vector<uint8_t>& outBinary) {
if (programID_ == 0) {
return false;
}
GLint binaryLength = 0;
glGetProgramiv(programID_, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
if (binaryLength <= 0) {
return false;
}
outBinary.resize(binaryLength);
GLenum binaryFormat = 0;
glGetProgramBinary(programID_, binaryLength, nullptr, &binaryFormat, outBinary.data());
return true;
}
/**
* @brief
* @param type
* @param source
* @return ID0
*/
GLuint GLShaderNew::compileShader(GLenum type, const char* source) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
E2D_LOG_ERROR("Shader compilation failed: {}", infoLog);
glDeleteShader(shader);
return 0;
}
return shader;
}
/**
* @brief uniform位置
* @param name uniform变量名
* @return uniform位置
*/
GLint GLShaderNew::getUniformLocation(const std::string& name) {
auto it = uniformCache_.find(name);
if (it != uniformCache_.end()) {
return it->second;
}
GLint location = glGetUniformLocation(programID_, name.c_str());
uniformCache_[name] = location;
return location;
}
// ============================================================================
// GLShaderFactory 实现
// ============================================================================
/**
* @brief Shader
* @param name Shader名称
* @param vertSource
* @param fragSource
* @return Shader实例
*/
Ptr<IShader> GLShaderFactory::createFromSource(
const std::string& name,
const std::string& vertSource,
const std::string& fragSource) {
auto shader = std::make_shared<GLShaderNew>();
shader->setName(name);
if (!shader->compileFromSource(vertSource.c_str(), fragSource.c_str())) {
E2D_LOG_ERROR("Failed to compile shader from source: {}", name);
return nullptr;
}
return shader;
}
/**
* @brief Shader
* @param name Shader名称
* @param binary
* @return Shader实例
*/
Ptr<IShader> GLShaderFactory::createFromBinary(
const std::string& name,
const std::vector<uint8_t>& binary) {
auto shader = std::make_shared<GLShaderNew>();
shader->setName(name);
if (!shader->compileFromBinary(binary)) {
E2D_LOG_ERROR("Failed to create shader from binary: {}", name);
return nullptr;
}
return shader;
}
/**
* @brief Shader的二进制数据
* @param shader Shader实例
* @param outBinary
* @return truefalse
*/
bool GLShaderFactory::getShaderBinary(const IShader& shader, std::vector<uint8_t>& outBinary) {
const GLShaderNew* glShader = dynamic_cast<const GLShaderNew*>(&shader);
if (!glShader) {
E2D_LOG_ERROR("Shader is not a GLShaderNew instance");
return false;
}
return const_cast<GLShaderNew*>(glShader)->getBinary(outBinary);
}
} // namespace extra2d

View File

@ -1,6 +1,6 @@
#include <extra2d/graphics/render_module.h> #include <extra2d/graphics/render_module.h>
#include <extra2d/config/module_registry.h> #include <extra2d/config/module_registry.h>
#include <extra2d/graphics/opengl/gl_shader_new.h> #include <extra2d/graphics/opengl/gl_shader.h>
#include <extra2d/graphics/shader_manager.h> #include <extra2d/graphics/shader_manager.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <extra2d/utils/logger.h> #include <extra2d/utils/logger.h>

View File

@ -107,10 +107,18 @@ Ptr<ShaderCacheEntry> ShaderCache::loadCache(const std::string& name) {
*/ */
bool ShaderCache::saveCache(const ShaderCacheEntry& entry) { bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_WARN("ShaderCache not initialized, cannot save cache");
return false;
}
if (entry.binary.empty()) {
E2D_LOG_WARN("Shader binary is empty, skipping cache save for: {}", entry.name);
return false; return false;
} }
std::string cachePath = getCachePath(entry.name); std::string cachePath = getCachePath(entry.name);
E2D_LOG_DEBUG("Saving shader cache to: {} ({} bytes)", cachePath, entry.binary.size());
std::ofstream file(cachePath, std::ios::binary); std::ofstream file(cachePath, std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
E2D_LOG_ERROR("Failed to create cache file: {}", cachePath); E2D_LOG_ERROR("Failed to create cache file: {}", cachePath);
@ -123,7 +131,7 @@ bool ShaderCache::saveCache(const ShaderCacheEntry& entry) {
cacheMap_[entry.name] = entry; cacheMap_[entry.name] = entry;
saveCacheIndex(); saveCacheIndex();
E2D_LOG_DEBUG("Shader cache saved: {}", entry.name); E2D_LOG_INFO("Shader cache saved: {} ({} bytes)", entry.name, entry.binary.size());
return true; return true;
} }

View File

@ -135,6 +135,7 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource); Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name);
shader = factory_->createFromSource(name, result.vertSource, result.fragSource); shader = factory_->createFromSource(name, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("Failed to create shader from source: {}", name); E2D_LOG_ERROR("Failed to create shader from source: {}", name);
@ -143,12 +144,15 @@ Ptr<IShader> ShaderManager::loadFromFiles(const std::string& name,
std::vector<uint8_t> binary; std::vector<uint8_t> binary;
if (factory_->getShaderBinary(*shader, binary)) { if (factory_->getShaderBinary(*shader, binary)) {
E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size());
ShaderCacheEntry entry; ShaderCacheEntry entry;
entry.name = name; entry.name = name;
entry.sourceHash = sourceHash; entry.sourceHash = sourceHash;
entry.binary = binary; entry.binary = binary;
entry.dependencies = result.dependencies; entry.dependencies = result.dependencies;
ShaderCache::getInstance().saveCache(entry); ShaderCache::getInstance().saveCache(entry);
} else {
E2D_LOG_WARN("Failed to get shader binary for: {}", name);
} }
} }
@ -205,6 +209,7 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource); Ptr<IShader> shader = loadFromCache(name, sourceHash, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_DEBUG("No valid cache found, compiling shader from source: {}", name);
shader = factory_->createFromSource(name, result.vertSource, result.fragSource); shader = factory_->createFromSource(name, result.vertSource, result.fragSource);
if (!shader) { if (!shader) {
E2D_LOG_ERROR("Failed to create shader from source: {}", name); E2D_LOG_ERROR("Failed to create shader from source: {}", name);
@ -213,12 +218,15 @@ Ptr<IShader> ShaderManager::loadFromCombinedFile(const std::string& path) {
std::vector<uint8_t> binary; std::vector<uint8_t> binary;
if (factory_->getShaderBinary(*shader, binary)) { if (factory_->getShaderBinary(*shader, binary)) {
E2D_LOG_DEBUG("Got shader binary, size: {} bytes", binary.size());
ShaderCacheEntry entry; ShaderCacheEntry entry;
entry.name = name; entry.name = name;
entry.sourceHash = sourceHash; entry.sourceHash = sourceHash;
entry.binary = binary; entry.binary = binary;
entry.dependencies = result.dependencies; entry.dependencies = result.dependencies;
ShaderCache::getInstance().saveCache(entry); ShaderCache::getInstance().saveCache(entry);
} else {
E2D_LOG_WARN("Failed to get shader binary for: {}", name);
} }
} }