4 c++ opengl multithreading textures
我正在创建一个新应用程序,我想支持多线程纹理加载。如何在单独的线程上将纹理加载到主内存?
我正在使用 SDL2 加载 png 文件。我创建了一个线程安全队列类,SDL_Surface surface使用IMG_Load函数将图像加载到队列中,将表面推送到队列,如果队列不为空,我会获取推送表面的像素并将其添加到纹理缓冲区 -glTexImage2D()
LoadingThread我尝试在function 和 on上放置断点Texture::LoadFromFile(),但当前不会命中断点。调试器目标代码类型的可执行代码没有与此行关联。可能的原因包括:条件编译、编译器优化、当前调试器代码类型不支持该行的目标体系结构。我正在调试(禁用优化)64 位上运行。
template<typename T>
class ThreadSafeQueue
{
public:
ThreadSafeQueue() {}
~ThreadSafeQueue() {}
void Push(T d)
{
std::unique_lock<std::mutex> locker(mutex);
data.push(std::move(d));
locker.unlock();
cond.notify_one();
}
T* get()
{
std::unique_lock<std::mutex> locker(mutex);
cond.wait(locker, [=]() { return stop || !data.empty(); });
if (stop && data.empty()) {
nullptr;
}
T res = std::move(data.front());
data.pop();
return &res;
}
bool Empty()
{
std::lock_guard<std::mutex> guard(mutex);
return data.empty();
}
std::queue<T> data;
std::mutex mutex;
std::condition_variable cond;
bool stop = false;
};
ThreadSafeQueue<SDL_Surface*> queue;
void LoadingThread(const std::string& path)
{
SDL_Surface* surf = std::async(std::launch::async, IMG_Load, path.c_str()).get();
queue.Push(surf);
}
void Texture::LoadFromFile(const std::string& path)
{
LoadingThread(path);
SDL_Surface* surface = nullptr;
if (!queue.data.empty() && path != "") {
surface = *queue.get();
if(surface) {
w = surface->w;
h = surface->h;
pixels = surface->pixels;
} else return;
} else return;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Draw()
{
drawThread = std::make_unique<std::thread>([&]() {
drawContext->MakeCurrent();
renderer2D.Create(window);
std::unique_ptr<Texture> texture = Texture::LoadPNG("Textures/test.png");
while (!quit) {
//glClearColor - I prefere 0 - 255 format
Renderer::ClearColor(sinf(SDL_GetTicks() / 500.0f) * 255.0f, 0.0f, 255.0f, 255.0f);
//glClear() color buffer bit default
Renderer::ClearBuffers();
//simple batch renderer
renderer2D.RenderClear();
renderer2D->Draw(texture, { 0.0f, 0.0f, 50.0f, 50.0f });
renderer2D.RenderPresent();
window.SwapWindows();
}
});
}
Run Code Online (Sandbox Code Playgroud)
现在,程序停止并等待纹理加载并渲染。我希望它在加载纹理时运行,并且当加载纹理时,程序将渲染纹理(渲染不是问题)。
这个问题有两个部分:
您需要在渲染线程和加载线程上设置 OpenGL 上下文,并将它们配置为共享资源。我只用 Qt 做过这个,但这个 SDL2 线程听起来很有前途。这允许您调用LoadFromFile加载线程并生成可从两个上下文访问的 OpenGL 纹理 ID。
您的想法是正确的std::async,但随后选择立即阻止。相反,您应该将返回的值存储std::future在某处,并检查它是否存在.valid()于渲染循环的每次迭代中。一旦它变得有效,获取结果并将其存储在渲染循环的本地状态中。(即局部变量)显然,从那时起您就不再需要检查未来了。
更通用的机制可能是将std::map<std::string, GLenum>纹理名称映射到 OpenGL 纹理 ID。加载的纹理可以初始化为已知无效的枚举,而加载的纹理将包含纹理 ID。
| 归档时间: |
|
| 查看次数: |
1765 次 |
| 最近记录: |