- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近一直在苦苦挣扎,因为我不得不更改我不久前编写的一些代码以在 Qt
中进行图像处理和 OpenGl
以支持多线程。
问题是我想用它在一组图像上应用批量过滤器,
我正在使用 openMP 来做这样的多线程:
void batchProcess(QVector<QImage> &images)
{
#pragma omp parallel
{
#pragma omp for schedule(dynamic) nowait
for (int i = 1; i < images.count(); i++)
{
images[i] = ImageProcessing::processImage(images[i], _vertexShader, _fragmentShader, _textureVar, _vertexPosVar, _textureCoordVar);
}
}
}
和
ImageProcessing::processImage()
函数看起来像这样:
QImage ImageProcessing::processImage(const QImage &source, const QString &vertexShader, const QString &fragmentShader, const QString &textureVar, const QString &vertexPosVar, const QString &textureCoordVar)
{
QOpenGLContext context;
if(!context.create())
return source;
QOffscreenSurface surface;
surface.setFormat(context.format());
surface.create();
if(!surface.isValid())
return source;
if(!context.makeCurrent(&surface))
return source;
QOpenGLFramebufferObject fbo(source.size());
context.functions()->glViewport(0, 0, source.width(), source.height());
QOpenGLShaderProgram program(&context);
if (!program.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader))
return source;
if (!program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader))
return source;
if (!program.link())
return source;
if (!program.bind())
return source;
QOpenGLTexture texture(QOpenGLTexture::Target2D);
texture.setData(source);
texture.bind();
if(!texture.isBound())
return source;
VertexData vertices[] =
{
{{ -1.0f, +1.0f }, { 0.0f, 1.0f }}, // top-left
{{ +1.0f, +1.0f }, { 1.0f, 1.0f }}, // top-right
{{ -1.0f, -1.0f }, { 0.0f, 0.0f }}, // bottom-left
{{ +1.0f, -1.0f }, { 1.0f, 0.0f }} // bottom-right
};
GLuint indices[] =
{
0, 1, 2, 3
};
QOpenGLBuffer vertexBuf(QOpenGLBuffer::VertexBuffer);
QOpenGLBuffer indexBuf(QOpenGLBuffer::IndexBuffer);
if(!vertexBuf.create())
return source;
if(!indexBuf.create())
return source;
if(!vertexBuf.bind())
return source;
vertexBuf.allocate(vertices, 4 * sizeof(VertexData));
if(!indexBuf.bind())
return source;
indexBuf.allocate(indices, 4 * sizeof(GLuint));
int offset = 0;
program.enableAttributeArray(vertexPosVar.toLatin1().data());
program.setAttributeBuffer(vertexPosVar.toLatin1().data(), GL_FLOAT, offset, 2, sizeof(VertexData));
offset += sizeof(QVector2D);
program.enableAttributeArray(textureCoordVar.toLatin1().data());
program.setAttributeBuffer(textureCoordVar.toLatin1().data(), GL_FLOAT, offset, 2, sizeof(VertexData));
program.setUniformValue(textureVar.toLatin1().data(), 0);
context.functions()->glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, Q_NULLPTR);
return fbo.toImage(false);
}
当
OpenMP
时它工作正常已禁用,但是当我启用它时,出现以下错误:
Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.
QOffscreenSurface
只是一个隐藏的
QWindow
在某些平台上,这意味着它只能从主线程创建或销毁。
QOffscreenSurface
在主线程中,我关注了这个
answer并实现了以下类
class OpenGlFilterPrivate : public QObject
{
Q_OBJECT
public:
enum CustomEventTypes
{
CreateSurface = QEvent::User,
CreateContext = QEvent::User + 1,
CreateProgram = QEvent::User + 2
};
void moveToMainThread()
{
moveToThread(QApplication::instance()->thread());
}
virtual bool event(QEvent *event )
{
switch (event->type())
{
case CreateSurface: // m_surface (create an offscreen surface from the main thread)
m_surface = QSharedPointer<QOffscreenSurface>::create();
m_surface->setFormat(m_context->format());
m_surface->create();
break;
case CreateContext: // m_context (create an openGl context from the main thread)
m_context = QSharedPointer<QOpenGLContext>::create();
break;
case CreateProgram: // m_shaderProgram (create an openGl shader program from the main thread)
m_shaderProgram = QSharedPointer<QOpenGLShaderProgram>::create(&*m_context);
}
return false;
}
QSharedPointer<QOpenGLContext> m_context;
QSharedPointer<QOffscreenSurface> m_surface;
QSharedPointer<QOpenGLShaderProgram> m_shaderProgram;
};
现在而不是直接创建一个
QOffscreenSurface
在我的
processImage
功能我执行以下操作:
OpenGlFilterPrivate openGlFilterPrivate;
openGlFilterPrivate.moveToMainThread();
QCoreApplication::postEvent(&openGlFilterPrivate, new QEvent(QEvent::Type(OpenGlFilterPrivate::CreateSurface)));
QSharedPointer<QOffscreenSurface> surface = openGlFilterPrivate.m_surface;
它有效,但现在我不断收到以下消息:
QObject::~QObject: Timers cannot be stopped from another thread
QObject
包含
QTimer
在内部,这就是导致问题的原因,但我想不出任何其他方法来解决这个问题。
openGl
应用一些图像处理过滤器或任何其他硬件加速方法,同时有能力在
thread-safe
中做到这一点道路。
QPainter
相同的方法来完成,它是线程安全的,据我所知,它是使用 OpenGL 进行硬件加速的。但我找不到关于如何做这样的事情的任何资源。 最佳答案
哦,我的,OpenMP 和 OpenGL 可能不能很好地混合。 OpenMP 创建多线程的方式并没有固定在 OpenGL 实现可以访问的方面。它很可能使用常规 POSIX 线程或 Windows native 线程。但它也可以是其他任何东西,在同一地址空间内创建额外的任务。
我认为创建一个由 N 个线程组成的池会更加健壮和容易,每个线程都有自己的共享 OpenGL 上下文,然后使用工作窃取来安排任务;使 OpenGL 在工作集之间的线程上保持最新状态。
使用现代 OpenGL 非常方便,甚至不需要窗口或类似的可绘制对象来使上下文成为当前状态。 glXMakeContextCurrent和 wglMakeContextCurrent将接受 drawables/HDC 的 Nil 参数。因此,您可以对帧缓冲区对象和所有其他内容执行 OpenGL 操作,唯一需要注意的是,没有主要的默认帧缓冲区。
随意使用这些代码片段来创建帮助器上下文。
#include "wglu_context.h"
#include <windows.h>
#include <GL/gl.h>
#include <GL/wglext.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
static char const *wgl_create_context_attribs_name = "wglCreateContextAttribsARB";
static
int wglu_get_proc_address(char const *name, PROC *pproc)
{
int rc= 0;
*pproc = wglGetProcAddress(name);
fprintf(stderr, "%s: %p\n", name, (void*)*pproc );
if( !(*pproc) ){
rc= GetLastError();
fprintf(stderr,
"error wglGetProcAddress('%s'): 0x%x\n",
name, rc);
}
if( rc ){ fprintf(stderr, "%s: %d\n", __func__, rc); }
return rc;
}
/* -----------------------------------------------------------------------
* Create a OpenGL context of desired version and share it */
int wglu_create_context_with_sharing(
int major, int minor, int profile,
HDC surface,
HGLRC share_context,
HGLRC *out_context )
{
int rc= 0;
int attribs[8] = {0};
size_t i_attrib = 0;
HGLRC context = 0;
HDC const save_surface = wglGetCurrentDC();
HGLRC const save_context = wglGetCurrentContext();
if( save_surface != surface
|| save_context != share_context
){
wglMakeCurrent(surface, share_context);
}
PFNWGLCREATECONTEXTATTRIBSARBPROC wgl_create_context_attribs;
if( (rc= wglu_get_proc_address(
wgl_create_context_attribs_name,
(PROC*)&wgl_create_context_attribs))
){
goto fail;
}
if( major ){
attribs[i_attrib++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attribs[i_attrib++] = major;
}
if( minor ){
attribs[i_attrib++] = WGL_CONTEXT_MINOR_VERSION_ARB;
attribs[i_attrib++] = minor;
}
if( profile ){
attribs[i_attrib++] = WGL_CONTEXT_PROFILE_MASK_ARB;
attribs[i_attrib++] = profile;
}
attribs[i_attrib] = attribs[i_attrib+1] = 0;
context = wgl_create_context_attribs(surface, *share_context, attribs);
if( !context ){
rc= GetLastError();
fprintf(stderr,
"error %s(surface=0x%x, share_context=0x%x, attribs=0x%p): %x\n",
wgl_create_context_attribs_name,
(uintptr_t)surface, (uintptr_t)share_context,
attribs,
rc );
goto fail;
}
if( !(wglMakeCurrent(surface, context)) ){
rc= GetLastError();
fprintf(stderr,
"error %s(surface=0x%x, contest=0x%x): 0x%x\n",
"wglMakeCurrent",
(uintptr_t)surface, (uintptr_t)context,
rc );
goto fail;
}
assert( context == wglGetCurrentContext() );
fprintf(stderr,
"GL_VENDOR = %s\n"
"GL_RENDERER = %s\n"
"GL_VERSION = %s\n",
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION) );
if( !(wglMakeCurrent(NULL, NULL)) ){
rc= GetLastError();
fprintf(stderr,
"error %s(0, 0): 0x%x\n",
"wglMakeCurrent",
(uintptr_t)surface, (uintptr_t)context,
rc );
goto fail;
}
if( !(wglShareLists(context, share_context)) ){
rc= GetLastError();
fprintf(stderr,
"error %s(context=0x%x, share_context=0x%x): 0x%x\n",
"wglShareLists",
(uintptr_t)context, (uintptr_t)share_context,
rc );
goto fail;
}
wglMakeCurrent(save_surface, save_context);
if( !rc ){
if( out_context ){ *out_context = context; }
} else {
if( context ){ wglDeleteContext(context); }
}
if( rc ){ fprintf(stderr, "%s: %d\n", __func__, rc); }
return rc;
}
#include <GL/glxext.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <dlfcn.h>
static char const *glX_create_context_attribs_name = "glXCreateContextAttribsARB";
typedef void (*PROC)();
static
int glxu_get_proc_address(char const *name, PROC *pproc)
{
int rc= 0;
static PROC (*glX_get_proc_address)(char const*) = NULL;
if( !glX_get_proc_address ){
*(void**)(&glX_get_proc_address) = dlsym(RTLD_DEFAULT, "glXGetProcAddress");
}
if( !glX_get_proc_address ){
rc = -EFAULT;
} else {
*pproc = glX_get_proc_address(name);
fprintf(stderr, "%s: %p\n", name, (void*)*pproc );
if( !(*pproc) ){
rc= -ENOENT;
fprintf(stderr, "error glXGetProcAddress('%s'): so such function\n", name);
}
}
if( rc ){ fprintf(stderr, "%s: %d\n", __func__, rc); }
return rc;
}
static
int glxu_get_fbconfig_for_xid(
Display *display,
GLXFBConfigID const id,
GLXFBConfig *out_fbconfig )
{
static GLXFBConfig* (*glX_get_fb_configs)(Display*,int,int*) = NULL;
static int (*glX_get_fb_config_attrib)(Display*,GLXFBConfig,int,int*) = NULL;
if( !glX_get_fb_configs ){
*(void**)(&glX_get_fb_configs) = dlsym(RTLD_DEFAULT, "glXGetFBConfigs");
}
if( !glX_get_fb_config_attrib ){
*(void**)(&glX_get_fb_config_attrib) = dlsym(RTLD_DEFAULT, "glXGetFBConfigAttrib");
}
int rc = 0;
int n_configs = 0;
/* we always assume to operate on screen 0, since hardly any X connection
* encountered these days actually operates on multiple screens. */
if( !glX_get_fb_configs || !glX_get_fb_config_attrib ){
rc = -EFAULT;
} else {
GLXFBConfig *const fbconfig = glX_get_fb_configs(display, 0, &n_configs);
for(int i=0; !rc && i < n_configs; ++i){
unsigned int qry_id;
rc= glX_get_fb_config_attrib(display, fbconfig[i], GLX_FBCONFIG_ID, &qry_id);
if( !rc && id == qry_id ){
*out_fbconfig = fbconfig[i];
break;
}
}
}
return rc;
}
Display *glxu_get_current_display(void)
{
static Display* (*glX_get_current_display)(void) = NULL;
if( !glX_get_current_display ){
*(void**)(&glX_get_current_display) = dlsym(RTLD_DEFAULT, "glXGetCurrentDisplay");
}
if( !glX_get_current_display ){
return NULL;
}
return glX_get_current_display();
}
GLXDrawable glxu_get_current_drawable(void)
{
static GLXDrawable (*glX_get_current_drawable)(void) = NULL;
if( !glX_get_current_drawable ){
*(void**)(&glX_get_current_drawable) = dlsym(RTLD_DEFAULT, "glXGetCurrentDrawable");
}
if( !glX_get_current_drawable ){
return 0;
}
return glX_get_current_drawable();
}
/* -----------------------------------------------------------------------
* Create a OpenGL context of desired version and share it */
int glxu_create_context_with_sharing(
int major, int minor, int profile,
Display *display,
GLXDrawable surface,
GLXContext share_context,
GLXContext *out_context )
{
int rc= 0;
int attribs[8] = {0};
size_t i_attrib = 0;
GLXContext context = 0;
unsigned int fbconfigxid = 0;
GLXFBConfig fbconfig = 0;
static GLXContext (*glX_get_current_context)(void) = NULL;
static void (*glX_query_drawable)(Display*,GLXDrawable,int,unsigned*) = NULL;
static Bool (*glX_make_current)(Display*,Drawable,GLXContext) = NULL;
static void (*glX_destroy_context)(Display*,GLXContext) = NULL;
if( !glX_get_current_context ){
*(void**)(&glX_get_current_context) = dlsym(RTLD_DEFAULT, "glXGetCurrentContext");
}
if( !glX_query_drawable ){
*(void**)(&glX_query_drawable) = dlsym(RTLD_DEFAULT, "glXQueryDrawable");
}
if( !glX_make_current ){
*(void**)(&glX_make_current) = dlsym(RTLD_DEFAULT, "glXMakeCurrent");
}
if( !glX_destroy_context ){
*(void**)(&glX_destroy_context) = dlsym(RTLD_DEFAULT, "glXDestroyContext");
}
if( !glX_get_current_context || !glX_query_drawable
|| !glX_make_current || !glX_destroy_context
){
return -EFAULT;
}
Display *const save_display = glxu_get_current_display();
GLXDrawable const save_surface = glxu_get_current_drawable();
GLXContext const save_context = glX_get_current_context();
if( !display ){ display = save_display; }
if( !surface ){ surface = save_surface; }
if( !share_context ){ share_context = save_context; }
if( save_display != display
|| save_surface != surface
|| save_context != share_context
){
fprintf(stderr, ".....\n");
if( !(glX_make_current(display, surface, share_context)) ){
rc = -1;
goto fail;
}
}
PFNGLXCREATECONTEXTATTRIBSARBPROC glX_create_context_attribs;
if( (rc= glxu_get_proc_address(
glX_create_context_attribs_name,
(PROC*)&glX_create_context_attribs))
){
rc = -2;
goto fail;
}
glX_query_drawable(display, surface, GLX_FBCONFIG_ID, &fbconfigxid);
glxu_get_fbconfig_for_xid(display, fbconfigxid, &fbconfig);
if( major ){
attribs[i_attrib++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
attribs[i_attrib++] = major;
}
if( minor ){
attribs[i_attrib++] = GLX_CONTEXT_MINOR_VERSION_ARB;
attribs[i_attrib++] = minor;
}
if( profile ){
attribs[i_attrib++] = GLX_CONTEXT_PROFILE_MASK_ARB;
attribs[i_attrib++] = profile;
}
attribs[i_attrib] = attribs[i_attrib+1] = 0;
context = glX_create_context_attribs(display, fbconfig, share_context, True, attribs);
if( !context ){
rc= -3;
fprintf(stderr,
"error %s(surface=0x%p, share_context=0x%p, attribs=0x%p): %x\n",
glX_create_context_attribs_name,
(void*)surface, (void*)share_context,
attribs,
rc );
goto fail;
}
if( !(glX_make_current(display, surface, context)) ){
rc= -4;
fprintf(stderr,
"error %s(surface=0x%p, contest=0x%p): 0x%x\n",
"wglMakeCurrent",
(void*)surface, (void*)context,
rc );
goto fail;
}
assert( context == glX_get_current_context() );
fprintf(stderr,
"GL_VENDOR = %s\n"
"GL_RENDERER = %s\n"
"GL_VERSION = %s\n",
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION) );
fail:
glX_make_current(display, save_surface, save_context);
if( !rc ){
if( out_context ){ *out_context = context; }
} else {
if( context ){ glX_destroy_context(display, context); }
}
if( rc ){ fprintf(stderr, "%s: %d\n", __func__, rc); }
return rc;
}
Bool glxu_make_context_current(
Display* display,
GLXDrawable read, GLXDrawable draw,
GLXContext ctx )
{
static Bool (*glX_make_context_current)(Display*,Drawable,Drawable,GLXContext) = NULL;
if( !glX_make_context_current ){
*(void**)(&glX_make_context_current) = dlsym(RTLD_DEFAULT, "glXMakeContextCurrent");
}
if( !glX_make_context_current ){
return False;
}
return glX_make_context_current(display, read, draw, ctx);
}
关于c++ - 我如何创建一个线程安全的 QOffscreenSurface 供 OpenGl 使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65560109/
我最近一直在苦苦挣扎,因为我不得不更改我不久前编写的一些代码以在 Qt 中进行图像处理和 OpenGl以支持多线程。 问题是我想用它在一组图像上应用批量过滤器, 我正在使用 openMP 来做这样的多
我是一名优秀的程序员,十分优秀!