better support for various bit rates

This commit is contained in:
itsmattkc
2019-03-26 21:42:45 +11:00
parent 3083e3920b
commit d8acef21a8
51 changed files with 812 additions and 712 deletions
+1 -2
View File
@@ -52,7 +52,6 @@ QAudioInput* audio_input = nullptr;
QFile output_recording;
bool recording = false;
bool audio_rendering = false;
int audio_rendering_rate = 0;
qint8 audio_ibuffer[audio_ibuffer_size];
@@ -154,7 +153,7 @@ void clear_audio_ibuffer() {
}
int current_audio_freq() {
return audio_rendering ? audio_rendering_rate : audio_output->format().sampleRate();
return olive::Global->is_exporting() ? audio_rendering_rate : audio_output->format().sampleRate();
}
qint64 get_buffer_offset_from_frame(double framerate, long frame) {
-1
View File
@@ -61,7 +61,6 @@ extern long audio_ibuffer_frame;
extern double audio_ibuffer_timecode;
extern bool audio_scrub;
extern bool recording;
extern bool audio_rendering;
extern int audio_rendering_rate;
void clear_audio_ibuffer();
+20 -13
View File
@@ -28,22 +28,29 @@ namespace rendering {
QVector<BitDepthInfo> bit_depths;
void InitializeBitDepths() {
BitDepthInfo bdi;
bdi.name = QCoreApplication::translate("bitdepths", "8-bit");
bdi.pixel_type = GL_UNSIGNED_BYTE;
bdi.internal_format = GL_RGBA8;
bit_depths.append(bdi);
bit_depths.resize(PIX_FMT_COUNT);
bdi.name = QCoreApplication::translate("bitdepths", "Half-Float (16-bit)");
bdi.pixel_type = GL_HALF_FLOAT;
bdi.internal_format = GL_RGBA16F;
bit_depths.append(bdi);
bit_depths[PIX_FMT_RGBA8].name = QCoreApplication::translate("bitdepths", "8-bit");
bit_depths[PIX_FMT_RGBA8].internal_format = GL_RGBA8;
bit_depths[PIX_FMT_RGBA8].pixel_format = GL_RGBA;
bit_depths[PIX_FMT_RGBA8].pixel_type = GL_UNSIGNED_BYTE;
bit_depths[PIX_FMT_RGBA16].name = QCoreApplication::translate("bitdepths", "16-bit Integer");
bit_depths[PIX_FMT_RGBA16].internal_format = GL_RGBA16UI;
bit_depths[PIX_FMT_RGBA16].pixel_format = GL_RGBA_INTEGER;
bit_depths[PIX_FMT_RGBA16].pixel_type = GL_UNSIGNED_SHORT;
bit_depths[PIX_FMT_RGBA16F].name = QCoreApplication::translate("bitdepths", "Half-Float (16-bit)");
bit_depths[PIX_FMT_RGBA16F].internal_format = GL_RGBA16F;
bit_depths[PIX_FMT_RGBA16F].pixel_format = GL_RGBA;
bit_depths[PIX_FMT_RGBA16F].pixel_type = GL_HALF_FLOAT;
bit_depths[PIX_FMT_RGBA32F].name = QCoreApplication::translate("bitdepths", "Full-Float (32-bit)");
bit_depths[PIX_FMT_RGBA32F].internal_format = GL_RGBA32F;
bit_depths[PIX_FMT_RGBA32F].pixel_format = GL_RGBA;
bit_depths[PIX_FMT_RGBA32F].pixel_type = GL_FLOAT;
bdi.name = QCoreApplication::translate("bitdepths", "Full-Float (32-bit)");
bdi.pixel_type = GL_FLOAT;
bdi.internal_format = GL_RGBA32F;
bit_depths.append(bdi);
}
}
+26 -9
View File
@@ -26,17 +26,34 @@
#include <QOpenGLExtraFunctions>
namespace olive {
namespace rendering {
struct BitDepthInfo {
QString name;
GLuint pixel_type;
GLuint internal_format;
};
namespace rendering {
extern QVector<BitDepthInfo> bit_depths;
struct BitDepthInfo {
QString name;
GLint internal_format;
GLenum pixel_format;
GLenum pixel_type;
};
void InitializeBitDepths();
}
/**
* @brief The OlivePixelFormat enum
*
* Olive's internal supported pixel formats. With the exception of OLIVE_PIX_FMT_COUNT, these must all
* be defined in InitializeBitDepths().
*/
enum PixelFormat {
PIX_FMT_RGBA8,
PIX_FMT_RGBA16,
PIX_FMT_RGBA16F,
PIX_FMT_RGBA32F,
PIX_FMT_COUNT
};
extern QVector<BitDepthInfo> bit_depths;
void InitializeBitDepths();
}
}
#endif // BITDEPTHS_H
+28 -6
View File
@@ -33,10 +33,11 @@
#include <QStatusBar>
#include <math.h>
#include "panels/panels.h"
#include "project/projectelements.h"
#include "rendering/audio.h"
#include "rendering/renderfunctions.h"
#include "panels/panels.h"
#include "global/timing.h"
#include "global/config.h"
#include "global/debug.h"
#include "ui/mainwindow.h"
@@ -44,7 +45,6 @@
// Enable verbose audio messages - good for debugging reversed audio
//#define AUDIOWARNINGS
const AVPixelFormat kDestPixFmt = AV_PIX_FMT_RGBA;
const AVSampleFormat kDestSampleFmt = AV_SAMPLE_FMT_S16;
double bytes_to_seconds(int nb_bytes, int nb_channels, int sample_rate) {
@@ -858,8 +858,6 @@ Cacher::Cacher(Clip* c) :
{}
void Cacher::OpenWorker() {
qint64 time_start = QDateTime::currentMSecsSinceEpoch();
// set some defaults for the audio cacher
if (clip->track() >= 0) {
audio_reset_ = false;
@@ -988,7 +986,26 @@ void Cacher::OpenWorker() {
last_filter = yadif_filter;
}
const char* chosen_format = av_get_pix_fmt_name(kDestPixFmt);
AVPixelFormat possible_pix_fmts[] = {
AV_PIX_FMT_RGBA,
AV_PIX_FMT_RGBA64,
AV_PIX_FMT_NONE
};
AVPixelFormat pix_fmt = avcodec_find_best_pix_fmt_of_list(possible_pix_fmts,
static_cast<AVPixelFormat>(stream->codecpar->format),
1,
nullptr);
if (pix_fmt == AV_PIX_FMT_RGBA) {
qDebug() << "This is an 8-bit image.";
media_pixel_format_ = olive::rendering::PIX_FMT_RGBA8;
} else {
qDebug() << "This is an HDR image.";
media_pixel_format_ = olive::rendering::PIX_FMT_RGBA16;
}
const char* chosen_format = av_get_pix_fmt_name(pix_fmt);
snprintf(filter_args, sizeof(filter_args), "pix_fmts=%s", chosen_format);
AVFilterContext* format_conv;
@@ -1091,7 +1108,7 @@ void Cacher::OpenWorker() {
frame_ = av_frame_alloc();
}
qInfo() << "Clip opened on track" << clip->track() << "(took" << (QDateTime::currentMSecsSinceEpoch() - time_start) << "ms)";
qInfo() << "Clip opened on track" << clip->track();
is_valid_state_ = true;
}
@@ -1336,6 +1353,11 @@ ClipQueue *Cacher::queue()
return &queue_;
}
const olive::rendering::PixelFormat &Cacher::media_pixel_format()
{
return media_pixel_format_;
}
int Cacher::RetrieveFrameFromDecoder(AVFrame* f) {
int result = 0;
int receive_ret;
+15
View File
@@ -43,6 +43,7 @@ extern "C" {
#include <QMutex>
#include "rendering/clipqueue.h"
#include "rendering/bitdepths.h"
class Clip;
@@ -254,6 +255,15 @@ public:
*/
ClipQueue* queue();
/**
* @brief Retrieve OpenGL information about this media's bit depth
*
* @return
*
* A olive::rendering::PixelFormat value corresponding to a member of olive::rendering::bit_depths.
*/
const olive::rendering::PixelFormat& media_pixel_format();
private:
/**
* @brief Reference to the parent clip. Set in the constructor and never changed during this object's lifetime.
@@ -582,6 +592,11 @@ private:
* @brief Internal function using the Cacher's known information to determine whether this media is playing in reverse
*/
bool IsReversed();
/**
* @brief Internal struct holding bit depth information for the current media
*/
olive::rendering::PixelFormat media_pixel_format_;
};
#endif // CACHER_H
+4 -4
View File
@@ -413,10 +413,10 @@ void ExportThread::Export()
long remaining_frames, frame_count = 1;
// Use Sequence Viewer's render thread - TODO separate this into a new render thread for background rendering
RenderThread* renderer = panel_sequence_viewer->viewer_widget->get_renderer();
RenderThread* renderer = panel_sequence_viewer->viewer_widget()->get_renderer();
// Override connection from RenderThread
disconnect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget, SLOT(queue_repaint()));
disconnect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget(), SLOT(queue_repaint()));
connect(renderer, SIGNAL(ready()), this, SLOT(wake()));
// Lock mutex (used for synchronization with RenderThread)
@@ -548,7 +548,7 @@ void ExportThread::Export()
// Restore original connection from RenderThread
disconnect(renderer, SIGNAL(ready()), this, SLOT(wake()));
connect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget, SLOT(queue_repaint()));
connect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget(), SLOT(queue_repaint()));
mutex.unlock();
@@ -559,7 +559,7 @@ void ExportThread::Export()
if (params_.video_enabled) vpkt_alloc = true;
if (params_.audio_enabled) apkt_alloc = true;
olive::Global->set_rendering_state(false);
olive::Global->set_export_state(false);
// If audio is enabled, flush the rest of the audio out of swresample
if (params_.audio_enabled) {
+18 -3
View File
@@ -24,8 +24,9 @@
#include <QOpenGLExtraFunctions>
#include <QDebug>
// TODO take this from Config rather than having a constant
const GLuint kPixelFormat = GL_RGBA16F;
#include "global/config.h"
#include "global/global.h"
#include "bitdepths.h"
FramebufferObject::FramebufferObject() :
buffer_(0),
@@ -64,8 +65,22 @@ void FramebufferObject::Create(QOpenGLContext *ctx, int width, int height)
ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture_);
// allocate storage for texture
const olive::rendering::BitDepthInfo& bit_depth = olive::rendering::bit_depths.at(olive::Global->is_exporting() ?
olive::CurrentConfig.export_bit_depth :
olive::CurrentConfig.playback_bit_depth);
qDebug() << "hello" << bit_depth.name;
ctx->functions()->glTexImage2D(
GL_TEXTURE_2D, 0, kPixelFormat, width, height, 0, GL_RGBA, GL_FLOAT, nullptr
GL_TEXTURE_2D,
0,
bit_depth.internal_format,
width,
height,
0,
bit_depth.pixel_format,
bit_depth.pixel_type,
nullptr
);
// set texture filtering to bilinear
+33 -93
View File
@@ -40,9 +40,9 @@ extern "C" {
#include "ui/collapsiblewidget.h"
#include "rendering/audio.h"
#include "global/math.h"
#include "global/timing.h"
#include "global/config.h"
#include "panels/timeline.h"
#include "panels/viewer.h"
#include "qopenglshaderprogramptr.h"
#include "shadergenerators.h"
@@ -365,6 +365,20 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams &params) {
int video_width = c->media_width();
int video_height = c->media_height();
// prepare framebuffers for backend drawing operations
if (c->fbo.isEmpty()) {
// create 3 fbos for nested sequences, 2 for most clips
int fbo_count = (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2;
c->fbo.resize(fbo_count);
for (int j=0;j<fbo_count;j++) {
c->fbo[j].Create(params.ctx, video_width, video_height);
}
}
bool convert_frame_to_internal = false;
// if media is footage
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
@@ -378,19 +392,13 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams &params) {
}
if (textureID == 0) {
qWarning() << "Failed to create texture";
}
}
// prepare framebuffers for backend drawing operations
if (c->fbo.isEmpty()) {
// create 3 fbos for nested sequences, 2 for most clips
int fbo_count = (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2;
} else {
c->fbo.resize(fbo_count);
convert_frame_to_internal = true;
for (int j=0;j<fbo_count;j++) {
c->fbo[j].Create(params.ctx, video_width, video_height);
}
}
@@ -422,60 +430,43 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams &params) {
} else if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
#ifndef NO_OCIO
// Convert texture to float
if (textureID != c->fbo.at(0).texture() && textureID != c->fbo.at(1).texture()) {
textureID = draw_clip(params.ctx, params.pipeline, c->fbo.at(fbo_switcher), textureID, true);
fbo_switcher = !fbo_switcher;
}
// Convert frame from source to linear colorspace
if (olive::CurrentConfig.enable_color_management)
{
if (c->ocio_shader == nullptr) {
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
// Convert texture to sequence's internal format
if (textureID != c->fbo.at(0).texture() && textureID != c->fbo.at(1).texture()) {
textureID = draw_clip(params.ctx, params.pipeline, c->fbo.at(fbo_switcher), textureID, true);
fbo_switcher = !fbo_switcher;
}
// Check if this clip has an OCIO shader set up or not
if (c->ocio_shader == nullptr) {
// Set default input colorspace
QString input_cs = OCIO::ROLE_SCENE_LINEAR;
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
if (!c->media()->to_footage()->colorspace.isEmpty()) {
input_cs = c->media()->to_footage()->colorspace;
} else {
// If this is a footage clip, try to guess the color space from the filename
QString guess_colorspace = config->parseColorSpaceFromString(c->media()->to_footage()->url.toUtf8());
if (!guess_colorspace.isEmpty()) {
input_cs = guess_colorspace;
}
}
input_cs = c->media()->to_footage()->Colorspace();
}
qDebug() << "Input colorspace:" << input_cs;
// Try to get a shader based on the input color space to scene linear
try {
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
OCIO::ConstProcessorRcPtr processor = config->getProcessor(input_cs.toUtf8(),
OCIO::ROLE_SCENE_LINEAR);
olive::shader::AlphaAssociateMode associate_mode = (c->media()->to_footage()->alpha_is_associated)
? olive::shader::DisassociateAndReassociate : olive::shader::Associate;
c->ocio_shader = olive::shader::SetupOCIO(params.ctx,
c->ocio_lut_texture,
processor,
associate_mode);
c->media()->to_footage()->alpha_is_associated);
} catch (OCIO::Exception& e) {
qWarning() << e.what();
}
}
// Ensure we got a shader, and if so, blit with it
if (c->ocio_shader != nullptr) {
textureID = olive::rendering::OCIOBlit(c->ocio_shader.get(),
c->ocio_lut_texture,
@@ -486,8 +477,6 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams &params) {
}
}
#endif
}
}
@@ -801,54 +790,6 @@ void olive::rendering::compose_audio(Viewer* viewer, Sequence* seq, int playback
compose_sequence(params);
}
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) {
return qRound((double(framenumber)/source_frame_rate)*target_frame_rate);
}
double get_timecode(Clip* c, long playhead) {
return double(playhead_to_clip_frame(c, playhead))/c->sequence->frame_rate;
}
long playhead_to_clip_frame(Clip* c, long playhead) {
return (qMax(0L, playhead - c->timeline_in(true)) + c->clip_in(true));
}
double playhead_to_clip_seconds(Clip* c, long playhead) {
// returns time in seconds
long clip_frame = playhead_to_clip_frame(c, playhead);
if (c->reversed()) {
clip_frame = c->media_length() - clip_frame - 1;
}
double secs = (double(clip_frame)/c->sequence->frame_rate)*c->speed().value;
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
secs *= c->media()->to_footage()->speed;
}
return secs;
}
int64_t seconds_to_timestamp(Clip *c, double seconds) {
return qRound64(seconds * av_q2d(av_inv_q(c->time_base())));
}
int64_t playhead_to_timestamp(Clip* c, long playhead) {
return seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead));
}
void close_active_clips(Sequence* s) {
if (s != nullptr) {
for (int i=0;i<s->clips.size();i++) {
Clip* c = s->clips.at(i).get();
if (c != nullptr) {
c->Close(true);
}
}
}
}
#ifndef NO_OCIO
GLuint olive::rendering::OCIOBlit(QOpenGLShaderProgram *pipeline,
GLuint lut,
const FramebufferObject& fbo,
@@ -880,4 +821,3 @@ GLuint olive::rendering::OCIOBlit(QOpenGLShaderProgram *pipeline,
return textureID;
}
#endif
-142
View File
@@ -24,10 +24,8 @@
#include <QOpenGLContext>
#include <QVector>
#include <QOpenGLShaderProgram>
#ifndef NO_OCIO
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#endif
#include "timeline/sequence.h"
#include "effects/effect.h"
@@ -244,143 +242,6 @@ void compose_audio(Viewer* viewer, Sequence *seq, int playback_speed, bool wait_
}
}
/**
* @brief Rescale a frame number between two frame rates
*
* Converts a frame number from one frame rate to its equivalent in another frame rate
*
* @param framenumber
*
* The frame number to convert
*
* @param source_frame_rate
*
* Frame rate that the frame number is currently in
*
* @param target_frame_rate
*
* Frame rate to convert to
*
* @return
*
* Rescaled frame number
*/
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
/**
* @brief Get timecode
*
* Get the current clip/media time from the Timeline playhead in seconds. For instance if the playhead was at the start
* of a clip (whose in point wasn't trimmed), this would be 0.0 as it's the start of the clip/media;
*
* @param c
*
* Clip to get the timecode of
*
* @param playhead
*
* Sequence playhead to convert to a clip/media timecode
*
* @return
*
* Timecode in seconds
*/
double get_timecode(Clip *c, long playhead);
/**
* @brief Convert playhead frame number to a clip frame number
*
* Converts a Timeline playhead to a the current clip's frame. Equivalent to
* `PLAYHEAD - CLIP_TIMELINE_IN + CLIP_MEDIA_IN`. All keyframes are in clip frames.
*
* @param c
*
* The clip to get the current frame number of
*
* @param playhead
*
* The current Timeline frame number
*
* @return
*
* The curren frame number of the clip at `playhead`
*/
long playhead_to_clip_frame(Clip* c, long playhead);
/**
* @brief Converts the playhead to clip seconds
*
* Get the current timecode at the playhead in terms of clip seconds.
*
* FIXME: Possible duplicate of get_timecode()? Will need to research this more.
*
* @param c
*
* Clip to return clip seconds of.
*
* @param playhead
*
* Current Timeline playhead to convert to clip seconds
*
* @return
*
* Clip time in seconds
*/
double playhead_to_clip_seconds(Clip *c, long playhead);
/**
* @brief Convert seconds to FFmpeg timestamp
*
* Used for interaction with FFmpeg, converts seconds in a floating-point value to a timestamp in AVStream->time_base
* units.
*
* @param c
*
* Clip to get timestamp of
*
* @param seconds
*
* Clip time in seconds
*
* @return
*
* An FFmpeg-compatible timestamp in AVStream->time_base units.
*/
int64_t seconds_to_timestamp(Clip* c, double seconds);
/**
* @brief Convert Timeline playhead to FFmpeg timestamp
*
* Used for interaction with FFmpeg, converts the Timeline playhead to a timestamp in AVStream->time_base
* units.
*
* @param c
*
* Clip to get timestamp of
*
* @param playhead
*
* Timeline playhead to convert to a timestamp
*
* @return
*
* An FFmpeg-compatible timestamp in AVStream->time_base units.
*/
int64_t playhead_to_timestamp(Clip *c, long playhead);
/**
* @brief Close all open clips in a Sequence
*
* Closes any currently open clips on a Sequence and waits for them to close before returning. This may be slow as a
* result on large Sequence objects. If a Clip is a nested Sequence, this function calls itself recursively on that
* Sequence too.
*
* @param s
*
* The Sequence to close all clips on.
*/
void close_active_clips(Sequence* s);
void UpdateOCIOGLState(const ComposeSequenceParams &params);
namespace olive {
@@ -389,13 +250,10 @@ namespace olive {
extern GLfloat blit_texcoords[];
extern GLfloat flipped_blit_texcoords[];
void Blit(QOpenGLShaderProgram* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
#ifndef NO_OCIO
GLuint OCIOBlit(QOpenGLShaderProgram *pipeline,
GLuint lut,
const FramebufferObject& fbo,
GLuint texture);
#endif
}
}
+9 -29
View File
@@ -27,10 +27,8 @@
#include <QOpenGLExtraFunctions>
#include <QDebug>
#ifndef NO_OCIO
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#endif
#include "timeline/sequence.h"
#include "effects/effectloaders.h"
@@ -48,14 +46,10 @@ RenderThread::RenderThread() :
tex_height(-1),
queued(false),
texture_failed(false),
#ifndef NO_OCIO
ocio_lut_texture(0),
ocio_shader(nullptr),
#endif
running(true),
#ifndef NO_OCIO
ocio_config_date(0),
#endif
front_buffer_switcher(false)
{
surface.create();
@@ -121,17 +115,12 @@ void RenderThread::run() {
pipeline_program = olive::shader::GetPipeline();
}
#ifndef NO_OCIO
// If there's no OpenColorIO shader or the configuration has changed, (re-)create it now
if (olive::CurrentConfig.enable_color_management
&& (ocio_shader == nullptr || ocio_config_date != olive::CurrentRuntimeConfig.ocio_config_date)) {
ocio_config_date = olive::CurrentRuntimeConfig.ocio_config_date;
if (olive::CurrentConfig.enable_color_management && ocio_shader == nullptr) {
destroy_ocio();
set_up_ocio();
}
#endif
// draw frame
paint();
@@ -160,7 +149,6 @@ const GLuint &RenderThread::get_texture()
return front_buffer_switcher ? front_buffer_2.texture() : front_buffer_1.texture();
}
#ifndef NO_OCIO
void RenderThread::set_up_ocio()
{
@@ -194,7 +182,7 @@ void RenderThread::set_up_ocio()
OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform);
// Create a OCIO shader with this processor
ocio_shader = olive::shader::SetupOCIO(ctx, ocio_lut_texture, processor, olive::shader::NoAssociate);
ocio_shader = olive::shader::SetupOCIO(ctx, ocio_lut_texture, processor, true);
} catch(OCIO::Exception & e) {
qCritical() << e.what();
@@ -205,12 +193,12 @@ void RenderThread::set_up_ocio()
void RenderThread::destroy_ocio()
{
// Destroy LUT texture
ctx->functions()->glDeleteTextures(1, &ocio_lut_texture);
if (ocio_lut_texture > 0) {
ctx->functions()->glDeleteTextures(1, &ocio_lut_texture);
}
ocio_lut_texture = 0;
ocio_shader = nullptr;
}
#endif
void RenderThread::paint() {
// set up compose_sequence() parameters
@@ -254,29 +242,24 @@ void RenderThread::paint() {
FramebufferObject& buffer = front_buffer_switcher ? front_buffer_1 : front_buffer_2;
// Blit the composite buffer to one of the front buffers
bool standard_blit = true;
#ifndef NO_OCIO
// If we're color managing, conver the linear composited frame to display color space
if (olive::CurrentConfig.enable_color_management && ocio_shader != nullptr) {
olive::rendering::OCIOBlit(ocio_shader.get(),
ocio_lut_texture,
buffer,
composite_buffer.texture());
standard_blit = false;
}
#else
} else {
#endif
// If we're not color managing, just blit normally
if (standard_blit) {
// If we're not color managing, just blit normally
buffer.BindBuffer();
composite_buffer.BindTexture();
olive::rendering::Blit(pipeline_program.get());
composite_buffer.ReleaseTexture();
buffer.ReleaseBuffer();
}
// flush changes
@@ -404,10 +387,7 @@ void RenderThread::delete_ctx() {
if (ctx != nullptr) {
delete_shaders();
delete_buffers();
#ifndef NO_OCIO
destroy_ocio();
#endif
}
delete ctx;
+3 -6
View File
@@ -60,23 +60,20 @@ public:
public slots:
// cleanup functions
void delete_ctx();
void delete_buffers();
void delete_shaders();
void destroy_ocio();
signals:
void ready();
private:
// cleanup functions
void delete_buffers();
void delete_shaders();
#ifndef NO_OCIO
// OpenColorIO functions
void set_up_ocio();
void destroy_ocio();
// OpenColorIO variables
GLuint ocio_lut_texture;
QOpenGLShaderProgramPtr ocio_shader;
qint64 ocio_config_date;
#endif
FramebufferObject front_buffer_1;
QMutex front_mutex1;
+27 -23
View File
@@ -118,8 +118,6 @@ QString olive::shader::GetAlphaAssociateFunction(const QString &function_name)
"}\n").arg(function_name);
}
#ifndef NO_OCIO
// copied from source code to OCIODisplay
const int OCIO_LUT3D_EDGE_SIZE = 32;
@@ -129,7 +127,7 @@ const int OCIO_NUM_3D_ENTRIES = 98304;
QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
GLuint& lut_texture,
OCIO::ConstProcessorRcPtr processor,
AlphaAssociateMode alpha_associate_mode)
bool alpha_is_associated)
{
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
@@ -157,8 +155,9 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
//
OCIO::GpuShaderDesc shaderDesc;
const char* ocio_func_name = "OCIODisplay";
shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
shaderDesc.setFunctionName("OCIODisplay");
shaderDesc.setFunctionName(ocio_func_name);
shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
//
@@ -179,39 +178,45 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
// Create OCIO shader code
QString shader_text(processor->getGpuShaderText(shaderDesc));
QString ocio_call_func;
QString shader_call;
// Enforce alpha association
switch (alpha_associate_mode) {
case Associate:
if (alpha_is_associated) {
// If alpha is already associated, we'll need to disassociate and reassociate
shader_text.append("\n");
QString disassociate_func_name = "disassoc";
shader_text.append(GetAlphaDisassociateFunction(disassociate_func_name));
QString reassociate_func_name = "reassoc";
shader_text.append(GetAlphaReassociateFunction(reassociate_func_name));
// Make OCIO call pass through disassociate and reassociate function
shader_call = QString("%3(%1(%2(col), tex2));").arg(ocio_func_name,
disassociate_func_name,
reassociate_func_name);
} else {
// If alpha is not already associated, we can just associate after OCIO
// Add associate function
shader_text.append(GetAlphaAssociateFunction("assoc"));
QString associate_func_name = "assoc";
shader_text.append(GetAlphaAssociateFunction(associate_func_name));
// Make OCIO call pass through associate function
ocio_call_func = "assoc(OCIODisplay(col, tex2));";
break;
case DisassociateAndReassociate:
// If alpha is already associated, we'll need to disassociate and reassociate
shader_text.append("\n");
shader_text.append(GetAlphaDisassociateFunction("disassoc"));
shader_text.append(GetAlphaReassociateFunction("reassoc"));
shader_call = QString("%2(%1(col, tex2));").arg(ocio_func_name, associate_func_name);
// Make OCIO call pass through disassociate and reassociate function
ocio_call_func = "reassoc(OCIODisplay(disassoc(col), tex2));";
break;
default:
// No association
ocio_call_func = "OCIODisplay(col, tex2);";
}
// Add process() function, which GetPipeline() will call if specified
shader_text.append(QString("\n"
"uniform sampler3D tex2;\n"
"\n"
"vec4 process(vec4 col) {\n"
" return %1\n"
"}\n").arg(ocio_call_func));
"}\n").arg(shader_call));
// Get pipeline-based shader to inject OCIO shader into
@@ -222,4 +227,3 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
return shader;
}
#endif
+1 -12
View File
@@ -3,29 +3,18 @@
#include "qopenglshaderprogramptr.h"
#include "framebufferobject.h"
#ifndef NO_OCIO
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE::v1;
#endif
namespace olive {
namespace shader {
QOpenGLShaderProgramPtr GetPipeline(const QString &shader_code = QString());
#ifndef NO_OCIO
enum AlphaAssociateMode {
NoAssociate,
Associate,
DisassociateAndReassociate
};
QOpenGLShaderProgramPtr SetupOCIO(QOpenGLContext *ctx,
GLuint &lut_texture,
OCIO::ConstProcessorRcPtr processor,
AlphaAssociateMode alpha_associate_mode);
#endif
bool alpha_is_associated);
QString GetAlphaDisassociateFunction(const QString& function_name);
QString GetAlphaReassociateFunction(const QString& function_name);