Files
oak-editor/app/render/backend/opengl/openglworker.cpp
T
itsmattkc 3b224c7638 multithreaded download and files that probably should have been in the last
commit

For testing the new iteration, the texture cache disk download was written
into the main thread instead of into the separate threads. Now they're back
in separate threads again.

Also I think some of these files probably should have been in the previous
commit.
2019-11-06 09:14:20 +11:00

220 lines
6.3 KiB
C++

#include "openglworker.h"
#include "functions.h"
#include "node/node.h"
#include "render/pixelservice.h"
OpenGLWorker::OpenGLWorker(QOpenGLContext *share_ctx, OpenGLShaderCache *shader_cache, DecoderCache *decoder_cache, QObject *parent) :
VideoRenderWorker(decoder_cache, parent),
share_ctx_(share_ctx),
ctx_(nullptr),
functions_(nullptr),
shader_cache_(shader_cache)
{
surface_.create();
}
OpenGLWorker::~OpenGLWorker()
{
surface_.destroy();
}
bool OpenGLWorker::InitInternal()
{
// Create context object
ctx_ = new QOpenGLContext();
// Set share context
ctx_->setShareContext(share_ctx_);
// Create OpenGL context (automatically destroys any existing if there is one)
if (!ctx_->create()) {
qWarning() << "Failed to create OpenGL context in thread" << thread();
return false;
}
ctx_->moveToThread(this->thread());
//qDebug() << "Processor initialized in thread" << thread() << "- context is in" << ctx_->thread();
// The rest of the initialization needs to occur in the other thread, so we signal for it to start
QMetaObject::invokeMethod(this, "FinishInit", Qt::QueuedConnection);
return true;
}
QVariant OpenGLWorker::FrameToTexture(FramePtr frame)
{
OpenGLTexturePtr footage_tex = std::make_shared<OpenGLTexture>();
footage_tex->Create(ctx_, frame);
// FIXME: Alpha association and color management
return QVariant::fromValue(footage_tex);
}
bool OpenGLWorker::OutputIsShader(NodeOutput* output)
{
return shader_cache_->HasShader(output);
}
void OpenGLWorker::CloseInternal()
{
buffer_.Destroy();
functions_ = nullptr;
delete ctx_;
}
void OpenGLWorker::ParametersChangedEvent()
{
if (functions_ != nullptr && video_params().is_valid()) {
functions_->glViewport(0, 0, video_params().effective_width(), video_params().effective_height());
}
}
QVariant OpenGLWorker::RunNodeAsShader(NodeOutput *out)
{
OpenGLShaderPtr shader = shader_cache_->GetShader(out);
Node* node = out->parent();
// Create the output texture
OpenGLTexturePtr output = std::make_shared<OpenGLTexture>();
output->Create(ctx_, video_params().effective_width(), video_params().effective_height(), video_params().format());
buffer_.Attach(output);
buffer_.Bind();
shader->bind();
unsigned int input_texture_count = 0;
foreach (NodeParam* param, node->parameters()) {
if (param->type() == NodeParam::kInput) {
// See if the shader has takes this parameter as an input
int variable_location = shader->uniformLocation(param->id());
if (variable_location > -1) {
// This variable is used in the shader, let's set it to our value
NodeInput* input = static_cast<NodeInput*>(param);
switch (input->data_type()) {
case NodeInput::kInt:
shader->setUniformValue(variable_location, input->value().toInt());
break;
case NodeInput::kFloat:
shader->setUniformValue(variable_location, input->value().toFloat());
break;
case NodeInput::kVec2:
shader->setUniformValue(variable_location, input->value().value<QVector2D>());
break;
case NodeInput::kVec3:
shader->setUniformValue(variable_location, input->value().value<QVector3D>());
break;
case NodeInput::kVec4:
shader->setUniformValue(variable_location, input->value().value<QVector4D>());
break;
case NodeInput::kMatrix:
shader->setUniformValue(variable_location, input->value().value<QMatrix4x4>());
break;
case NodeInput::kColor:
shader->setUniformValue(variable_location, input->value().value<QColor>());
break;
case NodeInput::kBoolean:
shader->setUniformValue(variable_location, input->value().toBool());
break;
case NodeInput::kTexture:
case NodeInput::kFootage:
{
OpenGLTexturePtr texture = input->value().value<OpenGLTexturePtr>();
qDebug() << " Binding" << texture->texture() << "from" << input << "to GL_TEXTURE" << input_texture_count;
functions_->glActiveTexture(GL_TEXTURE0 + input_texture_count);
functions_->glBindTexture(GL_TEXTURE_2D, texture->texture());
// Set value to bound texture
shader->setUniformValue(variable_location, input_texture_count);
qDebug() << " Setting" << input->id() << "to" << input_texture_count;
input_texture_count++;
break;
}
case NodeInput::kAny:
case NodeInput::kSamples:
case NodeInput::kTrack:
case NodeInput::kString:
case NodeInput::kRational:
case NodeInput::kBlock:
case NodeInput::kFont:
case NodeInput::kFile:
case NodeInput::kNone:
break;
}
}
}
}
qDebug() << " Blitting with shader!";
olive::gl::Blit(shader);
// Release any textures we bound before
while (input_texture_count > 0) {
input_texture_count--;
// Release texture here
functions_->glActiveTexture(GL_TEXTURE0 + input_texture_count);
functions_->glBindTexture(GL_TEXTURE_2D, 0);
}
shader->release();
buffer_.Release();
buffer_.Detach();
functions_->glFinish();
return QVariant::fromValue(output);
}
void OpenGLWorker::TextureToBuffer(const QVariant &tex_in, QByteArray &buffer)
{
OpenGLTexturePtr texture = tex_in.value<OpenGLTexturePtr>();
PixelFormatInfo format_info = PixelService::GetPixelFormatInfo(video_params().format());
QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
buffer_.Attach(texture);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, buffer_.buffer());
f->glReadPixels(0,
0,
texture->width(),
texture->height(),
format_info.pixel_format,
format_info.gl_pixel_type,
buffer.data());
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
buffer_.Detach();
}
void OpenGLWorker::FinishInit()
{
// Make context current on that surface
if (!ctx_->makeCurrent(&surface_)) {
qWarning() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
return;
}
// Store OpenGL functions instance
functions_ = ctx_->functions();
// Set up OpenGL parameters as necessary
functions_->glEnable(GL_BLEND);
ParametersChangedEvent();
buffer_.Create(ctx_);
}