C++中为gl_texture结构体添加状态的设计方案咨询
关于OpenGL纹理管理类的状态同步方案
你的std::shared_ptr<gl_texture>方案是否可行?
完全可行。通过让gl_context和用户都持有指向同一个gl_texture实例的std::shared_ptr,当set_data修改实例的宽高状态时,所有持有该指针的用户都能实时看到更新后的状态。
使用时需要注意两点:
gl_context的textures_容器要存储std::shared_ptr<gl_texture>,避免因用户释放所有外部指针导致实例被提前销毁;- 如果存在多线程操作纹理的场景,要给
gl_texture的状态修改加锁,保证线程安全。
其他可选设计方案
1. 轻量级句柄模式(推荐)
把gl_texture设计成仅包含唯一ID的轻量级句柄,所有纹理状态(宽高、OpenGL纹理ID等)统一由gl_context内部的哈希表管理。用户通过句柄来操作纹理,需要状态时从上下文查询。
这种设计是图形引擎中最常用的方式,优点是句柄复制成本极低,上下文完全掌控纹理生命周期,避免悬空指针和状态不一致问题。
示例代码:
#include <unordered_map> #include <cstdint> #include <GL/glew.h> using TextureID = uint32_t; // 存储纹理的实际状态和OpenGL资源 struct TextureData { GLuint gl_texture_id; int width = 0; int height = 0; // 可扩展其他状态:格式、mipmap状态等 }; class gl_context { private: std::unordered_map<TextureID, TextureData> textures_; TextureID next_available_id_ = 0; // 生成唯一ID的辅助方法 TextureID generate_unique_id() { return next_available_id_++; } public: // 创建纹理,返回句柄 TextureID gen_texture() { TextureID id = generate_unique_id(); // 初始化OpenGL纹理 GLuint gl_id; glGenTextures(1, &gl_id); glBindTexture(GL_TEXTURE_2D, gl_id); // 设置默认纹理参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); textures_[id] = {gl_id, 0, 0}; return id; } // 通过句柄设置纹理数据并更新状态 void set_data(TextureID tex_id, int width, int height, unsigned char* data) { auto& tex_data = textures_.at(tex_id); glBindTexture(GL_TEXTURE_2D, tex_data.gl_texture_id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); // 更新状态 tex_data.width = width; tex_data.height = height; } // 通过句柄查询纹理尺寸 std::pair<int, int> get_texture_size(TextureID tex_id) const { const auto& tex_data = textures_.at(tex_id); return {tex_data.width, tex_data.height}; } // 销毁纹理(可选) void destroy_texture(TextureID tex_id) { auto it = textures_.find(tex_id); if (it != textures_.end()) { glDeleteTextures(1, &it->second.gl_texture_id); textures_.erase(it); } } };
2. 带上下文引用的gl_texture结构体
让gl_texture持有gl_context的指针和纹理ID,自身不存储状态,而是在需要获取宽高等信息时,直接通过上下文查询。这种方式兼顾了易用性(用户不用每次传ID给上下文)和可控性(状态仍由上下文统一管理)。
示例代码:
#include <unordered_map> #include <cstdint> #include <GL/glew.h> using TextureID = uint32_t; struct TextureData { GLuint gl_texture_id; int width = 0; int height = 0; }; class gl_context; struct gl_texture { private: gl_context* ctx_; TextureID id_; // 让gl_context能构造gl_texture friend class gl_context; gl_texture(gl_context* ctx, TextureID id) : ctx_(ctx), id_(id) {} public: // 获取纹理宽度 int get_width() const; // 获取纹理高度 int get_height() const; }; class gl_context { private: std::unordered_map<TextureID, TextureData> textures_; TextureID next_available_id_ = 0; // 让gl_texture能访问内部的textures_ friend struct gl_texture; TextureID generate_unique_id() { return next_available_id_++; } public: gl_texture gen_texture() { TextureID id = generate_unique_id(); GLuint gl_id; glGenTextures(1, &gl_id); glBindTexture(GL_TEXTURE_2D, gl_id); // 设置默认参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); textures_[id] = {gl_id, 0, 0}; return gl_texture(this, id); } void set_data(gl_texture tex, int width, int height, unsigned char* data) { auto& tex_data = textures_.at(tex.id_); glBindTexture(GL_TEXTURE_2D, tex_data.gl_texture_id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); tex_data.width = width; tex_data.height = height; } }; int gl_texture::get_width() const { return ctx_->textures_.at(id_).width; } int gl_texture::get_height() const { return ctx_->textures_.at(id_).height; }
3. 值语义+观察者模式(不推荐)
如果坚持使用值语义的gl_texture,可以给每个纹理实例维护一个观察者列表,当gl_context修改纹理状态时,通知所有持有副本的实例更新。但这种实现复杂,容易出现性能瓶颈或通知遗漏,仅适合特殊场景,一般不推荐。
内容的提问来源于stack exchange,提问作者Lorenzo Celli
相关产品推荐
相关产品推荐

