refactor(rhi): 重构渲染硬件接口模块

feat(rhi): 新增RHI模块抽象层
feat(opengl): 实现OpenGL后端支持
refactor(renderer): 重构材质、纹理和网格类以使用RHI接口
refactor(scene): 移除移动构造函数并禁止移动操作
fix(shader): 修复默认片段着色器纹理采样问题
refactor(module): 改进模块注册表以支持实例存储
refactor(window): 移除OpenGL上下文管理交由RHI处理
feat(assets): 为默认材质添加纹理支持
refactor(timer): 移除移动操作并简化实现
refactor(input): 移除移动操作并简化实现
This commit is contained in:
ChestnutYueyue 2026-03-03 02:16:29 +08:00
parent b4a3d6b14b
commit 9041833430
60 changed files with 6056 additions and 2011 deletions

View File

@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(git diff:*)"
]
}
}

View File

@ -31,8 +31,8 @@ void PlayerNode::onUpdate(float dt) {
setPosition(x, y); setPosition(x, y);
// 根据移动方向旋转 // 根据移动方向旋转(顺时针,使用负角度)
float angle = time_ * 0.5f * 57.2958f + 90.0f; float angle = -time_ * 0.5f * 57.2958f + 90.0f;
setRotation(angle); setRotation(angle);
} }
@ -56,8 +56,8 @@ RotatingDecoration::RotatingDecoration() {
} }
void RotatingDecoration::onUpdate(float dt) { void RotatingDecoration::onUpdate(float dt) {
// 自转 // 自转(顺时针,使用负角度)
setRotation(getRotation() + rotationSpeed_ * dt); setRotation(getRotation() - rotationSpeed_ * dt);
} }
// ======================================== // ========================================

View File

@ -5,6 +5,7 @@
#include <module/module.h> #include <module/module.h>
#include <string> #include <string>
#include <typeindex> #include <typeindex>
#include <unordered_map>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
@ -67,9 +68,35 @@ public:
return registrations_; return registrations_;
} }
/**
* @brief
* @param module
*/
void storeModuleInstance(Module* module);
/**
* @brief
* @tparam T
* @return nullptr
*/
template <typename T>
T* getModule() {
auto it = instances_.find(std::type_index(typeid(T)));
if (it != instances_.end()) {
return static_cast<T*>(it->second);
}
return nullptr;
}
/**
* @brief
*/
void clearInstances();
private: private:
ModuleRegistry() = default; ModuleRegistry() = default;
std::vector<ModuleInfo> registrations_; std::vector<ModuleInfo> registrations_;
std::unordered_map<std::type_index, Module*> instances_;
}; };
/** /**
@ -108,4 +135,14 @@ public: \
#define E2D_REGISTER_MODULE_SIMPLE(ClassName) \ #define E2D_REGISTER_MODULE_SIMPLE(ClassName) \
E2D_REGISTER_MODULE(ClassName, #ClassName, 100) E2D_REGISTER_MODULE(ClassName, #ClassName, 100)
/**
* @brief
* @tparam T
* @return
*/
template <typename T>
T* getModule() {
return ModuleRegistry::instance().getModule<T>();
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,160 +0,0 @@
#pragma once
#include <module/module.h>
#include <module/module_registry.h>
#include <types/base/types.h>
#include <string>
#include <vector>
namespace extra2d {
/**
* @brief
*/
struct FileInfo {
std::string path;
std::string name;
bool isDir = false;
int64 size = 0;
};
/**
* @brief
*/
struct FileData {
bool ok = false;
std::vector<uint8> data;
std::string error;
operator bool() const { return ok; }
const uint8* ptr() const { return data.data(); }
size_t size() const { return data.size(); }
};
/**
* @brief
*
*
* Context
*/
class FileModule : public Module {
// 自动注册到模块系统,优先级为 20系统模块
E2D_REGISTER_MODULE(FileModule, "File", 20)
public:
FileModule();
~FileModule() override;
// 禁止拷贝
FileModule(const FileModule&) = delete;
FileModule& operator=(const FileModule&) = delete;
// 允许移动
FileModule(FileModule&&) noexcept;
FileModule& operator=(FileModule&&) noexcept;
// Module 接口实现
bool init() override;
void shutdown() override;
/**
* @brief
*/
bool exists(const std::string& path) const;
/**
* @brief
*/
bool isDir(const std::string& path) const;
/**
* @brief
*/
FileData read(const std::string& path) const;
/**
* @brief
*/
std::string readString(const std::string& path) const;
/**
* @brief
*/
bool write(const std::string& path, const void* data, size_t size) const;
/**
* @brief
*/
bool writeString(const std::string& path, const std::string& content) const;
/**
* @brief
*/
bool append(const std::string& path, const void* data, size_t size) const;
/**
* @brief
*/
bool remove(const std::string& path) const;
/**
* @brief
*/
bool mkdir(const std::string& path) const;
/**
* @brief
*/
std::vector<FileInfo> listDir(const std::string& path) const;
/**
* @brief
*/
int64 fileSize(const std::string& path) const;
/**
* @brief
*/
std::string ext(const std::string& path) const;
/**
* @brief
*/
std::string fileName(const std::string& path) const;
/**
* @brief
*/
std::string dirName(const std::string& path) const;
/**
* @brief
*/
std::string join(const std::string& a, const std::string& b) const;
/**
* @brief
*/
std::string writableDir() const;
/**
* @brief
*/
void setAssetRoot(const std::string& root) { assetRoot_ = root; }
/**
* @brief
*/
const std::string& assetRoot() const { return assetRoot_; }
/**
* @brief
*/
std::string assetPath(const std::string& relPath) const;
private:
std::string assetRoot_;
std::string writableDir_;
};
} // namespace extra2d

View File

@ -179,13 +179,11 @@ public:
InputModule(); InputModule();
~InputModule() override; ~InputModule() override;
// 禁止拷贝 // 禁止拷贝和移动
InputModule(const InputModule &) = delete; InputModule(const InputModule &) = delete;
InputModule &operator=(const InputModule &) = delete; InputModule &operator=(const InputModule &) = delete;
InputModule(InputModule &&) = delete;
// 允许移动 InputModule &operator=(InputModule &&) = delete;
InputModule(InputModule &&) noexcept;
InputModule &operator=(InputModule &&) noexcept;
// Module 接口实现 // Module 接口实现
bool init() override; bool init() override;

View File

@ -33,13 +33,11 @@ public:
WindowModule(); WindowModule();
~WindowModule() override; ~WindowModule() override;
// 禁止拷贝 // 禁止拷贝和移动
WindowModule(const WindowModule &) = delete; WindowModule(const WindowModule &) = delete;
WindowModule &operator=(const WindowModule &) = delete; WindowModule &operator=(const WindowModule &) = delete;
WindowModule(WindowModule &&) = delete;
// 允许移动 WindowModule &operator=(WindowModule &&) = delete;
WindowModule(WindowModule &&) noexcept;
WindowModule &operator=(WindowModule &&) noexcept;
// Module 接口实现 // Module 接口实现
bool init() override; bool init() override;
@ -121,28 +119,6 @@ public:
*/ */
bool shouldClose() const { return shouldClose_; } bool shouldClose() const { return shouldClose_; }
/**
* @brief OpenGL ES
* @return
*/
bool createGLContext();
/**
* @brief OpenGL ES
*/
void destroyGLContext();
/**
* @brief
*/
void swapBuffers();
/**
* @brief OpenGL ES
* @return SDL_GLContext
*/
void* getGLContext() const;
private: private:
void handleWindowEvent(const SDL_WindowEvent &evt); void handleWindowEvent(const SDL_WindowEvent &evt);
@ -162,7 +138,6 @@ private:
void onRenderPresent(); void onRenderPresent();
SDL_Window *window_ = nullptr; SDL_Window *window_ = nullptr;
SDL_GLContext glContext_ = nullptr;
bool shouldClose_ = false; bool shouldClose_ = false;
CloseCb onClose_; CloseCb onClose_;

View File

@ -0,0 +1,346 @@
#pragma once
#include <array>
#include <memory>
#include <renderer/rhi/rhi.h>
#include <renderer/rhi/rhi_command_list.h>
#include <types/math/color.h>
#include <types/math/transform.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
// 前向声明
class CommandQueue;
class Material;
class Mesh;
template <typename T> class Ptr;
/**
* @brief
*
* 64
* | ID (32) | (16) | (8) | (8) |
*/
struct DrawKey {
uint64_t value;
DrawKey() : value(0) {}
explicit DrawKey(uint64_t v) : value(v) {}
// 构建排序键
static DrawKey make(uint32_t materialId, uint16_t depth, uint8_t layer,
uint8_t flags = 0) {
DrawKey key;
key.value = (static_cast<uint64_t>(materialId) << 32) |
(static_cast<uint64_t>(depth) << 16) |
(static_cast<uint64_t>(layer) << 8) |
static_cast<uint64_t>(flags);
return key;
}
uint32_t getMaterialId() const { return static_cast<uint32_t>(value >> 32); }
uint16_t getDepth() const {
return static_cast<uint16_t>((value >> 16) & 0xFFFF);
}
uint8_t getLayer() const { return static_cast<uint8_t>((value >> 8) & 0xFF); }
uint8_t getFlags() const { return static_cast<uint8_t>(value & 0xFF); }
bool operator<(const DrawKey &other) const { return value < other.value; }
bool operator>(const DrawKey &other) const { return value > other.value; }
};
/**
* @brief
*
*
*/
struct DrawCommand {
DrawKey key; // 排序键
PipelineHandle pipeline; // 管线状态
BufferHandle vertexBuffer; // 顶点缓冲区
BufferHandle indexBuffer; // 索引缓冲区(可选)
uint32_t vertexCount; // 顶点数量
uint32_t indexCount; // 索引数量
uint32_t instanceCount; // 实例数量1表示非实例化
std::array<TextureHandle, 8> textures; // 纹理数组
uint32_t textureCount; // 纹理数量
BufferHandle materialUBO; // 材质 UBO
uint32_t materialUBOSize; // 材质 UBO 大小
// 变换和颜色数据(用于设置 shader uniform
Mat4 modelMatrix; // 模型矩阵
Color color; // 颜色
DrawCommand()
: vertexCount(0), indexCount(0), instanceCount(1), textureCount(0),
materialUBOSize(0), modelMatrix(glm::identity<Mat4>()), color(Color::White) {}
// 检查是否使用索引绘制
bool isIndexed() const { return indexCount > 0; }
// 检查是否实例化绘制
bool isInstanced() const { return instanceCount > 1; }
};
/**
* @brief
*
* 线
*/
struct CommandBatch {
PipelineHandle pipeline; // 共享管线
std::array<TextureHandle, 8> textures; // 共享纹理
uint32_t textureCount;
uint32_t startIndex; // 批次起始命令索引
uint32_t count; // 批次命令数量
CommandBatch() : textureCount(0), startIndex(0), count(0) {}
// 检查是否与命令兼容
bool isCompatibleWith(const DrawCommand &cmd) const {
if (pipeline != cmd.pipeline)
return false;
if (textureCount != cmd.textureCount)
return false;
for (uint32_t i = 0; i < textureCount; ++i) {
if (textures[i] != cmd.textures[i])
return false;
}
return true;
}
};
/**
* @brief
*
*
* 线> >
*/
class CommandSorter {
public:
/**
* @brief
* @param cmd
* @return
*/
uint32_t addCommand(const DrawCommand &cmd);
/**
* @brief
*/
void sort();
/**
* @brief
* @param index
* @return
*/
const DrawCommand &getCommand(uint32_t index) const {
return commands_[sortedIndices_[index]];
}
/**
* @brief
* @return
*/
uint32_t getCount() const { return static_cast<uint32_t>(commands_.size()); }
/**
* @brief
*/
void clear();
private:
std::vector<DrawCommand> commands_;
std::vector<uint32_t> sortedIndices_;
};
/**
* @brief
*
*
*
*/
class CommandBatcher {
public:
/**
* @brief
* @param sorter
*/
void process(const CommandSorter &sorter);
/**
* @brief
* @return
*/
uint32_t getBatchCount() const {
return static_cast<uint32_t>(batches_.size());
}
/**
* @brief
* @param index
* @return
*/
const CommandBatch &getBatch(uint32_t index) const { return batches_[index]; }
/**
* @brief
* @param batchIndex
* @param cmdIndex
* @return
*/
const DrawCommand &getCommand(uint32_t batchIndex, uint32_t cmdIndex) const;
/**
* @brief
*/
void clear();
private:
std::vector<CommandBatch> batches_;
const CommandSorter *sorter_ = nullptr;
};
/**
* @brief
*
*
*
*/
class CommandQueue {
public:
/**
* @brief
*/
CommandQueue();
/**
* @brief
*/
~CommandQueue();
// 禁止拷贝
CommandQueue(const CommandQueue&) = delete;
CommandQueue& operator=(const CommandQueue&) = delete;
// 允许移动
CommandQueue(CommandQueue&&) noexcept;
CommandQueue& operator=(CommandQueue&&) noexcept;
/**
* @brief
* @return
*/
bool initialize();
/**
* @brief
*/
void shutdown();
/**
* @brief
*/
void beginFrame();
/**
* @brief
*/
void endFrame();
/**
* @brief
* @param material
* @param mesh
* @param transform
* @param color
*/
void submitDraw(Ptr<Material> material, Ptr<Mesh> mesh,
const struct Transform &transform, const Color &color);
/**
* @brief
* @param material
* @param mesh
* @param instanceCount
*/
void submitDrawInstanced(Ptr<Material> material, Ptr<Mesh> mesh,
uint32_t instanceCount);
/**
* @brief
* @param color
* @param flags
*/
void submitClear(const Color &color, uint32_t flags);
/**
* @brief
* @param x X
* @param y Y
* @param width
* @param height
*/
void setViewport(int32_t x, int32_t y, int32_t width, int32_t height);
/**
* @brief
*
*
*/
void execute();
/**
* @brief
* @return
*/
uint32_t getCommandCount() const { return sorter_.getCount(); }
/**
* @brief
* @return
*/
RHICommandList* getCommandList() const { return commandList_.get(); }
private:
CommandSorter sorter_;
CommandBatcher batcher_;
RHIContext *context_ = nullptr;
std::unique_ptr<RHICommandList> commandList_;
// 全局 UBO 数据
struct GlobalUBOData {
float viewProjection[16];
float time;
float screenSize[2];
float padding;
} globalUBOData_;
// 材质 UBO 数据缓冲区
std::vector<uint8_t> materialUBOData_;
// 当前材质 ID 计数器
uint32_t nextMaterialId_ = 1;
// 材质到 ID 的映射
std::unordered_map<Material *, uint32_t> materialIds_;
/**
* @brief ID
* @param material
* @return ID
*/
uint32_t getMaterialId(Material *material);
/**
* @brief
* @param batchIndex
* @param batch
*/
void executeBatch(uint32_t batchIndex, const CommandBatch &batch);
};
} // namespace extra2d

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <renderer/rhi/rhi.h>
#include <renderer/shader.h>
#include <renderer/texture.h>
#include <types/ptr/ref_counted.h> #include <types/ptr/ref_counted.h>
#include <types/ptr/intrusive_ptr.h> #include <types/ptr/intrusive_ptr.h>
#include <types/math/vec2.h> #include <types/math/vec2.h>
#include <types/math/color.h> #include <types/math/color.h>
#include <renderer/render_types.h>
#include <renderer/shader.h>
#include <renderer/uniform_buffer.h>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -15,7 +15,37 @@ namespace extra2d {
// 前向声明 // 前向声明
class Material; class Material;
class Texture;
/**
* @brief
*/
enum class MaterialParamType : uint8_t {
Float, // 浮点数
Vec2, // 二维向量
Vec3, // 三维向量
Vec4, // 四维向量
Color, // 颜色
Mat4, // 4x4 矩阵
Texture // 纹理
};
/**
* @brief
* @param type
* @return
*/
inline uint32_t getMaterialParamSize(MaterialParamType type) {
switch (type) {
case MaterialParamType::Float: return sizeof(float);
case MaterialParamType::Vec2: return sizeof(float) * 2;
case MaterialParamType::Vec3: return sizeof(float) * 3;
case MaterialParamType::Vec4: return sizeof(float) * 4;
case MaterialParamType::Color: return sizeof(float) * 4;
case MaterialParamType::Mat4: return sizeof(float) * 16;
case MaterialParamType::Texture: return sizeof(uint32_t);
default: return 0;
}
}
/** /**
* @brief * @brief
@ -30,7 +60,7 @@ struct MaterialParamInfo {
* @brief * @brief
*/ */
struct TextureSlot { struct TextureSlot {
Handle<Texture> handle; Ptr<Texture> texture;
uint32_t slot; uint32_t slot;
std::string uniformName; std::string uniformName;
}; };
@ -87,7 +117,7 @@ private:
/** /**
* @brief * @brief
* *
* * RHI
* - * -
* - UBO * - UBO
* - * -
@ -112,10 +142,7 @@ private:
* material->setFloat("uOpacity", 1.0f); * material->setFloat("uOpacity", 1.0f);
* *
* // 设置纹理 * // 设置纹理
* material->setTexture("uTexture", textureHandle, 0); * material->setTexture("uTexture", texture, 0);
*
* // 注册到渲染器
* MaterialHandle handle = renderer->registerMaterial(material);
* @endcode * @endcode
*/ */
class Material : public RefCounted { class Material : public RefCounted {
@ -147,6 +174,12 @@ public:
*/ */
Ptr<Shader> getShader() const { return shader_; } Ptr<Shader> getShader() const { return shader_; }
/**
* @brief RHI 线
* @return RHI 线
*/
PipelineHandle getPipeline() const;
// ======================================== // ========================================
// 参数设置 // 参数设置
// ======================================== // ========================================
@ -168,7 +201,10 @@ public:
/** /**
* @brief vec4 * @brief vec4
* @param name * @param name
* @param value * @param x X
* @param y Y
* @param z Z
* @param w W
*/ */
void setVec4(const std::string& name, float x, float y, float z, float w); void setVec4(const std::string& name, float x, float y, float z, float w);
@ -193,10 +229,10 @@ public:
/** /**
* @brief * @brief
* @param uniformName uniform * @param uniformName uniform
* @param texture * @param texture
* @param slot 0-15 * @param slot 0-15
*/ */
void setTexture(const std::string& uniformName, Handle<Texture> texture, uint32_t slot); void setTexture(const std::string& uniformName, Ptr<Texture> texture, uint32_t slot);
/** /**
* @brief * @brief
@ -225,17 +261,11 @@ public:
*/ */
uint32_t getDataSize() const { return static_cast<uint32_t>(data_.size()); } uint32_t getDataSize() const { return static_cast<uint32_t>(data_.size()); }
// ========================================
// 应用材质(渲染时调用)
// ========================================
/** /**
* @brief * @brief
* * @return
* UBO
* @param uboManager UBO
*/ */
void apply(UniformBufferManager& uboManager); Ptr<MaterialLayout> getLayout() const { return layout_; }
private: private:
Ptr<MaterialLayout> layout_; // 材质布局 Ptr<MaterialLayout> layout_; // 材质布局

View File

@ -1,14 +1,12 @@
#pragma once #pragma once
#include <renderer/rhi/rhi.h>
#include <types/math/color.h> #include <types/math/color.h>
#include <types/math/rect.h> #include <types/math/rect.h>
#include <types/math/vec2.h> #include <types/math/vec2.h>
#include <types/ptr/intrusive_ptr.h> #include <types/ptr/intrusive_ptr.h>
#include <types/ptr/ref_counted.h> #include <types/ptr/ref_counted.h>
// 前向声明 OpenGL 类型
typedef unsigned int GLuint;
namespace extra2d { namespace extra2d {
/** /**
@ -27,7 +25,7 @@ struct Vertex {
/** /**
* @brief * @brief
* *
* OpenGL * RHI
* *
*/ */
class Mesh : public RefCounted { class Mesh : public RefCounted {
@ -64,27 +62,6 @@ public:
*/ */
void updateVertices(const Vertex* vertices, uint32_t count, uint32_t offset); void updateVertices(const Vertex* vertices, uint32_t count, uint32_t offset);
/**
* @brief
*/
void bind() const;
/**
* @brief
*/
void unbind() const;
/**
* @brief
*/
void draw() const;
/**
* @brief
* @param instanceCount
*/
void drawInstanced(uint32_t instanceCount) const;
/** /**
* @brief * @brief
* @return * @return
@ -97,6 +74,24 @@ public:
*/ */
uint32_t getIndexCount() const { return indexCount_; } uint32_t getIndexCount() const { return indexCount_; }
/**
* @brief
* @return
*/
BufferHandle getVertexBuffer() const { return vertexBuffer_; }
/**
* @brief
* @return
*/
BufferHandle getIndexBuffer() const { return indexBuffer_; }
/**
* @brief
* @return
*/
bool hasIndices() const { return indexCount_ > 0; }
/** /**
* @brief * @brief
* @param size * @param size
@ -107,9 +102,8 @@ public:
const Rect& uv = Rect(0, 0, 1, 1)); const Rect& uv = Rect(0, 0, 1, 1));
private: private:
GLuint vao_ = 0; // 顶点数组对象 BufferHandle vertexBuffer_; // 顶点缓冲区句柄
GLuint vbo_ = 0; // 顶点缓冲区 BufferHandle indexBuffer_; // 索引缓冲区句柄
GLuint ibo_ = 0; // 索引缓冲区
uint32_t vertexCount_ = 0; // 顶点数量 uint32_t vertexCount_ = 0; // 顶点数量
uint32_t indexCount_ = 0; // 索引数量 uint32_t indexCount_ = 0; // 索引数量
uint32_t vertexCapacity_ = 0; // 顶点缓冲区容量 uint32_t vertexCapacity_ = 0; // 顶点缓冲区容量

View File

@ -0,0 +1,365 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <renderer/command_queue.h>
#include <types/math/color.h>
#include <types/math/rect.h>
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include <unordered_map>
namespace extra2d {
// 前向声明
class RenderGraph;
class RenderPass;
class RenderGraphBuilder;
/**
* @brief
*/
enum class RenderGraphResourceType : uint8_t {
Texture, // 纹理
Buffer, // 缓冲区
RenderTarget // 渲染目标
};
/**
* @brief
*/
struct RenderGraphResourceHandle {
uint32_t index = static_cast<uint32_t>(-1);
RenderGraphResourceType type = RenderGraphResourceType::Texture;
bool isValid() const { return index != static_cast<uint32_t>(-1); }
static RenderGraphResourceHandle invalid() { return RenderGraphResourceHandle{}; }
};
/**
* @brief
*/
struct RenderGraphTextureDesc {
uint32_t width = 0;
uint32_t height = 0;
TextureFormat format = TextureFormat::RGBA8;
TextureUsage usage = TextureUsage::Sampled;
bool isRenderTarget = false;
std::string name;
static RenderGraphTextureDesc create2D(uint32_t w, uint32_t h, TextureFormat fmt,
const std::string& name = "") {
RenderGraphTextureDesc desc;
desc.width = w;
desc.height = h;
desc.format = fmt;
desc.name = name;
return desc;
}
};
/**
* @brief
*/
struct RenderGraphRenderTargetDesc {
RenderGraphResourceHandle colorTarget;
RenderGraphResourceHandle depthTarget;
Rect clearRect;
Color clearColor = Color::Black;
float clearDepth = 1.0f;
uint8_t clearStencil = 0;
bool clearColorFlag = true;
bool clearDepthFlag = false;
bool clearStencilFlag = false;
};
/**
* @brief
*/
enum class RenderPassType : uint8_t {
Graphics, // 图形渲染
Compute, // 计算
Copy // 拷贝/传输
};
/**
* @brief
*/
struct RenderPassContext {
RHIContext* context = nullptr;
CommandQueue* commandQueue = nullptr;
RenderGraph* graph = nullptr;
float deltaTime = 0.0f;
uint32_t frameIndex = 0;
// 获取纹理句柄
TextureHandle getTexture(RenderGraphResourceHandle handle) const;
};
/**
* @brief
*/
class RenderPass {
public:
virtual ~RenderPass() = default;
/**
* @brief
*/
virtual const char* getName() const = 0;
/**
* @brief
*/
virtual RenderPassType getType() const { return RenderPassType::Graphics; }
/**
* @brief
* @param builder
*/
virtual void declareResources(RenderGraphBuilder& builder) {}
/**
* @brief
* @param ctx
*/
virtual void execute(const RenderPassContext& ctx) = 0;
/**
* @brief
*/
void setEnabled(bool enabled) { enabled_ = enabled; }
/**
* @brief
*/
bool isEnabled() const { return enabled_; }
private:
bool enabled_ = true;
};
/**
* @brief
*
*
*/
class RenderGraphBuilder {
public:
/**
* @brief
* @param desc
* @return
*/
RenderGraphResourceHandle createTexture(const RenderGraphTextureDesc& desc);
/**
* @brief
* @param handle
*/
void readResource(RenderGraphResourceHandle handle);
/**
* @brief
* @param handle
*/
void writeResource(RenderGraphResourceHandle handle);
/**
* @brief
* @param desc
*/
void setRenderTarget(const RenderGraphRenderTargetDesc& desc);
// 内部使用
void setCurrentPass(RenderPass* pass) { currentPass_ = pass; }
private:
RenderPass* currentPass_ = nullptr;
std::vector<RenderGraphTextureDesc> textureDescs_;
};
/**
* @brief
*
*
*
*/
class RenderGraph {
public:
RenderGraph();
~RenderGraph();
// 禁止拷贝
RenderGraph(const RenderGraph&) = delete;
RenderGraph& operator=(const RenderGraph&) = delete;
// 允许移动
RenderGraph(RenderGraph&&) noexcept;
RenderGraph& operator=(RenderGraph&&) noexcept;
/**
* @brief
* @return
*/
bool initialize();
/**
* @brief
*/
void shutdown();
/**
* @brief
* @param pass
* @return
*/
RenderPass* addPass(std::unique_ptr<RenderPass> pass);
/**
* @brief 便
* @param name
* @param executeFunc
* @return
*/
RenderPass* addLambdaPass(const std::string& name,
std::function<void(const RenderPassContext&)> executeFunc);
/**
* @brief
*
*
*/
bool compile();
/**
* @brief
* @param deltaTime
*/
void execute(float deltaTime);
/**
* @brief
* @param handle
* @return
*/
TextureHandle getTexture(RenderGraphResourceHandle handle) const;
/**
* @brief
* @param width
* @param height
*/
void setOutputSize(uint32_t width, uint32_t height);
/**
* @brief
*/
uint32_t getOutputWidth() const { return outputWidth_; }
/**
* @brief
*/
uint32_t getOutputHeight() const { return outputHeight_; }
/**
* @brief
*/
CommandQueue* getCommandQueue() { return &commandQueue_; }
private:
// 渲染通道列表
std::vector<std::unique_ptr<RenderPass>> passes_;
// 编译后的执行顺序
std::vector<RenderPass*> executionOrder_;
// 资源管理
std::unordered_map<uint32_t, TextureHandle> textures_;
uint32_t nextResourceId_ = 1;
// 构建器
RenderGraphBuilder builder_;
// 命令队列
CommandQueue commandQueue_;
// 输出尺寸
uint32_t outputWidth_ = 1280;
uint32_t outputHeight_ = 720;
// 帧计数
uint32_t frameIndex_ = 0;
// 编译状态
bool compiled_ = false;
/**
* @brief
*/
void createResources();
/**
* @brief
*/
void destroyResources();
};
/**
* @brief
*
* 2D
*/
class GeometryRenderPass : public RenderPass {
public:
GeometryRenderPass(const std::string& name);
const char* getName() const override { return name_.c_str(); }
void declareResources(RenderGraphBuilder& builder) override;
void execute(const RenderPassContext& ctx) override;
/**
* @brief
*/
void setColorTarget(RenderGraphResourceHandle handle) { colorTarget_ = handle; }
/**
* @brief
*/
void setDepthTarget(RenderGraphResourceHandle handle) { depthTarget_ = handle; }
private:
std::string name_;
RenderGraphResourceHandle colorTarget_;
RenderGraphResourceHandle depthTarget_;
};
/**
* @brief
*/
class PostProcessRenderPass : public RenderPass {
public:
PostProcessRenderPass(const std::string& name);
const char* getName() const override { return name_.c_str(); }
void declareResources(RenderGraphBuilder& builder) override;
void execute(const RenderPassContext& ctx) override;
/**
* @brief
*/
void setInputTexture(RenderGraphResourceHandle handle) { inputTexture_ = handle; }
/**
* @brief
*/
void setOutputTarget(RenderGraphResourceHandle handle) { outputTarget_ = handle; }
private:
std::string name_;
RenderGraphResourceHandle inputTexture_;
RenderGraphResourceHandle outputTarget_;
};
} // namespace extra2d

View File

@ -1,12 +1,11 @@
#pragma once #pragma once
#include <assets/handle.h>
#include <cstdint>
#include <types/base/types.h> #include <types/base/types.h>
#include <types/math/vec2.h>
#include <types/math/color.h> #include <types/math/color.h>
#include <types/math/transform.h> #include <types/math/transform.h>
#include <assets/handle.h> #include <types/math/vec2.h>
#include <array>
#include <cstdint>
namespace extra2d { namespace extra2d {
@ -15,10 +14,7 @@ class Material;
class Mesh; class Mesh;
class Texture; class Texture;
// 资源句柄类型(使用新的 Handle<T> // 注意:资源句柄直接使用 Handle<T>,与 RHI 的 TextureHandle 等区分
using MaterialHandle = Handle<Material>;
using MeshHandle = Handle<Mesh>;
using TextureHandle = Handle<Texture>;
/** /**
* @brief * @brief
@ -30,64 +26,6 @@ enum class RenderCommandType : uint8_t {
Clear // 清除缓冲区 Clear // 清除缓冲区
}; };
/**
* @brief
*/
enum class TextureFormat : uint8_t {
RGBA8, // 32位 RGBA
RGB8, // 24位 RGB
RGBA4, // 16位 RGBA
R8, // 8位 灰度
RG8 // 16位 RG
};
/**
* @brief
* @param format
* @return
*/
inline uint32_t getTexturePixelSize(TextureFormat format) {
switch (format) {
case TextureFormat::RGBA8: return 4;
case TextureFormat::RGB8: return 3;
case TextureFormat::RGBA4: return 2;
case TextureFormat::R8: return 1;
case TextureFormat::RG8: return 2;
default: return 4;
}
}
/**
* @brief
*/
enum class MaterialParamType : uint8_t {
Float, // 浮点数
Vec2, // 二维向量
Vec3, // 三维向量
Vec4, // 四维向量
Color, // 颜色
Mat4, // 4x4 矩阵
Texture // 纹理
};
/**
* @brief
* @param type
* @return
*/
inline uint32_t getMaterialParamSize(MaterialParamType type) {
switch (type) {
case MaterialParamType::Float: return sizeof(float);
case MaterialParamType::Vec2: return sizeof(float) * 2;
case MaterialParamType::Vec3: return sizeof(float) * 3;
case MaterialParamType::Vec4: return sizeof(float) * 4;
case MaterialParamType::Color: return sizeof(float) * 4;
case MaterialParamType::Mat4: return sizeof(float) * 16;
case MaterialParamType::Texture: return sizeof(uint32_t) * 2; // Handle size
default: return 0;
}
}
/** /**
* @brief * @brief
* *
@ -100,8 +38,8 @@ struct RenderCommand {
// 绘制网格命令数据 // 绘制网格命令数据
struct DrawMeshData { struct DrawMeshData {
MeshHandle mesh; // 网格句柄 Handle<Mesh> mesh; // 网格句柄
MaterialHandle material; // 材质句柄 Handle<Material> material; // 材质句柄
Vec2 pos; // 位置 Vec2 pos; // 位置
Vec2 scale; // 缩放 Vec2 scale; // 缩放
float rot; // 旋转角度 float rot; // 旋转角度
@ -110,8 +48,8 @@ struct RenderCommand {
// 实例化绘制命令数据 // 实例化绘制命令数据
struct DrawInstancedData { struct DrawInstancedData {
MeshHandle mesh; // 网格句柄 Handle<Mesh> mesh; // 网格句柄
MaterialHandle material; // 材质句柄 Handle<Material> material; // 材质句柄
uint32_t instanceCount; // 实例数量 uint32_t instanceCount; // 实例数量
uint32_t instanceOffset; // 实例数据偏移 uint32_t instanceOffset; // 实例数据偏移
}; };
@ -139,8 +77,8 @@ struct RenderCommand {
* @brief * @brief
*/ */
RenderCommand() : type(RenderCommandType::DrawMesh), sortKey(0) { RenderCommand() : type(RenderCommandType::DrawMesh), sortKey(0) {
drawMesh.mesh = MeshHandle::invalid(); drawMesh.mesh = Handle<Mesh>::invalid();
drawMesh.material = MaterialHandle::invalid(); drawMesh.material = Handle<Material>::invalid();
drawMesh.pos = Vec2(0.0f, 0.0f); drawMesh.pos = Vec2(0.0f, 0.0f);
drawMesh.scale = Vec2(1.0f, 1.0f); drawMesh.scale = Vec2(1.0f, 1.0f);
drawMesh.rot = 0.0f; drawMesh.rot = 0.0f;
@ -159,9 +97,7 @@ struct RenderCommand {
/** /**
* @brief * @brief
*/ */
void setColor(const Color& c) { void setColor(const Color &c) { drawMesh.color = c; }
drawMesh.color = c;
}
/** /**
* @brief Transform * @brief Transform
@ -173,16 +109,15 @@ struct RenderCommand {
/** /**
* @brief * @brief
*/ */
Color getColor() const { Color getColor() const { return drawMesh.color; }
return drawMesh.color;
}
}; };
// 清除标志 // 清除标志
constexpr uint32_t CLEAR_COLOR_FLAG = 1 << 0; constexpr uint32_t CLEAR_COLOR_FLAG = 1 << 0;
constexpr uint32_t CLEAR_DEPTH_FLAG = 1 << 1; constexpr uint32_t CLEAR_DEPTH_FLAG = 1 << 1;
constexpr uint32_t CLEAR_STENCIL_FLAG = 1 << 2; constexpr uint32_t CLEAR_STENCIL_FLAG = 1 << 2;
constexpr uint32_t CLEAR_ALL_FLAG = CLEAR_COLOR_FLAG | CLEAR_DEPTH_FLAG | CLEAR_STENCIL_FLAG; constexpr uint32_t CLEAR_ALL_FLAG =
CLEAR_COLOR_FLAG | CLEAR_DEPTH_FLAG | CLEAR_STENCIL_FLAG;
// 最大渲染命令数 // 最大渲染命令数
constexpr uint32_t MAX_RENDER_COMMANDS = 10000; constexpr uint32_t MAX_RENDER_COMMANDS = 10000;
@ -190,7 +125,7 @@ constexpr uint32_t MAX_RENDER_COMMANDS = 10000;
// 最大实例数 // 最大实例数
constexpr uint32_t MAX_INSTANCES = 256; constexpr uint32_t MAX_INSTANCES = 256;
// UBO 绑定槽位 // UBO 绑定槽位(已移至 RHI
constexpr uint32_t GLOBAL_UBO_BINDING = 0; // 全局 UBO constexpr uint32_t GLOBAL_UBO_BINDING = 0; // 全局 UBO
constexpr uint32_t MATERIAL_UBO_BINDING = 1; // 材质 UBO constexpr uint32_t MATERIAL_UBO_BINDING = 1; // 材质 UBO
constexpr uint32_t INSTANCE_UBO_BINDING = 2; // 实例 UBO constexpr uint32_t INSTANCE_UBO_BINDING = 2; // 实例 UBO

View File

@ -1,15 +1,12 @@
#pragma once #pragma once
#include <array>
#include <event/events.h> #include <event/events.h>
#include <module/module.h> #include <module/module.h>
#include <module/module_registry.h> #include <module/module_registry.h>
#include <renderer/material.h> #include <renderer/command_queue.h>
#include <renderer/mesh.h> #include <renderer/render_graph.h>
#include <renderer/render_types.h> #include <renderer/render_types.h>
#include <renderer/shader.h> #include <renderer/rhi/rhi.h>
#include <renderer/texture.h>
#include <renderer/uniform_buffer.h>
#include <renderer/viewport_adapter.h> #include <renderer/viewport_adapter.h>
namespace extra2d { namespace extra2d {
@ -20,12 +17,11 @@ class AssetsModule;
/** /**
* @brief * @brief
* *
* * RHI
* - * -
* - * - 使 RenderGraph
* - 使 CommandQueue
* - * -
*
* AssetsModule
*/ */
class RendererModule : public Module { class RendererModule : public Module {
E2D_REGISTER_MODULE(RendererModule, "Renderer", 3) E2D_REGISTER_MODULE(RendererModule, "Renderer", 3)
@ -41,18 +37,16 @@ public:
*/ */
~RendererModule() override; ~RendererModule() override;
// 禁止拷贝 // 禁止拷贝和移动
RendererModule(const RendererModule &) = delete; RendererModule(const RendererModule &) = delete;
RendererModule &operator=(const RendererModule &) = delete; RendererModule &operator=(const RendererModule &) = delete;
RendererModule(RendererModule &&) = delete;
// 允许移动 RendererModule &operator=(RendererModule &&) = delete;
RendererModule(RendererModule &&) noexcept;
RendererModule &operator=(RendererModule &&) noexcept;
/** /**
* @brief * @brief
* *
* GL * RenderGraph CommandQueue
* *
* @return * @return
*/ */
@ -66,29 +60,7 @@ public:
void shutdown() override; void shutdown() override;
//=========================================================================== //===========================================================================
// 默认资源(通过 AssetsModule 获取) // 渲染接口
//===========================================================================
/**
* @brief
* @return
*/
MaterialHandle getDefaultMaterialHandle() const;
/**
* @brief
* @return
*/
MeshHandle getDefaultQuadHandle() const;
/**
* @brief 1x1
* @return
*/
TextureHandle getDefaultTextureHandle() const;
//===========================================================================
// 渲染状态设置
//=========================================================================== //===========================================================================
/** /**
@ -120,6 +92,42 @@ public:
*/ */
const ViewportAdapter &getViewportAdapter() const { return viewportAdapter_; } const ViewportAdapter &getViewportAdapter() const { return viewportAdapter_; }
/**
* @brief
* @return
*/
RenderGraph *getRenderGraph() { return &renderGraph_; }
/**
* @brief
* @return
*/
CommandQueue *getCommandQueue() { return renderGraph_.getCommandQueue(); }
/**
* @brief RHI
* @return RHI
*/
RHIContext *getRHIContext() const;
/**
* @brief
* @return
*/
Handle<Material> getDefaultMaterialHandle() const;
/**
* @brief
* @return
*/
Handle<Mesh> getDefaultQuadHandle() const;
/**
* @brief 1x1
* @return
*/
Handle<Texture> getDefaultTextureHandle() const;
private: private:
//=========================================================================== //===========================================================================
// 事件处理器 // 事件处理器
@ -128,7 +136,7 @@ private:
/** /**
* @brief * @brief
* *
* * RenderGraph
*/ */
void onRenderBegin(); void onRenderBegin();
@ -147,7 +155,7 @@ private:
/** /**
* @brief * @brief
* *
* * RenderGraph
*/ */
void onRenderEnd(); void onRenderEnd();
@ -161,7 +169,7 @@ private:
/** /**
* @brief * @brief
* *
* GL *
*/ */
void onWindowShow(); void onWindowShow();
@ -169,30 +177,6 @@ private:
// 渲染执行 // 渲染执行
//=========================================================================== //===========================================================================
/**
* @brief
*
* sortKey
*/
void sortCommands();
/**
* @brief
*
*
*/
void batchAndDraw();
/**
* @brief
* @param start
* @param count
* @param materialHandle
* @param meshHandle
*/
void drawBatch(uint32 start, uint32 count, MaterialHandle materialHandle,
MeshHandle meshHandle);
/** /**
* @brief * @brief
* @param cmd * @param cmd
@ -200,18 +184,11 @@ private:
void executeCommand(const RenderCommand &cmd); void executeCommand(const RenderCommand &cmd);
//=========================================================================== //===========================================================================
// 命令缓冲区 // 渲染图和命令队列
//=========================================================================== //===========================================================================
std::array<RenderCommand, MAX_RENDER_COMMANDS> RenderGraph renderGraph_; // 渲染图
commandBuffer_; // 预分配命令缓冲区 CommandQueue *commandQueue_ = nullptr; // 命令队列(指向 renderGraph_ 内部)
uint32 commandCount_ = 0; // 当前命令数量
//===========================================================================
// UBO 管理器
//===========================================================================
UniformBufferManager uniformManager_;
//=========================================================================== //===========================================================================
// 事件监听器 // 事件监听器
@ -228,7 +205,7 @@ private:
// 状态标志 // 状态标志
//=========================================================================== //===========================================================================
bool glInitialized_ = false; // GL 是否已初始化 bool initialized_ = false; // 是否已初始化
//=========================================================================== //===========================================================================
// 渲染统计 // 渲染统计
@ -236,7 +213,6 @@ private:
struct Stats { struct Stats {
uint32 commandsSubmitted = 0; // 提交的命令数 uint32 commandsSubmitted = 0; // 提交的命令数
uint32 commandsExecuted = 0; // 执行的命令数
uint32 drawCalls = 0; // 绘制调用次数 uint32 drawCalls = 0; // 绘制调用次数
uint32 batches = 0; // 批次数 uint32 batches = 0; // 批次数
} stats_; } stats_;
@ -246,7 +222,7 @@ private:
//=========================================================================== //===========================================================================
int32 viewportX_ = 0, viewportY_ = 0; int32 viewportX_ = 0, viewportY_ = 0;
int32 viewportWidth_ = 0, viewportHeight_ = 0; int32 viewportWidth_ = 1280, viewportHeight_ = 720;
//=========================================================================== //===========================================================================
// 视口适配器 // 视口适配器

View File

@ -0,0 +1,35 @@
#pragma once
#include <glad/glad.h>
#include <renderer/rhi/rhi.h>
namespace extra2d {
/**
* @brief OpenGL
*/
class GLBuffer : public RHIBuffer {
public:
explicit GLBuffer(const BufferDesc &desc);
~GLBuffer() override;
bool create();
void destroy();
bool update(const void *data, uint32_t size, uint32_t offset) override;
void *map() override;
void unmap() override;
const BufferDesc &getDesc() const { return desc_; }
uint32_t getSize() const override { return desc_.size; }
BufferType getType() const override { return desc_.type; }
bool isValid() const override { return buffer_ != 0; }
GLuint getGLBuffer() const { return buffer_; }
private:
BufferDesc desc_;
GLuint buffer_;
};
} // namespace extra2d

View File

@ -0,0 +1,99 @@
#pragma once
#include <glad/glad.h>
#include <renderer/rhi/rhi.h>
namespace extra2d {
// 前向声明
class GLPipeline;
class GLBuffer;
class GLTexture;
class GLFramebuffer;
/**
* @brief OpenGL
*/
class GLCommandList : public RHICommandList {
public:
GLCommandList();
~GLCommandList() override;
//===========================================================================
// 命令列表生命周期
//===========================================================================
void begin() override;
void end() override;
void submit() override;
//===========================================================================
// 渲染通道
//===========================================================================
void beginRenderPass(RHIFramebuffer *framebuffer,
ClearFlags clearFlags = ClearFlags::Color,
const Color &clearColor = Color::Black,
float clearDepth = 1.0f,
uint8_t clearStencil = 0) override;
void endRenderPass() override;
//===========================================================================
// 状态设置
//===========================================================================
void setViewport(const Viewport &viewport) override;
void setScissor(const ScissorRect &scissor) override;
void setPipeline(RHIPipeline *pipeline) override;
//===========================================================================
// 资源绑定
//===========================================================================
void setVertexBuffer(uint32_t slot, RHIBuffer *buffer,
uint32_t offset = 0) override;
void setIndexBuffer(RHIBuffer *buffer, IndexType type,
uint32_t offset = 0) override;
void setUniformBuffer(uint32_t slot, RHIBuffer *buffer) override;
void setTexture(uint32_t slot, RHITexture *texture) override;
void setSampler(uint32_t slot, TextureFilter minFilter,
TextureFilter magFilter, TextureWrap wrapS,
TextureWrap wrapT) override;
//===========================================================================
// 绘制命令
//===========================================================================
void draw(uint32_t vertexCount, uint32_t firstVertex = 0,
uint32_t instanceCount = 1, uint32_t firstInstance = 0) override;
void drawIndexed(uint32_t indexCount, uint32_t firstIndex = 0,
int32_t vertexOffset = 0, uint32_t instanceCount = 1,
uint32_t firstInstance = 0) override;
//===========================================================================
// 工具方法
//===========================================================================
void clear(ClearFlags flags, const Color &color = Color::Black,
float depth = 1.0f, uint8_t stencil = 0) override;
bool isRecording() const override;
// 设置 uniform 变量
void setUniform(const std::string& name, float value);
void setUniform(const std::string& name, const Vec2& value);
void setUniform(const std::string& name, const Vec3& value);
void setUniform(const std::string& name, const Color& value);
void setUniform(const std::string& name, const Mat4& value);
private:
bool recording_ = false;
GLPipeline *currentPipeline_ = nullptr;
GLBuffer *currentVertexBuffer_ = nullptr;
GLBuffer *currentIndexBuffer_ = nullptr;
GLFramebuffer *currentFramebuffer_ = nullptr;
GLuint currentShaderProgram_ = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,38 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h>
#include <memory>
namespace extra2d {
// 前向声明
class GLDevice;
class GLFramebuffer;
/**
* @brief OpenGL
*/
class GLContext : public RHIContext {
public:
explicit GLContext(GLDevice* device);
~GLContext() override;
bool initialize() override;
void shutdown() override;
void beginFrame() override;
void endFrame() override;
void setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height) override;
void bindDefaultFramebuffer() override;
RHIFramebuffer* getDefaultFramebuffer() override;
bool isFeatureSupported(const char* feature) const override;
private:
GLDevice* device_;
std::unique_ptr<GLFramebuffer> defaultFramebuffer_;
};
} // namespace extra2d

View File

@ -0,0 +1,53 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h>
#include <vector>
namespace extra2d {
// 前向声明
class GLTexture;
/**
* @brief OpenGL
*/
class GLFramebuffer : public RHIFramebuffer {
public:
GLFramebuffer();
explicit GLFramebuffer(const RenderPassDesc& desc);
~GLFramebuffer() override;
bool create();
void destroy();
void bind() override;
void unbind() override;
uint32_t getColorAttachmentCount() const override;
TextureHandle getColorAttachment(uint32_t index) const override;
TextureHandle getDepthStencilAttachment() const override;
uint32_t getWidth() const override { return width_; }
uint32_t getHeight() const override { return height_; }
bool hasDepthStencil() const override;
bool isValid() const override;
bool isDefault() const override;
void setSize(uint32_t width, uint32_t height);
GLuint getGLFramebuffer() const { return framebuffer_; }
const RenderPassDesc& getDesc() const { return desc_; }
void clear(ClearFlags flags, const Color& color, float depth, uint8_t stencil);
private:
RenderPassDesc desc_;
GLuint framebuffer_;
uint32_t width_;
uint32_t height_;
std::vector<std::unique_ptr<GLTexture>> colorAttachments_;
std::unique_ptr<GLTexture> depthStencilAttachment_;
};
} // namespace extra2d

View File

@ -0,0 +1,45 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h>
namespace extra2d {
// 前向声明
class GLShader;
/**
* @brief OpenGL 线
*/
class GLPipeline : public RHIPipeline {
public:
explicit GLPipeline(const PipelineDesc& desc);
~GLPipeline() override;
bool create();
void destroy();
void bind() override;
void unbind() override;
ShaderHandle getVertexShader() const override;
ShaderHandle getFragmentShader() const override;
const VertexLayout& getVertexLayout() const override;
bool isValid() const override;
const PipelineDesc& getDesc() const { return desc_; }
GLuint getGLVAO() const { return vao_; }
// 获取 shader program ID用于设置 uniform
GLuint getGLProgram() const { return shaderProgram_; }
// 设置 shader program ID在创建时调用
void setGLProgram(GLuint program) { shaderProgram_ = program; }
private:
PipelineDesc desc_;
GLuint vao_;
GLuint shaderProgram_ = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,45 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h>
#include <string>
namespace extra2d {
/**
* @brief OpenGL
*/
class GLShader : public RHIShader {
public:
explicit GLShader(const ShaderDesc& desc);
~GLShader() override;
bool compile();
void destroy();
ShaderType getType() const override { return ShaderType::Vertex; } // 返回 Vertex 表示这是一个程序着色器
bool isCompiled() const override;
std::string getCompileLog() const override;
bool isValid() const override;
void bind() const;
void unbind() const;
void setUniform(const std::string& name, float value);
void setUniform(const std::string& name, const Vec2& value);
void setUniform(const std::string& name, const Vec3& value);
void setUniform(const std::string& name, const Color& value);
void setUniform(const std::string& name, const Mat4& value);
const ShaderDesc& getDesc() const { return desc_; }
GLuint getGLProgram() const { return program_; }
private:
ShaderDesc desc_;
GLuint shader_;
GLuint program_;
std::string compileLog_;
bool compiled_;
};
} // namespace extra2d

View File

@ -0,0 +1,40 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h>
namespace extra2d {
/**
* @brief OpenGL
*/
class GLTexture : public RHITexture {
public:
explicit GLTexture(const TextureDesc& desc);
~GLTexture() override;
bool create();
void destroy();
TextureType getType() const override { return desc_.type; }
TextureFormat getFormat() const override { return desc_.format; }
uint32_t getWidth() const override { return desc_.width; }
uint32_t getHeight() const override { return desc_.height; }
uint32_t getMipLevels() const override { return desc_.mipLevels; }
bool update(const void* data, uint32_t mipLevel = 0) override;
void generateMipmap() override;
void bind(uint32_t slot) override;
void unbind() override;
bool isValid() const override;
bool isRenderTarget() const override;
GLuint getGLTexture() const { return texture_; }
private:
TextureDesc desc_;
GLuint texture_;
};
} // namespace extra2d

View File

@ -0,0 +1,307 @@
#pragma once
#include <renderer/rhi/rhi.h>
#include <glad/glad.h>
#include <utils/logger.h>
namespace extra2d {
/**
* @brief OpenGL
*/
#define GL_CHECK(call) do { \
call; \
GLenum err = glGetError(); \
if (err != GL_NO_ERROR) { \
E2D_LOG_ERROR("OpenGL error in {}: {} ({})", #call, getGLErrorString(err), err); \
} \
} while(0)
/**
* @brief OpenGL
* @param error OpenGL
* @return
*/
inline const char* getGLErrorString(GLenum error) {
switch (error) {
case GL_NO_ERROR: return "GL_NO_ERROR";
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW";
case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
default: return "Unknown Error";
}
}
/**
* @brief BufferType OpenGL
*/
inline GLenum bufferTypeToGL(BufferType type) {
switch (type) {
case BufferType::Vertex: return GL_ARRAY_BUFFER;
case BufferType::Index: return GL_ELEMENT_ARRAY_BUFFER;
case BufferType::Uniform: return GL_UNIFORM_BUFFER;
case BufferType::Storage: return GL_SHADER_STORAGE_BUFFER;
case BufferType::Staging: return GL_ARRAY_BUFFER;
default: return GL_ARRAY_BUFFER;
}
}
/**
* @brief BufferUsage OpenGL 使
*/
inline GLenum bufferUsageToGL(BufferUsage usage) {
switch (usage) {
case BufferUsage::Static: return GL_STATIC_DRAW;
case BufferUsage::Dynamic: return GL_DYNAMIC_DRAW;
case BufferUsage::Stream: return GL_STREAM_DRAW;
default: return GL_STATIC_DRAW;
}
}
/**
* @brief TextureFormat OpenGL
*/
inline GLenum textureFormatToGLInternal(TextureFormat format) {
switch (format) {
case TextureFormat::R8: return GL_R8;
case TextureFormat::RG8: return GL_RG8;
case TextureFormat::RGB8: return GL_RGB8;
case TextureFormat::RGBA8: return GL_RGBA8;
case TextureFormat::RGBA8_SRGB: return GL_SRGB8_ALPHA8;
case TextureFormat::Depth16: return GL_DEPTH_COMPONENT16;
case TextureFormat::Depth24: return GL_DEPTH_COMPONENT24;
case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT32F;
case TextureFormat::Depth24Stencil8: return GL_DEPTH24_STENCIL8;
case TextureFormat::Depth32FStencil8:return GL_DEPTH32F_STENCIL8;
case TextureFormat::BC1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case TextureFormat::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case TextureFormat::BC5: return 0x8DBD; // GL_COMPRESSED_RG_RGTC2
default: return GL_RGBA8;
}
}
/**
* @brief TextureFormat OpenGL
*/
inline GLenum textureFormatToGLFormat(TextureFormat format) {
switch (format) {
case TextureFormat::R8: return GL_RED;
case TextureFormat::RG8: return GL_RG;
case TextureFormat::RGB8: return GL_RGB;
case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return GL_RGBA;
case TextureFormat::Depth16:
case TextureFormat::Depth24:
case TextureFormat::Depth32F: return GL_DEPTH_COMPONENT;
case TextureFormat::Depth24Stencil8:
case TextureFormat::Depth32FStencil8:return GL_DEPTH_STENCIL;
default: return GL_RGBA;
}
}
/**
* @brief TextureFormat OpenGL
*/
inline GLenum textureFormatToGLType(TextureFormat format) {
switch (format) {
case TextureFormat::R8:
case TextureFormat::RG8:
case TextureFormat::RGB8:
case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return GL_UNSIGNED_BYTE;
case TextureFormat::Depth16: return GL_UNSIGNED_SHORT;
case TextureFormat::Depth24: return GL_UNSIGNED_INT;
case TextureFormat::Depth32F: return GL_FLOAT;
case TextureFormat::Depth24Stencil8: return GL_UNSIGNED_INT_24_8;
case TextureFormat::Depth32FStencil8:return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
default: return GL_UNSIGNED_BYTE;
}
}
/**
* @brief TextureFilter OpenGL
*/
inline GLenum textureFilterToGLMin(TextureFilter filter) {
switch (filter) {
case TextureFilter::Nearest: return GL_NEAREST;
case TextureFilter::Linear: return GL_LINEAR;
case TextureFilter::NearestMipmapNearest: return GL_NEAREST_MIPMAP_NEAREST;
case TextureFilter::LinearMipmapNearest: return GL_LINEAR_MIPMAP_NEAREST;
case TextureFilter::NearestMipmapLinear: return GL_NEAREST_MIPMAP_LINEAR;
case TextureFilter::LinearMipmapLinear: return GL_LINEAR_MIPMAP_LINEAR;
default: return GL_LINEAR;
}
}
inline GLenum textureFilterToGLMag(TextureFilter filter) {
// Mag filter doesn't support mipmaps
switch (filter) {
case TextureFilter::Nearest:
case TextureFilter::NearestMipmapNearest:
case TextureFilter::NearestMipmapLinear:
return GL_NEAREST;
case TextureFilter::Linear:
case TextureFilter::LinearMipmapNearest:
case TextureFilter::LinearMipmapLinear:
default:
return GL_LINEAR;
}
}
/**
* @brief TextureWrap OpenGL
*/
inline GLenum textureWrapToGL(TextureWrap wrap) {
switch (wrap) {
case TextureWrap::Repeat: return GL_REPEAT;
case TextureWrap::ClampToEdge: return GL_CLAMP_TO_EDGE;
case TextureWrap::ClampToBorder: return GL_CLAMP_TO_BORDER;
case TextureWrap::MirroredRepeat: return GL_MIRRORED_REPEAT;
default: return GL_REPEAT;
}
}
/**
* @brief VertexFormat OpenGL
*/
inline void vertexFormatToGL(VertexFormat format, GLint& components, GLenum& type, GLboolean& normalized) {
switch (format) {
case VertexFormat::Float1: components = 1; type = GL_FLOAT; normalized = GL_FALSE; break;
case VertexFormat::Float2: components = 2; type = GL_FLOAT; normalized = GL_FALSE; break;
case VertexFormat::Float3: components = 3; type = GL_FLOAT; normalized = GL_FALSE; break;
case VertexFormat::Float4: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break;
case VertexFormat::Int1: components = 1; type = GL_INT; normalized = GL_FALSE; break;
case VertexFormat::Int2: components = 2; type = GL_INT; normalized = GL_FALSE; break;
case VertexFormat::Int3: components = 3; type = GL_INT; normalized = GL_FALSE; break;
case VertexFormat::Int4: components = 4; type = GL_INT; normalized = GL_FALSE; break;
case VertexFormat::UInt1: components = 1; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break;
case VertexFormat::UInt2: components = 2; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break;
case VertexFormat::UInt3: components = 3; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break;
case VertexFormat::UInt4: components = 4; type = GL_UNSIGNED_INT; normalized = GL_FALSE; break;
case VertexFormat::Byte4: components = 4; type = GL_BYTE; normalized = GL_FALSE; break;
case VertexFormat::Byte4Normalized: components = 4; type = GL_BYTE; normalized = GL_TRUE; break;
case VertexFormat::UByte4: components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_FALSE; break;
case VertexFormat::UByte4Normalized:components = 4; type = GL_UNSIGNED_BYTE; normalized = GL_TRUE; break;
default: components = 4; type = GL_FLOAT; normalized = GL_FALSE; break;
}
}
/**
* @brief IndexType OpenGL
*/
inline GLenum indexTypeToGL(IndexType type) {
switch (type) {
case IndexType::UInt16: return GL_UNSIGNED_SHORT;
case IndexType::UInt32: return GL_UNSIGNED_INT;
default: return GL_UNSIGNED_SHORT;
}
}
/**
* @brief PrimitiveType OpenGL
*/
inline GLenum primitiveTypeToGL(PrimitiveType type) {
switch (type) {
case PrimitiveType::Points: return GL_POINTS;
case PrimitiveType::Lines: return GL_LINES;
case PrimitiveType::LineStrip: return GL_LINE_STRIP;
case PrimitiveType::Triangles: return GL_TRIANGLES;
case PrimitiveType::TriangleStrip: return GL_TRIANGLE_STRIP;
case PrimitiveType::TriangleFan: return GL_TRIANGLE_FAN;
default: return GL_TRIANGLES;
}
}
/**
* @brief BlendFactor OpenGL
*/
inline GLenum blendFactorToGL(BlendFactor factor) {
switch (factor) {
case BlendFactor::Zero: return GL_ZERO;
case BlendFactor::One: return GL_ONE;
case BlendFactor::SrcColor: return GL_SRC_COLOR;
case BlendFactor::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR;
case BlendFactor::DstColor: return GL_DST_COLOR;
case BlendFactor::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR;
case BlendFactor::SrcAlpha: return GL_SRC_ALPHA;
case BlendFactor::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA;
case BlendFactor::DstAlpha: return GL_DST_ALPHA;
case BlendFactor::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA;
default: return GL_ONE;
}
}
/**
* @brief BlendOp OpenGL
*/
inline GLenum blendOpToGL(BlendOp op) {
switch (op) {
case BlendOp::Add: return GL_FUNC_ADD;
case BlendOp::Subtract: return GL_FUNC_SUBTRACT;
case BlendOp::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT;
case BlendOp::Min: return GL_MIN;
case BlendOp::Max: return GL_MAX;
default: return GL_FUNC_ADD;
}
}
/**
* @brief CompareFunc OpenGL
*/
inline GLenum compareFuncToGL(CompareFunc func) {
switch (func) {
case CompareFunc::Never: return GL_NEVER;
case CompareFunc::Less: return GL_LESS;
case CompareFunc::Equal: return GL_EQUAL;
case CompareFunc::LessEqual: return GL_LEQUAL;
case CompareFunc::Greater: return GL_GREATER;
case CompareFunc::NotEqual: return GL_NOTEQUAL;
case CompareFunc::GreaterEqual: return GL_GEQUAL;
case CompareFunc::Always: return GL_ALWAYS;
default: return GL_LESS;
}
}
/**
* @brief ShaderType OpenGL
*/
inline GLenum shaderTypeToGL(ShaderType type) {
switch (type) {
case ShaderType::Vertex: return GL_VERTEX_SHADER;
case ShaderType::Fragment: return GL_FRAGMENT_SHADER;
case ShaderType::Geometry: return GL_GEOMETRY_SHADER;
case ShaderType::Compute: return GL_COMPUTE_SHADER;
default: return GL_VERTEX_SHADER;
}
}
/**
* @brief VertexFormat
*/
inline uint32_t getVertexFormatSize(VertexFormat format) {
switch (format) {
case VertexFormat::Float1: return sizeof(float) * 1;
case VertexFormat::Float2: return sizeof(float) * 2;
case VertexFormat::Float3: return sizeof(float) * 3;
case VertexFormat::Float4: return sizeof(float) * 4;
case VertexFormat::Int1: return sizeof(int32_t) * 1;
case VertexFormat::Int2: return sizeof(int32_t) * 2;
case VertexFormat::Int3: return sizeof(int32_t) * 3;
case VertexFormat::Int4: return sizeof(int32_t) * 4;
case VertexFormat::UInt1: return sizeof(uint32_t) * 1;
case VertexFormat::UInt2: return sizeof(uint32_t) * 2;
case VertexFormat::UInt3: return sizeof(uint32_t) * 3;
case VertexFormat::UInt4: return sizeof(uint32_t) * 4;
case VertexFormat::Byte4:
case VertexFormat::Byte4Normalized: return sizeof(int8_t) * 4;
case VertexFormat::UByte4:
case VertexFormat::UByte4Normalized: return sizeof(uint8_t) * 4;
default: return sizeof(float) * 4;
}
}
} // namespace extra2d

View File

@ -0,0 +1,14 @@
#pragma once
/**
* @brief RHI (Render Hardware Interface)
*
* RHI
*/
#include <renderer/rhi/rhi_types.h>
#include <renderer/rhi/rhi_device.h>
#include <renderer/rhi/rhi_buffer.h>
#include <renderer/rhi/rhi_shader.h>
#include <renderer/rhi/rhi_framebuffer.h>
#include <renderer/rhi/rhi_command_list.h>

View File

@ -0,0 +1,131 @@
#pragma once
#include <renderer/rhi/rhi_types.h>
namespace extra2d {
/**
* @brief RHI
*
* GPU
*/
class RHIBuffer {
public:
virtual ~RHIBuffer() = default;
/**
* @brief
* @return
*/
virtual BufferType getType() const = 0;
/**
* @brief
* @return
*/
virtual uint32_t getSize() const = 0;
/**
* @brief
* @param data
* @param size
* @param offset
* @return
*/
virtual bool update(const void* data, uint32_t size, uint32_t offset = 0) = 0;
/**
* @brief CPU
* @return nullptr
*/
virtual void* map() = 0;
/**
* @brief
*/
virtual void unmap() = 0;
/**
* @brief
* @return
*/
virtual bool isValid() const = 0;
};
/**
* @brief RHI
*
* GPU
*/
class RHITexture {
public:
virtual ~RHITexture() = default;
/**
* @brief
* @return
*/
virtual TextureType getType() const = 0;
/**
* @brief
* @return
*/
virtual TextureFormat getFormat() const = 0;
/**
* @brief
* @return
*/
virtual uint32_t getWidth() const = 0;
/**
* @brief
* @return
*/
virtual uint32_t getHeight() const = 0;
/**
* @brief Mipmap
* @return Mipmap
*/
virtual uint32_t getMipLevels() const = 0;
/**
* @brief
* @param data
* @param mipLevel Mipmap
* @return
*/
virtual bool update(const void* data, uint32_t mipLevel = 0) = 0;
/**
* @brief Mipmap
*/
virtual void generateMipmap() = 0;
/**
* @brief
* @param slot
*/
virtual void bind(uint32_t slot) = 0;
/**
* @brief
*/
virtual void unbind() = 0;
/**
* @brief
* @return
*/
virtual bool isValid() const = 0;
/**
* @brief
* @return
*/
virtual bool isRenderTarget() const = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,184 @@
#pragma once
#include <renderer/rhi/rhi_types.h>
#include <renderer/rhi/rhi_buffer.h>
#include <renderer/rhi/rhi_shader.h>
#include <renderer/rhi/rhi_framebuffer.h>
namespace extra2d {
/**
* @brief RHI
*
* GPU
*/
class RHICommandList {
public:
virtual ~RHICommandList() = default;
//===========================================================================
// 命令列表生命周期
//===========================================================================
/**
* @brief
*/
virtual void begin() = 0;
/**
* @brief
*/
virtual void end() = 0;
/**
* @brief GPU
*/
virtual void submit() = 0;
//===========================================================================
// 渲染通道
//===========================================================================
/**
* @brief
* @param framebuffer
* @param clearFlags
* @param clearColor Color
* @param clearDepth Depth
* @param clearStencil Stencil
*/
virtual void beginRenderPass(RHIFramebuffer* framebuffer,
ClearFlags clearFlags = ClearFlags::Color,
const Color& clearColor = Color::Black,
float clearDepth = 1.0f,
uint8_t clearStencil = 0) = 0;
/**
* @brief
*/
virtual void endRenderPass() = 0;
//===========================================================================
// 状态设置
//===========================================================================
/**
* @brief
* @param viewport
*/
virtual void setViewport(const Viewport& viewport) = 0;
/**
* @brief
* @param scissor
*/
virtual void setScissor(const ScissorRect& scissor) = 0;
/**
* @brief 线
* @param pipeline 线
*/
virtual void setPipeline(RHIPipeline* pipeline) = 0;
//===========================================================================
// 资源绑定
//===========================================================================
/**
* @brief
* @param slot
* @param buffer
* @param offset
*/
virtual void setVertexBuffer(uint32_t slot, RHIBuffer* buffer, uint32_t offset = 0) = 0;
/**
* @brief
* @param buffer
* @param type
* @param offset
*/
virtual void setIndexBuffer(RHIBuffer* buffer, IndexType type, uint32_t offset = 0) = 0;
/**
* @brief Uniform
* @param slot
* @param buffer
*/
virtual void setUniformBuffer(uint32_t slot, RHIBuffer* buffer) = 0;
/**
* @brief
* @param slot
* @param texture
*/
virtual void setTexture(uint32_t slot, RHITexture* texture) = 0;
/**
* @brief
* @param slot
* @param minFilter
* @param magFilter
* @param wrapS S
* @param wrapT T
*/
virtual void setSampler(uint32_t slot,
TextureFilter minFilter,
TextureFilter magFilter,
TextureWrap wrapS,
TextureWrap wrapT) = 0;
//===========================================================================
// 绘制命令
//===========================================================================
/**
* @brief
* @param vertexCount
* @param firstVertex
* @param instanceCount
* @param firstInstance
*/
virtual void draw(uint32_t vertexCount,
uint32_t firstVertex = 0,
uint32_t instanceCount = 1,
uint32_t firstInstance = 0) = 0;
/**
* @brief
* @param indexCount
* @param firstIndex
* @param vertexOffset
* @param instanceCount
* @param firstInstance
*/
virtual void drawIndexed(uint32_t indexCount,
uint32_t firstIndex = 0,
int32_t vertexOffset = 0,
uint32_t instanceCount = 1,
uint32_t firstInstance = 0) = 0;
//===========================================================================
// 工具方法
//===========================================================================
/**
* @brief
* @param flags
* @param color
* @param depth
* @param stencil
*/
virtual void clear(ClearFlags flags,
const Color& color = Color::Black,
float depth = 1.0f,
uint8_t stencil = 0) = 0;
/**
* @brief
* @return
*/
virtual bool isRecording() const = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,169 @@
#pragma once
#include <memory>
#include <renderer/rhi/rhi_types.h>
namespace extra2d {
/**
* @brief RHI
*
*
*/
class RHIDevice {
public:
virtual ~RHIDevice() = default;
/**
* @brief
* @param nativeWindow SDL_Window*
* @return
*/
virtual bool initialize(void* nativeWindow) = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
//===========================================================================
// 资源创建
//===========================================================================
/**
* @brief
* @param desc
* @return
*/
virtual std::unique_ptr<RHIBuffer> createBuffer(const BufferDesc &desc) = 0;
/**
* @brief
* @param desc
* @return
*/
virtual std::unique_ptr<RHITexture>
createTexture(const TextureDesc &desc) = 0;
/**
* @brief
* @param desc
* @return
*/
virtual std::unique_ptr<RHIShader> createShader(const ShaderDesc &desc) = 0;
/**
* @brief 线
* @param desc 线
* @return 线
*/
virtual std::unique_ptr<RHIPipeline>
createPipeline(const PipelineDesc &desc) = 0;
/**
* @brief
* @param desc
* @return
*/
virtual std::unique_ptr<RHIFramebuffer>
createFramebuffer(const RenderPassDesc &desc) = 0;
/**
* @brief
* @return
*/
virtual std::unique_ptr<RHICommandList> createCommandList() = 0;
//===========================================================================
// 上下文管理
//===========================================================================
/**
* @brief
* @return
*/
virtual RHIContext *getContext() = 0;
/**
* @brief
* @return "OpenGL", "Vulkan"
*/
virtual const char *getBackendName() const = 0;
/**
* @brief GPU
*/
virtual void waitIdle() = 0;
/**
* @brief
* @return
*/
virtual const RenderStats &getStats() const = 0;
/**
* @brief
*/
virtual void resetStats() = 0;
};
/**
* @brief RHI
*
*
*/
class RHIContext {
public:
virtual ~RHIContext() = default;
/**
* @brief
* @return
*/
virtual bool initialize() = 0;
/**
* @brief
*/
virtual void shutdown() = 0;
/**
* @brief
*/
virtual void beginFrame() = 0;
/**
* @brief
*/
virtual void endFrame() = 0;
/**
* @brief
* @param x X
* @param y Y
* @param width
* @param height
*/
virtual void setViewport(int32_t x, int32_t y, uint32_t width,
uint32_t height) = 0;
/**
* @brief
*/
virtual void bindDefaultFramebuffer() = 0;
/**
* @brief
* @return
*/
virtual RHIFramebuffer *getDefaultFramebuffer() = 0;
/**
* @brief
* @param feature
* @return
*/
virtual bool isFeatureSupported(const char *feature) const = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,76 @@
#pragma once
#include <renderer/rhi/rhi_types.h>
namespace extra2d {
/**
* @brief RHI
*
* GPU (FBO)
*/
class RHIFramebuffer {
public:
virtual ~RHIFramebuffer() = default;
/**
* @brief
*/
virtual void bind() = 0;
/**
* @brief
*/
virtual void unbind() = 0;
/**
* @brief
* @return
*/
virtual uint32_t getColorAttachmentCount() const = 0;
/**
* @brief
* @param index
* @return
*/
virtual TextureHandle getColorAttachment(uint32_t index) const = 0;
/**
* @brief /
* @return
*/
virtual TextureHandle getDepthStencilAttachment() const = 0;
/**
* @brief
* @return
*/
virtual uint32_t getWidth() const = 0;
/**
* @brief
* @return
*/
virtual uint32_t getHeight() const = 0;
/**
* @brief /
* @return /
*/
virtual bool hasDepthStencil() const = 0;
/**
* @brief
* @return
*/
virtual bool isValid() const = 0;
/**
* @brief
* @return
*/
virtual bool isDefault() const = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,86 @@
#pragma once
#include <renderer/rhi/rhi_types.h>
#include <string>
namespace extra2d {
/**
* @brief RHI
*
* GPU
*/
class RHIShader {
public:
virtual ~RHIShader() = default;
/**
* @brief
* @return
*/
virtual ShaderType getType() const = 0;
/**
* @brief
* @return
*/
virtual bool isCompiled() const = 0;
/**
* @brief
* @return
*/
virtual std::string getCompileLog() const = 0;
/**
* @brief
* @return
*/
virtual bool isValid() const = 0;
};
/**
* @brief RHI 线
*
* GPU 线 (PSO)
*/
class RHIPipeline {
public:
virtual ~RHIPipeline() = default;
/**
* @brief 线
*/
virtual void bind() = 0;
/**
* @brief 线
*/
virtual void unbind() = 0;
/**
* @brief
* @return
*/
virtual ShaderHandle getVertexShader() const = 0;
/**
* @brief
* @return
*/
virtual ShaderHandle getFragmentShader() const = 0;
/**
* @brief
* @return
*/
virtual const VertexLayout& getVertexLayout() const = 0;
/**
* @brief
* @return
*/
virtual bool isValid() const = 0;
};
} // namespace extra2d

View File

@ -0,0 +1,480 @@
#pragma once
#include <string>
#include <types/base/types.h>
#include <types/math/color.h>
#include <types/math/mat4.h>
#include <types/math/vec2.h>
#include <types/math/vec3.h>
#include <vector>
namespace extra2d {
// 前向声明
class RHIDevice;
class RHIContext;
class RHICommandList;
class RHIBuffer;
class RHITexture;
class RHIShader;
class RHIPipeline;
class RHIFramebuffer;
/**
* @brief RHI
*/
template <typename T> class RHIHandle {
public:
RHIHandle() = default;
explicit RHIHandle(T *ptr) : ptr_(ptr) {}
T *get() const { return ptr_; }
bool isValid() const { return ptr_ != nullptr; }
explicit operator bool() const { return isValid(); }
bool operator==(const RHIHandle &other) const { return ptr_ == other.ptr_; }
bool operator!=(const RHIHandle &other) const { return ptr_ != other.ptr_; }
private:
T *ptr_ = nullptr;
};
using BufferHandle = RHIHandle<RHIBuffer>;
using TextureHandle = RHIHandle<RHITexture>;
using ShaderHandle = RHIHandle<RHIShader>;
using PipelineHandle = RHIHandle<RHIPipeline>;
using FramebufferHandle = RHIHandle<RHIFramebuffer>;
/**
* @brief
*/
enum class BufferType : uint8_t {
Vertex, // 顶点缓冲区
Index, // 索引缓冲区
Uniform, // Uniform 缓冲区
Storage, // 存储缓冲区 (SSBO)
Staging // 暂存缓冲区
};
/**
* @brief 使
*/
enum class BufferUsage : uint8_t {
Static, // 静态数据,很少修改
Dynamic, // 动态数据,每帧修改
Stream // 流数据,每帧多次修改
};
/**
* @brief
*/
struct BufferDesc {
BufferType type = BufferType::Vertex;
BufferUsage usage = BufferUsage::Static;
uint32_t size = 0; // 缓冲区大小(字节)
const void *initialData = nullptr; // 初始数据
static BufferDesc vertex(uint32_t size,
BufferUsage usage = BufferUsage::Static);
static BufferDesc index(uint32_t size,
BufferUsage usage = BufferUsage::Static);
static BufferDesc uniform(uint32_t size);
};
/**
* @brief
*/
enum class TextureType : uint8_t {
Texture2D, // 2D 纹理
TextureCube, // 立方体贴图
TextureArray, // 纹理数组
RenderTarget // 渲染目标
};
/**
* @brief
*/
enum class TextureUsage : uint8_t {
Sampled, // 采样纹理(只读)
Storage, // 存储纹理(读写)
RenderTarget, // 渲染目标
DepthStencil // 深度/模板目标
};
/**
* @brief
*/
enum class TextureFormat : uint8_t {
// 颜色格式
R8, // 8位 红
RG8, // 8位 RG
RGB8, // 8位 RGB
RGBA8, // 8位 RGBA
RGBA8_SRGB, // sRGB 颜色空间
// 深度/模板格式
Depth16,
Depth24,
Depth32F,
Depth24Stencil8,
Depth32FStencil8,
// 压缩格式
BC1, // DXT1
BC3, // DXT5
BC5 // 3Dc
};
/**
* @brief
*/
enum class TextureFilter : uint8_t {
Nearest, // 最近邻
Linear, // 线性
NearestMipmapNearest,
LinearMipmapNearest,
NearestMipmapLinear,
LinearMipmapLinear
};
/**
* @brief
*/
enum class TextureWrap : uint8_t {
Repeat, // 重复
ClampToEdge, // 边缘钳制
ClampToBorder, // 边界钳制
MirroredRepeat // 镜像重复
};
/**
* @brief
*/
struct TextureDesc {
TextureType type = TextureType::Texture2D;
TextureFormat format = TextureFormat::RGBA8;
uint32_t width = 0;
uint32_t height = 0;
uint32_t depth = 1; // 对于 3D 纹理或数组层数
uint32_t mipLevels = 1;
TextureFilter minFilter = TextureFilter::Linear;
TextureFilter magFilter = TextureFilter::Linear;
TextureWrap wrapS = TextureWrap::Repeat;
TextureWrap wrapT = TextureWrap::Repeat;
bool renderTarget = false; // 是否可作为渲染目标
static TextureDesc texture2D(uint32_t width, uint32_t height,
TextureFormat format = TextureFormat::RGBA8);
static TextureDesc renderTarget2D(uint32_t width, uint32_t height,
TextureFormat format);
static TextureDesc depthStencil(uint32_t width, uint32_t height);
};
/**
* @brief
*/
enum class ShaderType : uint8_t {
Vertex, // 顶点着色器
Fragment, // 片段着色器
Geometry, // 几何着色器
Compute // 计算着色器
};
/**
* @brief
*
*
*/
struct ShaderDesc {
std::string vertexSource; // 顶点着色器源码
std::string fragmentSource; // 片段着色器源码
std::string entryPoint = "main"; // 入口函数名
static ShaderDesc fromSource(const std::string &vertexSrc,
const std::string &fragmentSrc) {
ShaderDesc desc;
desc.vertexSource = vertexSrc;
desc.fragmentSource = fragmentSrc;
return desc;
}
};
/**
* @brief
*/
enum class VertexFormat : uint8_t {
Float1,
Float2,
Float3,
Float4,
Int1,
Int2,
Int3,
Int4,
UInt1,
UInt2,
UInt3,
UInt4,
Byte4,
Byte4Normalized,
UByte4,
UByte4Normalized
};
/**
* @brief
*/
struct VertexAttribute {
uint32_t location = 0; // 属性位置
VertexFormat format = VertexFormat::Float3;
uint32_t offset = 0; // 在顶点结构中的偏移
uint32_t bufferIndex = 0; // 绑定的顶点缓冲区索引
static uint32_t getSize(VertexFormat format);
};
/**
* @brief
*/
struct VertexLayout {
std::vector<VertexAttribute> attributes;
uint32_t stride = 0; // 顶点大小(字节)
void addAttribute(uint32_t location, VertexFormat format, uint32_t offset,
uint32_t bufferIndex = 0);
};
/**
* @brief
*/
enum class IndexType : uint8_t { UInt16, UInt32 };
/**
* @brief
*/
enum class PrimitiveType : uint8_t {
Points,
Lines,
LineStrip,
Triangles,
TriangleStrip,
TriangleFan
};
/**
* @brief
*/
enum class BlendFactor : uint8_t {
Zero,
One,
SrcColor,
OneMinusSrcColor,
DstColor,
OneMinusDstColor,
SrcAlpha,
OneMinusSrcAlpha,
DstAlpha,
OneMinusDstAlpha
};
/**
* @brief
*/
enum class BlendOp : uint8_t { Add, Subtract, ReverseSubtract, Min, Max };
/**
* @brief
*/
struct BlendState {
bool enabled = false;
BlendFactor srcFactor = BlendFactor::One;
BlendFactor dstFactor = BlendFactor::Zero;
BlendOp op = BlendOp::Add;
BlendFactor srcAlphaFactor = BlendFactor::One;
BlendFactor dstAlphaFactor = BlendFactor::Zero;
BlendOp alphaOp = BlendOp::Add;
static BlendState opaque();
static BlendState alphaBlend();
static BlendState additive();
};
/**
* @brief
*/
enum class CompareFunc : uint8_t {
Never,
Less,
Equal,
LessEqual,
Greater,
NotEqual,
GreaterEqual,
Always
};
/**
* @brief /
*/
struct DepthStencilState {
bool depthTestEnabled = true;
bool depthWriteEnabled = true;
CompareFunc depthCompare = CompareFunc::Less;
bool stencilEnabled = false;
// 模板测试配置(简化版)
uint8_t stencilReadMask = 0xFF;
uint8_t stencilWriteMask = 0xFF;
uint8_t stencilRef = 0;
static DepthStencilState depthTest();
static DepthStencilState depthTestWrite();
static DepthStencilState depthTestNoWrite();
static DepthStencilState noDepthTest();
};
/**
* @brief
*/
struct RasterizerState {
bool cullEnabled = false;
bool cullFrontFace = false; // true = 剔除正面, false = 剔除背面
bool frontCCW = false; // 正面是否为逆时针
bool scissorEnabled = false;
bool wireframe = false;
static RasterizerState cullBack();
static RasterizerState cullFront();
static RasterizerState noCull();
};
/**
* @brief 线
*/
struct PipelineDesc {
ShaderHandle vertexShader;
ShaderHandle fragmentShader;
VertexLayout vertexLayout;
PrimitiveType primitiveType = PrimitiveType::Triangles;
BlendState blendState;
DepthStencilState depthStencilState;
RasterizerState rasterizerState;
static PipelineDesc create(ShaderHandle vs, ShaderHandle fs,
const VertexLayout &layout);
};
/**
* @brief /
*/
enum class LoadOp : uint8_t {
Load, // 加载现有内容
Clear, // 清除为指定值
DontCare // 不关心现有内容
};
enum class StoreOp : uint8_t {
Store, // 保存结果
DontCare // 不关心结果
};
/**
* @brief
*/
struct RenderPassAttachment {
TextureHandle texture;
LoadOp loadOp = LoadOp::Clear;
StoreOp storeOp = StoreOp::Store;
Color clearColor = Color::Black;
float clearDepth = 1.0f;
uint8_t clearStencil = 0;
};
/**
* @brief
*/
struct RenderPassDesc {
std::vector<RenderPassAttachment> colorAttachments;
RenderPassAttachment depthStencilAttachment;
bool hasDepthStencil = false;
};
/**
* @brief
*/
struct Viewport {
float x = 0.0f;
float y = 0.0f;
float width = 0.0f;
float height = 0.0f;
float minDepth = 0.0f;
float maxDepth = 1.0f;
Viewport() = default;
Viewport(float x, float y, float w, float h)
: x(x), y(y), width(w), height(h) {}
};
/**
* @brief
*/
struct ScissorRect {
int32_t x = 0;
int32_t y = 0;
int32_t width = 0;
int32_t height = 0;
ScissorRect() = default;
ScissorRect(int32_t x, int32_t y, int32_t w, int32_t h)
: x(x), y(y), width(w), height(h) {}
};
/**
* @brief
*/
enum class ClearFlags : uint32_t {
None = 0,
Color = 1 << 0,
Depth = 1 << 1,
Stencil = 1 << 2,
All = Color | Depth | Stencil
};
inline ClearFlags operator|(ClearFlags a, ClearFlags b) {
return static_cast<ClearFlags>(static_cast<uint32_t>(a) |
static_cast<uint32_t>(b));
}
inline ClearFlags operator&(ClearFlags a, ClearFlags b) {
return static_cast<ClearFlags>(static_cast<uint32_t>(a) &
static_cast<uint32_t>(b));
}
inline bool hasFlag(ClearFlags flags, ClearFlags flag) {
return (static_cast<uint32_t>(flags) & static_cast<uint32_t>(flag)) != 0;
}
/**
* @brief
*/
struct RenderStats {
uint32_t drawCalls = 0;
uint32_t triangles = 0;
uint32_t vertices = 0;
uint32_t textureBinds = 0;
uint32_t bufferBinds = 0;
uint32_t pipelineBinds = 0;
uint32_t renderPassSwitches = 0;
void reset() {
drawCalls = 0;
triangles = 0;
vertices = 0;
textureBinds = 0;
bufferBinds = 0;
pipelineBinds = 0;
renderPassSwitches = 0;
}
};
} // namespace extra2d

View File

@ -0,0 +1,113 @@
#pragma once
#include <event/events.h>
#include <module/module.h>
#include <module/module_registry.h>
#include <renderer/rhi/rhi.h>
#include <memory>
namespace extra2d {
/**
* @brief RHI
*
* RHI API
* 1 WindowModule
*/
class RHIModule : public Module {
E2D_REGISTER_MODULE(RHIModule, "RHI", 1)
public:
RHIModule();
~RHIModule() override;
/**
* @brief RHI
* @return
*/
bool init() override;
/**
* @brief RHI
*/
void shutdown() override;
/**
* @brief RHI
* @return RHI
*/
RHIDevice* getDevice() const { return device_.get(); }
/**
* @brief RHI
* @return RHI
*/
RHIContext* getContext() const { return context_; }
/**
* @brief RHIModule
* @return RHIModule
*/
static RHIModule* get();
/**
* @brief RHI
* @return
*/
bool isInitialized() const { return initialized_; }
/**
* @brief
* @param desc
* @return
*/
std::unique_ptr<RHIBuffer> createBuffer(const BufferDesc& desc);
/**
* @brief
* @param desc
* @return
*/
std::unique_ptr<RHITexture> createTexture(const TextureDesc& desc);
/**
* @brief
* @param desc
* @return
*/
std::unique_ptr<RHIShader> createShader(const ShaderDesc& desc);
/**
* @brief 线
* @param desc 线
* @return 线
*/
std::unique_ptr<RHIPipeline> createPipeline(const PipelineDesc& desc);
/**
* @brief
* @param desc
* @return
*/
std::unique_ptr<RHIFramebuffer> createFramebuffer(const RenderPassDesc& desc);
/**
* @brief
* @return
*/
std::unique_ptr<RHICommandList> createCommandList();
private:
/**
* @brief - OpenGL
*/
void onWindowShow();
private:
std::unique_ptr<RHIDevice> device_;
RHIContext* context_;
bool initialized_ = false;
std::unique_ptr<events::OnShow::Listener> onShowListener_;
};
} // namespace extra2d

View File

@ -1,22 +1,18 @@
#pragma once #pragma once
#include <types/ptr/ref_counted.h> #include <renderer/rhi/rhi.h>
#include <types/ptr/intrusive_ptr.h>
#include <types/base/types.h>
#include <string> #include <string>
#include <types/base/types.h>
#include <types/ptr/intrusive_ptr.h>
#include <types/ptr/ref_counted.h>
#include <unordered_map> #include <unordered_map>
// 前向声明 OpenGL 类型
typedef unsigned int GLuint;
typedef int GLint;
typedef unsigned int GLenum;
namespace extra2d { namespace extra2d {
/** /**
* @brief * @brief
* *
* OpenGL 使 * RHI
* *
*/ */
class Shader : public RefCounted { class Shader : public RefCounted {
@ -48,14 +44,22 @@ public:
bool loadFromSource(const std::string &vsSource, const std::string &fsSource); bool loadFromSource(const std::string &vsSource, const std::string &fsSource);
/** /**
* @brief * @brief RHI
* @return RHI
*/ */
void bind() const; ShaderHandle getHandle() const { return handle_; }
/** /**
* @brief * @brief RHI 线
* @return RHI 线
*/ */
void unbind() const; PipelineHandle getPipeline() const { return pipeline_; }
/**
* @brief
* @return
*/
bool isLoaded() const { return handle_.isValid() && pipeline_.isValid(); }
/** /**
* @brief Uniform Block * @brief Uniform Block
@ -65,91 +69,27 @@ public:
void setUniformBlock(const std::string &name, uint32_t binding); void setUniformBlock(const std::string &name, uint32_t binding);
/** /**
* @brief int uniform * @brief Uniform Block
* @param name uniform * @param name Uniform Block
* @param value * @return UINT32_MAX
*/ */
void setInt(const std::string& name, int value); uint32_t getUniformBlockBinding(const std::string& name) const;
/**
* @brief float uniform
* @param name uniform
* @param value
*/
void setFloat(const std::string& name, float value);
/**
* @brief vec2 uniform
* @param name uniform
* @param x X
* @param y Y
*/
void setVec2(const std::string& name, float x, float y);
/**
* @brief vec4 uniform
* @param name uniform
* @param x X
* @param y Y
* @param z Z
* @param w W
*/
void setVec4(const std::string& name, float x, float y, float z, float w);
/**
* @brief mat4 uniform
* @param name uniform
* @param value 16float
*/
void setMat4(const std::string& name, const float* value);
/**
* @brief ID
* @return OpenGL ID
*/
GLuint getProgram() const { return program_; }
/**
* @brief
* @return
*/
bool isLoaded() const { return program_ != 0; }
private: private:
/**
* @brief
* @param type
* @param source
* @return 0
*/
GLuint compileShader(GLenum type, const std::string& source);
/**
* @brief
* @param vertexShader
* @param fragmentShader
* @return
*/
bool linkProgram(GLuint vertexShader, GLuint fragmentShader);
/**
* @brief uniform
* @param name uniform
* @return uniform -1
*/
GLint getUniformLocation(const std::string& name);
/** /**
* @brief * @brief
* @param source * @param source
* @param type * @param isVertex
* @return * @return
*/ */
std::string addVersionIfNeeded(const std::string& source, GLenum type); std::string addVersionIfNeeded(const std::string &source, bool isVertex);
private: private:
GLuint program_ = 0; // OpenGL 程序对象 ShaderHandle handle_; // RHI 着色器句柄
std::unordered_map<std::string, GLint> uniformCache_; // Uniform 位置缓存 PipelineHandle pipeline_; // RHI 管线句柄
// Uniform Block 绑定映射
std::unordered_map<std::string, uint32_t> uniformBlockBindings_;
}; };
} // namespace extra2d } // namespace extra2d

View File

@ -1,20 +1,17 @@
#pragma once #pragma once
#include <renderer/rhi/rhi.h>
#include <types/ptr/ref_counted.h> #include <types/ptr/ref_counted.h>
#include <types/ptr/intrusive_ptr.h> #include <types/ptr/intrusive_ptr.h>
#include <renderer/render_types.h>
#include <types/base/types.h> #include <types/base/types.h>
#include <string> #include <string>
// 前向声明 OpenGL 类型
typedef unsigned int GLuint;
namespace extra2d { namespace extra2d {
/** /**
* @brief * @brief
* *
* OpenGL * RHI
* *
*/ */
class Texture : public RefCounted { class Texture : public RefCounted {
@ -55,17 +52,6 @@ public:
*/ */
bool create(int width, int height, TextureFormat format); bool create(int width, int height, TextureFormat format);
/**
* @brief
* @param slot
*/
void bind(uint32_t slot = 0) const;
/**
* @brief
*/
void unbind() const;
/** /**
* @brief * @brief
* @return * @return
@ -85,19 +71,25 @@ public:
TextureFormat getFormat() const { return format_; } TextureFormat getFormat() const { return format_; }
/** /**
* @brief OpenGL * @brief RHI
* @return OpenGL * @return RHI
*/ */
GLuint getHandle() const { return texture_; } TextureHandle getHandle() const { return handle_; }
/** /**
* @brief * @brief
* @return * @return
*/ */
bool isLoaded() const { return texture_ != 0; } bool isLoaded() const { return handle_.isValid(); }
private: private:
GLuint texture_ = 0; // OpenGL 纹理对象 /**
* @brief
* @param format
* @return
*/
static uint32_t getBytesPerPixel(TextureFormat format);
TextureHandle handle_; // RHI 纹理句柄
int width_ = 0; // 纹理宽度 int width_ = 0; // 纹理宽度
int height_ = 0; // 纹理高度 int height_ = 0; // 纹理高度
TextureFormat format_ = TextureFormat::RGBA8; // 像素格式 TextureFormat format_ = TextureFormat::RGBA8; // 像素格式

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include <glad/glad.h> #include <renderer/rhi/rhi.h>
#include <memory> #include <memory>
#include <renderer/render_types.h>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
@ -10,7 +9,7 @@ namespace extra2d {
/** /**
* @brief (UBO) * @brief (UBO)
* *
* uniform GPU * RHI UBO uniform GPU
* std140 * std140
*/ */
class UniformBuffer { class UniformBuffer {
@ -59,19 +58,25 @@ public:
uint32_t getSize() const { return size_; } uint32_t getSize() const { return size_; }
/** /**
* @brief OpenGL * @brief RHI
* @return OpenGL * @return RHI
*/ */
GLuint getHandle() const { return ubo_; } BufferHandle getHandle() const { return handle_; }
/**
* @brief RHI
* @return RHI
*/
RHIBuffer* getRHIBuffer() const;
/** /**
* @brief * @brief
* @return * @return
*/ */
bool isValid() const { return ubo_ != 0; } bool isValid() const { return handle_.isValid(); }
private: private:
GLuint ubo_ = 0; // OpenGL 缓冲区对象 BufferHandle handle_; // RHI 缓冲区句柄
uint32_t size_ = 0; // 缓冲区大小 uint32_t size_ = 0; // 缓冲区大小
uint32_t binding_ = 0; // 绑定槽位 uint32_t binding_ = 0; // 绑定槽位
}; };
@ -150,8 +155,9 @@ private:
// 常量 // 常量
static constexpr uint32_t INITIAL_UBO_POOL_SIZE = 16; static constexpr uint32_t INITIAL_UBO_POOL_SIZE = 16;
static constexpr uint32_t GLOBAL_UBO_SIZE = static constexpr uint32_t GLOBAL_UBO_SIZE = 256; // 足够存储 viewProjection + time + screenSize
256; // 足够存储 viewProjection + time + screenSize static constexpr uint32_t GLOBAL_UBO_BINDING = 0; // 全局 UBO 绑定槽位
static constexpr uint32_t MATERIAL_UBO_BINDING = 1; // 材质 UBO 绑定槽位
}; };
} // namespace extra2d } // namespace extra2d

View File

@ -20,13 +20,11 @@ public:
SceneModule(); SceneModule();
~SceneModule() override; ~SceneModule() override;
// 禁止拷贝 // 禁止拷贝和移动
SceneModule(const SceneModule &) = delete; SceneModule(const SceneModule &) = delete;
SceneModule &operator=(const SceneModule &) = delete; SceneModule &operator=(const SceneModule &) = delete;
SceneModule(SceneModule &&) = delete;
// 允许移动 SceneModule &operator=(SceneModule &&) = delete;
SceneModule(SceneModule &&) noexcept;
SceneModule &operator=(SceneModule &&) noexcept;
// Module 接口实现 // Module 接口实现
bool init() override; bool init() override;

View File

@ -51,13 +51,11 @@ public:
TimerModule(); TimerModule();
~TimerModule() override; ~TimerModule() override;
// 禁止拷贝 // 禁止拷贝和移动
TimerModule(const TimerModule &) = delete; TimerModule(const TimerModule &) = delete;
TimerModule &operator=(const TimerModule &) = delete; TimerModule &operator=(const TimerModule &) = delete;
TimerModule(TimerModule &&) = delete;
// 允许移动 TimerModule &operator=(TimerModule &&) = delete;
TimerModule(TimerModule &&) noexcept;
TimerModule &operator=(TimerModule &&) noexcept;
// Module 接口实现 // Module 接口实现
bool init() override; bool init() override;

View File

@ -21,9 +21,15 @@ out vec4 fragColor;
* *
*/ */
void main() { void main() {
// 采样纹理 // 采样纹理如果没有绑定纹理texture 会返回 vec4(0,0,0,1) 或 vec4(1,1,1,1) 取决于实现)
vec4 texColor = texture(uTexture, vTexCoord); vec4 texColor = texture(uTexture, vTexCoord);
// 如果纹理采样结果是黑色或透明,使用白色作为默认值
// 这样即使在没有纹理的情况下也能显示颜色
if (texColor.rgb == vec3(0.0) || texColor.a < 0.01) {
texColor = vec4(1.0, 1.0, 1.0, 1.0);
}
// 混合:纹理 * 顶点颜色 * 色调 // 混合:纹理 * 顶点颜色 * 色调
fragColor = texColor * vColor * uTintColor; fragColor = texColor * vColor * uTintColor;

View File

@ -63,6 +63,11 @@ void Application::initModules() {
// 从注册表自动创建所有模块 // 从注册表自动创建所有模块
modules_ = ModuleRegistry::instance().createModules(); modules_ = ModuleRegistry::instance().createModules();
// 存储模块实例到注册表,以便其他模块可以通过 getModule<T>() 获取
for (auto &module : modules_) {
ModuleRegistry::instance().storeModuleInstance(module.get());
}
// 初始化所有模块 // 初始化所有模块
for (auto &module : modules_) { for (auto &module : modules_) {
if (!module->init()) { if (!module->init()) {

View File

@ -410,8 +410,10 @@ bool AssetsModule::createDefaultResources() {
{ {
Ptr<Material> material = makePtr<Material>(); Ptr<Material> material = makePtr<Material>();
material->setShader(getPtr(defaultShader_)); material->setShader(getPtr(defaultShader_));
// 添加默认纹理到材质
material->setTexture("uTexture", getPtr(defaultTexture_), 0);
defaultMaterial_ = materials_.insert(material); defaultMaterial_ = materials_.insert(material);
E2D_LOG_DEBUG("Created default material"); E2D_LOG_DEBUG("Created default material with default texture");
} }
{ {

View File

@ -26,4 +26,21 @@ std::vector<std::unique_ptr<Module>> ModuleRegistry::createModules() {
return modules; return modules;
} }
void ModuleRegistry::storeModuleInstance(Module* module) {
if (!module) return;
// 通过模块名称查找对应的注册信息
for (const auto& info : registrations_) {
if (info.name == module->getName()) {
// 使用注册时存储的 type 作为键
instances_[info.type] = module;
return;
}
}
}
void ModuleRegistry::clearInstances() {
instances_.clear();
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,256 +0,0 @@
#include <SDL.h>
#include <fstream>
#include <platform/file_module.h>
#include <sstream>
#include <sys/stat.h>
#include <utils/logger.h>
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
#define mkdir_impl(path, mode) _mkdir(path)
#elif defined(__SWITCH__)
#include <dirent.h>
#include <unistd.h>
// Switch 使用 ::mkdir 避免与类成员函数冲突
#define mkdir_impl(path, mode) ::mkdir(path, mode)
#else
#include <dirent.h>
#include <unistd.h>
#define mkdir_impl(path, mode) mkdir(path, mode)
#endif
#ifdef __SWITCH__
#include <switch.h>
#endif
namespace extra2d {
FileModule::FileModule() = default;
FileModule::~FileModule() = default;
FileModule::FileModule(FileModule &&) noexcept = default;
FileModule &FileModule::operator=(FileModule &&) noexcept = default;
bool FileModule::init() {
writableDir_ = SDL_GetPrefPath("Extra2D", "Extra2D");
if (writableDir_.empty()) {
writableDir_ = "./";
}
#ifdef __SWITCH__
// 初始化 Switch 的 RomFS
Result rc = romfsInit();
if (R_SUCCEEDED(rc)) {
E2D_LOG_INFO("RomFS initialized successfully");
} else {
E2D_LOG_WARN("romfsInit failed: {:#08X}", rc);
}
#endif
return true;
}
void FileModule::shutdown() {
#ifdef __SWITCH__
// 关闭 RomFS
romfsExit();
#endif
}
bool FileModule::exists(const std::string &path) const {
struct stat st;
return stat(path.c_str(), &st) == 0;
}
bool FileModule::isDir(const std::string &path) const {
struct stat st;
if (stat(path.c_str(), &st) != 0)
return false;
return (st.st_mode & S_IFDIR) != 0;
}
FileData FileModule::read(const std::string &path) const {
FileData result;
std::ifstream file(path, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
result.error = "Cannot open file: " + path;
return result;
}
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
result.data.resize(static_cast<size_t>(size));
if (!file.read(reinterpret_cast<char *>(result.data.data()), size)) {
result.error = "Failed to read file: " + path;
return result;
}
result.ok = true;
return result;
}
std::string FileModule::readString(const std::string &path) const {
std::ifstream file(path);
if (!file.is_open())
return "";
std::stringstream buffer;
buffer << file.rdbuf();
return buffer.str();
}
bool FileModule::write(const std::string &path, const void *data,
size_t size) const {
std::ofstream file(path, std::ios::binary);
if (!file.is_open())
return false;
file.write(static_cast<const char *>(data),
static_cast<std::streamsize>(size));
return file.good();
}
bool FileModule::writeString(const std::string &path,
const std::string &content) const {
return write(path, content.data(), content.size());
}
bool FileModule::append(const std::string &path, const void *data,
size_t size) const {
std::ofstream file(path, std::ios::binary | std::ios::app);
if (!file.is_open())
return false;
file.write(static_cast<const char *>(data),
static_cast<std::streamsize>(size));
return file.good();
}
bool FileModule::remove(const std::string &path) const {
return std::remove(path.c_str()) == 0;
}
bool FileModule::mkdir(const std::string &path) const {
#ifdef _WIN32
return mkdir_impl(path.c_str(), 0755) == 0 || errno == EEXIST;
#else
return mkdir_impl(path.c_str(), 0755) == 0 || errno == EEXIST;
#endif
}
std::vector<FileInfo> FileModule::listDir(const std::string &path) const {
std::vector<FileInfo> result;
#ifdef _WIN32
WIN32_FIND_DATAA findData;
std::string searchPath = path + "\\*";
HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
return result;
do {
std::string name = findData.cFileName;
if (name == "." || name == "..")
continue;
FileInfo info;
info.name = name;
info.path = join(path, name);
info.isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (!info.isDir) {
info.size = static_cast<int64>(findData.nFileSizeLow) |
(static_cast<int64>(findData.nFileSizeHigh) << 32);
}
result.push_back(info);
} while (FindNextFileA(hFind, &findData));
FindClose(hFind);
#else
DIR *dir = opendir(path.c_str());
if (!dir)
return result;
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr) {
std::string name = entry->d_name;
if (name == "." || name == "..")
continue;
FileInfo info;
info.name = name;
info.path = join(path, name);
info.isDir = isDir(info.path);
if (!info.isDir) {
info.size = fileSize(info.path);
}
result.push_back(info);
}
closedir(dir);
#endif
return result;
}
int64 FileModule::fileSize(const std::string &path) const {
struct stat st;
if (stat(path.c_str(), &st) != 0)
return -1;
return static_cast<int64>(st.st_size);
}
std::string FileModule::ext(const std::string &path) const {
size_t pos = path.find_last_of('.');
if (pos == std::string::npos || pos == 0)
return "";
size_t lastSep = path.find_last_of("/\\");
if (lastSep != std::string::npos && pos < lastSep)
return "";
return path.substr(pos + 1);
}
std::string FileModule::fileName(const std::string &path) const {
size_t pos = path.find_last_of("/\\");
if (pos == std::string::npos)
return path;
return path.substr(pos + 1);
}
std::string FileModule::dirName(const std::string &path) const {
size_t pos = path.find_last_of("/\\");
if (pos == std::string::npos)
return ".";
if (pos == 0)
return "/";
return path.substr(0, pos);
}
std::string FileModule::join(const std::string &a, const std::string &b) const {
if (a.empty())
return b;
if (b.empty())
return a;
char last = a.back();
if (last == '/' || last == '\\') {
return a + b;
}
return a + "/" + b;
}
std::string FileModule::writableDir() const { return writableDir_; }
std::string FileModule::assetPath(const std::string &relPath) const {
if (assetRoot_.empty())
return relPath;
return join(assetRoot_, relPath);
}
} // namespace extra2d

View File

@ -12,64 +12,6 @@ InputModule::~InputModule() {
shutdown(); shutdown();
} }
InputModule::InputModule(InputModule&& other) noexcept
: mouseX_(other.mouseX_)
, mouseY_(other.mouseY_)
, mouseWheel_(other.mouseWheel_)
, activeTouches_(std::move(other.activeTouches_))
, endedTouches_(std::move(other.endedTouches_))
, onKeyDown_(std::move(other.onKeyDown_))
, onKeyUp_(std::move(other.onKeyUp_))
, onMouseDown_(std::move(other.onMouseDown_))
, onMouseUp_(std::move(other.onMouseUp_))
, onTouchBegan_(std::move(other.onTouchBegan_))
, onTouchMoved_(std::move(other.onTouchMoved_))
, onTouchEnded_(std::move(other.onTouchEnded_)) {
std::memcpy(keyState_.data(), other.keyState_.data(), KEY_COUNT);
std::memcpy(keyPrev_.data(), other.keyPrev_.data(), KEY_COUNT);
std::memcpy(mouseState_.data(), other.mouseState_.data(), static_cast<size_t>(MouseBtn::Count));
std::memcpy(mousePrev_.data(), other.mousePrev_.data(), static_cast<size_t>(MouseBtn::Count));
std::memcpy(gamepads_, other.gamepads_, sizeof(gamepads_));
std::memcpy(padState_, other.padState_, sizeof(padState_));
std::memcpy(padPrev_, other.padPrev_, sizeof(padPrev_));
for (int32 i = 0; i < MAX_GAMEPADS; ++i) {
other.gamepads_[i] = nullptr;
}
}
InputModule& InputModule::operator=(InputModule&& other) noexcept {
if (this != &other) {
shutdown();
mouseX_ = other.mouseX_;
mouseY_ = other.mouseY_;
mouseWheel_ = other.mouseWheel_;
activeTouches_ = std::move(other.activeTouches_);
endedTouches_ = std::move(other.endedTouches_);
onKeyDown_ = std::move(other.onKeyDown_);
onKeyUp_ = std::move(other.onKeyUp_);
onMouseDown_ = std::move(other.onMouseDown_);
onMouseUp_ = std::move(other.onMouseUp_);
onTouchBegan_ = std::move(other.onTouchBegan_);
onTouchMoved_ = std::move(other.onTouchMoved_);
onTouchEnded_ = std::move(other.onTouchEnded_);
std::memcpy(keyState_.data(), other.keyState_.data(), KEY_COUNT);
std::memcpy(keyPrev_.data(), other.keyPrev_.data(), KEY_COUNT);
std::memcpy(mouseState_.data(), other.mouseState_.data(), static_cast<size_t>(MouseBtn::Count));
std::memcpy(mousePrev_.data(), other.mousePrev_.data(), static_cast<size_t>(MouseBtn::Count));
std::memcpy(gamepads_, other.gamepads_, sizeof(gamepads_));
std::memcpy(padState_, other.padState_, sizeof(padState_));
std::memcpy(padPrev_, other.padPrev_, sizeof(padPrev_));
for (int32 i = 0; i < MAX_GAMEPADS; ++i) {
other.gamepads_[i] = nullptr;
}
}
return *this;
}
bool InputModule::init() { bool InputModule::init() {
std::memset(keyState_.data(), 0, KEY_COUNT); std::memset(keyState_.data(), 0, KEY_COUNT);
std::memset(keyPrev_.data(), 0, KEY_COUNT); std::memset(keyPrev_.data(), 0, KEY_COUNT);

View File

@ -4,39 +4,12 @@
#include <platform/window_module.h> #include <platform/window_module.h>
#include <utils/logger.h> #include <utils/logger.h>
// OpenGL ES 3.2 with GLAD
#include <glad/glad.h>
namespace extra2d { namespace extra2d {
WindowModule::WindowModule() = default; WindowModule::WindowModule() = default;
WindowModule::~WindowModule() { shutdown(); } WindowModule::~WindowModule() { shutdown(); }
WindowModule::WindowModule(WindowModule &&other) noexcept
: window_(other.window_), glContext_(other.glContext_),
shouldClose_(other.shouldClose_), onClose_(std::move(other.onClose_)),
onResize_(std::move(other.onResize_)),
configListener_(std::move(other.configListener_)) {
other.window_ = nullptr;
other.glContext_ = nullptr;
}
WindowModule &WindowModule::operator=(WindowModule &&other) noexcept {
if (this != &other) {
shutdown();
window_ = other.window_;
glContext_ = other.glContext_;
shouldClose_ = other.shouldClose_;
onClose_ = std::move(other.onClose_);
onResize_ = std::move(other.onResize_);
configListener_ = std::move(other.configListener_);
other.window_ = nullptr;
other.glContext_ = nullptr;
}
return *this;
}
bool WindowModule::init() { bool WindowModule::init() {
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
E2D_LOG_ERROR("Failed to initialize SDL video: {}", SDL_GetError()); E2D_LOG_ERROR("Failed to initialize SDL video: {}", SDL_GetError());
@ -58,7 +31,10 @@ bool WindowModule::init() {
} }
void WindowModule::shutdown() { void WindowModule::shutdown() {
destroyGLContext(); // 清理事件监听器
configListener_.reset();
renderPresentListener_.reset();
if (window_) { if (window_) {
SDL_DestroyWindow(window_); SDL_DestroyWindow(window_);
window_ = nullptr; window_ = nullptr;
@ -163,14 +139,8 @@ void WindowModule::onModuleConfig(const AppConfig &config) {
cfg.resizable = config.resizable; cfg.resizable = config.resizable;
if (create(cfg)) { if (create(cfg)) {
// 创建 OpenGL 上下文 // 发送窗口显示事件
if (!createGLContext()) { // RHI 模块会监听此事件并创建 OpenGL 上下文
E2D_LOG_ERROR("Failed to create OpenGL context");
return;
}
// GL 上下文创建完成后,再发送窗口显示事件
// 这样渲染模块可以在收到事件时安全地使用 GL 函数
events::OnShow::emit(); events::OnShow::emit();
setVisible(true); setVisible(true);
@ -240,56 +210,9 @@ bool WindowModule::isVisible() const {
return (flags & SDL_WINDOW_SHOWN) != 0; return (flags & SDL_WINDOW_SHOWN) != 0;
} }
bool WindowModule::createGLContext() {
if (!window_) {
return false;
}
// 创建 OpenGL ES 3.2 上下文
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
glContext_ = SDL_GL_CreateContext(window_);
if (!glContext_) {
E2D_LOG_ERROR("Failed to create OpenGL ES context: {}", SDL_GetError());
return false;
}
// 初始化 GLAD
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
E2D_LOG_ERROR("Failed to initialize GLAD");
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
return false;
}
E2D_LOG_INFO("OpenGL ES context created: {}.{}", GLVersion.major,
GLVersion.minor);
return true;
}
void WindowModule::destroyGLContext() {
if (glContext_) {
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
}
}
void WindowModule::swapBuffers() {
if (window_) {
SDL_GL_SwapWindow(window_);
}
}
void WindowModule::onRenderPresent() { void WindowModule::onRenderPresent() {
swapBuffers(); // 交换缓冲区由 RHI 模块处理
// 这里可以触发呈现事件
} }
void *WindowModule::getGLContext() const { return glContext_; }
} // namespace extra2d } // namespace extra2d

View File

@ -0,0 +1,435 @@
#include <algorithm>
#include <cstring>
#include <renderer/command_queue.h>
#include <renderer/material.h>
#include <renderer/mesh.h>
#include <renderer/rhi_module.h>
#include <renderer/rhi/opengl/gl_command_list.h>
#include <renderer/rhi/opengl/gl_texture.h>
#include <types/math/transform.h>
#include <types/ptr/intrusive_ptr.h>
#include <utils/logger.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
namespace extra2d {
// ========================================
// CommandSorter 实现
// ========================================
uint32_t CommandSorter::addCommand(const DrawCommand &cmd) {
uint32_t index = static_cast<uint32_t>(commands_.size());
commands_.push_back(cmd);
sortedIndices_.push_back(index);
return index;
}
void CommandSorter::sort() {
// 使用稳定排序保持相同键的命令顺序
std::stable_sort(sortedIndices_.begin(), sortedIndices_.end(),
[this](uint32_t a, uint32_t b) {
return commands_[a].key < commands_[b].key;
});
}
void CommandSorter::clear() {
commands_.clear();
sortedIndices_.clear();
}
// ========================================
// CommandBatcher 实现
// ========================================
void CommandBatcher::process(const CommandSorter &sorter) {
clear();
sorter_ = &sorter;
if (sorter.getCount() == 0) {
return;
}
CommandBatch currentBatch;
currentBatch.startIndex = 0;
currentBatch.count = 1;
const auto &firstCmd = sorter.getCommand(0);
currentBatch.pipeline = firstCmd.pipeline;
currentBatch.textureCount = firstCmd.textureCount;
for (uint32_t i = 0; i < firstCmd.textureCount; ++i) {
currentBatch.textures[i] = firstCmd.textures[i];
}
// 遍历所有命令,合并兼容的命令
for (uint32_t i = 1; i < sorter.getCount(); ++i) {
const auto &cmd = sorter.getCommand(i);
if (currentBatch.isCompatibleWith(cmd)) {
// 兼容,加入当前批次
currentBatch.count++;
} else {
// 不兼容,保存当前批次并创建新批次
batches_.push_back(currentBatch);
currentBatch.startIndex = i;
currentBatch.count = 1;
currentBatch.pipeline = cmd.pipeline;
currentBatch.textureCount = cmd.textureCount;
for (uint32_t j = 0; j < cmd.textureCount; ++j) {
currentBatch.textures[j] = cmd.textures[j];
}
}
}
// 保存最后一个批次
batches_.push_back(currentBatch);
}
const DrawCommand &CommandBatcher::getCommand(uint32_t batchIndex,
uint32_t cmdIndex) const {
const auto &batch = batches_[batchIndex];
return sorter_->getCommand(batch.startIndex + cmdIndex);
}
void CommandBatcher::clear() {
batches_.clear();
sorter_ = nullptr;
}
// ========================================
// CommandQueue 实现
// ========================================
CommandQueue::CommandQueue() = default;
CommandQueue::~CommandQueue() { shutdown(); }
CommandQueue::CommandQueue(CommandQueue &&other) noexcept
: sorter_(std::move(other.sorter_)), batcher_(std::move(other.batcher_)),
context_(other.context_), commandList_(std::move(other.commandList_)),
globalUBOData_(other.globalUBOData_),
materialUBOData_(std::move(other.materialUBOData_)),
nextMaterialId_(other.nextMaterialId_),
materialIds_(std::move(other.materialIds_)) {
other.context_ = nullptr;
other.globalUBOData_ = {};
other.nextMaterialId_ = 1;
}
CommandQueue &CommandQueue::operator=(CommandQueue &&other) noexcept {
if (this != &other) {
shutdown();
sorter_ = std::move(other.sorter_);
batcher_ = std::move(other.batcher_);
context_ = other.context_;
commandList_ = std::move(other.commandList_);
globalUBOData_ = other.globalUBOData_;
materialUBOData_ = std::move(other.materialUBOData_);
nextMaterialId_ = other.nextMaterialId_;
materialIds_ = std::move(other.materialIds_);
other.context_ = nullptr;
other.globalUBOData_ = {};
other.nextMaterialId_ = 1;
}
return *this;
}
bool CommandQueue::initialize() {
// 获取 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;
}
context_ = rhiModule->getContext();
if (!context_) {
E2D_LOG_ERROR("RHIContext not available");
return false;
}
// 创建命令列表
commandList_ = device->createCommandList();
if (!commandList_) {
E2D_LOG_ERROR("Failed to create command list");
return false;
}
// 预分配材质 UBO 数据缓冲区
materialUBOData_.reserve(1024 * 1024); // 1MB
E2D_LOG_INFO("CommandQueue initialized");
return true;
}
void CommandQueue::shutdown() {
commandList_.reset();
context_ = nullptr;
materialUBOData_.clear();
E2D_LOG_INFO("CommandQueue shutdown");
}
void CommandQueue::beginFrame() {
sorter_.clear();
batcher_.clear();
materialIds_.clear();
nextMaterialId_ = 1;
materialUBOData_.clear();
// 开始录制命令
if (commandList_) {
commandList_->begin();
}
}
void CommandQueue::endFrame() {
// 结束录制
if (commandList_) {
commandList_->end();
}
}
uint32_t CommandQueue::getMaterialId(Material *material) {
auto it = materialIds_.find(material);
if (it != materialIds_.end()) {
return it->second;
}
uint32_t id = nextMaterialId_++;
materialIds_[material] = id;
return id;
}
void CommandQueue::submitDraw(Ptr<Material> material, Ptr<Mesh> mesh,
const struct Transform &transform,
const Color &color) {
if (!material || !mesh || !material->getShader()) {
return;
}
DrawCommand cmd;
// 构建排序键
uint32_t materialId = getMaterialId(material.get());
cmd.key = DrawKey::make(materialId, 0, 0);
// 设置管线
cmd.pipeline = material->getPipeline();
// 设置网格数据
cmd.vertexBuffer = mesh->getVertexBuffer();
cmd.indexBuffer = mesh->getIndexBuffer();
cmd.vertexCount = mesh->getVertexCount();
cmd.indexCount = mesh->getIndexCount();
// 设置变换和颜色
float matrixData[16];
transform.toMatrix(matrixData);
cmd.modelMatrix = glm::make_mat4(matrixData);
cmd.color = color;
// 设置纹理
const auto &textures = material->getTextures();
cmd.textureCount =
static_cast<uint32_t>(std::min(textures.size(), size_t(8)));
for (uint32_t i = 0; i < cmd.textureCount; ++i) {
if (textures[i].texture) {
cmd.textures[i] = textures[i].texture->getHandle();
}
}
// 分配材质 UBO 数据
uint32_t materialDataSize = material->getDataSize();
if (materialDataSize > 0) {
uint32_t uboOffset = static_cast<uint32_t>(materialUBOData_.size());
materialUBOData_.resize(uboOffset + materialDataSize);
std::memcpy(materialUBOData_.data() + uboOffset, material->getData(),
materialDataSize);
cmd.materialUBOSize = materialDataSize;
// 注意:实际的 UBO 句柄需要在执行时从 UBO 管理器获取
}
sorter_.addCommand(cmd);
}
void CommandQueue::submitDrawInstanced(Ptr<Material> material, Ptr<Mesh> mesh,
uint32_t instanceCount) {
if (!material || !mesh || !material->getShader() || instanceCount == 0) {
return;
}
DrawCommand cmd;
// 构建排序键
uint32_t materialId = getMaterialId(material.get());
cmd.key = DrawKey::make(materialId, 0, 0);
// 设置管线
cmd.pipeline = material->getPipeline();
// 设置网格数据
cmd.vertexBuffer = mesh->getVertexBuffer();
cmd.indexBuffer = mesh->getIndexBuffer();
cmd.vertexCount = mesh->getVertexCount();
cmd.indexCount = mesh->getIndexCount();
cmd.instanceCount = instanceCount;
// 设置纹理
const auto &textures = material->getTextures();
cmd.textureCount =
static_cast<uint32_t>(std::min(textures.size(), size_t(8)));
for (uint32_t i = 0; i < cmd.textureCount; ++i) {
if (textures[i].texture) {
cmd.textures[i] = textures[i].texture->getHandle();
}
}
// 材质 UBO
uint32_t materialDataSize = material->getDataSize();
if (materialDataSize > 0) {
uint32_t uboOffset = static_cast<uint32_t>(materialUBOData_.size());
materialUBOData_.resize(uboOffset + materialDataSize);
std::memcpy(materialUBOData_.data() + uboOffset, material->getData(),
materialDataSize);
cmd.materialUBOSize = materialDataSize;
}
sorter_.addCommand(cmd);
}
void CommandQueue::submitClear(const Color &color, uint32_t flags) {
// 清除命令直接执行,不加入排序队列
if (!commandList_) {
return;
}
commandList_->clear(static_cast<ClearFlags>(flags), color, 1.0f, 0);
}
void CommandQueue::setViewport(int32_t x, int32_t y, int32_t width,
int32_t height) {
if (!commandList_) {
return;
}
Viewport viewport;
viewport.x = static_cast<float>(x);
viewport.y = static_cast<float>(y);
viewport.width = static_cast<float>(width);
viewport.height = static_cast<float>(height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
commandList_->setViewport(viewport);
}
void CommandQueue::execute() {
if (!commandList_) {
E2D_LOG_ERROR("CommandQueue::execute: commandList is null");
return;
}
// 排序命令
sorter_.sort();
// 批处理
batcher_.process(sorter_);
// 执行批次
for (uint32_t i = 0; i < batcher_.getBatchCount(); ++i) {
executeBatch(i, batcher_.getBatch(i));
}
// 提交命令到 GPU
commandList_->submit();
}
void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch) {
if (!commandList_) {
return;
}
// 绑定管线
if (batch.pipeline.isValid()) {
commandList_->setPipeline(batch.pipeline.get());
} else {
E2D_LOG_WARN("Batch has no valid pipeline!");
}
// 绑定纹理
if (batch.textureCount > 0) {
for (uint32_t i = 0; i < batch.textureCount; ++i) {
if (batch.textures[i].isValid()) {
commandList_->setTexture(i, batch.textures[i].get());
}
}
} else {
// 如果没有纹理,绑定默认的白色纹理
auto* rhiModule = RHIModule::get();
if (rhiModule && rhiModule->getDevice()) {
// 使用默认纹理(白色像素)
// 注意:这里应该使用 AssetsModule 的默认纹理
// 暂时跳过,因为我们需要访问 AssetsModule
}
}
// 执行批次中的所有命令
for (uint32_t i = 0; i < batch.count; ++i) {
const auto &cmd = batcher_.getCommand(batchIndex, i);
// 绑定顶点缓冲区
if (cmd.vertexBuffer.isValid()) {
commandList_->setVertexBuffer(0, cmd.vertexBuffer.get(), 0);
} else {
E2D_LOG_WARN("Draw command has no valid vertex buffer!");
}
// 绑定索引缓冲区(如果有)
if (cmd.isIndexed() && cmd.indexBuffer.isValid()) {
commandList_->setIndexBuffer(cmd.indexBuffer.get(), IndexType::UInt16, 0);
}
// 设置 shader uniform 变量
auto* glCmdList = dynamic_cast<extra2d::GLCommandList*>(commandList_.get());
if (glCmdList) {
// 设置模型矩阵
glCmdList->setUniform("uModelMatrix", cmd.modelMatrix);
// 设置颜色
glCmdList->setUniform("uColor", cmd.color);
// 设置 view projection 矩阵
Mat4 viewProj = glm::ortho(0.0f, 1280.0f, 0.0f, 720.0f, -1.0f, 1.0f);
glCmdList->setUniform("uViewProjection", viewProj);
// 设置色调颜色
glCmdList->setUniform("uTintColor", Color::White);
// 设置透明度
glCmdList->setUniform("uOpacity", 1.0f);
}
// 绘制
if (cmd.isInstanced()) {
if (cmd.isIndexed()) {
commandList_->drawIndexed(cmd.indexCount, 0, 0, cmd.instanceCount, 0);
} else {
commandList_->draw(cmd.vertexCount, 0, cmd.instanceCount, 0);
}
} else {
if (cmd.isIndexed()) {
commandList_->drawIndexed(cmd.indexCount, 0, 0, 1, 0);
} else {
commandList_->draw(cmd.vertexCount, 0, 1, 0);
}
}
}
}
} // namespace extra2d

View File

@ -117,6 +117,17 @@ void Material::setShader(Ptr<Shader> shader) {
shader_ = shader; shader_ = shader;
} }
/**
* @brief RHI 线
* @return RHI 线
*/
PipelineHandle Material::getPipeline() const {
if (shader_) {
return shader_->getPipeline();
}
return PipelineHandle{};
}
/** /**
* @brief float * @brief float
* @param name * @param name
@ -194,14 +205,14 @@ void Material::setMat4(const std::string& name, const float* value) {
/** /**
* @brief * @brief
* @param uniformName uniform * @param uniformName uniform
* @param texture * @param texture
* @param slot 0-15 * @param slot 0-15
*/ */
void Material::setTexture(const std::string& uniformName, Handle<Texture> texture, uint32_t slot) { void Material::setTexture(const std::string& uniformName, Ptr<Texture> texture, uint32_t slot) {
// 查找是否已存在相同名称的纹理 // 查找是否已存在相同名称的纹理
for (auto& texSlot : textures_) { for (auto& texSlot : textures_) {
if (texSlot.uniformName == uniformName) { if (texSlot.uniformName == uniformName) {
texSlot.handle = texture; texSlot.texture = texture;
texSlot.slot = slot; texSlot.slot = slot;
return; return;
} }
@ -218,31 +229,4 @@ void Material::clearTextures() {
textures_.clear(); textures_.clear();
} }
/**
* @brief
*
* UBO
* @param uboManager UBO
*/
void Material::apply(UniformBufferManager& uboManager) {
if (!shader_) return;
// 绑定着色器
shader_->bind();
// 设置 Uniform Block 绑定
shader_->setUniformBlock("GlobalUBO", GLOBAL_UBO_BINDING);
shader_->setUniformBlock("MaterialUBO", MATERIAL_UBO_BINDING);
shader_->setUniformBlock("InstanceUBO", INSTANCE_UBO_BINDING);
// 上传材质数据到 UBO
if (!data_.empty()) {
auto* ubo = uboManager.acquireMaterialUBO(static_cast<uint32_t>(data_.size()));
if (ubo) {
ubo->update(data_.data(), static_cast<uint32_t>(data_.size()));
ubo->bind(MATERIAL_UBO_BINDING);
}
}
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,147 +1,140 @@
#include <renderer/mesh.h> #include <renderer/mesh.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h> #include <utils/logger.h>
#include <glad/glad.h>
namespace extra2d { namespace extra2d {
Mesh::Mesh() = default; Mesh::Mesh() = default;
Mesh::~Mesh() { Mesh::~Mesh() {
if (vao_ != 0) { // BufferHandle 是轻量级句柄,不需要显式释放
glDeleteVertexArrays(1, &vao_); // 实际的缓冲区资源由 RHI 设备管理
vao_ = 0; vertexBuffer_ = BufferHandle();
} indexBuffer_ = BufferHandle();
if (vbo_ != 0) {
glDeleteBuffers(1, &vbo_);
vbo_ = 0;
}
if (ibo_ != 0) {
glDeleteBuffers(1, &ibo_);
ibo_ = 0;
}
} }
void Mesh::setVertices(const Vertex *vertices, uint32_t count) { void Mesh::setVertices(const Vertex *vertices, uint32_t count) {
if (vao_ == 0) { if (!vertices || count == 0)
glGenVertexArrays(1, &vao_); return;
glGenBuffers(1, &vbo_);
E2D_LOG_INFO("Created VAO: {}, VBO: {}", vao_, vbo_); // 获取 RHI 模块
auto *rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return;
} }
glBindVertexArray(vao_); auto *device = rhiModule->getDevice();
glBindBuffer(GL_ARRAY_BUFFER, vbo_); if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return;
}
// 如果容量不足,重新分配 uint32_t dataSize = count * sizeof(Vertex);
if (count > vertexCapacity_) {
glBufferData(GL_ARRAY_BUFFER, count * sizeof(Vertex), vertices, GL_DYNAMIC_DRAW); // 如果缓冲区已存在且容量足够,更新数据
vertexCapacity_ = count; if (vertexBuffer_.isValid() && vertexCapacity_ >= count) {
// 通过句柄获取缓冲区指针并更新数据
// 注意:这里假设可以通过某种方式获取缓冲区指针
// 实际实现可能需要通过 RHI 命令列表来更新
E2D_LOG_WARN("Vertex buffer update not implemented yet");
} else { } else {
glBufferSubData(GL_ARRAY_BUFFER, 0, count * sizeof(Vertex), vertices); // 需要创建新缓冲区
vertexBuffer_ = BufferHandle();
// 创建顶点缓冲区描述
BufferDesc desc = BufferDesc::vertex(dataSize, BufferUsage::Dynamic);
desc.initialData = vertices;
// 创建缓冲区
auto buffer = device->createBuffer(desc);
if (!buffer) {
E2D_LOG_ERROR("Failed to create vertex buffer");
return;
} }
// 设置顶点属性 // 获取缓冲区的句柄
// 位置 (location = 0) // 注意createBuffer 返回的是 unique_ptr我们需要存储句柄
glEnableVertexAttribArray(0); // 这里直接使用缓冲区指针作为句柄,然后释放所有权让 RHI 内部管理
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), vertexBuffer_ = BufferHandle(buffer.release());
reinterpret_cast<void*>(offsetof(Vertex, position)));
// 纹理坐标 (location = 1) vertexCapacity_ = count;
glEnableVertexAttribArray(1); }
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, texCoord)));
// 颜色 (location = 2)
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(offsetof(Vertex, color)));
glBindVertexArray(0);
vertexCount_ = count; vertexCount_ = count;
E2D_LOG_INFO("Set {} vertices", count);
E2D_LOG_INFO("Set {} vertices for VAO {}", count, vao_);
} }
void Mesh::setIndices(const uint16_t *indices, uint32_t count) { void Mesh::setIndices(const uint16_t *indices, uint32_t count) {
if (vao_ == 0) return; if (!indices || count == 0)
return;
if (ibo_ == 0) { // 获取 RHI 模块
glGenBuffers(1, &ibo_); auto *rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return;
} }
glBindVertexArray(vao_); auto *device = rhiModule->getDevice();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_); if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return;
}
uint32_t dataSize = count * sizeof(uint16_t);
// 如果缓冲区已存在且容量足够,更新数据
if (indexBuffer_.isValid() && indexCapacity_ >= count) {
E2D_LOG_WARN("Index buffer update not implemented yet");
} else {
// 需要创建新缓冲区
indexBuffer_ = BufferHandle();
// 创建索引缓冲区描述
BufferDesc desc = BufferDesc::index(dataSize, BufferUsage::Static);
desc.initialData = indices;
// 创建缓冲区
auto buffer = device->createBuffer(desc);
if (!buffer) {
E2D_LOG_ERROR("Failed to create index buffer");
return;
}
// 获取缓冲区的句柄
indexBuffer_ = BufferHandle(buffer.release());
// 如果容量不足,重新分配
if (count > indexCapacity_) {
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint16_t), indices, GL_STATIC_DRAW);
indexCapacity_ = count; indexCapacity_ = count;
} else {
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, count * sizeof(uint16_t), indices);
} }
glBindVertexArray(0);
indexCount_ = count; indexCount_ = count;
E2D_LOG_INFO("Set {} indices", count);
} }
void Mesh::updateVertices(const Vertex* vertices, uint32_t count, uint32_t offset) { void Mesh::updateVertices(const Vertex *vertices, uint32_t count,
if (vao_ == 0 || vbo_ == 0 || vertices == nullptr) return; uint32_t offset) {
if (!vertices || count == 0 || !vertexBuffer_.isValid())
return;
glBindBuffer(GL_ARRAY_BUFFER, vbo_); if (offset + count > vertexCount_) {
glBufferSubData(GL_ARRAY_BUFFER, offset * sizeof(Vertex), E2D_LOG_WARN("Vertex update out of bounds");
count * sizeof(Vertex), vertices); return;
glBindBuffer(GL_ARRAY_BUFFER, 0);
} }
void Mesh::bind() const { // 获取 RHI 模块
if (vao_ != 0) { auto *rhiModule = RHIModule::get();
glBindVertexArray(vao_); if (!rhiModule)
} return;
}
void Mesh::unbind() const { auto *device = rhiModule->getDevice();
glBindVertexArray(0); if (!device)
} return;
void Mesh::draw() const { // 通过句柄获取缓冲区并更新数据
if (vao_ == 0) return; // 注意:这里需要 RHI 提供更新缓冲区的方法
// 暂时记录为未实现
// 检查 OpenGL 错误 E2D_LOG_WARN("updateVertices not fully implemented yet");
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
static bool loggedOnce = false;
if (!loggedOnce) {
E2D_LOG_ERROR("OpenGL error before draw: {}", err);
loggedOnce = true;
}
}
if (indexCount_ > 0) {
glDrawElements(GL_TRIANGLES, indexCount_, GL_UNSIGNED_SHORT, nullptr);
} else {
glDrawArrays(GL_TRIANGLES, 0, vertexCount_);
}
// 检查绘制后的错误
err = glGetError();
if (err != GL_NO_ERROR) {
static bool loggedOnce2 = false;
if (!loggedOnce2) {
E2D_LOG_ERROR("OpenGL error after draw: {}", err);
loggedOnce2 = true;
}
}
}
void Mesh::drawInstanced(uint32_t instanceCount) const {
if (vao_ == 0) return;
if (indexCount_ > 0) {
glDrawElementsInstanced(GL_TRIANGLES, indexCount_, GL_UNSIGNED_SHORT,
nullptr, instanceCount);
} else {
glDrawArraysInstanced(GL_TRIANGLES, 0, vertexCount_, instanceCount);
}
} }
Ptr<Mesh> Mesh::createQuad(const Vec2 &size, const Rect &uv) { Ptr<Mesh> Mesh::createQuad(const Vec2 &size, const Rect &uv) {
@ -152,7 +145,8 @@ Ptr<Mesh> Mesh::createQuad(const Vec2& size, const Rect& uv) {
Vertex vertices[4] = { Vertex vertices[4] = {
{Vec2(-halfW, -halfH), Vec2(uv.x, uv.y + uv.h), Color::White}, // 左下 {Vec2(-halfW, -halfH), Vec2(uv.x, uv.y + uv.h), Color::White}, // 左下
{Vec2( halfW, -halfH), Vec2(uv.x + uv.w, uv.y + uv.h), Color::White}, // 右下 {Vec2(halfW, -halfH), Vec2(uv.x + uv.w, uv.y + uv.h),
Color::White}, // 右下
{Vec2(halfW, halfH), Vec2(uv.x + uv.w, uv.y), Color::White}, // 右上 {Vec2(halfW, halfH), Vec2(uv.x + uv.w, uv.y), Color::White}, // 右上
{Vec2(-halfW, halfH), Vec2(uv.x, uv.y), Color::White} // 左上 {Vec2(-halfW, halfH), Vec2(uv.x, uv.y), Color::White} // 左上
}; };

View File

@ -0,0 +1,334 @@
#include <renderer/render_graph.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h>
namespace extra2d {
// ========================================
// RenderPassContext 实现
// ========================================
TextureHandle
RenderPassContext::getTexture(RenderGraphResourceHandle handle) const {
if (graph) {
return graph->getTexture(handle);
}
return TextureHandle{};
}
// ========================================
// RenderGraphBuilder 实现
// ========================================
RenderGraphResourceHandle
RenderGraphBuilder::createTexture(const RenderGraphTextureDesc &desc) {
// 实际的资源创建由 RenderGraph 管理
// 这里只记录描述,返回临时句柄
textureDescs_.push_back(desc);
RenderGraphResourceHandle handle;
handle.index = static_cast<uint32_t>(textureDescs_.size()) - 1;
handle.type = RenderGraphResourceType::Texture;
return handle;
}
void RenderGraphBuilder::readResource(RenderGraphResourceHandle handle) {
// 记录资源读取依赖
// 用于后续的依赖分析和资源生命周期管理
}
void RenderGraphBuilder::writeResource(RenderGraphResourceHandle handle) {
// 记录资源写入依赖
}
void RenderGraphBuilder::setRenderTarget(
const RenderGraphRenderTargetDesc &desc) {
// 设置渲染目标
}
// ========================================
// RenderGraph 实现
// ========================================
RenderGraph::RenderGraph() = default;
RenderGraph::~RenderGraph() { shutdown(); }
RenderGraph::RenderGraph(RenderGraph &&other) noexcept
: passes_(std::move(other.passes_)),
executionOrder_(std::move(other.executionOrder_)),
textures_(std::move(other.textures_)),
nextResourceId_(other.nextResourceId_),
builder_(std::move(other.builder_)),
commandQueue_(std::move(other.commandQueue_)),
outputWidth_(other.outputWidth_), outputHeight_(other.outputHeight_),
frameIndex_(other.frameIndex_), compiled_(other.compiled_) {
other.nextResourceId_ = 1;
other.outputWidth_ = 1280;
other.outputHeight_ = 720;
other.frameIndex_ = 0;
other.compiled_ = false;
}
RenderGraph &RenderGraph::operator=(RenderGraph &&other) noexcept {
if (this != &other) {
shutdown();
passes_ = std::move(other.passes_);
executionOrder_ = std::move(other.executionOrder_);
textures_ = std::move(other.textures_);
nextResourceId_ = other.nextResourceId_;
builder_ = std::move(other.builder_);
commandQueue_ = std::move(other.commandQueue_);
outputWidth_ = other.outputWidth_;
outputHeight_ = other.outputHeight_;
frameIndex_ = other.frameIndex_;
compiled_ = other.compiled_;
other.nextResourceId_ = 1;
other.outputWidth_ = 1280;
other.outputHeight_ = 720;
other.frameIndex_ = 0;
other.compiled_ = false;
}
return *this;
}
bool RenderGraph::initialize() {
if (!commandQueue_.initialize()) {
E2D_LOG_ERROR("Failed to initialize CommandQueue");
return false;
}
E2D_LOG_INFO("RenderGraph initialized");
return true;
}
void RenderGraph::shutdown() {
destroyResources();
passes_.clear();
executionOrder_.clear();
commandQueue_.shutdown();
compiled_ = false;
E2D_LOG_INFO("RenderGraph shutdown");
}
RenderPass *RenderGraph::addPass(std::unique_ptr<RenderPass> pass) {
if (!pass)
return nullptr;
RenderPass *ptr = pass.get();
passes_.push_back(std::move(pass));
compiled_ = false; // 添加新通道需要重新编译
return ptr;
}
RenderPass *RenderGraph::addLambdaPass(
const std::string &name,
std::function<void(const RenderPassContext &)> executeFunc) {
// 创建一个简单的 lambda 渲染通道
class LambdaRenderPass : public RenderPass {
public:
std::string name;
std::function<void(const RenderPassContext &)> func;
LambdaRenderPass(const std::string &n,
std::function<void(const RenderPassContext &)> f)
: name(n), func(f) {}
const char *getName() const override { return name.c_str(); }
void execute(const RenderPassContext &ctx) override {
if (func) {
func(ctx);
}
}
};
return addPass(std::make_unique<LambdaRenderPass>(name, executeFunc));
}
bool RenderGraph::compile() {
if (compiled_)
return true;
// 清空之前的编译结果
executionOrder_.clear();
// 简单的编译策略:按添加顺序执行
// 实际实现中应该进行依赖分析和拓扑排序
for (auto &pass : passes_) {
if (pass->isEnabled()) {
executionOrder_.push_back(pass.get());
}
}
// 声明资源
for (auto *pass : executionOrder_) {
builder_.setCurrentPass(pass);
pass->declareResources(builder_);
}
// 创建资源
createResources();
compiled_ = true;
E2D_LOG_INFO("RenderGraph compiled with {} passes", executionOrder_.size());
return true;
}
void RenderGraph::execute(float deltaTime) {
if (!compiled_) {
if (!compile()) {
E2D_LOG_ERROR("Failed to compile RenderGraph");
return;
}
}
// 注意beginFrame 现在由 RendererModule::onRenderBegin 调用
// 这里不再调用,以避免清空已经提交的渲染命令
// 获取 RHI 上下文
auto *rhiModule = RHIModule::get();
RHIContext *context = nullptr;
if (rhiModule && rhiModule->getDevice()) {
context = rhiModule->getDevice()->getContext();
}
// 创建执行上下文
RenderPassContext ctx;
ctx.context = context;
ctx.commandQueue = &commandQueue_;
ctx.graph = this;
ctx.deltaTime = deltaTime;
ctx.frameIndex = frameIndex_;
// 执行所有通道
for (auto *pass : executionOrder_) {
if (pass->isEnabled()) {
pass->execute(ctx);
}
}
// 执行命令队列
// 执行命令队列
commandQueue_.execute();
// 结束帧
commandQueue_.endFrame();
// 调用 RHI 上下文的 endFrame 进行缓冲区交换
if (context) {
context->endFrame();
}
frameIndex_++;
}
TextureHandle RenderGraph::getTexture(RenderGraphResourceHandle handle) const {
auto it = textures_.find(handle.index);
if (it != textures_.end()) {
return it->second;
}
return TextureHandle{};
}
void RenderGraph::setOutputSize(uint32_t width, uint32_t height) {
outputWidth_ = width;
outputHeight_ = height;
}
void RenderGraph::createResources() {
auto *rhiModule = RHIModule::get();
if (!rhiModule || !rhiModule->getDevice())
return;
auto *device = rhiModule->getDevice();
// 创建渲染图内部资源
// 这里可以根据需要创建默认的后缓冲等
}
void RenderGraph::destroyResources() {
// 释放所有渲染图管理的资源
textures_.clear();
}
// ========================================
// GeometryRenderPass 实现
// ========================================
GeometryRenderPass::GeometryRenderPass(const std::string &name) : name_(name) {}
void GeometryRenderPass::declareResources(RenderGraphBuilder &builder) {
// 声明几何渲染通道的资源依赖
if (colorTarget_.isValid()) {
builder.writeResource(colorTarget_);
}
if (depthTarget_.isValid()) {
builder.writeResource(depthTarget_);
}
}
void GeometryRenderPass::execute(const RenderPassContext &ctx) {
// 几何渲染通道的执行逻辑
// 通常由外部的渲染系统填充具体的绘制命令
if (!ctx.commandQueue)
return;
// 清除颜色缓冲区
ctx.commandQueue->submitClear(Color::Black, CLEAR_COLOR_FLAG);
// 设置视口
if (ctx.graph) {
ctx.commandQueue->setViewport(
0, 0, static_cast<int32_t>(ctx.graph->getOutputWidth()),
static_cast<int32_t>(ctx.graph->getOutputHeight()));
}
}
// ========================================
// PostProcessRenderPass 实现
// ========================================
PostProcessRenderPass::PostProcessRenderPass(const std::string &name)
: name_(name) {}
void PostProcessRenderPass::declareResources(RenderGraphBuilder &builder) {
// 声明后期处理通道的资源依赖
if (inputTexture_.isValid()) {
builder.readResource(inputTexture_);
}
if (outputTarget_.isValid()) {
builder.writeResource(outputTarget_);
}
}
void PostProcessRenderPass::execute(const RenderPassContext &ctx) {
// 后期处理通道的执行逻辑
// 这里可以实现全屏四边形绘制等后期处理效果
if (!ctx.context || !ctx.commandQueue)
return;
// 获取命令列表
RHICommandList *cmdList = ctx.commandQueue->getCommandList();
if (!cmdList)
return;
// 绑定输入纹理
if (inputTexture_.isValid()) {
TextureHandle tex = ctx.getTexture(inputTexture_);
if (tex.isValid()) {
cmdList->setTexture(0, tex.get());
}
}
// 后期处理的具体实现由子类或外部提供
}
} // namespace extra2d

View File

@ -1,82 +1,20 @@
#include "glad/glad.h"
#include <algorithm>
#include <assets/assets_module.h> #include <assets/assets_module.h>
#include <event/events.h> #include <platform/window_module.h>
#include <glm/gtc/type_ptr.hpp> #include <renderer/render_graph.h>
#include <renderer/renderer_module.h> #include <renderer/renderer_module.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h> #include <utils/logger.h>
#include <SDL.h>
namespace extra2d { namespace extra2d {
RendererModule::RendererModule() = default; RendererModule::RendererModule() = default;
RendererModule::~RendererModule() = default; RendererModule::~RendererModule() = default;
RendererModule::RendererModule(RendererModule &&other) noexcept
: commandBuffer_(std::move(other.commandBuffer_)),
commandCount_(other.commandCount_),
uniformManager_(std::move(other.uniformManager_)),
onRenderBeginListener_(std::move(other.onRenderBeginListener_)),
onRenderSubmitListener_(std::move(other.onRenderSubmitListener_)),
onRenderSetCameraListener_(std::move(other.onRenderSetCameraListener_)),
onRenderEndListener_(std::move(other.onRenderEndListener_)),
onResizeListener_(std::move(other.onResizeListener_)),
onShowListener_(std::move(other.onShowListener_)),
glInitialized_(other.glInitialized_), stats_(other.stats_),
viewportX_(other.viewportX_), viewportY_(other.viewportY_),
viewportWidth_(other.viewportWidth_),
viewportHeight_(other.viewportHeight_),
viewportAdapter_(std::move(other.viewportAdapter_)),
viewProjectionMatrix_(std::move(other.viewProjectionMatrix_)) {
other.commandCount_ = 0;
other.glInitialized_ = false;
other.stats_ = {};
other.viewportX_ = 0;
other.viewportY_ = 0;
other.viewportWidth_ = 0;
other.viewportHeight_ = 0;
}
RendererModule &RendererModule::operator=(RendererModule &&other) noexcept {
if (this != &other) {
if (glInitialized_) {
uniformManager_.shutdown();
}
commandBuffer_ = std::move(other.commandBuffer_);
commandCount_ = other.commandCount_;
uniformManager_ = std::move(other.uniformManager_);
onRenderBeginListener_ = std::move(other.onRenderBeginListener_);
onRenderSubmitListener_ = std::move(other.onRenderSubmitListener_);
onRenderSetCameraListener_ = std::move(other.onRenderSetCameraListener_);
onRenderEndListener_ = std::move(other.onRenderEndListener_);
onResizeListener_ = std::move(other.onResizeListener_);
onShowListener_ = std::move(other.onShowListener_);
glInitialized_ = other.glInitialized_;
stats_ = other.stats_;
viewportX_ = other.viewportX_;
viewportY_ = other.viewportY_;
viewportWidth_ = other.viewportWidth_;
viewportHeight_ = other.viewportHeight_;
viewportAdapter_ = std::move(other.viewportAdapter_);
viewProjectionMatrix_ = std::move(other.viewProjectionMatrix_);
other.commandCount_ = 0;
other.glInitialized_ = false;
other.stats_ = {};
other.viewportX_ = 0;
other.viewportY_ = 0;
other.viewportWidth_ = 0;
other.viewportHeight_ = 0;
}
return *this;
}
bool RendererModule::init() { bool RendererModule::init() {
E2D_LOG_INFO("Initializing RendererModule..."); E2D_LOG_INFO("Initializing RendererModule...");
// 绑定事件监听器
onRenderBeginListener_.bind([this]() { onRenderBegin(); }); onRenderBeginListener_.bind([this]() { onRenderBegin(); });
onRenderSubmitListener_.bind( onRenderSubmitListener_.bind(
[this](const RenderCommand &cmd) { onRenderSubmit(cmd); }); [this](const RenderCommand &cmd) { onRenderSubmit(cmd); });
@ -84,69 +22,92 @@ bool RendererModule::init() {
[this](const Mat4 &viewProj) { onRenderSetCamera(viewProj); }); [this](const Mat4 &viewProj) { onRenderSetCamera(viewProj); });
onRenderEndListener_.bind([this]() { onRenderEnd(); }); onRenderEndListener_.bind([this]() { onRenderEnd(); });
onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); }); onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); });
onShowListener_.bind([this]() { onWindowShow(); }); onShowListener_.bind([this]() { onWindowShow(); });
E2D_LOG_INFO("RendererModule initialized (waiting for GL context)"); E2D_LOG_INFO("RendererModule initialized (waiting for window show)");
return true; return true;
} }
void RendererModule::onWindowShow() { void RendererModule::onWindowShow() {
if (glInitialized_) { if (initialized_) {
return; return;
} }
E2D_LOG_INFO("Initializing OpenGL context..."); E2D_LOG_INFO("Initializing RendererModule context...");
if (!uniformManager_.initialize()) { // 初始化 RHI 模块
E2D_LOG_ERROR("Failed to initialize UniformBufferManager"); auto *rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return; return;
} }
int windowWidth = 800, windowHeight = 600; if (!rhiModule->getDevice()) {
SDL_Window *sdlWindow = SDL_GL_GetCurrentWindow(); // RHI 设备尚未初始化,这是正常的时序问题
if (sdlWindow) { // RHIModule 会在窗口显示后初始化设备,然后再次触发此函数
SDL_GetWindowSize(sdlWindow, &windowWidth, &windowHeight); E2D_LOG_INFO("RHIDevice not ready yet, waiting for RHI initialization...");
E2D_LOG_INFO("Setting initial viewport to window size: {}x{}", windowWidth, return;
windowHeight);
} else {
E2D_LOG_WARN("Could not get SDL window, using default viewport 800x600");
} }
setViewport(0, 0, static_cast<int32>(windowWidth),
static_cast<int32>(windowHeight));
glEnable(GL_BLEND); // 初始化渲染图
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (!renderGraph_.initialize()) {
E2D_LOG_ERROR("Failed to initialize RenderGraph");
return;
}
glInitialized_ = true; commandQueue_ = renderGraph_.getCommandQueue();
E2D_LOG_INFO("OpenGL context initialized successfully");
// 添加默认的几何渲染通道
auto geometryPass = std::make_unique<GeometryRenderPass>("Geometry");
renderGraph_.addPass(std::move(geometryPass));
E2D_LOG_INFO("Added default geometry render pass");
auto windowModule = getModule<WindowModule>();
if (!windowModule) {
E2D_LOG_ERROR("WindowModule not available");
return;
}
setViewport(0, 0, static_cast<int32>(windowModule->getSize().w),
static_cast<int32>(windowModule->getSize().h));
initialized_ = true;
E2D_LOG_INFO("RendererModule context initialized successfully");
} }
void RendererModule::shutdown() { void RendererModule::shutdown() {
E2D_LOG_INFO("Shutting down RendererModule..."); E2D_LOG_INFO("Shutting down RendererModule...");
if (glInitialized_) { renderGraph_.shutdown();
uniformManager_.shutdown(); commandQueue_ = nullptr;
} initialized_ = false;
glInitialized_ = false; // 注意:事件监听器是值类型,会在析构时自动清理
E2D_LOG_INFO("RendererModule shutdown complete"); E2D_LOG_INFO("RendererModule shutdown complete");
} }
MaterialHandle RendererModule::getDefaultMaterialHandle() const { RHIContext *RendererModule::getRHIContext() const {
auto* assets = getAssets(); auto *rhiModule = RHIModule::get();
return assets ? assets->getDefaultMaterial() : MaterialHandle::invalid(); if (rhiModule && rhiModule->getDevice()) {
return rhiModule->getDevice()->getContext();
}
return nullptr;
} }
MeshHandle RendererModule::getDefaultQuadHandle() const { Handle<Material> RendererModule::getDefaultMaterialHandle() const {
auto *assets = getAssets(); auto *assets = getAssets();
return assets ? assets->getDefaultQuad() : MeshHandle::invalid(); return assets ? assets->getDefaultMaterial() : Handle<Material>::invalid();
} }
TextureHandle RendererModule::getDefaultTextureHandle() const { Handle<Mesh> RendererModule::getDefaultQuadHandle() const {
auto *assets = getAssets(); auto *assets = getAssets();
return assets ? assets->getDefaultTexture() : TextureHandle::invalid(); return assets ? assets->getDefaultQuad() : Handle<Mesh>::invalid();
}
Handle<Texture> RendererModule::getDefaultTextureHandle() const {
auto *assets = getAssets();
return assets ? assets->getDefaultTexture() : Handle<Texture>::invalid();
} }
void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) { void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) {
@ -157,216 +118,157 @@ void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) {
viewportAdapter_.update(width, height); viewportAdapter_.update(width, height);
// 更新渲染图输出尺寸
renderGraph_.setOutputSize(static_cast<uint32_t>(width),
static_cast<uint32_t>(height));
// 通过 RHI 设置视口
if (initialized_) {
auto *context = getRHIContext();
if (context) {
auto result = viewportAdapter_.getResult(); auto result = viewportAdapter_.getResult();
glViewport(static_cast<GLint>(result.viewport.x), context->setViewport(static_cast<int32_t>(result.viewport.x),
static_cast<GLint>(result.viewport.y), static_cast<int32_t>(result.viewport.y),
static_cast<GLsizei>(result.viewport.w), static_cast<uint32_t>(result.viewport.w),
static_cast<GLsizei>(result.viewport.h)); static_cast<uint32_t>(result.viewport.h));
}
}
} }
void RendererModule::clear(const Color &color, uint32 flags) { void RendererModule::clear(const Color &color, uint32 flags) {
GLbitfield mask = 0; if (!initialized_)
return;
if (flags & CLEAR_COLOR_FLAG) { if (commandQueue_) {
glClearColor(color.r, color.g, color.b, color.a); commandQueue_->submitClear(color, flags);
mask |= GL_COLOR_BUFFER_BIT;
}
if (flags & CLEAR_DEPTH_FLAG) {
mask |= GL_DEPTH_BUFFER_BIT;
}
if (flags & CLEAR_STENCIL_FLAG) {
mask |= GL_STENCIL_BUFFER_BIT;
}
if (mask != 0) {
glClear(mask);
} }
} }
void RendererModule::onRenderBegin() { void RendererModule::onRenderBegin() {
if (!glInitialized_) { if (!initialized_) {
return; return;
} }
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 重置统计
glClear(GL_COLOR_BUFFER_BIT);
commandCount_ = 0;
stats_ = {}; stats_ = {};
uniformManager_.resetMaterialUBOs(); // 开始渲染帧 - 清空命令队列准备接收新的渲染命令
if (commandQueue_) {
commandQueue_->beginFrame();
}
// 帧开始
} }
void RendererModule::onRenderSubmit(const RenderCommand &cmd) { void RendererModule::onRenderSubmit(const RenderCommand &cmd) {
if (!glInitialized_) { if (!initialized_ || !commandQueue_) {
E2D_LOG_WARN(
"onRenderSubmit: RendererModule not initialized or no command queue");
return; return;
} }
if (commandCount_ >= MAX_RENDER_COMMANDS) { (void)cmd; // 避免未使用警告
E2D_LOG_WARN("Render command buffer full!");
// 将渲染命令转换为绘制命令提交到队列
switch (cmd.type) {
case RenderCommandType::DrawMesh: {
auto *assets = getAssets();
if (!assets)
return; return;
// 获取材质,如果没有指定则使用默认材质
Material *material = assets->get(cmd.drawMesh.material);
if (!material) {
material = assets->get(assets->getDefaultMaterial());
} }
commandBuffer_[commandCount_++] = cmd; // 获取网格,如果没有指定则使用默认四边形
Mesh *mesh = assets->get(cmd.drawMesh.mesh);
if (!mesh) {
mesh = assets->get(assets->getDefaultQuad());
}
if (material && mesh) {
Transform transform(cmd.drawMesh.pos, cmd.drawMesh.scale,
cmd.drawMesh.rot);
commandQueue_->submitDraw(Ptr<Material>(material), Ptr<Mesh>(mesh),
transform, cmd.drawMesh.color);
stats_.commandsSubmitted++; stats_.commandsSubmitted++;
} else {
E2D_LOG_WARN("Failed to submit draw command: material={}, mesh={}",
material ? "valid" : "null", mesh ? "valid" : "null");
}
break;
}
case RenderCommandType::DrawMeshInstanced: {
auto *assets = getAssets();
if (!assets)
return;
Material *material = assets->get(cmd.drawInstanced.material);
Mesh *mesh = assets->get(cmd.drawInstanced.mesh);
if (material && mesh) {
commandQueue_->submitDrawInstanced(Ptr<Material>(material),
Ptr<Mesh>(mesh),
cmd.drawInstanced.instanceCount);
stats_.commandsSubmitted++;
}
break;
}
case RenderCommandType::SetViewport: {
setViewport(cmd.viewport.x, cmd.viewport.y, cmd.viewport.width,
cmd.viewport.height);
break;
}
case RenderCommandType::Clear: {
clear(cmd.clear.color, cmd.clear.flags);
break;
}
}
} }
void RendererModule::onRenderSetCamera(const Mat4 &viewProj) { void RendererModule::onRenderSetCamera(const Mat4 &viewProj) {
if (!glInitialized_) { if (!initialized_) {
return; return;
} }
viewProjectionMatrix_ = viewProj; viewProjectionMatrix_ = viewProj;
uniformManager_.updateGlobalUBO(&viewProj, sizeof(Mat4)); // 更新全局 UBO通过 RenderGraph 的命令队列)
// 实际的 UBO 更新会在 RenderGraph 执行时进行
} }
void RendererModule::onRenderEnd() { void RendererModule::onRenderEnd() {
if (!glInitialized_) { if (!initialized_) {
E2D_LOG_WARN("onRenderEnd: RendererModule not initialized");
return; return;
} }
sortCommands(); // 执行渲染图
batchAndDraw(); // 执行渲染图
// 这里会执行所有渲染通道并提交命令
renderGraph_.execute(0.016f); // TODO: 使用实际的 deltaTime
E2D_LOG_DEBUG("Render: {} commands, {} draw calls, {} batches", // 获取统计信息
stats_.commandsExecuted, stats_.drawCalls, stats_.batches); if (commandQueue_) {
stats_.drawCalls = commandQueue_->getCommandCount();
}
// 渲染完成
} }
void RendererModule::onResize(int32 width, int32 height) { void RendererModule::onResize(int32 width, int32 height) {
setViewport(0, 0, width, height); setViewport(0, 0, width, height);
} }
void RendererModule::sortCommands() {
std::sort(commandBuffer_.begin(), commandBuffer_.begin() + commandCount_,
[](const RenderCommand &a, const RenderCommand &b) {
return a.sortKey < b.sortKey;
});
}
void RendererModule::batchAndDraw() {
auto* assets = getAssets();
if (!assets) {
E2D_LOG_ERROR("AssetsModule not available");
return;
}
MaterialHandle lastMaterial = MaterialHandle::invalid();
MeshHandle lastMesh = MeshHandle::invalid();
uint32_t batchStart = 0;
uint32_t batchCount = 0;
for (uint32_t i = 0; i < commandCount_; ++i) {
const auto &cmd = commandBuffer_[i];
if (cmd.type != RenderCommandType::DrawMesh) {
if (batchCount > 0) {
drawBatch(batchStart, batchCount, lastMaterial, lastMesh);
stats_.batches++;
batchCount = 0;
}
executeCommand(cmd);
continue;
}
if (cmd.drawMesh.material != lastMaterial ||
cmd.drawMesh.mesh != lastMesh) {
if (batchCount > 0) {
drawBatch(batchStart, batchCount, lastMaterial, lastMesh);
stats_.batches++;
}
lastMaterial = cmd.drawMesh.material;
lastMesh = cmd.drawMesh.mesh;
batchStart = i;
batchCount = 1;
} else {
++batchCount;
}
stats_.commandsExecuted++;
}
if (batchCount > 0) {
drawBatch(batchStart, batchCount, lastMaterial, lastMesh);
stats_.batches++;
}
}
void RendererModule::drawBatch(uint32_t start, uint32_t count,
MaterialHandle materialHandle,
MeshHandle meshHandle) {
auto* assets = getAssets();
if (!assets) return;
Material* material = assets->get(materialHandle);
if (!material) {
material = assets->getDefaultMaterialPtr();
}
Mesh* mesh = assets->get(meshHandle);
if (!mesh) {
mesh = assets->getDefaultQuadPtr();
}
if (!material || !mesh)
return;
Shader* shader = material->getShader().get();
if (!shader)
return;
shader->bind();
shader->setMat4("uViewProjection", glm::value_ptr(viewProjectionMatrix_));
shader->setVec4("uTintColor", 1.0f, 1.0f, 1.0f, 1.0f);
shader->setFloat("uOpacity", 1.0f);
const auto &textureSlots = material->getTextures();
bool hasMaterialTexture = false;
for (const auto &slot : textureSlots) {
if (slot.handle.isValid()) {
Texture* texture = assets->get(slot.handle);
if (texture) {
texture->bind(slot.slot);
shader->setInt(slot.uniformName, static_cast<int>(slot.slot));
hasMaterialTexture = true;
}
}
}
if (!hasMaterialTexture) {
Texture* defaultTexture = assets->getDefaultTexturePtr();
if (defaultTexture) {
defaultTexture->bind(0);
shader->setInt("uTexture", 0);
}
}
mesh->bind();
for (uint32_t i = 0; i < count; ++i) {
Transform transform = commandBuffer_[start + i].getTransform();
float matrix[16];
transform.toMatrix(matrix);
shader->setMat4("uModelMatrix", matrix);
Color color = commandBuffer_[start + i].getColor();
shader->setVec4("uColor", color.r, color.g, color.b, color.a);
mesh->draw();
stats_.drawCalls++;
}
}
void RendererModule::executeCommand(const RenderCommand &cmd) { void RendererModule::executeCommand(const RenderCommand &cmd) {
// 此方法保留用于直接执行特定命令
// 大部分命令现在通过 RenderGraph 处理
switch (cmd.type) { switch (cmd.type) {
case RenderCommandType::SetViewport: case RenderCommandType::SetViewport:
setViewport(cmd.viewport.x, cmd.viewport.y, cmd.viewport.width, setViewport(cmd.viewport.x, cmd.viewport.y, cmd.viewport.width,

View File

@ -0,0 +1,65 @@
#include <renderer/rhi/opengl/gl_buffer.h>
#include <renderer/rhi/opengl/gl_utils.h>
namespace extra2d {
GLBuffer::GLBuffer(const BufferDesc &desc) : desc_(desc), buffer_(0) {}
GLBuffer::~GLBuffer() { destroy(); }
bool GLBuffer::create() {
glGenBuffers(1, &buffer_);
if (buffer_ == 0) {
return false;
}
GLenum target = bufferTypeToGL(desc_.type);
glBindBuffer(target, buffer_);
GLenum usage = bufferUsageToGL(desc_.usage);
glBufferData(target, desc_.size, desc_.initialData, usage);
glBindBuffer(target, 0);
return true;
}
void GLBuffer::destroy() {
if (buffer_ != 0) {
glDeleteBuffers(1, &buffer_);
buffer_ = 0;
}
}
bool GLBuffer::update(const void *data, uint32_t size, uint32_t offset) {
if (buffer_ == 0 || data == nullptr)
return false;
GLenum target = bufferTypeToGL(desc_.type);
glBindBuffer(target, buffer_);
glBufferSubData(target, offset, size, data);
glBindBuffer(target, 0);
return true;
}
void *GLBuffer::map() {
// OpenGL ES 3.2 不支持 glMapBuffer使用 glMapBufferRange
if (buffer_ == 0)
return nullptr;
GLenum target = bufferTypeToGL(desc_.type);
glBindBuffer(target, buffer_);
void *ptr = glMapBufferRange(target, 0, desc_.size, GL_MAP_WRITE_BIT);
return ptr;
}
void GLBuffer::unmap() {
if (buffer_ == 0)
return;
GLenum target = bufferTypeToGL(desc_.type);
glBindBuffer(target, buffer_);
glUnmapBuffer(target);
glBindBuffer(target, 0);
}
} // namespace extra2d

View File

@ -0,0 +1,261 @@
#include <renderer/rhi/opengl/gl_command_list.h>
#include <renderer/rhi/opengl/gl_pipeline.h>
#include <renderer/rhi/opengl/gl_buffer.h>
#include <renderer/rhi/opengl/gl_texture.h>
#include <renderer/rhi/opengl/gl_framebuffer.h>
#include <glm/gtc/type_ptr.hpp>
namespace extra2d {
GLCommandList::GLCommandList() = default;
GLCommandList::~GLCommandList() = default;
void GLCommandList::begin() {
// 开始记录命令
recording_ = true;
}
void GLCommandList::end() {
// 结束记录命令
recording_ = false;
}
void GLCommandList::submit() {
// 提交命令列表OpenGL 是立即模式,这里不需要特殊处理)
}
void GLCommandList::beginRenderPass(RHIFramebuffer *framebuffer,
ClearFlags clearFlags,
const Color &clearColor,
float clearDepth,
uint8_t clearStencil) {
if (framebuffer) {
auto *glFramebuffer = static_cast<GLFramebuffer *>(framebuffer);
glFramebuffer->bind();
currentFramebuffer_ = glFramebuffer;
} else {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
currentFramebuffer_ = nullptr;
}
// 禁用2D渲染不需要的OpenGL状态
glDisable(GL_DEPTH_TEST); // 禁用深度测试
glDisable(GL_CULL_FACE); // 禁用面剔除
glDisable(GL_STENCIL_TEST); // 禁用模板测试
// 启用混合2D渲染通常需要透明度混合
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 禁用裁剪测试(除非需要)
glDisable(GL_SCISSOR_TEST);
// 执行清除操作
if (clearFlags != ClearFlags::None) {
clear(clearFlags, clearColor, clearDepth, clearStencil);
}
}
void GLCommandList::endRenderPass() {
// 结束渲染通道
currentFramebuffer_ = nullptr;
}
void GLCommandList::setViewport(const Viewport &viewport) {
glViewport(static_cast<GLint>(viewport.x), static_cast<GLint>(viewport.y),
static_cast<GLsizei>(viewport.width),
static_cast<GLsizei>(viewport.height));
}
void GLCommandList::setScissor(const ScissorRect &scissor) {
glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
}
void GLCommandList::setPipeline(RHIPipeline *pipeline) {
if (pipeline) {
auto *glPipeline = static_cast<GLPipeline *>(pipeline);
glPipeline->bind();
currentPipeline_ = glPipeline;
// 获取 shader program
currentShaderProgram_ = glPipeline->getGLProgram();
}
}
void GLCommandList::setVertexBuffer(uint32_t slot, RHIBuffer *buffer,
uint32_t offset) {
if (buffer) {
auto *glBuffer = static_cast<GLBuffer *>(buffer);
glBindBuffer(GL_ARRAY_BUFFER, glBuffer->getGLBuffer());
currentVertexBuffer_ = glBuffer;
// 如果有当前管线,配置顶点属性
if (currentPipeline_) {
const auto &layout = currentPipeline_->getVertexLayout();
for (const auto &attr : layout.attributes) {
glEnableVertexAttribArray(attr.location);
GLenum type = GL_FLOAT;
GLint size = 1;
GLboolean normalized = GL_FALSE;
switch (attr.format) {
case VertexFormat::Float1:
size = 1;
break;
case VertexFormat::Float2:
size = 2;
break;
case VertexFormat::Float3:
size = 3;
break;
case VertexFormat::Float4:
size = 4;
break;
default:
break;
}
glVertexAttribPointer(attr.location, size, type, normalized, layout.stride,
reinterpret_cast<const void *>(attr.offset));
}
}
}
}
void GLCommandList::setIndexBuffer(RHIBuffer *buffer, IndexType type,
uint32_t offset) {
if (buffer) {
auto *glBuffer = static_cast<GLBuffer *>(buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBuffer->getGLBuffer());
currentIndexBuffer_ = glBuffer;
}
}
void GLCommandList::setUniformBuffer(uint32_t slot, RHIBuffer *buffer) {
if (buffer) {
auto *glBuffer = static_cast<GLBuffer *>(buffer);
glBindBufferBase(GL_UNIFORM_BUFFER, slot, glBuffer->getGLBuffer());
}
}
void GLCommandList::setTexture(uint32_t slot, RHITexture *texture) {
if (texture) {
auto *glTexture = static_cast<GLTexture *>(texture);
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, glTexture->getGLTexture());
}
}
void GLCommandList::setSampler(uint32_t slot, TextureFilter minFilter,
TextureFilter magFilter, TextureWrap wrapS,
TextureWrap wrapT) {
// OpenGL 的采样器状态是纹理对象的一部分
// 这里可以设置当前绑定纹理的采样参数
}
void GLCommandList::draw(uint32_t vertexCount, uint32_t firstVertex,
uint32_t instanceCount, uint32_t firstInstance) {
if (instanceCount > 1) {
glDrawArraysInstanced(GL_TRIANGLES, firstVertex, vertexCount, instanceCount);
} else {
glDrawArrays(GL_TRIANGLES, firstVertex, vertexCount);
}
}
void GLCommandList::drawIndexed(uint32_t indexCount, uint32_t firstIndex,
int32_t vertexOffset, uint32_t instanceCount,
uint32_t firstInstance) {
GLenum indexType = GL_UNSIGNED_SHORT;
if (currentIndexBuffer_) {
// 根据缓冲区类型确定索引类型
// 这里简化处理,使用 GL_UNSIGNED_SHORT
}
if (instanceCount > 1) {
glDrawElementsInstanced(
GL_TRIANGLES, indexCount, indexType,
reinterpret_cast<const void *>(firstIndex * sizeof(uint16_t)),
instanceCount);
} else {
glDrawElements(GL_TRIANGLES, indexCount, indexType,
reinterpret_cast<const void *>(firstIndex * sizeof(uint16_t)));
}
}
void GLCommandList::clear(ClearFlags flags, const Color &color, float depth,
uint8_t stencil) {
GLbitfield mask = 0;
if (hasFlag(flags, ClearFlags::Color)) {
glClearColor(color.r, color.g, color.b, color.a);
mask |= GL_COLOR_BUFFER_BIT;
}
if (hasFlag(flags, ClearFlags::Depth)) {
glClearDepthf(depth);
mask |= GL_DEPTH_BUFFER_BIT;
}
if (hasFlag(flags, ClearFlags::Stencil)) {
glClearStencil(stencil);
mask |= GL_STENCIL_BUFFER_BIT;
}
if (mask != 0) {
glClear(mask);
}
}
bool GLCommandList::isRecording() const {
return recording_;
}
void GLCommandList::setUniform(const std::string& name, float value) {
if (currentShaderProgram_ != 0) {
GLint location = glGetUniformLocation(currentShaderProgram_, name.c_str());
if (location != -1) {
glUniform1f(location, value);
}
}
}
void GLCommandList::setUniform(const std::string& name, const Vec2& value) {
if (currentShaderProgram_ != 0) {
GLint location = glGetUniformLocation(currentShaderProgram_, name.c_str());
if (location != -1) {
glUniform2f(location, value.x, value.y);
}
}
}
void GLCommandList::setUniform(const std::string& name, const Vec3& value) {
if (currentShaderProgram_ != 0) {
GLint location = glGetUniformLocation(currentShaderProgram_, name.c_str());
if (location != -1) {
glUniform3f(location, value.x, value.y, value.z);
}
}
}
void GLCommandList::setUniform(const std::string& name, const Color& value) {
if (currentShaderProgram_ != 0) {
GLint location = glGetUniformLocation(currentShaderProgram_, name.c_str());
if (location != -1) {
glUniform4f(location, value.r, value.g, value.b, value.a);
}
}
}
void GLCommandList::setUniform(const std::string& name, const Mat4& value) {
if (currentShaderProgram_ != 0) {
GLint location = glGetUniformLocation(currentShaderProgram_, name.c_str());
if (location != -1) {
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}
}
}
} // namespace extra2d

View File

@ -0,0 +1,84 @@
#include <cstring>
#include <renderer/rhi/opengl/gl_context.h>
#include <renderer/rhi/opengl/gl_framebuffer.h>
#include <utils/logger.h>
namespace extra2d {
GLContext::GLContext(GLDevice *device)
: device_(device), defaultFramebuffer_(nullptr) {}
GLContext::~GLContext() = default;
bool GLContext::initialize() {
E2D_LOG_INFO("Initializing OpenGL context...");
// 创建默认帧缓冲(窗口帧缓冲)
defaultFramebuffer_ = std::make_unique<GLFramebuffer>();
defaultFramebuffer_->setSize(800, 600); // 默认大小,会被更新
E2D_LOG_INFO("OpenGL context initialized");
return true;
}
void GLContext::shutdown() {
E2D_LOG_INFO("Shutting down OpenGL context...");
defaultFramebuffer_.reset();
E2D_LOG_INFO("OpenGL context shutdown complete");
}
void GLContext::beginFrame() {
// 重置每帧的统计
// device_->resetStats(); // 需要在 GLDevice 中添加此方法
}
void GLContext::endFrame() {
// 交换缓冲区
// 通过 SDL 获取当前窗口并交换缓冲区
SDL_Window* window = SDL_GL_GetCurrentWindow();
if (window) {
SDL_GL_SwapWindow(window);
}
}
void GLContext::setViewport(int32_t x, int32_t y, uint32_t width,
uint32_t height) {
glViewport(x, y, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
// 更新默认帧缓冲大小
if (defaultFramebuffer_) {
defaultFramebuffer_->setSize(width, height);
}
}
void GLContext::bindDefaultFramebuffer() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
RHIFramebuffer *GLContext::getDefaultFramebuffer() {
return defaultFramebuffer_.get();
}
bool GLContext::isFeatureSupported(const char *feature) const {
// 检查 OpenGL 扩展或版本
if (std::strcmp(feature, "instancing") == 0) {
return glad_glDrawArraysInstanced != nullptr;
}
if (std::strcmp(feature, "compute") == 0) {
return glad_glDispatchCompute != nullptr;
}
if (std::strcmp(feature, "sRGB") == 0) {
return GLAD_GL_EXT_texture_sRGB_R8;
}
if (std::strcmp(feature, "anisotropic") == 0) {
return GLAD_GL_EXT_texture_filter_anisotropic;
}
if (std::strcmp(feature, "debug") == 0) {
return GLAD_GL_KHR_debug;
}
return false;
}
} // namespace extra2d

View File

@ -0,0 +1,200 @@
#include <renderer/rhi/opengl/gl_buffer.h>
#include <renderer/rhi/opengl/gl_command_list.h>
#include <renderer/rhi/opengl/gl_context.h>
#include <renderer/rhi/opengl/gl_framebuffer.h>
#include <renderer/rhi/opengl/gl_pipeline.h>
#include <renderer/rhi/opengl/gl_shader.h>
#include <renderer/rhi/opengl/gl_texture.h>
#include <renderer/rhi/opengl/gl_utils.h>
#include <glad/glad.h>
#include <SDL.h>
#include <utils/logger.h>
namespace extra2d {
// 前向声明
class GLDevice;
/**
* @brief OpenGL
*/
class GLDevice : public RHIDevice {
public:
GLDevice() : window_(nullptr), glContext_(nullptr), context_(nullptr), stats_() {}
~GLDevice() override { shutdown(); }
bool initialize(void* nativeWindow) override {
E2D_LOG_INFO("Initializing OpenGL device...");
if (!nativeWindow) {
E2D_LOG_ERROR("Native window handle is null");
return false;
}
window_ = static_cast<SDL_Window*>(nativeWindow);
// 创建 OpenGL ES 3.2 上下文
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
glContext_ = SDL_GL_CreateContext(window_);
if (!glContext_) {
E2D_LOG_ERROR("Failed to create OpenGL ES context: {}", SDL_GetError());
return false;
}
// 初始化 GLAD
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress)) {
E2D_LOG_ERROR("Failed to initialize GLAD");
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
return false;
}
E2D_LOG_INFO("OpenGL ES context created: {}.{}", GLVersion.major, GLVersion.minor);
const char* version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
if (!version) {
E2D_LOG_ERROR("Failed to get OpenGL version");
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
return false;
}
E2D_LOG_INFO("OpenGL Version: {}", version);
E2D_LOG_INFO("OpenGL Vendor: {}",
reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
E2D_LOG_INFO("OpenGL Renderer: {}",
reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
// 创建上下文管理器
context_ = std::make_unique<GLContext>(this);
if (!context_->initialize()) {
E2D_LOG_ERROR("Failed to initialize GL context");
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
return false;
}
// 设置默认状态
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
E2D_LOG_INFO("OpenGL device initialized successfully");
return true;
}
void shutdown() override {
E2D_LOG_INFO("Shutting down OpenGL device...");
if (context_) {
context_->shutdown();
context_.reset();
}
if (glContext_) {
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
}
window_ = nullptr;
E2D_LOG_INFO("OpenGL device shutdown complete");
}
std::unique_ptr<RHIBuffer> createBuffer(const BufferDesc &desc) override {
auto buffer = std::make_unique<GLBuffer>(desc);
if (!buffer->create()) {
return nullptr;
}
return buffer;
}
std::unique_ptr<RHITexture> createTexture(const TextureDesc &desc) override {
auto texture = std::make_unique<GLTexture>(desc);
if (!texture->create()) {
return nullptr;
}
return texture;
}
std::unique_ptr<RHIShader> createShader(const ShaderDesc &desc) override {
auto shader = std::make_unique<GLShader>(desc);
if (!shader->compile()) {
E2D_LOG_ERROR("Shader compilation failed: {}", shader->getCompileLog());
return nullptr;
}
return shader;
}
std::unique_ptr<RHIPipeline>
createPipeline(const PipelineDesc &desc) override {
auto pipeline = std::make_unique<GLPipeline>(desc);
if (!pipeline->create()) {
return nullptr;
}
// 获取 vertex shader 的 program ID
if (desc.vertexShader.isValid()) {
RHIShader* shader = desc.vertexShader.get();
if (shader) {
auto* glShader = static_cast<GLShader*>(shader);
pipeline->setGLProgram(glShader->getGLProgram());
}
}
return pipeline;
}
std::unique_ptr<RHIFramebuffer>
createFramebuffer(const RenderPassDesc &desc) override {
auto framebuffer = std::make_unique<GLFramebuffer>(desc);
if (!framebuffer->create()) {
return nullptr;
}
return framebuffer;
}
std::unique_ptr<RHICommandList> createCommandList() override {
return std::make_unique<GLCommandList>();
}
RHIContext *getContext() override { return context_.get(); }
const char *getBackendName() const override { return "OpenGL"; }
void *getNativeWindow() const { return window_; }
void waitIdle() override { glFinish(); }
const RenderStats &getStats() const override { return stats_; }
void resetStats() override { stats_.reset(); }
void incrementDrawCalls() { stats_.drawCalls++; }
void incrementTriangles(uint32_t count) { stats_.triangles += count; }
void incrementVertices(uint32_t count) { stats_.vertices += count; }
void incrementTextureBinds() { stats_.textureBinds++; }
void incrementBufferBinds() { stats_.bufferBinds++; }
void incrementPipelineBinds() { stats_.pipelineBinds++; }
void incrementRenderPassSwitches() { stats_.renderPassSwitches++; }
private:
SDL_Window* window_;
SDL_GLContext glContext_;
std::unique_ptr<GLContext> context_;
RenderStats stats_;
};
// 创建设备的工厂函数
std::unique_ptr<RHIDevice> CreateGLDevice() {
return std::make_unique<GLDevice>();
}
} // namespace extra2d

View File

@ -0,0 +1,151 @@
#include <renderer/rhi/opengl/gl_framebuffer.h>
#include <renderer/rhi/opengl/gl_texture.h>
#include <renderer/rhi/opengl/gl_utils.h>
namespace extra2d {
/**
* @brief
* @param format
* @return /
*/
static inline bool isStencilFormat(TextureFormat format) {
switch (format) {
case TextureFormat::Depth24Stencil8:
case TextureFormat::Depth32FStencil8:
return true;
default:
return false;
}
}
GLFramebuffer::GLFramebuffer()
: desc_(), framebuffer_(0), width_(0), height_(0) {}
GLFramebuffer::GLFramebuffer(const RenderPassDesc &desc)
: desc_(desc), framebuffer_(0), width_(0), height_(0) {}
GLFramebuffer::~GLFramebuffer() { destroy(); }
bool GLFramebuffer::create() {
glGenFramebuffers(1, &framebuffer_);
if (framebuffer_ == 0) {
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
// 附加颜色附件
std::vector<GLenum> drawBuffers;
for (size_t i = 0; i < desc_.colorAttachments.size(); ++i) {
const auto &attachment = desc_.colorAttachments[i];
if (attachment.texture.isValid()) {
auto *texture = static_cast<GLTexture *>(attachment.texture.get());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
GL_TEXTURE_2D, texture->getGLTexture(), 0);
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
if (i == 0) {
width_ = texture->getWidth();
height_ = texture->getHeight();
}
}
}
// 附加深度/模板附件
if (desc_.hasDepthStencil && desc_.depthStencilAttachment.texture.isValid()) {
auto *texture =
static_cast<GLTexture *>(desc_.depthStencilAttachment.texture.get());
GLenum attachment = isStencilFormat(texture->getFormat())
? GL_DEPTH_STENCIL_ATTACHMENT
: GL_DEPTH_ATTACHMENT;
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D,
texture->getGLTexture(), 0);
}
if (!drawBuffers.empty()) {
glDrawBuffers(static_cast<GLsizei>(drawBuffers.size()), drawBuffers.data());
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return status == GL_FRAMEBUFFER_COMPLETE;
}
void GLFramebuffer::destroy() {
if (framebuffer_ != 0) {
glDeleteFramebuffers(1, &framebuffer_);
framebuffer_ = 0;
}
}
void GLFramebuffer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glViewport(0, 0, width_, height_);
}
void GLFramebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
void GLFramebuffer::clear(ClearFlags flags, const Color &color, float depth,
uint8_t stencil) {
bind();
GLbitfield mask = 0;
if (hasFlag(flags, ClearFlags::Color)) {
glClearColor(color.r, color.g, color.b, color.a);
mask |= GL_COLOR_BUFFER_BIT;
}
if (hasFlag(flags, ClearFlags::Depth)) {
glClearDepthf(depth);
mask |= GL_DEPTH_BUFFER_BIT;
}
if (hasFlag(flags, ClearFlags::Stencil)) {
glClearStencil(stencil);
mask |= GL_STENCIL_BUFFER_BIT;
}
if (mask != 0) {
glClear(mask);
}
}
void GLFramebuffer::setSize(uint32_t width, uint32_t height) {
width_ = width;
height_ = height;
}
uint32_t GLFramebuffer::getColorAttachmentCount() const {
return static_cast<uint32_t>(desc_.colorAttachments.size());
}
TextureHandle GLFramebuffer::getColorAttachment(uint32_t index) const {
if (index < desc_.colorAttachments.size()) {
return desc_.colorAttachments[index].texture;
}
return TextureHandle();
}
TextureHandle GLFramebuffer::getDepthStencilAttachment() const {
if (desc_.hasDepthStencil) {
return desc_.depthStencilAttachment.texture;
}
return TextureHandle();
}
bool GLFramebuffer::hasDepthStencil() const {
return desc_.hasDepthStencil;
}
bool GLFramebuffer::isValid() const {
return framebuffer_ != 0;
}
bool GLFramebuffer::isDefault() const {
return framebuffer_ == 0;
}
} // namespace extra2d

View File

@ -0,0 +1,115 @@
#include <renderer/rhi/opengl/gl_pipeline.h>
#include <renderer/rhi/opengl/gl_utils.h>
namespace extra2d {
GLPipeline::GLPipeline(const PipelineDesc &desc) : desc_(desc), vao_(0) {}
GLPipeline::~GLPipeline() { destroy(); }
bool GLPipeline::create() {
// 创建 VAO
glGenVertexArrays(1, &vao_);
if (vao_ == 0) {
return false;
}
glBindVertexArray(vao_);
// 配置顶点属性
const auto &layout = desc_.vertexLayout;
for (const auto &attr : layout.attributes) {
glEnableVertexAttribArray(attr.location);
GLenum type = GL_FLOAT;
GLint size = 1;
GLboolean normalized = GL_FALSE;
switch (attr.format) {
case VertexFormat::Float1:
size = 1;
break;
case VertexFormat::Float2:
size = 2;
break;
case VertexFormat::Float3:
size = 3;
break;
case VertexFormat::Float4:
size = 4;
break;
default:
break;
}
glVertexAttribPointer(attr.location, size, type, normalized, layout.stride,
reinterpret_cast<const void *>(attr.offset));
}
glBindVertexArray(0);
return true;
}
void GLPipeline::destroy() {
if (vao_ != 0) {
glDeleteVertexArrays(1, &vao_);
vao_ = 0;
}
}
void GLPipeline::bind() {
// 绑定着色器程序
if (shaderProgram_ != 0) {
glUseProgram(shaderProgram_);
}
// 注意不再绑定VAO因为我们使用动态顶点属性配置
// 顶点属性在 GLCommandList::setVertexBuffer 中配置
// 应用混合状态
if (desc_.blendState.enabled) {
glEnable(GL_BLEND);
glBlendFunc(blendFactorToGL(desc_.blendState.srcFactor),
blendFactorToGL(desc_.blendState.dstFactor));
} else {
glDisable(GL_BLEND);
}
// 应用深度状态
if (desc_.depthStencilState.depthTestEnabled) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(compareFuncToGL(desc_.depthStencilState.depthCompare));
glDepthMask(desc_.depthStencilState.depthWriteEnabled ? GL_TRUE : GL_FALSE);
} else {
glDisable(GL_DEPTH_TEST);
}
// 应用光栅化状态
if (desc_.rasterizerState.cullEnabled) {
glEnable(GL_CULL_FACE);
glCullFace(desc_.rasterizerState.cullFrontFace ? GL_FRONT : GL_BACK);
glFrontFace(desc_.rasterizerState.frontCCW ? GL_CCW : GL_CW);
} else {
glDisable(GL_CULL_FACE);
}
}
void GLPipeline::unbind() { glBindVertexArray(0); }
ShaderHandle GLPipeline::getVertexShader() const {
return desc_.vertexShader;
}
ShaderHandle GLPipeline::getFragmentShader() const {
return desc_.fragmentShader;
}
const VertexLayout& GLPipeline::getVertexLayout() const {
return desc_.vertexLayout;
}
bool GLPipeline::isValid() const {
return vao_ != 0;
}
} // namespace extra2d

View File

@ -0,0 +1,137 @@
#include <glm/gtc/type_ptr.hpp>
#include <renderer/rhi/opengl/gl_shader.h>
namespace extra2d {
GLShader::GLShader(const ShaderDesc &desc)
: desc_(desc), shader_(0), program_(0) {}
GLShader::~GLShader() { destroy(); }
bool GLShader::compile() {
// 创建程序
program_ = glCreateProgram();
if (program_ == 0) {
compileLog_ = "Failed to create shader program";
return false;
}
// 编译顶点着色器
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
const char *vsSource = desc_.vertexSource.c_str();
glShaderSource(vs, 1, &vsSource, nullptr);
glCompileShader(vs);
GLint success;
glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(vs, 512, nullptr, infoLog);
compileLog_ = std::string("Vertex shader compilation failed: ") + infoLog;
glDeleteShader(vs);
return false;
}
// 编译片段着色器
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
const char *fsSource = desc_.fragmentSource.c_str();
glShaderSource(fs, 1, &fsSource, nullptr);
glCompileShader(fs);
glGetShaderiv(fs, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(fs, 512, nullptr, infoLog);
compileLog_ = std::string("Fragment shader compilation failed: ") + infoLog;
glDeleteShader(vs);
glDeleteShader(fs);
return false;
}
// 链接着色器程序
glAttachShader(program_, vs);
glAttachShader(program_, fs);
glLinkProgram(program_);
glGetProgramiv(program_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(program_, 512, nullptr, infoLog);
compileLog_ = std::string("Shader program linking failed: ") + infoLog;
glDeleteShader(vs);
glDeleteShader(fs);
glDeleteProgram(program_);
program_ = 0;
return false;
}
// 清理着色器对象
glDeleteShader(vs);
glDeleteShader(fs);
return true;
}
void GLShader::destroy() {
if (program_ != 0) {
glDeleteProgram(program_);
program_ = 0;
}
}
void GLShader::bind() const {
if (program_ != 0) {
glUseProgram(program_);
}
}
void GLShader::unbind() const { glUseProgram(0); }
void GLShader::setUniform(const std::string &name, float value) {
GLint location = glGetUniformLocation(program_, name.c_str());
if (location != -1) {
glUniform1f(location, value);
}
}
void GLShader::setUniform(const std::string &name, const Vec2 &value) {
GLint location = glGetUniformLocation(program_, name.c_str());
if (location != -1) {
glUniform2f(location, value.x, value.y);
}
}
void GLShader::setUniform(const std::string &name, const Vec3 &value) {
GLint location = glGetUniformLocation(program_, name.c_str());
if (location != -1) {
glUniform3f(location, value.x, value.y, value.z);
}
}
void GLShader::setUniform(const std::string &name, const Color &value) {
GLint location = glGetUniformLocation(program_, name.c_str());
if (location != -1) {
glUniform4f(location, value.r, value.g, value.b, value.a);
}
}
void GLShader::setUniform(const std::string &name, const Mat4 &value) {
GLint location = glGetUniformLocation(program_, name.c_str());
if (location != -1) {
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}
}
bool GLShader::isCompiled() const {
return program_ != 0;
}
std::string GLShader::getCompileLog() const {
return compileLog_;
}
bool GLShader::isValid() const {
return program_ != 0;
}
} // namespace extra2d

View File

@ -0,0 +1,120 @@
#include <renderer/rhi/opengl/gl_texture.h>
#include <renderer/rhi/opengl/gl_utils.h>
namespace extra2d {
/**
* @brief
* @param format
* @return
*/
static inline bool isDepthFormat(TextureFormat format) {
switch (format) {
case TextureFormat::Depth16:
case TextureFormat::Depth24:
case TextureFormat::Depth32F:
case TextureFormat::Depth24Stencil8:
case TextureFormat::Depth32FStencil8:
return true;
default:
return false;
}
}
GLTexture::GLTexture(const TextureDesc &desc) : desc_(desc), texture_(0) {}
GLTexture::~GLTexture() { destroy(); }
bool GLTexture::create() {
glGenTextures(1, &texture_);
if (texture_ == 0) {
return false;
}
GLenum target = GL_TEXTURE_2D;
glBindTexture(target, texture_);
// 设置纹理参数
glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
textureFilterToGLMin(desc_.minFilter));
glTexParameteri(target, GL_TEXTURE_MAG_FILTER,
textureFilterToGLMag(desc_.magFilter));
glTexParameteri(target, GL_TEXTURE_WRAP_S, textureWrapToGL(desc_.wrapS));
glTexParameteri(target, GL_TEXTURE_WRAP_T, textureWrapToGL(desc_.wrapT));
// 分配纹理存储
GLenum format = textureFormatToGLFormat(desc_.format);
GLenum internalFormat = textureFormatToGLInternal(desc_.format);
GLenum type = GL_UNSIGNED_BYTE;
if (isDepthFormat(desc_.format)) {
type = GL_FLOAT;
}
glTexImage2D(target, 0, internalFormat, desc_.width, desc_.height, 0, format,
type, nullptr);
// 生成 mipmap如果需要
if (desc_.mipLevels > 1) {
glGenerateMipmap(target);
}
glBindTexture(target, 0);
return true;
}
void GLTexture::destroy() {
if (texture_ != 0) {
glDeleteTextures(1, &texture_);
texture_ = 0;
}
}
bool GLTexture::update(const void *data, uint32_t mipLevel) {
if (texture_ == 0 || data == nullptr)
return false;
glBindTexture(GL_TEXTURE_2D, texture_);
GLenum format = textureFormatToGLFormat(desc_.format);
GLenum type = isDepthFormat(desc_.format) ? GL_FLOAT : GL_UNSIGNED_BYTE;
// 计算当前 mipmap 层级的尺寸
uint32_t width = desc_.width >> mipLevel;
uint32_t height = desc_.height >> mipLevel;
if (width == 0)
width = 1;
if (height == 0)
height = 1;
glTexSubImage2D(GL_TEXTURE_2D, mipLevel, 0, 0, width, height, format, type,
data);
glBindTexture(GL_TEXTURE_2D, 0);
return true;
}
void GLTexture::generateMipmap() {
if (texture_ == 0)
return;
glBindTexture(GL_TEXTURE_2D, texture_);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
void GLTexture::bind(uint32_t slot) {
if (texture_ == 0)
return;
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, texture_);
}
void GLTexture::unbind() { glBindTexture(GL_TEXTURE_2D, 0); }
bool GLTexture::isValid() const {
return texture_ != 0;
}
bool GLTexture::isRenderTarget() const {
return desc_.renderTarget;
}
} // namespace extra2d

352
src/renderer/rhi_module.cpp Normal file
View File

@ -0,0 +1,352 @@
#include <module/module_registry.h>
#include <platform/window_module.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h>
// 包含 OpenGL 设备实现
// 注意GLDevice 定义在 gl_device.cpp 中,需要确保链接时包含
namespace extra2d {
// 前向声明 GLDevice 类
class GLDevice;
} // namespace extra2d
namespace extra2d {
// 全局实例指针
static RHIModule *g_rhiModule = nullptr;
// GLDevice 创建函数声明 - 在 gl_device.cpp 中定义
std::unique_ptr<RHIDevice> CreateGLDevice();
RHIModule::RHIModule() : context_(nullptr) { g_rhiModule = this; }
RHIModule::~RHIModule() {
shutdown();
g_rhiModule = nullptr;
}
bool RHIModule::init() {
E2D_LOG_INFO("Initializing RHIModule...");
// 注册窗口显示事件监听,在窗口显示时创建 OpenGL 上下文
onShowListener_ = std::make_unique<events::OnShow::Listener>();
onShowListener_->bind([this]() { this->onWindowShow(); });
E2D_LOG_INFO("RHIModule initialized (waiting for window show)");
return true;
}
void RHIModule::onWindowShow() {
if (initialized_) {
return;
}
E2D_LOG_INFO("RHIModule: Creating OpenGL device...");
// 获取窗口模块
auto *windowModule = getModule<WindowModule>();
if (!windowModule) {
E2D_LOG_ERROR("WindowModule not available");
return;
}
// 等待窗口创建完成
if (!windowModule->handle()) {
E2D_LOG_ERROR("Window not created yet");
return;
}
// 创建 OpenGL 设备并传入窗口句柄
device_ = CreateGLDevice();
if (!device_) {
E2D_LOG_ERROR("Failed to create RHI device");
return;
}
if (!device_->initialize(windowModule->handle())) {
E2D_LOG_ERROR("Failed to initialize RHI device");
device_.reset();
return;
}
context_ = device_->getContext();
if (!context_) {
E2D_LOG_ERROR("Failed to get RHI context");
device_->shutdown();
device_.reset();
return;
}
// 初始化上下文
if (!context_->initialize()) {
E2D_LOG_ERROR("Failed to initialize RHI context");
device_->shutdown();
device_.reset();
context_ = nullptr;
return;
}
initialized_ = true;
E2D_LOG_INFO("RHIModule initialized successfully (backend: {})",
device_->getBackendName());
// RHI 初始化完成,再次触发 OnShow 事件通知其他模块
// 这样 RendererModule 等依赖 RHI 的模块可以完成初始化
events::OnShow::emit();
}
void RHIModule::shutdown() {
E2D_LOG_INFO("Shutting down RHIModule...");
// 清理事件监听器
onShowListener_.reset();
if (context_) {
context_->shutdown();
context_ = nullptr;
}
if (device_) {
device_->shutdown();
device_.reset();
}
initialized_ = false;
E2D_LOG_INFO("RHIModule shutdown complete");
}
RHIModule *RHIModule::get() { return g_rhiModule; }
std::unique_ptr<RHIBuffer> RHIModule::createBuffer(const BufferDesc &desc) {
if (!device_) {
E2D_LOG_ERROR("Cannot create buffer: RHI device not initialized");
return nullptr;
}
return device_->createBuffer(desc);
}
std::unique_ptr<RHITexture> RHIModule::createTexture(const TextureDesc &desc) {
if (!device_) {
E2D_LOG_ERROR("Cannot create texture: RHI device not initialized");
return nullptr;
}
return device_->createTexture(desc);
}
std::unique_ptr<RHIShader> RHIModule::createShader(const ShaderDesc &desc) {
if (!device_) {
E2D_LOG_ERROR("Cannot create shader: RHI device not initialized");
return nullptr;
}
return device_->createShader(desc);
}
std::unique_ptr<RHIPipeline>
RHIModule::createPipeline(const PipelineDesc &desc) {
if (!device_) {
E2D_LOG_ERROR("Cannot create pipeline: RHI device not initialized");
return nullptr;
}
return device_->createPipeline(desc);
}
std::unique_ptr<RHIFramebuffer>
RHIModule::createFramebuffer(const RenderPassDesc &desc) {
if (!device_) {
E2D_LOG_ERROR("Cannot create framebuffer: RHI device not initialized");
return nullptr;
}
return device_->createFramebuffer(desc);
}
std::unique_ptr<RHICommandList> RHIModule::createCommandList() {
if (!device_) {
E2D_LOG_ERROR("Cannot create command list: RHI device not initialized");
return nullptr;
}
return device_->createCommandList();
}
// BufferDesc 静态方法实现
BufferDesc BufferDesc::vertex(uint32_t size, BufferUsage usage) {
BufferDesc desc;
desc.type = BufferType::Vertex;
desc.usage = usage;
desc.size = size;
return desc;
}
BufferDesc BufferDesc::index(uint32_t size, BufferUsage usage) {
BufferDesc desc;
desc.type = BufferType::Index;
desc.usage = usage;
desc.size = size;
return desc;
}
BufferDesc BufferDesc::uniform(uint32_t size) {
BufferDesc desc;
desc.type = BufferType::Uniform;
desc.usage = BufferUsage::Dynamic;
desc.size = size;
return desc;
}
// BlendState 静态方法实现
BlendState BlendState::opaque() {
BlendState state;
state.enabled = false;
state.srcFactor = BlendFactor::One;
state.dstFactor = BlendFactor::Zero;
state.op = BlendOp::Add;
state.srcAlphaFactor = BlendFactor::One;
state.dstAlphaFactor = BlendFactor::Zero;
state.alphaOp = BlendOp::Add;
return state;
}
BlendState BlendState::alphaBlend() {
BlendState state;
state.enabled = true;
state.srcFactor = BlendFactor::SrcAlpha;
state.dstFactor = BlendFactor::OneMinusSrcAlpha;
state.op = BlendOp::Add;
state.srcAlphaFactor = BlendFactor::One;
state.dstAlphaFactor = BlendFactor::OneMinusSrcAlpha;
state.alphaOp = BlendOp::Add;
return state;
}
BlendState BlendState::additive() {
BlendState state;
state.enabled = true;
state.srcFactor = BlendFactor::SrcAlpha;
state.dstFactor = BlendFactor::One;
state.op = BlendOp::Add;
state.srcAlphaFactor = BlendFactor::SrcAlpha;
state.dstAlphaFactor = BlendFactor::One;
state.alphaOp = BlendOp::Add;
return state;
}
// DepthStencilState 静态方法实现
DepthStencilState DepthStencilState::depthTest() {
DepthStencilState state;
state.depthTestEnabled = true;
state.depthWriteEnabled = true;
state.depthCompare = CompareFunc::Less;
state.stencilEnabled = false;
return state;
}
DepthStencilState DepthStencilState::depthTestWrite() {
DepthStencilState state;
state.depthTestEnabled = true;
state.depthWriteEnabled = true;
state.depthCompare = CompareFunc::Less;
state.stencilEnabled = false;
return state;
}
DepthStencilState DepthStencilState::depthTestNoWrite() {
DepthStencilState state;
state.depthTestEnabled = true;
state.depthWriteEnabled = false;
state.depthCompare = CompareFunc::Less;
state.stencilEnabled = false;
return state;
}
DepthStencilState DepthStencilState::noDepthTest() {
DepthStencilState state;
state.depthTestEnabled = false;
state.depthWriteEnabled = false;
state.depthCompare = CompareFunc::Always;
state.stencilEnabled = false;
return state;
}
// RasterizerState 静态方法实现
RasterizerState RasterizerState::cullBack() {
RasterizerState state;
state.cullEnabled = true;
state.cullFrontFace = false;
state.frontCCW = false;
state.scissorEnabled = false;
state.wireframe = false;
return state;
}
RasterizerState RasterizerState::cullFront() {
RasterizerState state;
state.cullEnabled = true;
state.cullFrontFace = true;
state.frontCCW = false;
state.scissorEnabled = false;
state.wireframe = false;
return state;
}
RasterizerState RasterizerState::noCull() {
RasterizerState state;
state.cullEnabled = false;
state.cullFrontFace = false;
state.frontCCW = false;
state.scissorEnabled = false;
state.wireframe = false;
return state;
}
// VertexLayout 方法实现
void VertexLayout::addAttribute(uint32_t location, VertexFormat format,
uint32_t offset, uint32_t bufferIndex) {
VertexAttribute attr;
attr.location = location;
attr.format = format;
attr.offset = offset;
attr.bufferIndex = bufferIndex;
attributes.push_back(attr);
}
// VertexAttribute 方法实现
uint32_t VertexAttribute::getSize(VertexFormat format) {
switch (format) {
case VertexFormat::Float1:
return 4;
case VertexFormat::Float2:
return 8;
case VertexFormat::Float3:
return 12;
case VertexFormat::Float4:
return 16;
case VertexFormat::Int1:
return 4;
case VertexFormat::Int2:
return 8;
case VertexFormat::Int3:
return 12;
case VertexFormat::Int4:
return 16;
case VertexFormat::UInt1:
return 4;
case VertexFormat::UInt2:
return 8;
case VertexFormat::UInt3:
return 12;
case VertexFormat::UInt4:
return 16;
case VertexFormat::Byte4:
return 4;
case VertexFormat::Byte4Normalized:
return 4;
case VertexFormat::UByte4:
return 4;
case VertexFormat::UByte4Normalized:
return 4;
default:
return 0;
}
}
} // namespace extra2d

View File

@ -1,5 +1,5 @@
#include <fstream> #include <fstream>
#include <glad/glad.h> #include <renderer/rhi_module.h>
#include <renderer/shader.h> #include <renderer/shader.h>
#include <sstream> #include <sstream>
#include <utils/logger.h> #include <utils/logger.h>
@ -9,10 +9,10 @@ namespace extra2d {
Shader::Shader() = default; Shader::Shader() = default;
Shader::~Shader() { Shader::~Shader() {
if (program_ != 0) { // RHIHandle 是轻量级句柄,不需要显式释放
glDeleteProgram(program_); // 实际的资源由 RHI 设备管理
program_ = 0; pipeline_ = PipelineHandle();
} handle_ = ShaderHandle();
} }
bool Shader::loadFromFile(const std::string &vsPath, bool Shader::loadFromFile(const std::string &vsPath,
@ -42,170 +42,92 @@ bool Shader::loadFromFile(const std::string &vsPath,
bool Shader::loadFromSource(const std::string &vsSource, bool Shader::loadFromSource(const std::string &vsSource,
const std::string &fsSource) { const std::string &fsSource) {
// 删除旧程序 // 释放旧资源
if (program_ != 0) { pipeline_ = PipelineHandle();
glDeleteProgram(program_); handle_ = ShaderHandle();
program_ = 0;
// 获取 RHI 设备
auto *rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
} }
uniformCache_.clear(); auto *device = rhiModule->getDevice();
if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return false;
}
// 处理源码(添加版本声明) // 处理源码(添加版本声明)
std::string processedVS = addVersionIfNeeded(vsSource, GL_VERTEX_SHADER); std::string processedVS = addVersionIfNeeded(vsSource, true);
std::string processedFS = addVersionIfNeeded(fsSource, GL_FRAGMENT_SHADER); std::string processedFS = addVersionIfNeeded(fsSource, false);
E2D_LOG_INFO("Compiling vertex shader..."); // 创建着色器描述
// 编译顶点着色器 ShaderDesc shaderDesc;
GLuint vs = compileShader(GL_VERTEX_SHADER, processedVS); shaderDesc.vertexSource = processedVS;
if (vs == 0) { shaderDesc.fragmentSource = processedFS;
E2D_LOG_ERROR("Vertex shader compilation failed");
// 创建着色器
auto shader = device->createShader(shaderDesc);
if (!shader) {
E2D_LOG_ERROR("Failed to create shader");
return false; return false;
} }
E2D_LOG_INFO("Compiling fragment shader..."); // 获取着色器句柄
// 编译片段着色器 handle_ = ShaderHandle(shader.release());
GLuint fs = compileShader(GL_FRAGMENT_SHADER, processedFS);
if (fs == 0) { // 创建顶点布局2D 标准布局:位置 + 纹理坐标 + 颜色)
E2D_LOG_ERROR("Fragment shader compilation failed"); VertexLayout vertexLayout;
glDeleteShader(vs); 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; return false;
} }
E2D_LOG_INFO("Linking shader program..."); // 获取管线句柄
// 链接程序 pipeline_ = PipelineHandle(pipeline.release());
if (!linkProgram(vs, fs)) {
E2D_LOG_ERROR("Shader program linking failed");
glDeleteShader(vs);
glDeleteShader(fs);
return false;
}
// 清理着色器对象 E2D_LOG_INFO("Shader created successfully");
glDeleteShader(vs);
glDeleteShader(fs);
E2D_LOG_INFO("Shader program created successfully, program ID: {}", program_);
return true; return true;
} }
void Shader::bind() const {
if (program_ != 0) {
glUseProgram(program_);
}
}
void Shader::unbind() const { glUseProgram(0); }
void Shader::setUniformBlock(const std::string &name, uint32_t binding) { void Shader::setUniformBlock(const std::string &name, uint32_t binding) {
if (program_ == 0) // 存储 uniform block 绑定信息
return; uniformBlockBindings_[name] = binding;
GLuint index = glGetUniformBlockIndex(program_, name.c_str()); // 注意:实际的 uniform block 绑定需要在渲染时通过 RHI 命令列表设置
if (index != GL_INVALID_INDEX) { // 这里仅存储绑定信息,供后续渲染使用
glUniformBlockBinding(program_, index, binding); // 例如commandList->setUniformBlock(binding, buffer);
}
} }
void Shader::setInt(const std::string &name, int value) { uint32_t Shader::getUniformBlockBinding(const std::string &name) const {
GLint location = getUniformLocation(name); auto it = uniformBlockBindings_.find(name);
if (location != -1) { if (it != uniformBlockBindings_.end()) {
glUniform1i(location, value);
}
}
void Shader::setFloat(const std::string &name, float value) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform1f(location, value);
}
}
void Shader::setVec2(const std::string &name, float x, float y) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform2f(location, x, y);
}
}
void Shader::setVec4(const std::string &name, float x, float y, float z,
float w) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform4f(location, x, y, z, w);
}
}
void Shader::setMat4(const std::string &name, const float *value) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniformMatrix4fv(location, 1, GL_FALSE, value);
}
}
GLuint Shader::compileShader(GLenum type, const std::string &source) {
GLuint shader = glCreateShader(type);
const char *src = source.c_str();
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
// 检查编译状态
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
const char *typeStr = (type == GL_VERTEX_SHADER) ? "vertex" : "fragment";
E2D_LOG_ERROR("{} shader compilation failed: {}", typeStr, infoLog);
glDeleteShader(shader);
return 0;
}
return shader;
}
bool Shader::linkProgram(GLuint vertexShader, GLuint fragmentShader) {
program_ = glCreateProgram();
glAttachShader(program_, vertexShader);
glAttachShader(program_, fragmentShader);
glLinkProgram(program_);
// 检查链接状态
GLint success;
glGetProgramiv(program_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(program_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Shader program linking failed: {}", infoLog);
glDeleteProgram(program_);
program_ = 0;
return false;
}
return true;
}
GLint Shader::getUniformLocation(const std::string &name) {
if (program_ == 0)
return -1;
// 检查缓存
auto it = uniformCache_.find(name);
if (it != uniformCache_.end()) {
return it->second; return it->second;
} }
return UINT32_MAX; // 未找到
// 查询 uniform 位置
GLint location = glGetUniformLocation(program_, name.c_str());
uniformCache_[name] = location;
return location;
} }
std::string Shader::addVersionIfNeeded(const std::string &source, GLenum type) { std::string Shader::addVersionIfNeeded(const std::string &source,
bool isVertex) {
// 如果已经包含版本声明,直接返回 // 如果已经包含版本声明,直接返回
if (source.find("#version") != std::string::npos) { if (source.find("#version") != std::string::npos) {
return source; return source;
@ -215,7 +137,7 @@ std::string Shader::addVersionIfNeeded(const std::string &source, GLenum type) {
std::string result = "#version 320 es\n"; std::string result = "#version 320 es\n";
// 片段着色器需要添加精度声明 // 片段着色器需要添加精度声明
if (type == GL_FRAGMENT_SHADER) { if (!isVertex) {
result += "precision mediump float;\n"; result += "precision mediump float;\n";
} }

View File

@ -1,46 +1,17 @@
#include <renderer/texture.h> #include <renderer/texture.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h> #include <utils/logger.h>
#include <glad/glad.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h> #include <stb/stb_image.h>
namespace extra2d { namespace extra2d {
// OpenGL 格式转换函数
static GLint getTextureInternalFormat(TextureFormat format) {
switch (format) {
case TextureFormat::RGBA8: return GL_RGBA8;
case TextureFormat::RGB8: return GL_RGB8;
case TextureFormat::RGBA4: return GL_RGBA4;
case TextureFormat::R8: return GL_R8;
case TextureFormat::RG8: return GL_RG8;
default: return GL_RGBA8;
}
}
static GLenum getTextureFormat(TextureFormat format) {
switch (format) {
case TextureFormat::RGBA8:
case TextureFormat::RGBA4:
return GL_RGBA;
case TextureFormat::RGB8:
return GL_RGB;
case TextureFormat::R8:
return GL_RED;
case TextureFormat::RG8:
return GL_RG;
default:
return GL_RGBA;
}
}
Texture::Texture() = default; Texture::Texture() = default;
Texture::~Texture() { Texture::~Texture() {
if (texture_ != 0) { // RHI 纹理句柄是轻量级句柄,不需要显式释放
glDeleteTextures(1, &texture_); // 实际的纹理资源由 RHI 设备管理
texture_ = 0; handle_ = TextureHandle();
}
} }
bool Texture::loadFromFile(const std::string& path) { bool Texture::loadFromFile(const std::string& path) {
@ -75,81 +46,111 @@ bool Texture::loadFromFile(const std::string& path) {
} }
bool Texture::loadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) { bool Texture::loadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) {
if (texture_ != 0) { // 释放旧纹理
glDeleteTextures(1, &texture_); handle_ = TextureHandle();
texture_ = 0;
}
width_ = width; width_ = width;
height_ = height; height_ = height;
format_ = format; format_ = format;
// 创建纹理 // 获取 RHI 设备
glGenTextures(1, &texture_); auto* rhiModule = RHIModule::get();
glBindTexture(GL_TEXTURE_2D, texture_); if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
}
// 设置纹理参数 auto* device = rhiModule->getDevice();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); if (!device) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); E2D_LOG_ERROR("RHIDevice not available");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); return false;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }
// 创建纹理描述
TextureDesc desc;
desc.width = static_cast<uint32_t>(width);
desc.height = static_cast<uint32_t>(height);
desc.format = format;
desc.mipLevels = 1; // 初始创建 1 层,后续生成 mipmap
// 创建 RHI 纹理
auto texture = device->createTexture(desc);
if (!texture) {
E2D_LOG_ERROR("Failed to create RHI texture");
return false;
}
// 上传纹理数据 // 上传纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, if (data) {
getTextureInternalFormat(format_), // 注意update 方法的参数需要根据实际 RHI 接口调整
width_, height_, 0, // 这里假设 update 接受数据指针
getTextureFormat(format_), texture->update(data, static_cast<size_t>(width * height * getBytesPerPixel(format)));
GL_UNSIGNED_BYTE, data);
// 生成 mipmap // 生成 mipmap
glGenerateMipmap(GL_TEXTURE_2D); // 注意generateMipmap 方法需要在 RHI 接口中实现
}
glBindTexture(GL_TEXTURE_2D, 0); // 获取纹理句柄
handle_ = TextureHandle(texture.release());
return true; return true;
} }
bool Texture::create(int width, int height, TextureFormat format) { bool Texture::create(int width, int height, TextureFormat format) {
if (texture_ != 0) { // 释放旧纹理
glDeleteTextures(1, &texture_); handle_ = TextureHandle();
texture_ = 0;
}
width_ = width; width_ = width;
height_ = height; height_ = height;
format_ = format; format_ = format;
// 创建纹理 // 获取 RHI 设备
glGenTextures(1, &texture_); auto* rhiModule = RHIModule::get();
glBindTexture(GL_TEXTURE_2D, texture_); if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
}
// 设置纹理参数 auto* device = rhiModule->getDevice();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); if (!device) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); E2D_LOG_ERROR("RHIDevice not available");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); return false;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }
// 分配纹理存储(无数据) // 创建纹理描述
glTexImage2D(GL_TEXTURE_2D, 0, TextureDesc desc;
getTextureInternalFormat(format_), desc.width = static_cast<uint32_t>(width);
width_, height_, 0, desc.height = static_cast<uint32_t>(height);
getTextureFormat(format_), desc.format = format;
GL_UNSIGNED_BYTE, nullptr); desc.mipLevels = 1; // 不生成 mipmap
glBindTexture(GL_TEXTURE_2D, 0); // 创建 RHI 纹理
auto texture = device->createTexture(desc);
if (!texture) {
E2D_LOG_ERROR("Failed to create RHI texture");
return false;
}
// 获取纹理句柄
handle_ = TextureHandle(texture.release());
return true; return true;
} }
void Texture::bind(uint32_t slot) const { // 辅助函数:获取每个像素的字节数
if (texture_ != 0) { uint32_t Texture::getBytesPerPixel(TextureFormat format) {
glActiveTexture(GL_TEXTURE0 + slot); switch (format) {
glBindTexture(GL_TEXTURE_2D, texture_); case TextureFormat::R8: return 1;
case TextureFormat::RG8: return 2;
case TextureFormat::RGB8: return 3;
case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return 4;
case TextureFormat::Depth16: return 2;
case TextureFormat::Depth24: return 3;
case TextureFormat::Depth32F: return 4;
case TextureFormat::Depth24Stencil8: return 4;
case TextureFormat::Depth32FStencil8: return 5;
default: return 4;
} }
} }
void Texture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,3 +1,5 @@
#include <renderer/rhi/rhi_buffer.h>
#include <renderer/rhi_module.h>
#include <renderer/uniform_buffer.h> #include <renderer/uniform_buffer.h>
#include <utils/logger.h> #include <utils/logger.h>
@ -5,43 +7,54 @@ namespace extra2d {
UniformBuffer::UniformBuffer() = default; UniformBuffer::UniformBuffer() = default;
UniformBuffer::~UniformBuffer() { UniformBuffer::~UniformBuffer() { destroy(); }
destroy();
}
bool UniformBuffer::create(uint32_t size, uint32_t binding) { bool UniformBuffer::create(uint32_t size, uint32_t binding) {
if (ubo_ != 0) {
destroy(); destroy();
// 获取 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;
} }
size_ = size; size_ = size;
binding_ = binding; binding_ = binding;
glGenBuffers(1, &ubo_); // 创建 uniform 缓冲区描述
if (ubo_ == 0) { BufferDesc desc = BufferDesc::uniform(size);
E2D_LOG_ERROR("Failed to generate UBO");
// 创建缓冲区
auto buffer = device->createBuffer(desc);
if (!buffer) {
E2D_LOG_ERROR("Failed to create uniform buffer");
return false; return false;
} }
glBindBuffer(GL_UNIFORM_BUFFER, ubo_); // 获取缓冲区句柄
glBufferData(GL_UNIFORM_BUFFER, size, nullptr, GL_DYNAMIC_DRAW); handle_ = BufferHandle(buffer.release());
glBindBufferBase(GL_UNIFORM_BUFFER, binding, ubo_);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
E2D_LOG_DEBUG("UBO created: size={}, binding={}", size, binding); E2D_LOG_DEBUG("UBO created: size={}, binding={}", size, binding);
return true; return true;
} }
void UniformBuffer::destroy() { void UniformBuffer::destroy() {
if (ubo_ != 0) { // RHIHandle 是轻量级句柄,不需要显式释放
glDeleteBuffers(1, &ubo_); // 实际的缓冲区资源由 RHI 设备管理
ubo_ = 0; handle_ = BufferHandle();
size_ = 0; size_ = 0;
} }
}
void UniformBuffer::update(const void *data, uint32_t size, uint32_t offset) { void UniformBuffer::update(const void *data, uint32_t size, uint32_t offset) {
if (ubo_ == 0 || data == nullptr) return; if (!handle_.isValid() || data == nullptr)
return;
if (offset + size > size_) { if (offset + size > size_) {
E2D_LOG_WARN("UBO update out of bounds: offset={}, size={}, bufferSize={}", E2D_LOG_WARN("UBO update out of bounds: offset={}, size={}, bufferSize={}",
@ -49,31 +62,39 @@ void UniformBuffer::update(const void* data, uint32_t size, uint32_t offset) {
return; return;
} }
glBindBuffer(GL_UNIFORM_BUFFER, ubo_); // 通过 RHI 缓冲区接口直接更新数据
glBufferSubData(GL_UNIFORM_BUFFER, offset, size, data); RHIBuffer *buffer = handle_.get();
glBindBuffer(GL_UNIFORM_BUFFER, 0); if (buffer) {
buffer->update(data, size, offset);
}
} }
void UniformBuffer::bind(uint32_t binding) { void UniformBuffer::bind(uint32_t binding) {
if (ubo_ == 0) return; if (!handle_.isValid())
return;
glBindBufferBase(GL_UNIFORM_BUFFER, binding, ubo_); // 记录绑定槽位
// 注意:实际的 GPU 绑定操作需要在渲染时通过 RHICommandList::setUniformBuffer
// 进行 示例commandList->setUniformBuffer(binding, handle_.get());
binding_ = binding;
} }
RHIBuffer *UniformBuffer::getRHIBuffer() const { return handle_.get(); }
UniformBufferManager::UniformBufferManager() = default; UniformBufferManager::UniformBufferManager() = default;
UniformBufferManager::~UniformBufferManager() { UniformBufferManager::~UniformBufferManager() { shutdown(); }
shutdown();
}
UniformBufferManager::UniformBufferManager(UniformBufferManager&& other) noexcept UniformBufferManager::UniformBufferManager(
UniformBufferManager &&other) noexcept
: globalUBO_(std::move(other.globalUBO_)), : globalUBO_(std::move(other.globalUBO_)),
materialUBOPool_(std::move(other.materialUBOPool_)), materialUBOPool_(std::move(other.materialUBOPool_)),
currentUBOIndex_(other.currentUBOIndex_) { currentUBOIndex_(other.currentUBOIndex_) {
other.currentUBOIndex_ = 0; other.currentUBOIndex_ = 0;
} }
UniformBufferManager& UniformBufferManager::operator=(UniformBufferManager&& other) noexcept { UniformBufferManager &
UniformBufferManager::operator=(UniformBufferManager &&other) noexcept {
if (this != &other) { if (this != &other) {
shutdown(); shutdown();
@ -89,7 +110,8 @@ UniformBufferManager& UniformBufferManager::operator=(UniformBufferManager&& oth
bool UniformBufferManager::initialize() { bool UniformBufferManager::initialize() {
// 创建全局 UBO // 创建全局 UBO
globalUBO_ = std::make_unique<UniformBuffer>(); globalUBO_ = std::make_unique<UniformBuffer>();
if (!globalUBO_->create(GLOBAL_UBO_SIZE, GLOBAL_UBO_BINDING)) { if (!globalUBO_->create(UniformBufferManager::GLOBAL_UBO_SIZE,
UniformBufferManager::GLOBAL_UBO_BINDING)) {
E2D_LOG_ERROR("Failed to create global UBO"); E2D_LOG_ERROR("Failed to create global UBO");
return false; return false;
} }
@ -109,9 +131,7 @@ void UniformBufferManager::shutdown() {
E2D_LOG_INFO("UniformBufferManager shutdown"); E2D_LOG_INFO("UniformBufferManager shutdown");
} }
UniformBuffer* UniformBufferManager::getGlobalUBO() { UniformBuffer *UniformBufferManager::getGlobalUBO() { return globalUBO_.get(); }
return globalUBO_.get();
}
UniformBuffer *UniformBufferManager::acquireMaterialUBO(uint32_t size) { UniformBuffer *UniformBufferManager::acquireMaterialUBO(uint32_t size) {
// 查找或创建合适大小的 UBO // 查找或创建合适大小的 UBO
@ -124,7 +144,7 @@ UniformBuffer* UniformBufferManager::acquireMaterialUBO(uint32_t size) {
// 需要创建新的 UBO // 需要创建新的 UBO
auto ubo = std::make_unique<UniformBuffer>(); auto ubo = std::make_unique<UniformBuffer>();
if (!ubo->create(size, MATERIAL_UBO_BINDING)) { if (!ubo->create(size, UniformBufferManager::MATERIAL_UBO_BINDING)) {
E2D_LOG_ERROR("Failed to create material UBO"); E2D_LOG_ERROR("Failed to create material UBO");
return nullptr; return nullptr;
} }
@ -136,14 +156,12 @@ UniformBuffer* UniformBufferManager::acquireMaterialUBO(uint32_t size) {
return result; return result;
} }
void UniformBufferManager::resetMaterialUBOs() { void UniformBufferManager::resetMaterialUBOs() { currentUBOIndex_ = 0; }
currentUBOIndex_ = 0;
}
void UniformBufferManager::updateGlobalUBO(const void *data, uint32_t size) { void UniformBufferManager::updateGlobalUBO(const void *data, uint32_t size) {
if (globalUBO_) { if (globalUBO_) {
globalUBO_->update(data, size); globalUBO_->update(data, size);
globalUBO_->bind(GLOBAL_UBO_BINDING); globalUBO_->bind(UniformBufferManager::GLOBAL_UBO_BINDING);
} }
} }

View File

@ -33,8 +33,9 @@ void SpriteRenderer::render() {
uint32_t textureId = texture_.index(); uint32_t textureId = texture_.index();
cmd.sortKey = (materialId << 16) | (textureId & 0xFFFF); cmd.sortKey = (materialId << 16) | (textureId & 0xFFFF);
cmd.drawMesh.mesh = MeshHandle::invalid(); // 如果没有指定网格,使用默认的四边形网格
cmd.drawMesh.material = material_.isValid() ? material_ : MaterialHandle::invalid(); cmd.drawMesh.mesh = Handle<Mesh>::invalid(); // RendererModule 会使用默认网格
cmd.drawMesh.material = material_.isValid() ? material_ : Handle<Material>::invalid();
cmd.setTransform(worldTransform); cmd.setTransform(worldTransform);
cmd.setColor(color_); cmd.setColor(color_);

View File

@ -8,10 +8,6 @@ SceneModule::~SceneModule() {
shutdown(); shutdown();
} }
SceneModule::SceneModule(SceneModule &&) noexcept = default;
SceneModule &SceneModule::operator=(SceneModule &&) noexcept = default;
bool SceneModule::init() { bool SceneModule::init() {
// 创建导演 // 创建导演
director_ = makePtr<Director>(); director_ = makePtr<Director>();

View File

@ -7,24 +7,6 @@ TimerModule::TimerModule() = default;
TimerModule::~TimerModule() { shutdown(); } TimerModule::~TimerModule() { shutdown(); }
TimerModule::TimerModule(TimerModule &&other) noexcept
: timers_(std::move(other.timers_)),
pendingRemove_(std::move(other.pendingRemove_)), nextId_(other.nextId_),
timeScale_(other.timeScale_), inUpdate_(other.inUpdate_) {}
TimerModule &TimerModule::operator=(TimerModule &&other) noexcept {
if (this != &other) {
shutdown();
timers_ = std::move(other.timers_);
pendingRemove_ = std::move(other.pendingRemove_);
nextId_ = other.nextId_;
timeScale_ = other.timeScale_;
inUpdate_ = other.inUpdate_;
}
return *this;
}
bool TimerModule::init() { bool TimerModule::init() {
// 初始化完成,等待 OnUpdate 事件 // 初始化完成,等待 OnUpdate 事件
return true; return true;