qt: More error handling and tweaking to opengl 3 renderer
This commit is contained in:
@@ -172,7 +172,7 @@ OpenGLOptions::addShader(const QString &path)
|
|||||||
if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % "\n#extension GL_ARB_shading_language_420pack : enable\n" % "\n#define VERTEX\n" % shader_text))
|
if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % "\n#extension GL_ARB_shading_language_420pack : enable\n" % "\n#define VERTEX\n" % shader_text))
|
||||||
throw_shader_error(tr("Error compiling vertex shader in file \"%1\""));
|
throw_shader_error(tr("Error compiling vertex shader in file \"%1\""));
|
||||||
|
|
||||||
if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % "\n#extension GL_ARB_shading_language_420pack : enable\n" "\n#define FRAGMENT\n" % shader_text))
|
if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % "\n#extension GL_ARB_shading_language_420pack : enable\n" % "\n#define FRAGMENT\n" % shader_text))
|
||||||
throw_shader_error(tr("Error compiling fragment shader in file \"%1\""));
|
throw_shader_error(tr("Error compiling fragment shader in file \"%1\""));
|
||||||
|
|
||||||
if (!shader->link())
|
if (!shader->link())
|
||||||
|
@@ -18,8 +18,8 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
|
#include <QStringBuilder>
|
||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
#include <QOpenGLTexture>
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@@ -44,18 +44,13 @@ OpenGLRenderer::OpenGLRenderer(QWidget *parent)
|
|||||||
|
|
||||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
||||||
format.setMajorVersion(3);
|
format.setMajorVersion(3);
|
||||||
format.setMinorVersion(0);
|
format.setMinorVersion(2);
|
||||||
|
|
||||||
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
|
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
|
||||||
format.setRenderableType(QSurfaceFormat::OpenGLES);
|
format.setRenderableType(QSurfaceFormat::OpenGLES);
|
||||||
|
|
||||||
setFormat(format);
|
setFormat(format);
|
||||||
|
|
||||||
context = new QOpenGLContext(this);
|
|
||||||
|
|
||||||
context->setFormat(format);
|
|
||||||
|
|
||||||
context->create();
|
|
||||||
|
|
||||||
parentWidget = parent;
|
parentWidget = parent;
|
||||||
|
|
||||||
source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT);
|
source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT);
|
||||||
@@ -108,21 +103,22 @@ OpenGLRenderer::event(QEvent *event)
|
|||||||
void
|
void
|
||||||
OpenGLRenderer::initialize()
|
OpenGLRenderer::initialize()
|
||||||
{
|
{
|
||||||
if (!context->makeCurrent(this)) {
|
try {
|
||||||
/* TODO: This could be done much better */
|
context = new QOpenGLContext(this);
|
||||||
QMessageBox::critical((QWidget *) qApp->findChild<QWindow *>(), tr("Error initializing OpenGL"), tr("Error setting OpenGL context. Falling back to software rendering."));
|
|
||||||
context->doneCurrent();
|
context->setFormat(format());
|
||||||
isFinalized = true;
|
|
||||||
isInitialized = true;
|
if (!context->create())
|
||||||
emit errorInitializing();
|
throw opengl_init_error(tr("Couldn't create OpenGL context."));
|
||||||
return;
|
|
||||||
}
|
if (!context->makeCurrent(this))
|
||||||
|
throw opengl_init_error(tr("Couldn't switch to OpenGL context."));
|
||||||
|
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
|
|
||||||
setupExtensions();
|
initializeExtensions();
|
||||||
|
|
||||||
setupBuffers();
|
initializeBuffers();
|
||||||
|
|
||||||
/* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */
|
/* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */
|
||||||
const GLfloat surface[] = {
|
const GLfloat surface[] = {
|
||||||
@@ -160,12 +156,30 @@ OpenGLRenderer::initialize()
|
|||||||
glViewport(
|
glViewport(
|
||||||
destination.x(),
|
destination.x(),
|
||||||
destination.y(),
|
destination.y(),
|
||||||
destination.width(),
|
destination.width() * devicePixelRatio(),
|
||||||
destination.height());
|
destination.height() * devicePixelRatio());
|
||||||
|
|
||||||
|
GLenum error = glGetError();
|
||||||
|
if (error != GL_NO_ERROR)
|
||||||
|
throw opengl_init_error(tr("OpenGL initialization failed. Error %1.").arg(error));
|
||||||
|
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
|
|
||||||
emit initialized();
|
emit initialized();
|
||||||
|
|
||||||
|
} catch (const opengl_init_error &e) {
|
||||||
|
/* Mark all buffers as in use */
|
||||||
|
for (auto &flag : buf_usage)
|
||||||
|
flag.test_and_set();
|
||||||
|
|
||||||
|
QMessageBox::critical((QWidget *) qApp->findChild<QWindow *>(), tr("Error initializing OpenGL"), e.what() % tr("\nFalling back to software rendering."));
|
||||||
|
|
||||||
|
context->doneCurrent();
|
||||||
|
isFinalized = true;
|
||||||
|
isInitialized = true;
|
||||||
|
|
||||||
|
emit errorInitializing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -174,6 +188,8 @@ OpenGLRenderer::finalize()
|
|||||||
if (isFinalized)
|
if (isFinalized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
renderTimer->stop();
|
||||||
|
|
||||||
context->makeCurrent(this);
|
context->makeCurrent(this);
|
||||||
|
|
||||||
if (hasBufferStorage)
|
if (hasBufferStorage)
|
||||||
@@ -203,7 +219,7 @@ OpenGLRenderer::getOptions(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenGLRenderer::setupExtensions()
|
OpenGLRenderer::initializeExtensions()
|
||||||
{
|
{
|
||||||
#ifndef NO_BUFFER_STORAGE
|
#ifndef NO_BUFFER_STORAGE
|
||||||
if (context->hasExtension("GL_ARB_buffer_storage")) {
|
if (context->hasExtension("GL_ARB_buffer_storage")) {
|
||||||
@@ -215,7 +231,7 @@ OpenGLRenderer::setupExtensions()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OpenGLRenderer::setupBuffers()
|
OpenGLRenderer::initializeBuffers()
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &unpackBufferID);
|
glGenBuffers(1, &unpackBufferID);
|
||||||
|
|
||||||
@@ -232,6 +248,9 @@ OpenGLRenderer::setupBuffers()
|
|||||||
/* Fallback; create our own buffer. */
|
/* Fallback; create our own buffer. */
|
||||||
unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT);
|
unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT);
|
||||||
|
|
||||||
|
if (unpackBuffer == nullptr)
|
||||||
|
throw opengl_init_error(tr("Allocating memory for unpack buffer failed."));
|
||||||
|
|
||||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW);
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,7 +394,7 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h)
|
|||||||
|
|
||||||
/* Resize the texture */
|
/* Resize the texture */
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, (GLenum)QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum)QOpenGLTexture::BGRA, (GLenum)QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
|
glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +403,7 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h)
|
|||||||
|
|
||||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x);
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH);
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum)QOpenGLTexture::BGRA, (GLenum)QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL);
|
||||||
|
|
||||||
/* TODO: check if fence sync is implementable here and still has any benefit. */
|
/* TODO: check if fence sync is implementable here and still has any benefit. */
|
||||||
glFinish();
|
glFinish();
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <stdexcept>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -90,8 +91,8 @@ private:
|
|||||||
void *unpackBuffer = nullptr;
|
void *unpackBuffer = nullptr;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void setupExtensions();
|
void initializeExtensions();
|
||||||
void setupBuffers();
|
void initializeBuffers();
|
||||||
void applyOptions();
|
void applyOptions();
|
||||||
void applyShader(const OpenGLShaderPass &shader);
|
void applyShader(const OpenGLShaderPass &shader);
|
||||||
bool notReady() const { return !isInitialized || isFinalized; }
|
bool notReady() const { return !isInitialized || isFinalized; }
|
||||||
@@ -107,4 +108,12 @@ private slots:
|
|||||||
void updateOptions(OpenGLOptions *newOptions);
|
void updateOptions(OpenGLOptions *newOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class opengl_init_error : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
opengl_init_error(const QString &what)
|
||||||
|
: std::runtime_error(what.toStdString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -272,6 +272,7 @@ RendererStack::createRenderer(Renderer renderer)
|
|||||||
});
|
});
|
||||||
connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
|
connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
|
||||||
/* Renderer could initialize, fallback to software. */
|
/* Renderer could initialize, fallback to software. */
|
||||||
|
imagebufs = {};
|
||||||
endblit();
|
endblit();
|
||||||
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
|
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
|
||||||
});
|
});
|
||||||
@@ -299,7 +300,7 @@ RendererStack::createRenderer(Renderer renderer)
|
|||||||
void
|
void
|
||||||
RendererStack::blit(int x, int y, int w, int h)
|
RendererStack::blit(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || std::get<std::atomic_flag *>(imagebufs[currentBuf])->test_and_set()) {
|
if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || imagebufs.empty() || std::get<std::atomic_flag *>(imagebufs[currentBuf])->test_and_set()) {
|
||||||
video_blit_complete();
|
video_blit_complete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user