opengl: use shared contexts and downgrade to ES 2.0 (BIG CHANGE)
If you run into new OpenGL issues, this is likely the commit that caused it. I've tested this on as many systems as I have access to (including AMD, Apple, Intel, and NVIDIA GPUs with a mixture of Windows, Linux, and macOS) and it appears to work fine, however we all know how unpredictable GPUs can be. This should help increase GPU performance and compatibility. Squashed commit of the following: commit fa3c0ac7c469aebe2941a803736bdc06cdd5a2d8 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 13:17:44 2021 +1000 viewer: updated pixel sampling for shared contexts commit 9334261da235f09cb67b193c5bb6169abd7a95f7 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 13:12:39 2021 +1000 pixelsampler: show color preview box commit dacd9be6971c5c0312ae45c8db349d47910a80dd Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 12:43:32 2021 +1000 renderer: interlace on GPU commit 074cea06cb87e9fdc4e8ea6b09587be6df296057 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 12:43:14 2021 +1000 renderer: added texture clear option commit 5d4f86b4cf1b1dcd3fb8e8c854ffa7f6fb8ca346 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 12:42:12 2021 +1000 renderer: updated scopes for shared textures commit 6fad96358d189874cf45f7887b7e13cc2b1603c4 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 11:42:05 2021 +1000 opengl: fixed edge case commit 1a19ffb53703ac6f30ed210f6d8eb5fc4b7b0f2d Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 10:56:13 2021 +1000 opengl: fix deinterlace shader commit 085961aa39cca90ebf51b919a78ef07a4882f0e1 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 10:08:40 2021 +1000 opengl: downgrade to ES 2.0 With half-float/float/3D extensions, this should be doable commit ea1ab45cbcf5e017dfd0d8f28b231ff3255dfe92 Author: itsmattkc <itsmattkc@gmail.com> Date: Thu May 27 10:06:59 2021 +1000 renderer: fixed mutex deadlock commit ecc2f08b16f03421870c5b61625ecd26f2f96582 Author: itsmattkc <itsmattkc@gmail.com> Date: Wed May 26 21:28:13 2021 +1000 opengl: fixed shared contexts commit 261c689ea8089463155cf11b9ab15aa3f879f439 Merge: bfd4338a91c88b1cAuthor: itsmattkc <itsmattkc@gmail.com> Date: Wed May 26 19:52:00 2021 +1000 Merge branch 'master' into shared-contexts commit bfd4338aaa3b09b6fbb7717c637face8d5490721 Author: itsmattkc <itsmattkc@gmail.com> Date: Wed May 26 18:52:38 2021 +1000 viewer: remove debug line commit 45868d8a396181bf81c24b92a1ac5ce9ffed3426 Merge: 642f8e9dd0bd5e21Author: itsmattkc <itsmattkc@gmail.com> Date: Wed May 26 17:21:48 2021 +1000 Merge branch 'master' into shared-contexts commit 642f8e9df7d7d1a9ed4202d428f4d968ff668552 Merge: 861e5b894de0a727Author: itsmattkc <itsmattkc@gmail.com> Date: Wed May 26 17:01:38 2021 +1000 Merge branch 'master' of https://github.com/olive-editor/olive into shared-contexts commit 861e5b89a38c281897dc44b20e3587d39c4f808c Merge: 472598a7ef31c3fbAuthor: itsmattkc <itsmattkc@gmail.com> Date: Wed May 26 14:28:21 2021 +1000 Merge branch 'master' into shared-contexts commit 472598a740a095aa43a4aad5680dd5abcf453a4c Author: itsmattkc <itsmattkc@gmail.com> Date: Fri May 14 16:29:35 2021 +1000 attempt at sharing contexts
This commit is contained in:
+3
-1
@@ -162,7 +162,7 @@ int main(int argc, char *argv[])
|
||||
//
|
||||
// https://bugreports.qt.io/browse/QTBUG-46140
|
||||
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||
format.setVersion(3, 2);
|
||||
format.setVersion(2, 0);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setOption(QSurfaceFormat::DeprecatedFunctions);
|
||||
|
||||
@@ -172,6 +172,8 @@ int main(int argc, char *argv[])
|
||||
// Enable application automatically using higher resolution images from icons
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
|
||||
// Create application instance
|
||||
std::unique_ptr<QCoreApplication> a;
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ QString ScopePanel::TypeToName(ScopePanel::Type t)
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ScopePanel::SetReferenceBuffer(Frame *frame)
|
||||
void ScopePanel::SetReferenceBuffer(TexturePtr frame)
|
||||
{
|
||||
histogram_->SetBuffer(frame);
|
||||
waveform_view_->SetBuffer(frame);
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
static QString TypeToName(Type t);
|
||||
|
||||
public slots:
|
||||
void SetReferenceBuffer(Frame* frame);
|
||||
void SetReferenceBuffer(TexturePtr frame);
|
||||
|
||||
void SetColorManager(ColorManager* manager);
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ void ViewerPanelBase::CreateScopePanel(ScopePanel::Type type)
|
||||
p->SetType(type);
|
||||
|
||||
// Connect viewer widget texture drawing to scope panel
|
||||
connect(vw, &ViewerWidget::LoadedBuffer, p, &ScopePanel::SetReferenceBuffer);
|
||||
connect(vw, &ViewerWidget::TextureChanged, p, &ScopePanel::SetReferenceBuffer);
|
||||
connect(vw, &ViewerWidget::ColorManagerChanged, p, &ScopePanel::SetColorManager);
|
||||
|
||||
p->SetColorManager(vw->color_manager());
|
||||
|
||||
@@ -76,6 +76,11 @@ private:
|
||||
|
||||
#define PRINT_GL_ERRORS ErrorPrinter __e(__FUNCTION__, functions_)
|
||||
|
||||
#define GL_PREAMBLE \
|
||||
QMutexLocker __l(&global_opengl_mutex);
|
||||
|
||||
QMutex global_opengl_mutex;
|
||||
|
||||
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
||||
Renderer(parent),
|
||||
cache_timer_(this),
|
||||
@@ -104,6 +109,8 @@ void OpenGLRenderer::Init(QOpenGLContext *existing_ctx)
|
||||
|
||||
bool OpenGLRenderer::Init()
|
||||
{
|
||||
QMutexLocker locker(&global_opengl_mutex);
|
||||
|
||||
if (context_) {
|
||||
qCritical() << "Can't initialize already initialized OpenGLRenderer";
|
||||
return false;
|
||||
@@ -112,6 +119,7 @@ bool OpenGLRenderer::Init()
|
||||
surface_.create();
|
||||
|
||||
context_ = new QOpenGLContext(this);
|
||||
context_->setShareContext(QOpenGLContext::globalShareContext());
|
||||
if (!context_->create()) {
|
||||
qCritical() << "Failed to create OpenGL context";
|
||||
return false;
|
||||
@@ -132,6 +140,8 @@ void OpenGLRenderer::PostDestroy()
|
||||
|
||||
void OpenGLRenderer::PostInit()
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
// Make context current on that surface
|
||||
if (context_->parent() == this && !context_->makeCurrent(&surface_)) {
|
||||
qCritical() << "Failed to makeCurrent() on offscreen surface in thread" << thread();
|
||||
@@ -152,6 +162,8 @@ void OpenGLRenderer::PostInit()
|
||||
void OpenGLRenderer::DestroyInternal()
|
||||
{
|
||||
if (context_) {
|
||||
GL_PREAMBLE;
|
||||
|
||||
// Delete framebuffer
|
||||
functions_->glDeleteFramebuffers(1, &framebuffer_);
|
||||
framebuffer_ = 0;
|
||||
@@ -171,55 +183,32 @@ void OpenGLRenderer::DestroyInternal()
|
||||
cache_timer_.stop();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::ClearDestination(double r, double g, double b, double a)
|
||||
void OpenGLRenderer::ClearDestination(Texture *texture, double r, double g, double b, double a)
|
||||
{
|
||||
functions_->glClearColor(r, g, b, a);
|
||||
functions_->glClear(GL_COLOR_BUFFER_BIT);
|
||||
GL_PREAMBLE;
|
||||
|
||||
if (texture) {
|
||||
AttachTextureAsDestination(texture);
|
||||
}
|
||||
|
||||
ClearDestinationInternal(r, g, b, a);
|
||||
|
||||
if (texture) {
|
||||
DetachTextureAsDestination();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize)
|
||||
{
|
||||
GLuint texture = GetCachedTexture(width, height, 1, format, channel_count);
|
||||
GL_PREAMBLE;
|
||||
|
||||
// If no texture in cache, generate new texture
|
||||
bool new_tex = (texture == 0);
|
||||
if (new_tex) {
|
||||
functions_->glGenTextures(1, &texture);
|
||||
texture_params_.insert(texture, {width, height, 1, format, channel_count});
|
||||
}
|
||||
|
||||
if (new_tex || data) {
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
GLint current_tex;
|
||||
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
{
|
||||
PRINT_GL_ERRORS;
|
||||
if (new_tex) {
|
||||
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(format, channel_count),
|
||||
width, height, 0, GetPixelFormat(channel_count),
|
||||
GetPixelType(format), data);
|
||||
} else {
|
||||
functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||
width, height,
|
||||
GetPixelFormat(channel_count), GetPixelType(format),
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
}
|
||||
|
||||
return texture;
|
||||
return CreateNativeTexture2DInternal(width, height, format, channel_count, data, linesize);
|
||||
}
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize)
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
GLuint texture = GetCachedTexture(width, height, depth, format, channel_count);
|
||||
|
||||
// If no texture in cache, generate new texture
|
||||
@@ -287,6 +276,8 @@ void OpenGLRenderer::DestroyNativeTexture(QVariant texture)
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
PRINT_GL_ERRORS;
|
||||
|
||||
QOpenGLShaderProgram* program = new QOpenGLShaderProgram(context_);
|
||||
@@ -294,17 +285,8 @@ QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
|
||||
QString vert_code = code.vert_code();
|
||||
QString frag_code = code.frag_code();
|
||||
|
||||
QString shader_preamble;
|
||||
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
|
||||
shader_preamble = QStringLiteral("#version 300 es\n"
|
||||
"\n"
|
||||
"precision highp int;\n"
|
||||
"precision highp float;\n"
|
||||
"\n");
|
||||
} else {
|
||||
shader_preamble = QStringLiteral("#version 150\n"
|
||||
"\n");
|
||||
}
|
||||
QString shader_preamble = QStringLiteral("#version 110\n"
|
||||
"\n");
|
||||
|
||||
vert_code.prepend(shader_preamble);
|
||||
frag_code.prepend(shader_preamble);
|
||||
@@ -333,12 +315,14 @@ error:
|
||||
|
||||
void OpenGLRenderer::DestroyNativeShader(QVariant shader)
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
delete Node::ValueToPtr<QOpenGLShaderProgram>(shader);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int linesize)
|
||||
{
|
||||
PRINT_GL_ERRORS;
|
||||
GL_PREAMBLE;
|
||||
|
||||
GLuint t = texture->id().value<GLuint>();
|
||||
const VideoParams& p = texture->params();
|
||||
@@ -354,16 +338,20 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int lin
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
if (texture->type() == Texture::k2D) {
|
||||
functions_->glTexSubImage2D(tex_type, 0, 0, 0,
|
||||
p.effective_width(), p.effective_height(),
|
||||
GetPixelFormat(p.channel_count()), GetPixelType(p.format()),
|
||||
data);
|
||||
} else {
|
||||
context_->extraFunctions()->glTexSubImage3D(tex_type, 0, 0, 0, 0,
|
||||
p.effective_width(), p.effective_height(), p.effective_depth(),
|
||||
GetPixelFormat(p.channel_count()), GetPixelType(p.format()),
|
||||
data);
|
||||
{
|
||||
PRINT_GL_ERRORS;
|
||||
|
||||
if (texture->type() == Texture::k2D) {
|
||||
functions_->glTexSubImage2D(tex_type, 0, 0, 0,
|
||||
p.effective_width(), p.effective_height(),
|
||||
GetPixelFormat(p.channel_count()), GetPixelType(p.format()),
|
||||
data);
|
||||
} else {
|
||||
context_->extraFunctions()->glTexSubImage3D(tex_type, 0, 0, 0, 0,
|
||||
p.effective_width(), p.effective_height(), p.effective_depth(),
|
||||
GetPixelFormat(p.channel_count()), GetPixelType(p.format()),
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
@@ -373,6 +361,8 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int lin
|
||||
|
||||
void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int linesize)
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
const VideoParams& p = texture->params();
|
||||
|
||||
GLint current_tex;
|
||||
@@ -388,7 +378,7 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
|
||||
0,
|
||||
p.effective_width(),
|
||||
p.effective_height(),
|
||||
(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) ? GL_RGBA : GetPixelFormat(p.channel_count()),
|
||||
GetPixelFormat(p.channel_count()),
|
||||
GetPixelType(p.format()),
|
||||
data);
|
||||
}
|
||||
@@ -400,6 +390,33 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::Flush()
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
functions_->glFinish();
|
||||
}
|
||||
|
||||
Color OpenGLRenderer::GetPixelFromTexture(Texture *texture, const QPointF &pt)
|
||||
{
|
||||
AttachTextureAsDestination(texture);
|
||||
|
||||
QByteArray data(VideoParams::GetBytesPerPixel(texture->format(), texture->channel_count()), Qt::Uninitialized);
|
||||
|
||||
functions_->glReadPixels(pt.x(), pt.y(), 1, 1, GetPixelFormat(texture->channel_count()), GetPixelType(texture->format()), data.data());
|
||||
|
||||
Color c = Color::fromData(data.data(), texture->format(), texture->channel_count());
|
||||
|
||||
if (texture->channel_count() == VideoParams::kRGBChannelCount) {
|
||||
// No alpha channel, set to 1.0
|
||||
c.set_alpha(1.0);
|
||||
}
|
||||
|
||||
DetachTextureAsDestination();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
struct TextureToBind {
|
||||
TexturePtr texture;
|
||||
Texture::Interpolation interpolation;
|
||||
@@ -407,6 +424,8 @@ struct TextureToBind {
|
||||
|
||||
void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, VideoParams destination_params, bool clear_destination)
|
||||
{
|
||||
GL_PREAMBLE;
|
||||
|
||||
// If this node is iterative, we'll pick up which input here
|
||||
QString iterative_name;
|
||||
GLuint iterative_input = 0;
|
||||
@@ -581,11 +600,11 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
|
||||
TexturePtr output_tex, input_tex;
|
||||
if (real_iteration_count > 1) {
|
||||
// Create one texture to bounce off
|
||||
output_tex = CreateTexture(destination_params);
|
||||
output_tex = CreateTextureFromNativeHandle(CreateNativeTexture2DInternal(destination_params), destination_params);
|
||||
|
||||
if (real_iteration_count > 2) {
|
||||
// Create a second texture bounce off
|
||||
input_tex = CreateTexture(destination_params);
|
||||
input_tex = CreateTextureFromNativeHandle(CreateNativeTexture2DInternal(destination_params), destination_params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,7 +625,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
|
||||
|
||||
// Clear the destination if the caller requested it
|
||||
if (clear_destination) {
|
||||
ClearDestination();
|
||||
ClearDestinationInternal();
|
||||
}
|
||||
} else {
|
||||
// Always draw to output_tex, which gets swapped with input_tex every iteration
|
||||
@@ -771,6 +790,58 @@ void OpenGLRenderer::PrepareInputTexture(GLenum target, Texture::Interpolation i
|
||||
functions_->glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::ClearDestinationInternal(double r, double g, double b, double a)
|
||||
{
|
||||
functions_->glClearColor(r, g, b, a);
|
||||
functions_->glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeTexture2DInternal(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize)
|
||||
{
|
||||
GLuint texture = GetCachedTexture(width, height, 1, format, channel_count);
|
||||
|
||||
// If no texture in cache, generate new texture
|
||||
bool new_tex = (texture == 0);
|
||||
if (new_tex) {
|
||||
functions_->glGenTextures(1, &texture);
|
||||
texture_params_.insert(texture, {width, height, 1, format, channel_count});
|
||||
}
|
||||
|
||||
if (new_tex || data) {
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
GLint current_tex;
|
||||
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
{
|
||||
PRINT_GL_ERRORS;
|
||||
if (new_tex) {
|
||||
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(format, channel_count),
|
||||
width, height, 0, GetPixelFormat(channel_count),
|
||||
GetPixelType(format), data);
|
||||
} else {
|
||||
functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||
width, height,
|
||||
GetPixelFormat(channel_count), GetPixelType(format),
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
QVariant OpenGLRenderer::CreateNativeTexture2DInternal(const VideoParams ¶ms, const void *data, int linesize)
|
||||
{
|
||||
return CreateNativeTexture2DInternal(params.effective_width(), params.effective_height(), params.format(), params.channel_count(), data, linesize);
|
||||
}
|
||||
|
||||
GLuint OpenGLRenderer::GetCachedTexture(int width, int height, int depth, VideoParams::Format format, int channel_count)
|
||||
{
|
||||
TextureCacheKey input_key = {width, height, depth, format, channel_count};
|
||||
@@ -795,6 +866,7 @@ void OpenGLRenderer::GarbageCollectTextureCache()
|
||||
qint64 max_age = QDateTime::currentMSecsSinceEpoch() - kTextureCacheMaxSize;
|
||||
for (auto it=texture_cache_.begin(); it!=texture_cache_.end(); ) {
|
||||
if (it->age < max_age) {
|
||||
GL_PREAMBLE;
|
||||
GLuint t = it->texture;
|
||||
texture_params_.remove(t);
|
||||
functions_->glDeleteTextures(1, &t);
|
||||
|
||||
@@ -52,7 +52,7 @@ public slots:
|
||||
|
||||
virtual void DestroyInternal() override;
|
||||
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
virtual void ClearDestination(olive::Texture *texture = nullptr, double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
|
||||
virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
|
||||
virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
|
||||
@@ -67,6 +67,10 @@ public slots:
|
||||
|
||||
virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) override;
|
||||
|
||||
virtual void Flush() override;
|
||||
|
||||
virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) override;
|
||||
|
||||
protected slots:
|
||||
virtual void Blit(QVariant shader,
|
||||
olive::ShaderJob job,
|
||||
@@ -87,6 +91,11 @@ private:
|
||||
|
||||
void PrepareInputTexture(GLenum target, Texture::Interpolation interp);
|
||||
|
||||
void ClearDestinationInternal(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0);
|
||||
|
||||
QVariant CreateNativeTexture2DInternal(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0);
|
||||
QVariant CreateNativeTexture2DInternal(const VideoParams ¶ms, const void* data = nullptr, int linesize = 0);
|
||||
|
||||
GLuint GetCachedTexture(int width, int height, int depth, VideoParams::Format format, int channel_count);
|
||||
|
||||
QTimer cache_timer_;
|
||||
|
||||
@@ -530,7 +530,8 @@ void PreviewAutoCacher::TryRender()
|
||||
} else {
|
||||
watcher = RenderFrame(hash,
|
||||
single_frame_render_->property("time").value<rational>(),
|
||||
single_frame_render_->property("prioritize").toBool());
|
||||
single_frame_render_->property("prioritize").toBool(),
|
||||
paused_);
|
||||
|
||||
video_immediate_passthroughs_[watcher].append(single_frame_render_);
|
||||
}
|
||||
@@ -539,7 +540,7 @@ void PreviewAutoCacher::TryRender()
|
||||
}
|
||||
}
|
||||
|
||||
RenderTicketWatcher* PreviewAutoCacher::RenderFrame(const QByteArray &hash, const rational& time, bool prioritize)
|
||||
RenderTicketWatcher* PreviewAutoCacher::RenderFrame(const QByteArray &hash, const rational& time, bool prioritize, bool texture_only)
|
||||
{
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
watcher->setProperty("hash", hash);
|
||||
@@ -550,7 +551,8 @@ RenderTicketWatcher* PreviewAutoCacher::RenderFrame(const QByteArray &hash, cons
|
||||
time,
|
||||
RenderMode::kOffline,
|
||||
viewer_node_->video_frame_cache(),
|
||||
prioritize));
|
||||
prioritize,
|
||||
texture_only));
|
||||
return watcher;
|
||||
}
|
||||
|
||||
@@ -585,7 +587,7 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
// We want this hash, if we're not already rendering, start render now
|
||||
if (!render_task && !video_download_tasks_.key(hash)) {
|
||||
// Don't render any hash more than once
|
||||
RenderFrame(hash, t, false);
|
||||
RenderFrame(hash, t, false, false);
|
||||
}
|
||||
} else if (render_task) {
|
||||
// Cancel this frame unless it's already started
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
|
||||
void TryRender();
|
||||
|
||||
RenderTicketWatcher *RenderFrame(const QByteArray& hash, const rational &time, bool prioritize);
|
||||
RenderTicketWatcher *RenderFrame(const QByteArray& hash, const rational &time, bool prioritize, bool texture_only);
|
||||
|
||||
/**
|
||||
* @brief Process all changes to internal NodeGraph copy
|
||||
|
||||
+44
-18
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
#include <QVector2D>
|
||||
|
||||
#include "common/ocioutils.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -42,11 +44,7 @@ TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, Texture::Type type
|
||||
params.channel_count(), data, linesize);
|
||||
}
|
||||
|
||||
if (v.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_shared<Texture>(this, v, params, type);
|
||||
return CreateTextureFromNativeHandle(v, params, type);
|
||||
}
|
||||
|
||||
TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, int linesize)
|
||||
@@ -64,13 +62,47 @@ void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr so
|
||||
BlitColorManagedInternal(color_processor, source, source_is_premultiplied, nullptr, params, clear_destination, matrix, crop_matrix);
|
||||
}
|
||||
|
||||
TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms)
|
||||
{
|
||||
color_cache_mutex_.lock();
|
||||
if (interlace_texture_.isNull()) {
|
||||
interlace_texture_ = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/interlace.frag"))));
|
||||
}
|
||||
color_cache_mutex_.unlock();
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("top_tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(top)));
|
||||
job.InsertValue(QStringLiteral("bottom_tex_in"), NodeValue(NodeValue::kTexture, QVariant::fromValue(bottom)));
|
||||
job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(params.effective_width(), params.effective_height())));
|
||||
|
||||
TexturePtr output = CreateTexture(params);
|
||||
|
||||
BlitToTexture(interlace_texture_, job, output.get());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void Renderer::Destroy()
|
||||
{
|
||||
color_cache_.clear();
|
||||
|
||||
if (!interlace_texture_.isNull()) {
|
||||
DestroyNativeShader(interlace_texture_);
|
||||
interlace_texture_.clear();
|
||||
}
|
||||
|
||||
DestroyInternal();
|
||||
}
|
||||
|
||||
TexturePtr Renderer::CreateTextureFromNativeHandle(const QVariant &v, const VideoParams ¶ms, Texture::Type type)
|
||||
{
|
||||
if (v.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_shared<Texture>(this, v, params, type);
|
||||
}
|
||||
|
||||
bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::ColorContext *ctx)
|
||||
{
|
||||
QMutexLocker locker(&color_cache_mutex_);
|
||||
@@ -103,15 +135,9 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo
|
||||
"#define ALPHA_UNASSOC 1\n"
|
||||
"#define ALPHA_ASSOC 2\n"
|
||||
"\n"
|
||||
"// Macros so OCIO's shaders work on this GLSL version\n"
|
||||
"#define texture2D texture\n"
|
||||
"#define texture3D texture\n"
|
||||
"\n"
|
||||
"// Main texture coordinate\n"
|
||||
"in vec2 ove_texcoord;\n"
|
||||
"\n"
|
||||
"// Texture output\n"
|
||||
"out vec4 fragColor;\n"));
|
||||
"varying vec2 ove_texcoord;\n"
|
||||
"\n"));
|
||||
shader_frag.append(shader_desc->getShaderText());
|
||||
shader_frag.append(QStringLiteral("\n"
|
||||
"// Alpha association functions\n"
|
||||
@@ -128,13 +154,13 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo
|
||||
"}\n"
|
||||
"\n"
|
||||
"void main() {\n"
|
||||
" vec2 cropped_coord = (vec4(ove_texcoord-vec2(0.5, 0.5), 0.0, 1.0)*inverse(ove_cropmatrix)).xy + vec2(0.5, 0.5);\n"
|
||||
" vec2 cropped_coord = (vec4(ove_texcoord-vec2(0.5, 0.5), 0.0, 1.0)*ove_cropmatrix).xy + vec2(0.5, 0.5);\n"
|
||||
" if (cropped_coord.x < 0.0 || cropped_coord.x >= 1.0 || cropped_coord.y < 0.0 || cropped_coord.y >= 1.0) {\n"
|
||||
" fragColor = vec4(0.0);\n"
|
||||
" gl_FragColor = vec4(0.0);\n"
|
||||
" return;\n"
|
||||
" }\n"
|
||||
" \n"
|
||||
" vec4 col = texture(ove_maintex, cropped_coord);\n"
|
||||
" vec4 col = texture2D(ove_maintex, cropped_coord);\n"
|
||||
"\n"
|
||||
" // If alpha is associated, de-associate now\n"
|
||||
" if (ove_maintex_alpha == ALPHA_ASSOC) {\n"
|
||||
@@ -151,7 +177,7 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo
|
||||
" col = assoc(col);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" fragColor = col;\n"
|
||||
" gl_FragColor = col;\n"
|
||||
"}\n").arg(ocio_func_name));
|
||||
|
||||
// Try to compile shader
|
||||
@@ -244,7 +270,7 @@ void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, Textu
|
||||
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(source)));
|
||||
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix));
|
||||
job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix));
|
||||
job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix.inverted()));
|
||||
|
||||
AlphaAssociated associated;
|
||||
if (source->channel_count() == VideoParams::kRGBAChannelCount) {
|
||||
|
||||
+12
-1
@@ -66,6 +66,8 @@ public:
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, Texture* destination, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4());
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, VideoParams params, bool clear_destination = true, const QMatrix4x4& matrix = QMatrix4x4(), const QMatrix4x4 &crop_matrix = QMatrix4x4());
|
||||
|
||||
TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams ¶ms);
|
||||
|
||||
void Destroy();
|
||||
|
||||
virtual void PostDestroy() = 0;
|
||||
@@ -75,7 +77,7 @@ public slots:
|
||||
|
||||
virtual void DestroyInternal() = 0;
|
||||
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0;
|
||||
virtual void ClearDestination(olive::Texture *texture = nullptr, double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0;
|
||||
|
||||
virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0;
|
||||
virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0;
|
||||
@@ -90,6 +92,10 @@ public slots:
|
||||
|
||||
virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) = 0;
|
||||
|
||||
virtual void Flush() = 0;
|
||||
|
||||
virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) = 0;
|
||||
|
||||
protected slots:
|
||||
virtual void Blit(QVariant shader,
|
||||
olive::ShaderJob job,
|
||||
@@ -97,6 +103,9 @@ protected slots:
|
||||
olive::VideoParams destination_params,
|
||||
bool clear_destination) = 0;
|
||||
|
||||
protected:
|
||||
TexturePtr CreateTextureFromNativeHandle(const QVariant &v, const VideoParams ¶ms, Texture::Type type = Texture::k2D);
|
||||
|
||||
private:
|
||||
struct ColorContext {
|
||||
struct LUT {
|
||||
@@ -128,6 +137,8 @@ private:
|
||||
|
||||
QMutex color_cache_mutex_;
|
||||
|
||||
QVariant interlace_texture_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -69,9 +69,10 @@ void RendererThreadWrapper::DestroyInternal()
|
||||
}
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::ClearDestination(double r, double g, double b, double a)
|
||||
void RendererThreadWrapper::ClearDestination(Texture *texture, double r, double g, double b, double a)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "ClearDestination", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_ARG(Texture*, texture),
|
||||
Q_ARG(double, r),
|
||||
Q_ARG(double, g),
|
||||
Q_ARG(double, b),
|
||||
@@ -150,6 +151,23 @@ void RendererThreadWrapper::DownloadFromTexture(Texture *texture, void *data, in
|
||||
Q_ARG(int, linesize));
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::Flush()
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "Flush", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
Color RendererThreadWrapper::GetPixelFromTexture(Texture *texture, const QPointF &pt)
|
||||
{
|
||||
Color c;
|
||||
|
||||
QMetaObject::invokeMethod(inner_, "GetPixelFromTexture", Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_RETURN_ARG(Color, c),
|
||||
OLIVE_NS_ARG(Texture*, texture),
|
||||
Q_ARG(QPointF, pt));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void RendererThreadWrapper::Blit(QVariant shader, ShaderJob job, Texture *destination, VideoParams destination_params, bool clear_destination)
|
||||
{
|
||||
QMetaObject::invokeMethod(inner_, "Blit", Qt::BlockingQueuedConnection,
|
||||
|
||||
@@ -48,7 +48,7 @@ public slots:
|
||||
|
||||
virtual void DestroyInternal() override;
|
||||
|
||||
virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
virtual void ClearDestination(olive::Texture *texture = nullptr, double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override;
|
||||
|
||||
virtual QVariant CreateNativeTexture2D(int width, int height, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
|
||||
virtual QVariant CreateNativeTexture3D(int width, int height, int depth, olive::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override;
|
||||
@@ -63,6 +63,10 @@ public slots:
|
||||
|
||||
virtual void DownloadFromTexture(olive::Texture* texture, void* data, int linesize) override;
|
||||
|
||||
virtual void Flush() override;
|
||||
|
||||
virtual Color GetPixelFromTexture(olive::Texture *texture, const QPointF &pt) override;
|
||||
|
||||
protected slots:
|
||||
virtual void Blit(QVariant shader,
|
||||
olive::ShaderJob job,
|
||||
|
||||
@@ -126,7 +126,7 @@ QByteArray RenderManager::Hash(const Node *n, const QString& output, const Video
|
||||
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* color_manager,
|
||||
const rational& time, RenderMode::Mode mode,
|
||||
FrameHashCache* cache, bool prioritize)
|
||||
FrameHashCache* cache, bool prioritize, bool texture_only)
|
||||
{
|
||||
return RenderFrame(viewer,
|
||||
color_manager,
|
||||
@@ -139,7 +139,8 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* c
|
||||
VideoParams::kFormatInvalid,
|
||||
nullptr,
|
||||
cache,
|
||||
prioritize);
|
||||
prioritize,
|
||||
texture_only);
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* color_manager,
|
||||
@@ -148,7 +149,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* c
|
||||
const QSize& force_size,
|
||||
const QMatrix4x4& force_matrix, VideoParams::Format force_format,
|
||||
ColorProcessorPtr force_color_output,
|
||||
FrameHashCache* cache, bool prioritize)
|
||||
FrameHashCache* cache, bool prioritize, bool texture_only)
|
||||
{
|
||||
// Create ticket
|
||||
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
||||
@@ -164,6 +165,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* c
|
||||
ticket->setProperty("coloroutput", QVariant::fromValue(force_color_output));
|
||||
ticket->setProperty("vparam", QVariant::fromValue(video_params));
|
||||
ticket->setProperty("aparam", QVariant::fromValue(audio_params));
|
||||
ticket->setProperty("textureonly", texture_only);
|
||||
|
||||
if (cache) {
|
||||
ticket->setProperty("cache", cache->GetCacheDirectory());
|
||||
|
||||
@@ -86,14 +86,14 @@ public:
|
||||
*/
|
||||
RenderTicketPtr RenderFrame(ViewerOutput *viewer, ColorManager* color_manager,
|
||||
const rational& time, RenderMode::Mode mode,
|
||||
FrameHashCache* cache = nullptr, bool prioritize = false);
|
||||
FrameHashCache* cache = nullptr, bool prioritize = false, bool texture_only = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager,
|
||||
const rational& time, RenderMode::Mode mode,
|
||||
const VideoParams& video_params, const AudioParams& audio_params,
|
||||
const QSize& force_size,
|
||||
const QMatrix4x4& force_matrix, VideoParams::Format force_format,
|
||||
ColorProcessorPtr force_color_output,
|
||||
FrameHashCache* cache = nullptr, bool prioritize = false);
|
||||
FrameHashCache* cache = nullptr, bool prioritize = false, bool texture_only = false);
|
||||
|
||||
/**
|
||||
* @brief Asynchronously generate a chunk of audio
|
||||
|
||||
@@ -40,7 +40,7 @@ RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, S
|
||||
{
|
||||
}
|
||||
|
||||
FramePtr RenderProcessor::GenerateFrame(const rational& time, const rational& frame_length)
|
||||
TexturePtr RenderProcessor::GenerateTexture(const rational &time, const rational &frame_length)
|
||||
{
|
||||
ViewerOutput* viewer = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"));
|
||||
|
||||
@@ -51,8 +51,11 @@ FramePtr RenderProcessor::GenerateFrame(const rational& time, const rational& fr
|
||||
TimeRange(time, time + frame_length));
|
||||
}
|
||||
|
||||
TexturePtr texture = table.Get(NodeValue::kTexture).value<TexturePtr>();
|
||||
return table.Get(NodeValue::kTexture).value<TexturePtr>();
|
||||
}
|
||||
|
||||
FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time)
|
||||
{
|
||||
// Set up output frame parameters
|
||||
VideoParams frame_params = GetCacheVideoParams();
|
||||
|
||||
@@ -128,25 +131,35 @@ void RenderProcessor::Run()
|
||||
frame_length /= 2;
|
||||
}
|
||||
|
||||
FramePtr frame = GenerateFrame(time, frame_length);
|
||||
TexturePtr texture = GenerateTexture(time, frame_length);
|
||||
|
||||
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
|
||||
// Get next between frame and interlace it
|
||||
FramePtr next_frame = GenerateFrame(time + frame_length, frame_length);
|
||||
TexturePtr top = texture;
|
||||
TexturePtr bottom = GenerateTexture(time + frame_length, frame_length);
|
||||
|
||||
FramePtr top, bottom;
|
||||
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedTopFirst) {
|
||||
top = frame;
|
||||
bottom = next_frame;
|
||||
} else {
|
||||
top = next_frame;
|
||||
bottom = frame;
|
||||
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedBottomFirst) {
|
||||
std::swap(top, bottom);
|
||||
}
|
||||
|
||||
frame = Frame::Interlace(top, bottom);
|
||||
texture = render_ctx_->InterlaceTexture(top, bottom, GetCacheVideoParams());
|
||||
}
|
||||
|
||||
ticket_->Finish(QVariant::fromValue(frame));
|
||||
if (ticket_->property("textureonly").toBool()) {
|
||||
// Return GPU texture
|
||||
if (!texture) {
|
||||
texture = render_ctx_->CreateTexture(GetCacheVideoParams());
|
||||
}
|
||||
|
||||
render_ctx_->Flush();
|
||||
|
||||
ticket_->Finish(QVariant::fromValue(texture));
|
||||
} else {
|
||||
// Convert to CPU frame
|
||||
FramePtr frame = GenerateFrame(texture, time);
|
||||
|
||||
ticket_->Finish(QVariant::fromValue(frame));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RenderManager::kTypeAudio:
|
||||
|
||||
@@ -62,7 +62,9 @@ protected:
|
||||
private:
|
||||
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader);
|
||||
|
||||
FramePtr GenerateFrame(const rational &time, const rational &frame_length);
|
||||
TexturePtr GenerateTexture(const rational& time, const rational& frame_length);
|
||||
|
||||
FramePtr GenerateFrame(TexturePtr texture, const rational &time);
|
||||
|
||||
void Run();
|
||||
|
||||
|
||||
@@ -120,6 +120,11 @@ public:
|
||||
return type_;
|
||||
}
|
||||
|
||||
Renderer* renderer() const
|
||||
{
|
||||
return renderer_;
|
||||
}
|
||||
|
||||
private:
|
||||
Renderer* renderer_;
|
||||
|
||||
|
||||
@@ -3,31 +3,29 @@ uniform sampler2D blend_in;
|
||||
uniform bool base_in_enabled;
|
||||
uniform bool blend_in_enabled;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main(void) {
|
||||
vec4 base_col = texture(base_in, ove_texcoord);
|
||||
vec4 blend_col = texture(blend_in, ove_texcoord);
|
||||
vec4 base_col = texture2D(base_in, ove_texcoord);
|
||||
vec4 blend_col = texture2D(blend_in, ove_texcoord);
|
||||
|
||||
if (!base_in_enabled && !blend_in_enabled) {
|
||||
fragColor = vec4(0.0);
|
||||
gl_FragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!base_in_enabled) {
|
||||
fragColor = blend_col;
|
||||
gl_FragColor = blend_col;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blend_in_enabled) {
|
||||
fragColor = base_col;
|
||||
return;
|
||||
gl_FragColor = base_col;
|
||||
return;
|
||||
}
|
||||
|
||||
base_col *= 1.0 - blend_col.a;
|
||||
base_col += blend_col;
|
||||
|
||||
fragColor = base_col;
|
||||
gl_FragColor = base_col;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ uniform vec2 resolution_in;
|
||||
|
||||
uniform int ove_iteration;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
// Gaussian function uses PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
@@ -65,7 +63,7 @@ void main(void) {
|
||||
int mode = determine_mode();
|
||||
|
||||
if (mode == MODE_NONE) {
|
||||
fragColor = texture(tex_in, ove_texcoord);
|
||||
gl_FragColor = texture2D(tex_in, ove_texcoord);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,9 +115,9 @@ void main(void) {
|
||||
&& pixel_coord.x < 1.0
|
||||
&& pixel_coord.y >= 0.0
|
||||
&& pixel_coord.y < 1.0)) {
|
||||
composite += texture(tex_in, pixel_coord) * weight;
|
||||
composite += texture2D(tex_in, pixel_coord) * weight;
|
||||
}
|
||||
}
|
||||
|
||||
fragColor = composite;
|
||||
gl_FragColor = composite;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ uniform float feather_in;
|
||||
uniform vec2 resolution_in;
|
||||
|
||||
// Input texture coordinate
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
// Output color
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main() {
|
||||
float multiplier = 1.0;
|
||||
@@ -47,9 +44,9 @@ void main() {
|
||||
}
|
||||
|
||||
if (multiplier > 0.0) {
|
||||
vec4 color = texture(tex_in, ove_texcoord) * multiplier;
|
||||
fragColor = color;
|
||||
vec4 color = texture2D(tex_in, ove_texcoord) * multiplier;
|
||||
gl_FragColor = color;
|
||||
} else {
|
||||
fragColor = vec4(0.0);
|
||||
gl_FragColor = vec4(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ uniform int curve_in;
|
||||
|
||||
uniform float ove_tprog_all;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
float TransformCurve(float linear) {
|
||||
if (curve_in == EXPONENTIAL_CURVE) {
|
||||
@@ -28,12 +26,12 @@ void main(void) {
|
||||
vec4 composite = vec4(0.0);
|
||||
|
||||
if (out_block_in_enabled) {
|
||||
composite += texture(out_block_in, ove_texcoord) * TransformCurve(1.0 - ove_tprog_all);
|
||||
composite += texture2D(out_block_in, ove_texcoord) * TransformCurve(1.0 - ove_tprog_all);
|
||||
}
|
||||
|
||||
if (in_block_in_enabled) {
|
||||
composite += texture(in_block_in, ove_texcoord) * TransformCurve(ove_tprog_all);
|
||||
composite += texture2D(in_block_in, ove_texcoord) * TransformCurve(ove_tprog_all);
|
||||
}
|
||||
|
||||
fragColor = composite;
|
||||
gl_FragColor = composite;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
uniform sampler2D ove_maintex;
|
||||
|
||||
// Input texture coordinate
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
// Output color
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main() {
|
||||
vec4 color = texture(ove_maintex, ove_texcoord);
|
||||
fragColor = color;
|
||||
vec4 color = texture2D(ove_maintex, ove_texcoord);
|
||||
gl_FragColor = color;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
uniform mat4 ove_mvpmat;
|
||||
|
||||
in vec4 a_position;
|
||||
in vec2 a_texcoord;
|
||||
attribute vec4 a_position;
|
||||
attribute vec2 a_texcoord;
|
||||
|
||||
out vec2 ove_texcoord;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = ove_mvpmat * a_position;
|
||||
ove_texcoord = a_texcoord;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ uniform sampler2D ove_maintex;
|
||||
|
||||
uniform vec2 resolution_in;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
float round(float x)
|
||||
{
|
||||
return floor(x + 0.5);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 using_texcoord = ove_texcoord;
|
||||
@@ -15,6 +18,6 @@ void main() {
|
||||
float half_vert = round(resolution_in.y / 2.0);
|
||||
using_texcoord.y = (round(using_texcoord.y * half_vert) + 0.25) / half_vert;
|
||||
|
||||
vec4 color = texture(ove_maintex, using_texcoord);
|
||||
fragColor = color;
|
||||
vec4 color = texture2D(ove_maintex, using_texcoord);
|
||||
gl_FragColor = color;
|
||||
}
|
||||
|
||||
@@ -8,21 +8,19 @@ uniform float ove_tprog_all;
|
||||
uniform float ove_tprog_out;
|
||||
uniform float ove_tprog_in;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main(void) {
|
||||
if (out_block_in_enabled && in_block_in_enabled) {
|
||||
vec4 out_block_col = mix(texture(out_block_in, ove_texcoord), color_in, ove_tprog_out);
|
||||
vec4 in_block_col = mix(texture(in_block_in, ove_texcoord), color_in, 1.0 - ove_tprog_in);
|
||||
vec4 out_block_col = mix(texture2D(out_block_in, ove_texcoord), color_in, ove_tprog_out);
|
||||
vec4 in_block_col = mix(texture2D(in_block_in, ove_texcoord), color_in, 1.0 - ove_tprog_in);
|
||||
|
||||
fragColor = out_block_col + in_block_col;
|
||||
gl_FragColor = out_block_col + in_block_col;
|
||||
} else if (out_block_in_enabled) {
|
||||
fragColor = mix(texture(out_block_in, ove_texcoord), color_in, ove_tprog_all);
|
||||
gl_FragColor = mix(texture2D(out_block_in, ove_texcoord), color_in, ove_tprog_all);
|
||||
} else if (in_block_in_enabled) {
|
||||
fragColor = mix(texture(in_block_in, ove_texcoord), color_in, 1.0 - ove_tprog_all);
|
||||
gl_FragColor = mix(texture2D(in_block_in, ove_texcoord), color_in, 1.0 - ove_tprog_all);
|
||||
} else {
|
||||
fragColor = vec4(0.0);
|
||||
gl_FragColor = vec4(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
uniform sampler2D top_tex_in;
|
||||
uniform sampler2D bottom_tex_in;
|
||||
uniform vec2 resolution_in;
|
||||
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main() {
|
||||
float y_pixel = floor(ove_texcoord.y * resolution_in.y);
|
||||
|
||||
if (mod(y_pixel, 2.0) == 0.0) {
|
||||
gl_FragColor = texture2D(top_tex_in, ove_texcoord);
|
||||
} else {
|
||||
gl_FragColor = texture2D(bottom_tex_in, ove_texcoord);
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,7 @@ uniform float horiz_in;
|
||||
uniform float vert_in;
|
||||
|
||||
// Input texture coordinate
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
// Output color
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main() {
|
||||
float x;
|
||||
@@ -26,6 +23,6 @@ void main() {
|
||||
y = ove_texcoord.y;
|
||||
}
|
||||
|
||||
vec4 color = texture(tex_in, vec2(x, y));
|
||||
fragColor = color;
|
||||
vec4 color = texture2D(tex_in, vec2(x, y));
|
||||
gl_FragColor = color;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ uniform vec4 color_in;
|
||||
|
||||
uniform vec2 resolution_in;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
/*
|
||||
int pnpoly(int npol, float *xp, float *yp, float x, float y) {
|
||||
@@ -35,8 +33,8 @@ bool pnpoly(vec2 p) {
|
||||
|
||||
void main(void) {
|
||||
if (points_in_count > 0 && pnpoly(ove_texcoord * resolution_in)) {
|
||||
fragColor = color_in;
|
||||
gl_FragColor = color_in;
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ uniform sampler2D ove_maintex;
|
||||
uniform vec2 viewport;
|
||||
uniform float histogram_scale;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main(void) {
|
||||
float histogram_width = ceil(histogram_scale * viewport.y);
|
||||
@@ -13,9 +11,9 @@ void main(void) {
|
||||
vec3 sum = vec3(0.0);
|
||||
float ratio = 0.0;
|
||||
|
||||
for (int i = 0; i < histogram_width; i++) {
|
||||
ratio = float(i) / float(histogram_width - 1);
|
||||
cur_col = texture(
|
||||
for (int i = 0; float(i) < histogram_width; i++) {
|
||||
ratio = float(i) / float(histogram_width - 1.0);
|
||||
cur_col = texture2D(
|
||||
ove_maintex,
|
||||
vec2(ove_texcoord.y, ratio)
|
||||
).rgb;
|
||||
@@ -29,5 +27,5 @@ void main(void) {
|
||||
);
|
||||
}
|
||||
|
||||
fragColor = vec4(sum, 1.0);
|
||||
gl_FragColor = vec4(sum, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
uniform float histogram_scale;
|
||||
|
||||
in vec4 a_position;
|
||||
in vec2 a_texcoord;
|
||||
attribute vec4 a_position;
|
||||
attribute vec2 a_texcoord;
|
||||
|
||||
out vec2 ove_texcoord;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
mat4 scale_mat4(vec3 scale) {
|
||||
return mat4(
|
||||
|
||||
@@ -4,9 +4,7 @@ uniform vec2 viewport;
|
||||
uniform float histogram_scale;
|
||||
uniform float histogram_power;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main(void) {
|
||||
vec3 col = vec3(0.0);
|
||||
@@ -17,9 +15,9 @@ void main(void) {
|
||||
vec3 total_pixels = vec3(ceil(viewport.x * viewport.y *
|
||||
histogram_scale));
|
||||
|
||||
for (int i = 0; i < histogram_height; i++) {
|
||||
for (int i = 0; float(i) < histogram_height; i++) {
|
||||
ratio = float(i) / float(histogram_height - 1.0);
|
||||
sum += texture(
|
||||
sum += texture2D(
|
||||
ove_maintex,
|
||||
vec2(ove_texcoord.x, ratio)
|
||||
).rgb;
|
||||
@@ -28,5 +26,5 @@ void main(void) {
|
||||
histogram_ratio = pow(sum / total_pixels, vec3(histogram_power));
|
||||
col = step(vec3(ove_texcoord.y), histogram_ratio);
|
||||
|
||||
fragColor = vec4(col, 1.0);
|
||||
gl_FragColor = vec4(col, 1.0);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ uniform vec3 luma_coeffs;
|
||||
|
||||
uniform float waveform_scale;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main(void) {
|
||||
float waveform_height = ceil(waveform_scale * viewport.y);
|
||||
@@ -17,9 +15,9 @@ void main(void) {
|
||||
vec4 cur_col = vec4(0.0);
|
||||
float ratio = 0.0;
|
||||
|
||||
for (int i = 0; i < waveform_height; i++) {
|
||||
for (int i = 0; float(i) < waveform_height; i++) {
|
||||
ratio = float(i) / float(waveform_height - 1.0);
|
||||
cur_col.rgb = texture(
|
||||
cur_col.rgb = texture2D(
|
||||
ove_maintex,
|
||||
vec2(ove_texcoord.x, ratio)
|
||||
).rgb;
|
||||
@@ -35,5 +33,5 @@ void main(void) {
|
||||
}
|
||||
|
||||
col.rgb += vec3(col.w);
|
||||
fragColor = vec4(col.rgb, 1.0);
|
||||
gl_FragColor = vec4(col.rgb, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
uniform float waveform_scale;
|
||||
|
||||
in vec4 a_position;
|
||||
in vec2 a_texcoord;
|
||||
attribute vec4 a_position;
|
||||
attribute vec2 a_texcoord;
|
||||
|
||||
out vec2 ove_texcoord;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
mat4 scale_mat4(vec3 scale) {
|
||||
return mat4(
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
uniform vec4 color_in;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main(void) {
|
||||
fragColor = color_in;
|
||||
gl_FragColor = color_in;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ uniform vec2 resolution_in;
|
||||
// Standard inputs
|
||||
uniform int ove_iteration;
|
||||
|
||||
in vec2 ove_texcoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
varying vec2 ove_texcoord;
|
||||
|
||||
void main(void) {
|
||||
vec4 pixel_here = texture(tex_in, ove_texcoord);
|
||||
vec4 pixel_here = texture2D(tex_in, ove_texcoord);
|
||||
|
||||
// Detect no-op situations
|
||||
if (radius_in == 0.0
|
||||
@@ -22,7 +20,7 @@ void main(void) {
|
||||
|| (inner_in && pixel_here.a == 0.0)
|
||||
|| (!inner_in && pixel_here.a == 1.0)) {
|
||||
// No-op, do nothing
|
||||
fragColor = pixel_here;
|
||||
gl_FragColor = pixel_here;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +37,7 @@ void main(void) {
|
||||
|
||||
if (abs(length(vec2(i, j))) < radius) {
|
||||
// Get pixel here
|
||||
float alpha = texture(tex_in, ove_texcoord + vec2(x_coord, y_coord)).a;
|
||||
float alpha = texture2D(tex_in, ove_texcoord + vec2(x_coord, y_coord)).a;
|
||||
|
||||
if (inner_in) {
|
||||
alpha = 1.0 - alpha;
|
||||
@@ -76,5 +74,5 @@ void main(void) {
|
||||
stroke_col = stroke_col * (1.0 - pixel_here.a) + pixel_here;
|
||||
}
|
||||
|
||||
fragColor = stroke_col;
|
||||
gl_FragColor = stroke_col;
|
||||
}
|
||||
|
||||
@@ -60,10 +60,19 @@ void ColorPreviewBox::paintEvent(QPaintEvent *e)
|
||||
|
||||
QPainter p(this);
|
||||
|
||||
QRect draw_rect = rect().adjusted(0, 0, -1, -1);
|
||||
|
||||
p.setPen(Qt::black);
|
||||
|
||||
if (color_.alpha() < 1.0) {
|
||||
// Draw black background so the background isn't the window color
|
||||
p.setBrush(Qt::black);
|
||||
p.drawRect(draw_rect);
|
||||
}
|
||||
|
||||
// Draw with color over the top
|
||||
p.setBrush(c);
|
||||
|
||||
p.drawRect(rect().adjusted(0, 0, -1, -1));
|
||||
p.drawRect(draw_rect);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,13 @@ namespace olive {
|
||||
PixelSamplerWidget::PixelSamplerWidget(QWidget *parent) :
|
||||
QGroupBox(parent)
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
|
||||
box_ = new ColorPreviewBox();
|
||||
QFontMetrics fm = fontMetrics();
|
||||
int box_sz = fm.height() * 2;
|
||||
box_->setFixedSize(box_sz, box_sz);
|
||||
layout->addWidget(box_);
|
||||
|
||||
label_ = new QLabel();
|
||||
layout->addWidget(label_);
|
||||
@@ -45,6 +51,8 @@ void PixelSamplerWidget::SetValues(const Color &color)
|
||||
|
||||
void PixelSamplerWidget::UpdateLabelInternal()
|
||||
{
|
||||
box_->SetColor(color_);
|
||||
|
||||
label_->setText(tr("<html>"
|
||||
"<font color='#FF8080'>R: %1</font><br>"
|
||||
"<font color='#80FF80'>G: %2</font><br>"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "render/color.h"
|
||||
#include "widget/colorwheel/colorpreviewbox.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -43,6 +44,8 @@ private:
|
||||
|
||||
Color color_;
|
||||
|
||||
ColorPreviewBox *box_;
|
||||
|
||||
QLabel* label_;
|
||||
|
||||
};
|
||||
|
||||
@@ -28,23 +28,22 @@ namespace olive {
|
||||
|
||||
ScopeBase::ScopeBase(QWidget* parent) :
|
||||
super(parent),
|
||||
buffer_(nullptr)
|
||||
texture_(nullptr),
|
||||
managed_tex_up_to_date_(false)
|
||||
{
|
||||
EnableDefaultContextMenu();
|
||||
}
|
||||
|
||||
void ScopeBase::SetBuffer(Frame *frame)
|
||||
void ScopeBase::SetBuffer(TexturePtr frame)
|
||||
{
|
||||
buffer_ = frame;
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
texture_ = frame;
|
||||
managed_tex_up_to_date_ = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void ScopeBase::showEvent(QShowEvent* e)
|
||||
{
|
||||
super::showEvent(e);
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
}
|
||||
|
||||
void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
|
||||
@@ -58,32 +57,6 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
|
||||
VideoParams::kInternalChannelCount));
|
||||
}
|
||||
|
||||
void ScopeBase::UploadTextureFromBuffer()
|
||||
{
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer_) {
|
||||
makeCurrent();
|
||||
|
||||
if (!texture_ || texture_->params() != buffer_->video_params()) {
|
||||
texture_ = nullptr;
|
||||
managed_tex_ = nullptr;
|
||||
|
||||
texture_ = renderer()->CreateTexture(buffer_->video_params(),
|
||||
buffer_->data(), buffer_->linesize_pixels());
|
||||
managed_tex_ = renderer()->CreateTexture(buffer_->video_params());
|
||||
} else {
|
||||
texture_->Upload(buffer_->data(), buffer_->linesize_pixels());
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ScopeBase::OnInit()
|
||||
{
|
||||
super::OnInit();
|
||||
@@ -96,13 +69,13 @@ void ScopeBase::OnPaint()
|
||||
// Clear display surface
|
||||
renderer()->ClearDestination();
|
||||
|
||||
if (buffer_) {
|
||||
if (texture_) {
|
||||
// Convert reference frame to display space
|
||||
if (!texture_ || !managed_tex_) {
|
||||
UploadTextureFromBuffer();
|
||||
makeCurrent(); // UploadTextureFromBuffer calls "doneCurrent", so we re-call "makeCurrent"
|
||||
if (!managed_tex_ || !managed_tex_up_to_date_
|
||||
|| managed_tex_->params() != texture_->params()) {
|
||||
managed_tex_ = renderer()->CreateTexture(texture_->params());
|
||||
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
|
||||
}
|
||||
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
|
||||
|
||||
DrawScope(managed_tex_, pipeline_);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
MANAGEDDISPLAYWIDGET_DEFAULT_DESTRUCTOR(ScopeBase)
|
||||
|
||||
public slots:
|
||||
void SetBuffer(Frame* frame);
|
||||
void SetBuffer(TexturePtr frame);
|
||||
|
||||
protected slots:
|
||||
virtual void OnInit() override;
|
||||
@@ -57,15 +57,13 @@ protected:
|
||||
virtual void DrawScope(TexturePtr managed_tex, QVariant pipeline);
|
||||
|
||||
private:
|
||||
void UploadTextureFromBuffer();
|
||||
|
||||
QVariant pipeline_;
|
||||
|
||||
TexturePtr texture_;
|
||||
|
||||
TexturePtr managed_tex_;
|
||||
|
||||
Frame* buffer_;
|
||||
bool managed_tex_up_to_date_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -56,8 +56,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
color_menu_enabled_(true),
|
||||
time_changed_from_timer_(false),
|
||||
prequeuing_(false),
|
||||
last_loaded_buffer_(nullptr),
|
||||
last_loaded_buffer_is_empty_(false),
|
||||
active_queue_jobs_(0),
|
||||
cache_time_(rational::NaN)
|
||||
{
|
||||
@@ -83,6 +81,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered);
|
||||
connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped);
|
||||
connect(display_widget_, &ViewerDisplayWidget::VisibilityChanged, this, &ViewerWidget::Pause);
|
||||
connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged);
|
||||
connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom);
|
||||
connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate);
|
||||
connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove);
|
||||
@@ -249,7 +248,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
|
||||
disconnect(n->audio_playback_cache(), &AudioPlaybackCache::Validated, this, &ViewerWidget::AudioCacheValidated);
|
||||
disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateStack);
|
||||
|
||||
SetDisplayImage(nullptr);
|
||||
SetDisplayImage(QVariant());
|
||||
|
||||
ruler()->SetPlaybackCache(nullptr);
|
||||
|
||||
@@ -351,7 +350,7 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
|
||||
vw->display_widget()->SetDeinterlacing(vw->display_widget()->IsDeinterlacing());
|
||||
}
|
||||
|
||||
vw->display_widget()->SetImage(last_loaded_buffer_);
|
||||
vw->display_widget()->SetImage(QVariant::fromValue(display_widget()->GetCurrentTexture()));
|
||||
|
||||
windows_.insert(screen, vw);
|
||||
}
|
||||
@@ -420,33 +419,10 @@ bool ViewerWidget::ShouldForceWaveform() const
|
||||
|
||||
void ViewerWidget::SetEmptyImage()
|
||||
{
|
||||
FramePtr frame = nullptr;
|
||||
display_widget()->SetBlank();
|
||||
|
||||
if (GetConnectedNode()) {
|
||||
frame = last_loaded_buffer_;
|
||||
|
||||
if (!frame) {
|
||||
frame = Frame::Create();
|
||||
}
|
||||
|
||||
if (frame->video_params() != GetConnectedNode()->GetVideoParams()) {
|
||||
frame->destroy();
|
||||
frame->set_video_params(GetConnectedNode()->GetVideoParams());
|
||||
}
|
||||
|
||||
if (!frame->is_allocated()) {
|
||||
frame->allocate();
|
||||
}
|
||||
|
||||
if (!last_loaded_buffer_is_empty_) {
|
||||
memset(frame->data(), 0, frame->allocated_size());
|
||||
}
|
||||
}
|
||||
|
||||
SetDisplayImage(frame);
|
||||
|
||||
if (frame) {
|
||||
last_loaded_buffer_is_empty_ = true;
|
||||
foreach (ViewerWindow *vw, windows_) {
|
||||
vw->display_widget()->SetBlank();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,6 +530,7 @@ void ViewerWidget::UpdateTextureFromNode()
|
||||
} else {
|
||||
// Not playing, run a task to get the frame either from the cache or the renderer
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
watcher->setProperty("time", QVariant::fromValue(time));
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
|
||||
nonqueue_watchers_.append(watcher);
|
||||
watcher->SetTicket(GetFrame(time, true));
|
||||
@@ -723,7 +700,7 @@ bool ViewerWidget::ViewerMightBeAStill()
|
||||
return GetConnectedNode() && GetConnectedNode()->GetConnectedTextureOutput().IsValid() && GetConnectedNode()->GetVideoLength().isNull();
|
||||
}
|
||||
|
||||
void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
|
||||
void ViewerWidget::SetDisplayImage(QVariant frame, bool main_only)
|
||||
{
|
||||
display_widget_->SetImage(frame);
|
||||
|
||||
@@ -732,10 +709,6 @@ void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
|
||||
vw->display_widget()->SetImage(frame);
|
||||
}
|
||||
}
|
||||
|
||||
last_loaded_buffer_ = frame;
|
||||
last_loaded_buffer_is_empty_ = false;
|
||||
emit LoadedBuffer(frame.get());
|
||||
}
|
||||
|
||||
void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
|
||||
@@ -749,6 +722,7 @@ void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
|
||||
}
|
||||
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
watcher->setProperty("time", QVariant::fromValue(next_time));
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
|
||||
watcher->SetTicket(GetFrame(next_time, prioritize));
|
||||
active_queue_jobs_++;
|
||||
@@ -886,8 +860,6 @@ void ViewerWidget::RendererGeneratedFrame()
|
||||
RenderTicketWatcher* ticket = static_cast<RenderTicketWatcher*>(sender());
|
||||
|
||||
if (ticket->HasResult()) {
|
||||
FramePtr frame = ticket->Get().value<FramePtr>();
|
||||
|
||||
if (nonqueue_watchers_.contains(ticket)) {
|
||||
while (!nonqueue_watchers_.isEmpty()) {
|
||||
if (nonqueue_watchers_.takeFirst() == ticket) {
|
||||
@@ -895,7 +867,7 @@ void ViewerWidget::RendererGeneratedFrame()
|
||||
}
|
||||
}
|
||||
|
||||
SetDisplayImage(frame);
|
||||
SetDisplayImage(ticket->Get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,14 +879,16 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
|
||||
RenderTicketWatcher* watcher = static_cast<RenderTicketWatcher*>(sender());
|
||||
|
||||
if (watcher->HasResult()) {
|
||||
FramePtr frame = watcher->Get().value<FramePtr>();
|
||||
QVariant frame = watcher->Get();
|
||||
|
||||
// Ignore this signal if we've paused now
|
||||
if (IsPlaying() || prequeuing_) {
|
||||
playback_queue_.AppendTimewise({frame->timestamp(), frame}, playback_speed_);
|
||||
rational ts = watcher->property("time").value<rational>();
|
||||
|
||||
playback_queue_.AppendTimewise({ts, frame}, playback_speed_);
|
||||
|
||||
foreach (ViewerWindow* window, windows_) {
|
||||
window->queue()->AppendTimewise({frame->timestamp(), frame}, playback_speed_);
|
||||
window->queue()->AppendTimewise({ts, frame}, playback_speed_);
|
||||
}
|
||||
|
||||
if (prequeuing_ && int(playback_queue_.size()) == prequeue_length_) {
|
||||
|
||||
@@ -128,7 +128,7 @@ signals:
|
||||
/**
|
||||
* @brief Signal emitted when a new frame is loaded
|
||||
*/
|
||||
void LoadedBuffer(Frame* load_buffer);
|
||||
void TextureChanged(TexturePtr t);
|
||||
|
||||
/**
|
||||
* @brief Request a scope panel
|
||||
@@ -185,7 +185,7 @@ private:
|
||||
|
||||
bool ViewerMightBeAStill();
|
||||
|
||||
void SetDisplayImage(FramePtr frame, bool main_only = false);
|
||||
void SetDisplayImage(QVariant frame, bool main_only = false);
|
||||
|
||||
void RequestNextFrameForQueue(bool prioritize = false, bool increment = true);
|
||||
|
||||
@@ -251,9 +251,6 @@ private:
|
||||
|
||||
QTimer audio_restart_timer_;
|
||||
|
||||
FramePtr last_loaded_buffer_;
|
||||
bool last_loaded_buffer_is_empty_;
|
||||
|
||||
int active_queue_jobs_;
|
||||
|
||||
rational cache_time_;
|
||||
|
||||
@@ -45,13 +45,12 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
|
||||
signal_cursor_color_(false),
|
||||
gizmos_(nullptr),
|
||||
gizmo_click_(false),
|
||||
last_loaded_buffer_(nullptr),
|
||||
hand_dragging_(false),
|
||||
deinterlace_(false),
|
||||
show_fps_(false),
|
||||
frames_skipped_(0),
|
||||
show_widget_background_(false),
|
||||
texture_equal_to_frame_(false)
|
||||
push_mode_(kPushNull)
|
||||
{
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::UpdateCursor);
|
||||
|
||||
@@ -100,17 +99,26 @@ void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
|
||||
inner_widget()->setMouseTracking(e);
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
|
||||
void ViewerDisplayWidget::SetImage(const QVariant &buffer)
|
||||
{
|
||||
if (last_loaded_buffer_ != in_buffer) {
|
||||
last_loaded_buffer_ = in_buffer;
|
||||
load_frame_ = buffer;
|
||||
|
||||
texture_equal_to_frame_ = false;
|
||||
if (load_frame_.isNull()) {
|
||||
push_mode_ = kPushNull;
|
||||
} else {
|
||||
push_mode_ = kPushFrame;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetBlank()
|
||||
{
|
||||
push_mode_ = kPushBlank;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetDeinterlacing(bool e)
|
||||
{
|
||||
deinterlace_ = e;
|
||||
@@ -318,51 +326,73 @@ void ViewerDisplayWidget::OnPaint()
|
||||
{
|
||||
// Clear background to empty
|
||||
QColor bg_color = show_widget_background_ ? palette().window().color() : Qt::black;
|
||||
renderer()->ClearDestination(bg_color.redF(), bg_color.greenF(), bg_color.blueF());
|
||||
renderer()->ClearDestination(nullptr, bg_color.redF(), bg_color.greenF(), bg_color.blueF());
|
||||
|
||||
// We only draw if we have a pipeline
|
||||
if (last_loaded_buffer_ && color_service()) {
|
||||
if (!texture_
|
||||
|| texture_->width() != last_loaded_buffer_->width()
|
||||
|| texture_->height() != last_loaded_buffer_->height()
|
||||
|| texture_->format() != last_loaded_buffer_->format()
|
||||
|| texture_->channel_count() != last_loaded_buffer_->channel_count()) {
|
||||
texture_ = renderer()->CreateTexture(last_loaded_buffer_->video_params(), last_loaded_buffer_->data(), last_loaded_buffer_->linesize_pixels());
|
||||
} else if (!texture_equal_to_frame_) {
|
||||
texture_->Upload(last_loaded_buffer_->data(), last_loaded_buffer_->linesize_pixels());
|
||||
}
|
||||
texture_equal_to_frame_ = true;
|
||||
|
||||
TexturePtr texture_to_draw = texture_;
|
||||
|
||||
if (deinterlace_) {
|
||||
if (deinterlace_shader_.isNull()) {
|
||||
deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag"))));
|
||||
}
|
||||
|
||||
if (!deinterlace_texture_
|
||||
|| deinterlace_texture_->params() != texture_to_draw->params()) {
|
||||
// (Re)create texture
|
||||
deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params());
|
||||
}
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
|
||||
|
||||
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
|
||||
|
||||
texture_to_draw = deinterlace_texture_;
|
||||
}
|
||||
|
||||
if (push_mode_ != kPushNull) {
|
||||
// Draw texture through color transform
|
||||
int device_width = width() * devicePixelRatioF();
|
||||
int device_height = height() * devicePixelRatioF();
|
||||
VideoParams::Format device_format = static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt());
|
||||
VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount);
|
||||
|
||||
renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false,
|
||||
combined_matrix_flipped_, crop_matrix_);
|
||||
if (push_mode_ == kPushBlank) {
|
||||
if (blank_shader_.isNull()) {
|
||||
blank_shader_ = renderer()->CreateNativeShader(ShaderCode());
|
||||
}
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_));
|
||||
job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_));
|
||||
|
||||
renderer()->Blit(blank_shader_, job, device_params, false);
|
||||
} else if (color_service()) {
|
||||
if (FramePtr frame = load_frame_.value<FramePtr>()) {
|
||||
// This is a CPU frame, upload it now
|
||||
if (!texture_
|
||||
|| texture_->renderer() != renderer() // Some implementations don't like it if we upload to a texture created in another (albeit shared) context
|
||||
|| texture_->width() != frame->width()
|
||||
|| texture_->height() != frame->height()
|
||||
|| texture_->format() != frame->format()
|
||||
|| texture_->channel_count() != frame->channel_count()) {
|
||||
texture_ = renderer()->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||
} else {
|
||||
texture_->Upload(frame->data(), frame->linesize_pixels());
|
||||
}
|
||||
} else if (TexturePtr texture = load_frame_.value<TexturePtr>()) {
|
||||
// This is a GPU texture, switch to it directly
|
||||
texture_ = texture;
|
||||
}
|
||||
|
||||
emit TextureChanged(texture_);
|
||||
|
||||
push_mode_ = kPushUnnecessary;
|
||||
|
||||
TexturePtr texture_to_draw = texture_;
|
||||
|
||||
if (deinterlace_) {
|
||||
if (deinterlace_shader_.isNull()) {
|
||||
deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag"))));
|
||||
}
|
||||
|
||||
if (!deinterlace_texture_
|
||||
|| deinterlace_texture_->params() != texture_to_draw->params()) {
|
||||
// (Re)create texture
|
||||
deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params());
|
||||
}
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
|
||||
|
||||
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
|
||||
|
||||
texture_to_draw = deinterlace_texture_;
|
||||
}
|
||||
|
||||
renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false,
|
||||
combined_matrix_flipped_, crop_matrix_);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw gizmos if we have any
|
||||
@@ -452,12 +482,20 @@ void ViewerDisplayWidget::OnPaint()
|
||||
|
||||
void ViewerDisplayWidget::OnDestroy()
|
||||
{
|
||||
renderer()->DestroyNativeShader(deinterlace_shader_);
|
||||
deinterlace_shader_.clear();
|
||||
renderer()->DestroyNativeShader(blank_shader_);
|
||||
blank_shader_.clear();
|
||||
|
||||
super::OnDestroy();
|
||||
|
||||
texture_ = nullptr;
|
||||
deinterlace_texture_ = nullptr;
|
||||
if (load_frame_.isNull()) {
|
||||
push_mode_ = kPushNull;
|
||||
} else {
|
||||
push_mode_ = kPushFrame;
|
||||
}
|
||||
}
|
||||
|
||||
QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos)
|
||||
@@ -542,12 +580,11 @@ void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e)
|
||||
if (signal_cursor_color_) {
|
||||
Color reference, display;
|
||||
|
||||
if (last_loaded_buffer_) {
|
||||
if (texture_) {
|
||||
QPointF pixel_pos = GenerateGizmoTransform().inverted().map(e->pos());
|
||||
pixel_pos /= texture_->params().divider();
|
||||
|
||||
pixel_pos /= last_loaded_buffer_->video_params().divider();
|
||||
|
||||
reference = last_loaded_buffer_->get_pixel(qRound(pixel_pos.x()), qRound(pixel_pos.y()));
|
||||
reference = renderer()->GetPixelFromTexture(texture_.get(), pixel_pos);
|
||||
display = color_service()->ConvertColor(reference);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,11 @@ public:
|
||||
fps_timer_update_count_++;
|
||||
}
|
||||
|
||||
TexturePtr GetCurrentTexture() const
|
||||
{
|
||||
return texture_;
|
||||
}
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Set the transformation matrix to draw with
|
||||
@@ -126,13 +131,9 @@ public slots:
|
||||
*/
|
||||
void SetSignalCursorColorEnabled(bool e);
|
||||
|
||||
/**
|
||||
* @brief Overrides the image with the load buffer of another ViewerGLWidget
|
||||
*
|
||||
* If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file
|
||||
* each time.
|
||||
*/
|
||||
void SetImage(FramePtr in_buffer);
|
||||
void SetImage(const QVariant &buffer);
|
||||
|
||||
void SetBlank();
|
||||
|
||||
/**
|
||||
* @brief Changes the pointer type if the tool is changed to the hand tool. Otherwise resets the pointer to it's
|
||||
@@ -181,6 +182,8 @@ signals:
|
||||
|
||||
void VisibilityChanged(bool visible);
|
||||
|
||||
void TextureChanged(TexturePtr texture);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Override the mouse press event for the DragStarted() signal and gizmos
|
||||
@@ -249,6 +252,11 @@ private:
|
||||
*/
|
||||
QVariant deinterlace_shader_;
|
||||
|
||||
/**
|
||||
* @brief Blank shader
|
||||
*/
|
||||
QVariant blank_shader_;
|
||||
|
||||
/**
|
||||
* @brief Translation only matrix (defaults to identity).
|
||||
*/
|
||||
@@ -283,8 +291,6 @@ private:
|
||||
|
||||
rational time_;
|
||||
|
||||
FramePtr last_loaded_buffer_;
|
||||
|
||||
/**
|
||||
* @brief Position of mouse to calculate delta from.
|
||||
*/
|
||||
@@ -304,7 +310,23 @@ private:
|
||||
|
||||
bool show_widget_background_;
|
||||
|
||||
bool texture_equal_to_frame_;
|
||||
QVariant load_frame_;
|
||||
|
||||
enum PushMode {
|
||||
/// New frame to push to internal texture
|
||||
kPushFrame,
|
||||
|
||||
/// Internal texture reference is up to date, keep showing it
|
||||
kPushUnnecessary,
|
||||
|
||||
/// Draw blank/black screen
|
||||
kPushBlank,
|
||||
|
||||
/// Draw nothing (not even a black frame)
|
||||
kPushNull,
|
||||
};
|
||||
|
||||
PushMode push_mode_;
|
||||
|
||||
private slots:
|
||||
void EmitColorAtCursor(QMouseEvent* e);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace olive {
|
||||
|
||||
struct ViewerPlaybackFrame {
|
||||
rational timestamp;
|
||||
FramePtr frame;
|
||||
QVariant frame;
|
||||
};
|
||||
|
||||
class ViewerQueue : public std::list<ViewerPlaybackFrame> {
|
||||
|
||||
Reference in New Issue
Block a user