You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:45:39