问题描述
通过 OpenGL 的几个特性,使用 OpenGL 进行多线程是一个相当困难的主题。尽管存在共享上下文,但不能保证 OpenGL 资源在上下文之间正确初始化、上传和共享,并且跟踪什至能够共享的资源类型本身就是一个小问题(是的,保留一个列表(in-)official docs 是可能的,仍然没有单一的方法来处理所有资源类型而不求助于有问题的解决方案。
我得到的一个建议是,在主线程上上传到 GPU 的同时,在单独的线程中处理从磁盘加载资源。加载屏幕的绝佳机会。
所以我想做几个步骤来优化这个过程。因此,我将要上传到 GPU 的数据拆分为 GPU 上的句柄(Texture 类)和 cpu 上的数据(TextureData 类)。
class TextureData { // Data can be copied without a problem
gluint width;
gluint height;
GLvoid *data;
public:
friend void swap(TextureData &a,TextureData &b) noexcept {
using std::swap;
swap(a.width,b.width);
swap(a.height,b.height);
swap(a.data,b.data);
}
TextureData() : width(0),height(0),data(nullptr) {}
TextureData(std::string filename);
TextureData(gluint width,gluint height,GLvoid* data) : width(width),height(height),data(data) {}
// There is a conceptual problem with ownership of the data pointer about this constructor though
TextureData(TextureData &other) : width(other.width),height(other.height),data(other.data) {}
// Similarily here ...
TextureData(TextureData &&other) : TextureData()
{
using std::swap;
swap(*this,other);
}
TextureData & operator=(TextureData other)
{
using std::swap;
swap(*this,other);
return *this;
}
~TextureData() {
delete data; // I expect the pointer isn't needed anymore after uploading the data but if there is a better way to make ownership of the data pointer more clear,feel free to elaborate
}
gluint get_width() {
return this->width;
}
gluint get_height() {
return this->height;
}
GLvoid *get_data() {
return this->data;
}
};
与其他一切相关的实际纹理很简单:
class Texture { // Handles a resource handle (the numerical ID of the texture) and therefore is not copiable
gluint texture;
gluint width;
gluint height;
public:
Texture();
Texture(TextureData &data); // In theroy,data can be freed right after construction
Texture(gluint width,GLvoid* data); // Similar here
Texture(Texture &&temp); // Move Constructor
~Texture();
Texture & operator=(Texture &&temp); // Move Assignment
#ifdef ALLOW_TEXTURE_copY
Texture(const Texture ©);
Texture &operator=(const Texture ©);
#endif
void bind();
gluint get_name() const { return this->texture; }
gluint get_width() const { return this->width; }
gluint get_height() const { return this->height; }
void read_size(gluint &width,gluint &height) const;
};
因此,如果我想在场景中绘制图像,例如:
class Scene {
struct TextureInfo {
TextureData *data;
Texture &resource;
};
Texture image;
std::mutex load_mutex;
std::vector<TextureInfo> loaded;
public:
Scene(ThreadPool pool) {
pool.task([this](){
TextureInfo info;
info.data = load_image("res/image.png");
info.resource = this->image;
std::unique_lock<std::mutex> lock(this->load_mutex);
this->loaded.emplace_back(info);
});
}
void draw(Renderer r) {
if(!all_resources_loaded) { // however I find that out
draw_loading_screen(); // spinning wheels wheeeeeee
} else {
r.draw_image(0,image);
}
}
void update(double time) { // gets called in the main thread the OpenGL context is made current in ; also: double time *drums the beat*
{
std::unique_lock<std::mutex> lock(this->load_mutex);
for(TextureInfo info : this->loaded) {
info.resource = Texture(*info.data);
//glFinish();
/* I remember a case where the upload itself is actually off-thread and
* therefore the deletion of the data in the next line can corrupt the data
* that openGL fetches in the meantime,but I have no idea if that was
* because of the shared context I used before or because of some other
* reason */
delete info.data;
}
this->loaded.clear();
}
if(!all_resources_loaded) {
update_loading_screen();
} else {
update_scene();
}
}
所以我的问题基本上是......这是理智的吗?有替代品吗?关于什么是资源和什么不是资源的假设是否正确?会不会有重大改进的策略?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)