From 05ac0314d7b3dedf44d70b2f2607a91a8696ac76 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 17 Mar 2019 18:19:12 +1100 Subject: [PATCH] nearly finished gles transition --- effects/effect.cpp | 57 +++--- effects/effect.h | 41 ++-- effects/effectfield.cpp | 4 +- effects/effectgizmo.h | 2 +- effects/internal/cornerpineffect.cpp | 34 ++-- effects/internal/shakeeffect.cpp | 13 +- effects/internal/texteffect.cpp | 4 +- effects/internal/transformeffect.cpp | 49 +++-- olive.pro | 6 +- rendering/framebufferobject.cpp | 14 +- rendering/qopenglshaderprogramptr.cpp | 2 + rendering/qopenglshaderprogramptr.h | 8 + rendering/renderfunctions.cpp | 266 ++++++++++++++------------ rendering/renderfunctions.h | 16 ++ rendering/renderthread.cpp | 74 ++++--- rendering/renderthread.h | 6 +- timeline/clip.cpp | 6 +- ui/viewerwidget.cpp | 129 +++---------- ui/viewerwidget.h | 5 +- 19 files changed, 344 insertions(+), 392 deletions(-) create mode 100644 rendering/qopenglshaderprogramptr.cpp create mode 100644 rendering/qopenglshaderprogramptr.h diff --git a/effects/effect.cpp b/effects/effect.cpp index e5f356cf3..e87bae604 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -120,7 +120,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) : parent_clip(c), meta(em), flags_(0), - glslProgram(nullptr), + shader_program_(nullptr), texture(nullptr), isOpen(false), bound(false), @@ -304,9 +304,9 @@ Effect::Effect(Clip* c, const EffectMeta *em) : for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; + if (!meta->path.isEmpty() || (shader_vert_path_.isEmpty() && shader_frag_path_.isEmpty())) return; QList effects_paths = get_effects_paths(); - const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; + const QString& test_fn = shader_vert_path_.isEmpty() ? shader_frag_path_ : shader_vert_path_; for (int i=0;i(); validate_meta_path(); bool glsl_compiled = true; - if (!vertPath.isEmpty()) { - if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { + if (!shader_vert_path_.isEmpty()) { + if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + shader_vert_path_)) { qInfo() << "Vertex shader added successfully"; } else { glsl_compiled = false; qWarning() << "Vertex shader could not be added"; } } - if (!fragPath.isEmpty()) { - if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { + if (!shader_frag_path_.isEmpty()) { + if (shader_program_->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + shader_frag_path_)) { qInfo() << "Fragment shader added successfully"; } else { glsl_compiled = false; @@ -753,7 +753,7 @@ void Effect::open() { } } if (glsl_compiled) { - if (glslProgram->link()) { + if (shader_program_->link()) { qInfo() << "Shader program linked successfully"; } else { qWarning() << "Shader program failed to link"; @@ -771,15 +771,12 @@ void Effect::close() { qWarning() << "Tried to close an effect that was already closed"; } delete_texture(); - if (glslProgram != nullptr) { - delete glslProgram; - glslProgram = nullptr; - } + shader_program_ = nullptr; isOpen = false; } bool Effect::is_glsl_linked() { - return glslProgram != nullptr && glslProgram->isLinked(); + return shader_program_ != nullptr && shader_program_->isLinked(); } void Effect::startEffect() { @@ -789,13 +786,13 @@ void Effect::startEffect() { } if (olive::CurrentRuntimeConfig.shaders_are_enabled && (Flags() & Effect::ShaderFlag) - && glslProgram->isLinked()) { - bound = glslProgram->bind(); + && shader_program_->isLinked()) { + bound = shader_program_->bind(); } } void Effect::endEffect() { - if (bound) glslProgram->release(); + if (bound) shader_program_->release(); bound = false; } @@ -827,9 +824,9 @@ EffectPtr Effect::copy(Clip *c) { } void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { - glslProgram->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); - glslProgram->setUniformValue("time", GLfloat(timecode)); - glslProgram->setUniformValue("iteration", iteration); + shader_program_->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); + shader_program_->setUniformValue("time", GLfloat(timecode)); + shader_program_->setUniformValue("iteration", iteration); for (int i=0;i(field); - glslProgram->setUniformValue(double_field->id().toUtf8().constData(), + shader_program_->setUniformValue(double_field->id().toUtf8().constData(), GLfloat(double_field->GetDoubleAt(timecode))); } break; case EffectField::EFFECT_FIELD_COLOR: { ColorField* color_field = static_cast(field); - glslProgram->setUniformValue( + shader_program_->setUniformValue( color_field->id().toUtf8().constData(), GLfloat(color_field->GetColorAt(timecode).redF()), GLfloat(color_field->GetColorAt(timecode).greenF()), @@ -856,10 +853,10 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { } break; case EffectField::EFFECT_FIELD_BOOL: - glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool()); + shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool()); break; case EffectField::EFFECT_FIELD_COMBO: - glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); + shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); break; // can you even send a string to a uniform value? @@ -1058,7 +1055,7 @@ void Effect::redraw(double) { } bool Effect::valueHasChanged(double timecode) { - if (cachedValues.size() == 0) { + if (cachedValues.isEmpty()) { for (int i=0;i(); QColor after_data = keyframes.at(after_keyframe).data.value(); - value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); + value = QColor(lerp(before_data.red(), after_data.red(), progress), + lerp(before_data.green(), after_data.green(), progress), + lerp(before_data.blue(), after_data.blue(), progress)); } persistent_data_ = value; break; diff --git a/effects/effectgizmo.h b/effects/effectgizmo.h index 30332b21d..e39aa34a2 100644 --- a/effects/effectgizmo.h +++ b/effects/effectgizmo.h @@ -45,7 +45,7 @@ class EffectGizmo : public QObject { public: EffectGizmo(Effect* parent, int type); - QVector world_pos; + QVector world_pos; QVector screen_pos; DoubleField* x_field1; diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index db802503b..632d20ae9 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -63,35 +63,31 @@ CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) bottom_right_gizmo->x_field1 = bottom_right_x; bottom_right_gizmo->y_field1 = bottom_right_y; - vertPath = "cornerpin.vert"; - fragPath = "cornerpin.frag"; + shader_vert_path_ = "cornerpin.vert"; + shader_frag_path_ = "cornerpin.frag"; } void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) { - coords.vertexTopLeftX += top_left_x->GetDoubleAt(timecode); - coords.vertexTopLeftY += top_left_y->GetDoubleAt(timecode); + coords.vertex_top_left += QVector3D(top_left_x->GetDoubleAt(timecode), top_left_y->GetDoubleAt(timecode), 0.0f); - coords.vertexTopRightX += top_right_x->GetDoubleAt(timecode); - coords.vertexTopRightY += top_right_y->GetDoubleAt(timecode); + coords.vertex_top_right += QVector3D(top_right_x->GetDoubleAt(timecode), top_right_y->GetDoubleAt(timecode), 0.0f); - coords.vertexBottomLeftX += bottom_left_x->GetDoubleAt(timecode); - coords.vertexBottomLeftY += bottom_left_y->GetDoubleAt(timecode); + coords.vertex_bottom_left += QVector3D(bottom_left_x->GetDoubleAt(timecode), bottom_left_y->GetDoubleAt(timecode), 0.0f); - coords.vertexBottomRightX += bottom_right_x->GetDoubleAt(timecode); - coords.vertexBottomRightY += bottom_right_y->GetDoubleAt(timecode); + coords.vertex_bottom_right += QVector3D(bottom_right_x->GetDoubleAt(timecode), bottom_right_y->GetDoubleAt(timecode), 0.0f); } void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords, int) { - glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY)); - glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY)); - glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY)); - glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY)); - glslProgram->setUniformValue("perspective", perspective->GetBoolAt(timecode)); + shader_program_->setUniformValue("p0", coords.vertex_bottom_left.x(), coords.vertex_bottom_left.y()); + shader_program_->setUniformValue("p1", coords.vertex_bottom_right.x(), coords.vertex_bottom_right.y()); + shader_program_->setUniformValue("p2", coords.vertex_top_left.x(), coords.vertex_top_left.y()); + shader_program_->setUniformValue("p3", coords.vertex_top_right.x(), coords.vertex_top_right.y()); + shader_program_->setUniformValue("perspective", perspective->GetBoolAt(timecode)); } void CornerPinEffect::gizmo_draw(double, GLTextureCoords &coords) { - top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + top_left_gizmo->world_pos[0] = coords.vertex_top_left; + top_right_gizmo->world_pos[0] = coords.vertex_top_right; + bottom_right_gizmo->world_pos[0] = coords.vertex_bottom_right; + bottom_left_gizmo->world_pos[0] = coords.vertex_bottom_left; } diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index 6467e2bb5..b8b92a496 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -78,15 +78,10 @@ void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int) yoff *= multiplier; rotoff *= rotmult; - coords.vertexTopLeftX += xoff; - coords.vertexTopRightX += xoff; - coords.vertexBottomLeftX += xoff; - coords.vertexBottomRightX += xoff; - - coords.vertexTopLeftY += yoff; - coords.vertexTopRightY += yoff; - coords.vertexBottomLeftY += yoff; - coords.vertexBottomRightY += yoff; + coords.vertex_top_left += QVector3D(xoff, yoff, 0.0); + coords.vertex_top_right += QVector3D(xoff, yoff, 0.0); + coords.vertex_bottom_left += QVector3D(xoff, yoff, 0.0); + coords.vertex_bottom_right += QVector3D(xoff, yoff, 0.0); glRotatef(rotoff, 0, 0, 1); } diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index ee183f0b3..5a805461d 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -151,8 +151,8 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : connect(shadow_bool, SIGNAL(Toggled(bool)), this, SLOT(shadow_enable(bool))); connect(outline_bool, SIGNAL(Toggled(bool)), this, SLOT(outline_enable(bool))); - vertPath = "common.vert"; - fragPath = "dropshadow.frag"; + shader_vert_path_ = "common.vert"; + shader_frag_path_ = "dropshadow.frag"; } void TextEffect::redraw(double timecode) { diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index f623661fd..0e766ff1b 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -198,14 +198,10 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode)); int anchor_y_offset = qRound(anchor_y_box->GetDoubleAt(timecode)); - coords.vertexTopLeftX -= anchor_x_offset; - coords.vertexTopRightX -= anchor_x_offset; - coords.vertexBottomLeftX -= anchor_x_offset; - coords.vertexBottomRightX -= anchor_x_offset; - coords.vertexTopLeftY -= anchor_y_offset; - coords.vertexTopRightY -= anchor_y_offset; - coords.vertexBottomLeftY -= anchor_y_offset; - coords.vertexBottomRightY -= anchor_y_offset; + coords.vertex_top_left -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); + coords.vertex_top_right -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); + coords.vertex_bottom_left -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); + coords.vertex_bottom_right -= QVector3D(anchor_x_offset, anchor_y_offset, 0.0f); // rotation glRotated(rotation->GetDoubleAt(timecode), 0, 0, 1); @@ -223,19 +219,30 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i } void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) { - top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5)); - top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5)); - bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5)); - bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); - left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5)); + top_left_gizmo->world_pos[0] = coords.vertex_top_left; + top_right_gizmo->world_pos[0] = coords.vertex_top_right; + bottom_right_gizmo->world_pos[0] = coords.vertex_bottom_right; + bottom_left_gizmo->world_pos[0] = coords.vertex_bottom_left; - rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1)); + top_center_gizmo->world_pos[0] = QVector3D(lerp(coords.vertex_top_left.x(), coords.vertex_top_right.x(), 0.5), + lerp(coords.vertex_top_left.y(), coords.vertex_top_right.y(), 0.5), + 0.0f); + right_center_gizmo->world_pos[0] = QVector3D(lerp(coords.vertex_top_right.x(), coords.vertex_bottom_right.x(), 0.5), + lerp(coords.vertex_top_right.y(), coords.vertex_bottom_right.y(), 0.5), + 0.0f); + bottom_center_gizmo->world_pos[0] = QVector3D(lerp(coords.vertex_bottom_right.x(), coords.vertex_bottom_left.x(), 0.5), + lerp(coords.vertex_bottom_right.y(), coords.vertex_bottom_left.y(), 0.5), + 0.0f); + left_center_gizmo->world_pos[0] = QVector3D(lerp(coords.vertex_bottom_left.x(), coords.vertex_top_left.x(), 0.5), + lerp(coords.vertex_bottom_left.y(), coords.vertex_top_left.y(), 0.5), + 0.0f); - rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + rotate_gizmo->world_pos[0] = QVector3D(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), + lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1), + 0.0f); + + rect_gizmo->world_pos[0] = coords.vertex_top_left; + rect_gizmo->world_pos[1] = coords.vertex_top_right; + rect_gizmo->world_pos[2] = coords.vertex_bottom_right; + rect_gizmo->world_pos[3] = coords.vertex_bottom_left; } diff --git a/olive.pro b/olive.pro index ad25ff17d..d71a71ddd 100644 --- a/olive.pro +++ b/olive.pro @@ -175,7 +175,8 @@ SOURCES += \ undo/undostack.cpp \ effects/internal/richtexteffect.cpp \ ui/blur.cpp \ - ui/menu.cpp + ui/menu.cpp \ + rendering/qopenglshaderprogramptr.cpp HEADERS += \ ui/mainwindow.h \ @@ -304,7 +305,8 @@ HEADERS += \ undo/undostack.h \ effects/internal/richtexteffect.h \ ui/blur.h \ - ui/menu.h + ui/menu.h \ + rendering/qopenglshaderprogramptr.h FORMS += diff --git a/rendering/framebufferobject.cpp b/rendering/framebufferobject.cpp index bb31ce231..cf2f7d0cb 100644 --- a/rendering/framebufferobject.cpp +++ b/rendering/framebufferobject.cpp @@ -41,19 +41,23 @@ void FramebufferObject::Create(QOpenGLContext *ctx, int width, int height) ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture_); // allocate storage for texture - glTexImage2D( - GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA8, GL_UNSIGNED_BYTE, nullptr + ctx->functions()->glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr ); // set texture filtering to bilinear - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ctx->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ctx->functions()->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // attach texture to framebuffer ctx->extraFunctions()->glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0 + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0 ); + // clear new texture + ctx->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); + // release texture ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); diff --git a/rendering/qopenglshaderprogramptr.cpp b/rendering/qopenglshaderprogramptr.cpp new file mode 100644 index 000000000..f5aeb84af --- /dev/null +++ b/rendering/qopenglshaderprogramptr.cpp @@ -0,0 +1,2 @@ +#include "qopenglshaderprogramptr.h" + diff --git a/rendering/qopenglshaderprogramptr.h b/rendering/qopenglshaderprogramptr.h new file mode 100644 index 000000000..25c8fc6ff --- /dev/null +++ b/rendering/qopenglshaderprogramptr.h @@ -0,0 +1,8 @@ +#ifndef QOPENGLSHADERPROGRAMPTR_H +#define QOPENGLSHADERPROGRAMPTR_H + +#include + +using QOpenGLShaderProgramPtr = std::shared_ptr; + +#endif // QOPENGLSHADERPROGRAMPTR_H diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 32477ee9b..fffdd566b 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -39,71 +39,111 @@ namespace OCIO = OCIO_NAMESPACE; #include "effects/effect.h" #include "project/footage.h" #include "effects/transition.h" - #include "ui/collapsiblewidget.h" - #include "rendering/audio.h" - #include "global/math.h" #include "global/config.h" - #include "panels/timeline.h" #include "panels/viewer.h" +#include "qopenglshaderprogramptr.h" -void full_blit() { - glPushMatrix(); - glLoadIdentity(); - glOrtho(0, 1, 0, 1, -1, 1); +GLfloat olive::rendering::blit_vertices[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, - glBegin(GL_QUADS); - glTexCoord2f(0, 0); // top left - glVertex2f(0, 0); // top left - glTexCoord2f(1, 0); // top right - glVertex2f(1, 0); // top right - glTexCoord2f(1, 1); // bottom right - glVertex2f(1, 1); // bottom right - glTexCoord2f(0, 1); // bottom left - glVertex2f(0, 1); // bottom left - glEnd(); + -1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f +}; - glPopMatrix(); +GLfloat olive::rendering::blit_texcoords[] = { + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0 +}; + +void olive::rendering::Blit(QOpenGLShaderProgram* pipeline) { + QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions(); + + pipeline->bind(); + + pipeline->setUniformValue("mvp_matrix", QMatrix4x4()); + pipeline->setUniformValue("texture", 0); + + GLuint vertex_location = pipeline->attributeLocation("a_position"); + func->glEnableVertexAttribArray(vertex_location); + func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, blit_vertices); + + GLuint tex_location = pipeline->attributeLocation("a_texcoord"); + func->glEnableVertexAttribArray(tex_location); + func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, blit_texcoords); + + func->glDrawArrays(GL_TRIANGLES, 0, 6); + + pipeline->release(); } -void draw_clip(QOpenGLContext* ctx, GLuint fbo, GLuint texture, bool clear) { +QOpenGLShaderProgramPtr olive::rendering::GetPipeline() +{ + QOpenGLShaderProgramPtr program = std::make_shared(); + + program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/pipeline.vert"); + program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/internalshaders/pipeline.frag"); + program->link(); + + return program; +} + +void draw_clip(QOpenGLContext* ctx, + QOpenGLShaderProgram* pipeline, + GLuint fbo, + GLuint texture, + bool clear) { ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); if (clear) { - glClear(GL_COLOR_BUFFER_BIT); + ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); } - glBindTexture(GL_TEXTURE_2D, texture); + ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture); - full_blit(); + olive::rendering::Blit(pipeline); - glBindTexture(GL_TEXTURE_2D, 0); + ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } -GLuint draw_clip(const FramebufferObject& fbo, GLuint texture, bool clear) { +GLuint draw_clip(QOpenGLContext* ctx, + QOpenGLShaderProgram* pipeline, + const FramebufferObject& fbo, + GLuint texture, + bool clear) { fbo.BindBuffer(); if (clear) { - glClear(GL_COLOR_BUFFER_BIT); + ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); } - glBindTexture(GL_TEXTURE_2D, texture); + ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture); - full_blit(); + olive::rendering::Blit(pipeline); - glBindTexture(GL_TEXTURE_2D, 0); + ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); fbo.ReleaseBuffer(); return fbo.texture(); } -void process_effect(Clip* c, +void process_effect(QOpenGLContext* ctx, + QOpenGLShaderProgram* pipeline, + Clip* c, Effect* e, double timecode, GLTextureCoords& coords, @@ -121,7 +161,7 @@ void process_effect(Clip* c, if (can_process_shaders && e->is_glsl_linked()) { for (int i=0;igetIterations();i++) { e->process_shader(timecode, coords, i); - composite_texture = draw_clip(c->fbo[fbo_switcher], composite_texture, true); + composite_texture = draw_clip(ctx, pipeline, c->fbo[fbo_switcher], composite_texture, true); fbo_switcher = !fbo_switcher; } } @@ -140,10 +180,10 @@ void process_effect(Clip* c, // if the source texture is not already a framebuffer texture, // we'll need to make it one before drawing a superimpose effect on it if (composite_texture != c->fbo[0].texture() && composite_texture != c->fbo[1].texture()) { - draw_clip(c->fbo[!fbo_switcher], composite_texture, true); + draw_clip(ctx, pipeline, c->fbo[!fbo_switcher], composite_texture, true); } - composite_texture = draw_clip(c->fbo[!fbo_switcher], superimpose_texture, false); + composite_texture = draw_clip(ctx, pipeline, c->fbo[!fbo_switcher], superimpose_texture, false); } } e->endEffect(); @@ -152,8 +192,6 @@ void process_effect(Clip* c, } GLuint compose_sequence(ComposeSequenceParams ¶ms) { -// qint64 time = QDateTime::currentMSecsSinceEpoch(); - GLuint final_fbo = params.main_buffer; Sequence* s = params.seq; @@ -266,16 +304,19 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } } + QMatrix4x4 projection; + if (params.video) { // set default coordinates based on the sequence, with 0 in the direct center - glPushMatrix(); - glLoadIdentity(); + //glPushMatrix(); + //glLoadIdentity(); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + params.ctx->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); int half_width = s->width/2; int half_height = s->height/2; - glOrtho(-half_width, half_width, -half_height, half_height, -1, 10); + //glOrtho(-half_width, half_width, -half_height, half_height, -1, 10); + projection.ortho(-half_width, half_width, -half_height, half_height, -1, 1); } // loop through current clips @@ -296,9 +337,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // if clip is a video clip if (c->track() < 0) { - // reset OpenGL to full color - glColor4f(1.0, 1.0, 1.0, 1.0); - // textureID variable contains texture to be drawn on screen at the end GLuint textureID = 0; @@ -316,7 +354,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } else { // retrieve ID from c->texture textureID = c->texture->textureId(); - qDebug() << "tex 1" << textureID; } if (textureID == 0) { @@ -339,15 +376,15 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // if clip should actually be shown on screen in this frame if (playhead >= c->timeline_in(true) && playhead < c->timeline_out(true)) { - glPushMatrix(); // simple bool for switching between the two framebuffers bool fbo_switcher = false; - glViewport(0, 0, video_width, video_height); + params.ctx->functions()->glViewport(0, 0, video_width, video_height); if (c->media() != nullptr) { if (c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { + // for a nested sequence, run this function again on that sequence and retrieve the texture // add nested sequence to nest list @@ -361,6 +398,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // compose_sequence() would have written to this clip's fbo[0], so we switch to fbo[1] fbo_switcher = !fbo_switcher; + } else if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { if (!c->media()->to_footage()->alpha_is_premultiplied) { @@ -368,13 +406,11 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // alpha is not premultiplied, we'll need to multiply it for the rest of the pipeline params.ctx->functions()->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ZERO); - qDebug() << "about to draw on" << fbo_switcher; - textureID = draw_clip(c->fbo[fbo_switcher], textureID, true); + textureID = draw_clip(params.ctx, params.pipeline, c->fbo[fbo_switcher], textureID, true); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + params.ctx->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); fbo_switcher = !fbo_switcher; - qDebug() << "tex 3" << textureID << fbo_switcher; } @@ -387,14 +423,12 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { params.ocio_shader->setUniformValue("tex1", 0); params.ocio_shader->setUniformValue("tex2", 2); - qDebug() << "about to draw on" << fbo_switcher; - textureID = draw_clip(c->fbo[fbo_switcher], textureID, true); + textureID = draw_clip(params.ctx, params.pipeline, c->fbo[fbo_switcher], textureID, true); params.ocio_shader->release(); fbo_switcher = !fbo_switcher; - qDebug() << "tex 4" << textureID << fbo_switcher; } #endif @@ -403,15 +437,14 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // set up default coordinates for drawing the clip GLTextureCoords coords; - coords.grid_size = 1; - coords.vertexTopLeftX = coords.vertexBottomLeftX = -video_width/2; - coords.vertexTopLeftY = coords.vertexTopRightY = -video_height/2; - coords.vertexTopRightX = coords.vertexBottomRightX = video_width/2; - coords.vertexBottomLeftY = coords.vertexBottomRightY = video_height/2; - coords.vertexBottomLeftZ = coords.vertexBottomRightZ = coords.vertexTopLeftZ = coords.vertexTopRightZ = 1; - coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0.0; - coords.textureBottomLeftY = coords.textureBottomRightY = coords.textureTopRightX = coords.textureBottomRightX = 1.0; - coords.textureTopLeftQ = coords.textureTopRightQ = coords.textureTopLeftQ = coords.textureBottomLeftQ = 1; + coords.vertex_top_left = QVector3D(-video_width/2, -video_height/2, 0.0f); + coords.vertex_top_right = QVector3D(video_width/2, -video_height/2, 0.0f); + coords.vertex_bottom_left = QVector3D(-video_width/2, video_height/2, 0.0f); + coords.vertex_bottom_right = QVector3D(video_width/2, video_height/2, 0.0f); + coords.texture_top_left = QVector2D(0.0f, 0.0f); + coords.texture_top_right = QVector2D(1.0f, 0.0f); + coords.texture_bottom_left = QVector2D(0.0f, 1.0f); + coords.texture_bottom_right = QVector2D(1.0f, 1.0f); coords.blendmode = -1; coords.opacity = 1.0; @@ -424,9 +457,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { for (int j=0;jeffects.size();j++) { Effect* e = c->effects.at(j).get(); - qDebug() << "about to draw on" << fbo_switcher; - process_effect(c, e, timecode, coords, textureID, fbo_switcher, params.texture_failed, kTransitionNone); - qDebug() << "tex 5" << textureID << fbo_switcher; + process_effect(params.ctx, params.pipeline, c, e, timecode, coords, textureID, fbo_switcher, params.texture_failed, kTransitionNone); } @@ -435,7 +466,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { if (c->opening_transition != nullptr) { int transition_progress = playhead - c->timeline_in(true); if (transition_progress < c->opening_transition->get_length()) { - process_effect(c, c->opening_transition.get(), double(transition_progress)/double(c->opening_transition->get_length()), coords, textureID, fbo_switcher, params.texture_failed, kTransitionOpening); + process_effect(params.ctx, params.pipeline, c, c->opening_transition.get(), double(transition_progress)/double(c->opening_transition->get_length()), coords, textureID, fbo_switcher, params.texture_failed, kTransitionOpening); } } @@ -443,14 +474,16 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { if (c->closing_transition != nullptr) { int transition_progress = playhead - (c->timeline_out(true) - c->closing_transition->get_length()); if (transition_progress >= 0 && transition_progress < c->closing_transition->get_length()) { - process_effect(c, c->closing_transition.get(), double(transition_progress)/double(c->closing_transition->get_length()), coords, textureID, fbo_switcher, params.texture_failed, kTransitionClosing); + process_effect(params.ctx, params.pipeline, c, c->closing_transition.get(), double(transition_progress)/double(c->closing_transition->get_length()), coords, textureID, fbo_switcher, params.texture_failed, kTransitionClosing); } } // == EFFECT CODE END == - // Check whether the parent clip is auto-scaledc + // Check whether the parent clip is auto-scaled + // TODO redo this + /* if (c->autoscaled() && (video_width != s->width && video_height != s->height)) { @@ -459,6 +492,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { float scale_multiplier = qMin(width_multiplier, height_multiplier); glScalef(scale_multiplier, scale_multiplier, 1); } + */ // Configure effect gizmos if they exist if (params.gizmos != nullptr) { @@ -468,7 +502,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { - qDebug() << "final texture ID" << textureID; if (textureID > 0) { // set viewport to sequence size params.ctx->functions()->glViewport(0, 0, s->width, s->height); @@ -496,32 +529,57 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // render a backbuffer params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, back_buffer_1); - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); + params.ctx->functions()->glClearColor(0.0, 0.0, 0.0, 0.0); + params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); // bind final clip texture - glBindTexture(GL_TEXTURE_2D, textureID); + params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, textureID); // set texture filter to bilinear params.ctx->functions()->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); params.ctx->functions()->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // draw clip on screen according to gl coordinates - glBegin(GL_QUADS); + params.pipeline->bind(); - glTexCoord2f(coords.textureTopLeftX, coords.textureTopLeftY); // top left - glVertex2f(coords.vertexTopLeftX, coords.vertexTopLeftY); // top left - glTexCoord2f(coords.textureTopRightX, coords.textureTopRightY); // top right - glVertex2f(coords.vertexTopRightX, coords.vertexTopRightY); // top right - glTexCoord2f(coords.textureBottomRightX, coords.textureBottomRightY); // bottom right - glVertex2f(coords.vertexBottomRightX, coords.vertexBottomRightY); // bottom right - glTexCoord2f(coords.textureBottomLeftX, coords.textureBottomLeftY); // bottom left - glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left + params.pipeline->setUniformValue("mvp_matrix", projection); + params.pipeline->setUniformValue("texture", 0); - glEnd(); + GLfloat vertices[] = { + coords.vertex_top_left.x(), coords.vertex_top_left.y(), 0.0f, + coords.vertex_top_right.x(), coords.vertex_top_right.y(), 0.0f, + coords.vertex_bottom_right.x(), coords.vertex_bottom_right.y(), 0.0f, + + coords.vertex_top_left.x(), coords.vertex_top_left.y(), 0.0f, + coords.vertex_bottom_left.x(), coords.vertex_bottom_left.y(), 0.0f, + coords.vertex_bottom_right.x(), coords.vertex_bottom_right.y(), 0.0f, + }; + + GLfloat texcoords[] = { + coords.texture_top_left.x(), coords.texture_top_left.y(), + coords.texture_top_right.x(), coords.texture_top_right.y(), + coords.texture_bottom_right.x(), coords.texture_bottom_right.y(), + + coords.texture_top_left.x(), coords.texture_top_left.y(), + + coords.texture_bottom_left.x(), coords.texture_bottom_left.y(), + coords.texture_bottom_right.x(), coords.texture_bottom_right.y(), + }; + + GLuint vertex_location = params.pipeline->attributeLocation("a_position"); + params.ctx->functions()->glEnableVertexAttribArray(vertex_location); + params.ctx->functions()->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, vertices); + + GLuint tex_location = params.pipeline->attributeLocation("a_texcoord"); + params.ctx->functions()->glEnableVertexAttribArray(tex_location); + params.ctx->functions()->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, texcoords); + + params.ctx->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); + + params.pipeline->release(); // release final clip texture - glBindTexture(GL_TEXTURE_2D, 0); + params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); @@ -542,9 +600,9 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // copy front buffer to back buffer (only if we're using a blending mode) if (coords.blendmode >= 0) { if (params.nests.size() > 0) { - draw_clip(params.ctx, params.nests.last()->fbo[2].buffer(), params.nests.last()->fbo[0].texture(), true); + draw_clip(params.ctx, params.pipeline, params.nests.last()->fbo[2].buffer(), params.nests.last()->fbo[0].texture(), true); } else { - draw_clip(params.ctx, params.backend_buffer2, params.main_attachment, true); + draw_clip(params.ctx, params.pipeline, params.backend_buffer2, params.main_attachment, true); } } @@ -561,20 +619,14 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // Check if we're using a blend mode (< 0 means no blend mode) if (coords.blendmode < 0) { - qDebug() << "normal blending"; - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_1); - glColor4f(coords.opacity, coords.opacity, coords.opacity, coords.opacity); - - full_blit(); + olive::rendering::Blit(params.pipeline); params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); } else { - qDebug() << "blending mode?"; - // load background texture into texture unit 0 params.ctx->functions()->glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_2); @@ -590,9 +642,9 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { params.blend_mode_program->setUniformValue("background", 0); params.blend_mode_program->setUniformValue("foreground", 1); - glClear(GL_COLOR_BUFFER_BIT); + params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - full_blit(); + olive::rendering::Blit(params.pipeline); // release blend mode shader params.blend_mode_program->release(); @@ -615,18 +667,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // == END FINAL DRAW ON SEQUENCE BUFFER == } - // prepare gizmos - /* - if ((*params.gizmos) != nullptr - && params.nests.isEmpty() - && ((*params.gizmos) == first_gizmo_effect - || (*params.gizmos) == selected_effect)) { - (*params.gizmos)->gizmo_draw(timecode, coords); // set correct gizmo coords - (*params.gizmos)->gizmo_world_to_screen(); // convert gizmo coords to screen coords - } - */ - - glPopMatrix(); } } else { if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { @@ -646,22 +686,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } } - - /* - // visually update all the keyframe values - if (c->sequence == params.seq) { // only if you can currently see them - double ts = (playhead - c->timeline_in(true) + c->clip_in(true))/s->frame_rate; - for (int i=0;ieffects.size();i++) { - EffectPtr e = c->effects.at(i); - for (int j=0;jrow_count();j++) { - EffectRow* r = e->row(j); - for (int k=0;kfieldCount();k++) { - r->field(k)->validate_keyframe_data(ts); - } - } - } - } - */ } } else { params.texture_failed = true; diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h index 6e0205bc1..03bffa4e3 100644 --- a/rendering/renderfunctions.h +++ b/rendering/renderfunctions.h @@ -52,6 +52,13 @@ struct ComposeSequenceParams { */ QOpenGLContext* ctx; + /** + * @brief The OpenGL pipeline used for rendering + * + * \see olive::rendering::GetPipeline(). + */ + QOpenGLShaderProgram* pipeline; + /** * @brief The sequence to compose * @@ -403,4 +410,13 @@ void close_active_clips(Sequence* s); void UpdateOCIOGLState(const ComposeSequenceParams ¶ms); +namespace olive { + namespace rendering { + extern GLfloat blit_vertices[]; + extern GLfloat blit_texcoords[]; + void Blit(QOpenGLShaderProgram* pipeline); + QOpenGLShaderProgramPtr GetPipeline(); + } +} + #endif // RENDERFUNCTIONS_H diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 19ebeed04..9741814bc 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -32,10 +32,10 @@ namespace OCIO = OCIO_NAMESPACE; #endif -#include "rendering/renderfunctions.h" #include "timeline/sequence.h" #include "effects/effectloaders.h" #include "global/config.h" +#include "rendering/renderfunctions.h" RenderThread::RenderThread() : gizmos(nullptr), @@ -102,12 +102,14 @@ void RenderThread::run() { if (blend_mode_program == nullptr) { delete_shaders(); - blend_mode_program = new QOpenGLShaderProgram(); + blend_mode_program = std::make_shared(); blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/common.vert"); olive::effects_loaded.lock(); blend_mode_program->addShaderFromSourceCode(QOpenGLShader::Fragment, olive::generated_blending_shader); olive::effects_loaded.unlock(); blend_mode_program->link(); + + pipeline_program = olive::rendering::GetPipeline(); } #ifndef NO_OCIO @@ -148,15 +150,15 @@ const GLuint &RenderThread::get_texture() } const char * g_fragShaderText = "" -"\n" -"uniform sampler2D tex1;\n" -"uniform sampler3D tex2;\n" -"\n" -"void main()\n" -"{\n" -" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" -" gl_FragColor = OCIODisplay(col, tex2);\n" -"}\n"; + "\n" + "uniform sampler2D tex1;\n" + "uniform sampler3D tex2;\n" + "\n" + "void main()\n" + "{\n" + " vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" + " gl_FragColor = OCIODisplay(col, tex2);\n" + "}\n"; #ifndef NO_OCIO void RenderThread::set_up_ocio() @@ -182,8 +184,8 @@ void RenderThread::set_up_ocio() // Allocate storage for texture ctx->extraFunctions()->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB, - OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, - 0, GL_RGB,GL_FLOAT, ocio_lut_data); + OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, + 0, GL_RGB,GL_FLOAT, ocio_lut_data); // // SET UP OCIO DISPLAY @@ -240,17 +242,17 @@ void RenderThread::set_up_ocio() processor->getGpuLut3D(ocio_lut_data, shaderDesc); - glBindTexture(GL_TEXTURE_3D, ocio_lut_texture); + ctx->extraFunctions()->glBindTexture(GL_TEXTURE_3D, ocio_lut_texture); ctx->extraFunctions()->glTexSubImage3D(GL_TEXTURE_3D, 0, - 0, 0, 0, - OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, - GL_RGB,GL_FLOAT, ocio_lut_data); + 0, 0, 0, + OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, + GL_RGB,GL_FLOAT, ocio_lut_data); QString shader_text = processor->getGpuShaderText(shaderDesc); shader_text.append("\n"); shader_text.append(g_fragShaderText); - ocio_shader = new QOpenGLShaderProgram(); + ocio_shader = std::make_shared(); ocio_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, shader_text); ocio_shader->link(); @@ -264,7 +266,6 @@ void RenderThread::destroy_ocio() ctx->functions()->glDeleteTextures(1, &ocio_lut_texture); ocio_lut_texture = 0; - delete ocio_shader; ocio_shader = nullptr; } #endif @@ -279,9 +280,10 @@ void RenderThread::paint() { params.texture_failed = false; params.wait_for_mutexes = true; params.playback_speed = 1; - params.blend_mode_program = blend_mode_program; + params.blend_mode_program = blend_mode_program.get(); + params.pipeline = pipeline_program.get(); #ifndef NO_OCIO - params.ocio_shader = ocio_shader; + params.ocio_shader = ocio_shader.get(); #endif params.backend_buffer1 = back_buffer_1.buffer(); params.backend_buffer2 = back_buffer_2.buffer(); @@ -300,15 +302,8 @@ void RenderThread::paint() { // bind framebuffer for drawing ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, params.main_buffer); - glLoadIdentity(); - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - - glEnable(GL_TEXTURE_2D); - glEnable(GL_BLEND); + ctx->functions()->glClearColor(0.0, 0.0, 0.0, 0.0); + ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); compose_sequence(params); @@ -339,13 +334,13 @@ void RenderThread::paint() { ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, params.main_buffer); // store pixels in buffer - glReadPixels(0, - 0, - pixel_buffer_linesize == 0 ? tex_width : pixel_buffer_linesize, - tex_height, - GL_RGBA, - GL_UNSIGNED_BYTE, - pixel_buffer); + ctx->functions()->glReadPixels(0, + 0, + pixel_buffer_linesize == 0 ? tex_width : pixel_buffer_linesize, + tex_height, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixel_buffer); // release current read buffer ctx->functions()->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); @@ -353,9 +348,6 @@ void RenderThread::paint() { pixel_buffer = nullptr; } - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - // release ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } @@ -410,8 +402,8 @@ void RenderThread::delete_buffers() { } void RenderThread::delete_shaders() { - delete blend_mode_program; blend_mode_program = nullptr; + pipeline_program = nullptr; } void RenderThread::delete_ctx() { diff --git a/rendering/renderthread.h b/rendering/renderthread.h index 62e4ec2bc..29e2d5091 100644 --- a/rendering/renderthread.h +++ b/rendering/renderthread.h @@ -32,6 +32,7 @@ #include "timeline/sequence.h" #include "effects/effect.h" #include "rendering/framebufferobject.h" +#include "qopenglshaderprogramptr.h" #ifndef NO_OCIO // copied from source code to OCIODisplay @@ -81,7 +82,7 @@ private: // OpenColorIO variables float ocio_lut_data[OCIO_NUM_3D_ENTRIES]; GLuint ocio_lut_texture; - QOpenGLShaderProgram* ocio_shader; + QOpenGLShaderProgramPtr ocio_shader; QString ocio_loaded_config; #endif @@ -102,7 +103,8 @@ private: QOffscreenSurface surface; QOpenGLContext* share_ctx; QOpenGLContext* ctx; - QOpenGLShaderProgram* blend_mode_program; + QOpenGLShaderProgramPtr blend_mode_program; + QOpenGLShaderProgramPtr pipeline_program; FramebufferObject back_buffer_1; FramebufferObject back_buffer_2; diff --git a/timeline/clip.cpp b/timeline/clip.cpp index 5a6c97408..5c9ebbf07 100644 --- a/timeline/clip.cpp +++ b/timeline/clip.cpp @@ -573,7 +573,9 @@ bool Clip::Retrieve() texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); } - glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/kRGBAComponentCount); + QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); + + f->glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/kRGBAComponentCount); // 2 data buffers to ping-pong between bool using_db_1 = true; @@ -611,7 +613,7 @@ bool Clip::Retrieve() delete [] data_buffer_2; } - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); ret = true; } else { diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index b96d0fc6b..35e167882 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -71,8 +71,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : gizmos(nullptr), selected_gizmo(nullptr), x_scroll(0), - y_scroll(0), - pipeline_(nullptr) + y_scroll(0) { setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); @@ -80,19 +79,14 @@ ViewerWidget::ViewerWidget(QWidget *parent) : setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); - renderer = new RenderThread(); - renderer->start(QThread::HighestPriority); - connect(renderer, SIGNAL(ready()), this, SLOT(queue_repaint())); - connect(renderer, SIGNAL(finished()), renderer, SLOT(deleteLater())); + renderer.start(QThread::HighestPriority); + connect(&renderer, SIGNAL(ready()), this, SLOT(queue_repaint())); window = new ViewerWindow(this); - - projection_.setToIdentity(); } ViewerWidget::~ViewerWidget() { - renderer->cancel(); - delete renderer; + renderer.cancel(); } void ViewerWidget::delete_function() { @@ -174,7 +168,7 @@ void ViewerWidget::save_frame() { fn += selected_ext; } - renderer->start_render(context(), viewer->seq.get(), fn); + renderer.start_render(context(), viewer->seq.get(), fn); } } @@ -226,10 +220,7 @@ void ViewerWidget::initializeGL() { connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(context_destroy()), Qt::DirectConnection); - pipeline_ = new QOpenGLShaderProgram(); - pipeline_->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/pipeline.vert"); - pipeline_->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/internalshaders/pipeline.frag"); - pipeline_->link(); + pipeline_ = olive::rendering::GetPipeline(); } void ViewerWidget::frame_update() { @@ -239,7 +230,7 @@ void ViewerWidget::frame_update() { update(); } else { doneCurrent(); - renderer->start_render(context(), viewer->seq.get()); + renderer.start_render(context(), viewer->seq.get()); } // render the audio @@ -248,7 +239,7 @@ void ViewerWidget::frame_update() { } RenderThread *ViewerWidget::get_renderer() { - return renderer; + return &renderer; } void ViewerWidget::set_scroll(double x, double y) { @@ -268,9 +259,8 @@ void ViewerWidget::context_destroy() { close_active_clips(viewer->seq.get()); } - renderer->delete_ctx(); + renderer.delete_ctx(); - delete pipeline_; pipeline_ = nullptr; doneCurrent(); @@ -556,86 +546,28 @@ void ViewerWidget::draw_gizmos() { } void ViewerWidget::paintGL() { - QOpenGLFunctions* f = context()->functions(); - QOpenGLExtraFunctions* xf = context()->extraFunctions(); - - f->glClearColor(0.0, 0.0, 0.0, 0.0); - - GLfloat vertices[] = { - -1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - }; - - GLfloat tex_coords[] = { - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - - 0.0, 0.0, - 0.0, 1.0, - 1.0, 1.0 - }; - - f->glViewport(0, 0, width(), height()); - - f->glClear(GL_COLOR_BUFFER_BIT); - - QOpenGLTexture texture(QImage("C:/Users/Matt/Desktop/bliss.png")); - - pipeline_->bind(); - texture.bind(); - - pipeline_->setUniformValue("mvp_matrix", projection_); - pipeline_->setUniformValue("texture", 0); - - GLuint vertex_location = pipeline_->attributeLocation("a_position"); - f->glEnableVertexAttribArray(vertex_location); - f->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, vertices); - - GLuint tex_location = pipeline_->attributeLocation("a_texcoord"); - f->glEnableVertexAttribArray(tex_location); - f->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, tex_coords); - - f->glDrawArrays(GL_TRIANGLES, 0, 6); - - texture.release(); - pipeline_->release(); - - /* if (waveform) { draw_waveform_func(); } else { - const GLuint tex = renderer->get_texture(); - QMutex* tex_lock = renderer->get_texture_mutex(); + const GLuint tex = renderer.get_texture(); + QMutex* tex_lock = renderer.get_texture_mutex(); tex_lock->lock(); + QOpenGLFunctions* f = context()->functions(); + //QOpenGLExtraFunctions* xf = context()->extraFunctions(); + makeCurrent(); // clear to solid black - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + f->glClearColor(0.0, 0.0, 0.0, 0.0); + f->glClear(GL_COLOR_BUFFER_BIT); - // set color multipler to straight white - glColor4f(1.0, 1.0, 1.0, 1.0); - - glEnable(GL_TEXTURE_2D); - - // set screen coords to widget size - glLoadIdentity(); - glOrtho(-1, 1, -1, 1, -1, 1); // draw texture from render thread - glBindTexture(GL_TEXTURE_2D, tex); - - glBegin(GL_QUADS); + // TODO fix zooming double zoom_factor = container->zoom/(double(width())/double(viewer->seq->width)); double zoom_size = (zoom_factor*2.0) - 2.0; double zoom_left = -zoom_size*x_scroll - 1.0; @@ -643,45 +575,34 @@ void ViewerWidget::paintGL() { double zoom_bottom = -zoom_size*(1.0-y_scroll) - 1.0; double zoom_top = zoom_size*(y_scroll) + 1.0; - //zoom_left *= ar_diff; - //zoom_right *= ar_diff; - glVertex2d(zoom_left, zoom_bottom); - glTexCoord2d(0, 0); - glVertex2d(zoom_left, zoom_top); - glTexCoord2d(1, 0); - glVertex2d(zoom_right, zoom_top); - glTexCoord2d(1, 1); - glVertex2d(zoom_right, zoom_bottom); - glTexCoord2d(0, 1); + f->glViewport(0, 0, width(), height()); - glEnd(); + f->glBindTexture(GL_TEXTURE_2D, tex); - glBindTexture(GL_TEXTURE_2D, 0); + olive::rendering::Blit(pipeline_.get()); + + f->glBindTexture(GL_TEXTURE_2D, 0); // draw title/action safe area if (olive::CurrentConfig.show_title_safe_area) { draw_title_safe_area(); } - gizmos = renderer->gizmos; + gizmos = renderer.gizmos; if (gizmos != nullptr) { draw_gizmos(); } - glDisable(GL_TEXTURE_2D); - glFinish(); - if (window->isVisible()) { window->set_texture(tex, double(viewer->seq->width)/double(viewer->seq->height), tex_lock); } tex_lock->unlock(); - if (renderer->did_texture_fail() && !viewer->playing) { + if (renderer.did_texture_fail() && !viewer->playing) { doneCurrent(); - renderer->start_render(context(), viewer->seq.get()); + renderer.start_render(context(), viewer->seq.get()); } } - */ } diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index edd5a3938..c9d46398b 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -87,13 +87,12 @@ private: int gizmo_x_mvmt; int gizmo_y_mvmt; EffectGizmo* selected_gizmo; - RenderThread* renderer; + RenderThread renderer; ViewerWindow* window; double x_scroll; double y_scroll; - QMatrix4x4 projection_; - QOpenGLShaderProgram* pipeline_; + QOpenGLShaderProgramPtr pipeline_; private slots: void context_destroy();