Extra2D/src/renderer/shader.cpp

149 lines
4.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <fstream>
#include <renderer/rhi_module.h>
#include <renderer/shader.h>
#include <sstream>
#include <utils/logger.h>
namespace extra2d {
Shader::Shader() = default;
Shader::~Shader() {
// RHIHandle 是轻量级句柄,不需要显式释放
// 实际的资源由 RHI 设备管理
pipeline_ = PipelineHandle();
handle_ = ShaderHandle();
}
bool Shader::loadFromFile(const std::string &vsPath,
const std::string &fsPath) {
// 读取顶点着色器
std::ifstream vsFile(vsPath);
if (!vsFile.is_open()) {
E2D_LOG_ERROR("Failed to open vertex shader: {}", vsPath);
return false;
}
std::stringstream vsStream;
vsStream << vsFile.rdbuf();
std::string vsSource = vsStream.str();
// 读取片段着色器
std::ifstream fsFile(fsPath);
if (!fsFile.is_open()) {
E2D_LOG_ERROR("Failed to open fragment shader: {}", fsPath);
return false;
}
std::stringstream fsStream;
fsStream << fsFile.rdbuf();
std::string fsSource = fsStream.str();
return loadFromSource(vsSource, fsSource);
}
bool Shader::loadFromSource(const std::string &vsSource,
const std::string &fsSource) {
// 释放旧资源
pipeline_ = PipelineHandle();
handle_ = ShaderHandle();
// 获取 RHI 设备
auto *rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
}
auto *device = rhiModule->getDevice();
if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return false;
}
// 处理源码(添加版本声明)
std::string processedVS = addVersionIfNeeded(vsSource, true);
std::string processedFS = addVersionIfNeeded(fsSource, false);
// 创建着色器描述
ShaderDesc shaderDesc;
shaderDesc.vertexSource = processedVS;
shaderDesc.fragmentSource = processedFS;
// 创建着色器
auto shader = device->createShader(shaderDesc);
if (!shader) {
E2D_LOG_ERROR("Failed to create shader");
return false;
}
// 获取着色器句柄
handle_ = ShaderHandle(shader.release());
// 创建顶点布局2D 标准布局:位置 + 纹理坐标 + 颜色)
VertexLayout vertexLayout;
vertexLayout.stride = sizeof(float) * 8; // 2 (pos) + 2 (uv) + 4 (color)
vertexLayout.addAttribute(0, VertexFormat::Float2, 0); // 位置
vertexLayout.addAttribute(1, VertexFormat::Float2, 8); // 纹理坐标
vertexLayout.addAttribute(2, VertexFormat::Float4, 16); // 颜色
// 创建管线描述
PipelineDesc pipelineDesc;
pipelineDesc.vertexShader = handle_;
pipelineDesc.fragmentShader = handle_;
pipelineDesc.vertexLayout = vertexLayout;
pipelineDesc.blendState = BlendState::alphaBlend();
pipelineDesc.depthStencilState = DepthStencilState::noDepthTest();
pipelineDesc.rasterizerState = RasterizerState::noCull();
// 创建管线
auto pipeline = device->createPipeline(pipelineDesc);
if (!pipeline) {
E2D_LOG_ERROR("Failed to create pipeline");
handle_ = ShaderHandle();
return false;
}
// 获取管线句柄
pipeline_ = PipelineHandle(pipeline.release());
E2D_LOG_INFO("Shader created successfully");
return true;
}
void Shader::setUniformBlock(const std::string &name, uint32_t binding) {
// 存储 uniform block 绑定信息
uniformBlockBindings_[name] = binding;
// 注意:实际的 uniform block 绑定需要在渲染时通过 RHI 命令列表设置
// 这里仅存储绑定信息,供后续渲染使用
// 例如commandList->setUniformBlock(binding, buffer);
}
uint32_t Shader::getUniformBlockBinding(const std::string &name) const {
auto it = uniformBlockBindings_.find(name);
if (it != uniformBlockBindings_.end()) {
return it->second;
}
return UINT32_MAX; // 未找到
}
std::string Shader::addVersionIfNeeded(const std::string &source,
bool isVertex) {
// 如果已经包含版本声明,直接返回
if (source.find("#version") != std::string::npos) {
return source;
}
// 添加 OpenGL ES 3.2 版本声明
std::string result = "#version 320 es\n";
// 片段着色器需要添加精度声明
if (!isVertex) {
result += "precision mediump float;\n";
}
result += source;
return result;
}
} // namespace extra2d