app: migrate all engine access to the C ABI facade (nm U _ZN5olive = 0)

Every app module now reaches liboakengine exclusively through
oakengine_* C calls, EngineEventBridge subscriptions and app-side
handle headers (cliphandle/keyframehandle/nodevaluehandle/oakvaluehelper).
Direct C++ command construction, engine signal connect()s, and engine
type usage in MOC-visible signatures are gone: 557 -> 0 undefined
olive:: symbols in oak-editor.
This commit is contained in:
2026-07-26 22:43:21 +08:00
parent f95590e924
commit 0aa5879f35
256 changed files with 12357 additions and 4044 deletions
@@ -0,0 +1,246 @@
/***
Oak - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OAK_COLORPROCESSORHANDLE_H
#define OAK_COLORPROCESSORHANDLE_H
#include <memory>
#include <QString>
#include <QStringList>
#include <oakengine/color.h>
#include <olive/core/core.h>
#include "render/colortransform.h"
namespace olive
{
class ColorManager;
/**
* @brief App-side replacement for the engine's former ManagedColor class.
*
* The engine-side class was removed during the C ABI migration; this
* header-only equivalent lives entirely in application code (every method
* is inline), so no olive::ManagedColor symbol is imported from the engine
* shared library. It pairs an RGBA color with the color-space input id and
* the output transform, exactly like the original.
*/
class ManagedColor : public Color {
public:
ManagedColor() = default;
ManagedColor(const double &r, const double &g, const double &b,
const double &a = 1.0)
: Color(r, g, b, a)
{
}
ManagedColor(const char *data, const core::PixelFormat &format,
int channel_layout)
: Color(data, format, channel_layout)
{
}
ManagedColor(const Color &c)
: Color(c)
{
}
const QString &color_input() const
{
return color_input_;
}
void set_color_input(const QString &color_input)
{
color_input_ = color_input;
}
const ColorTransform &color_output() const
{
return color_transform_;
}
void set_color_output(const ColorTransform &color_output)
{
color_transform_ = color_output;
}
private:
QString color_input_;
ColorTransform color_transform_;
};
/**
* @brief Opaque-handle replacement for ColorProcessorPtr
*
* The color processor object lives behind the engine's C ABI
* (oakengine/color.h); application code only ever holds this shared
* handle, so no olive::ColorProcessor symbol is imported from the engine
* library.
*/
struct ColorProcessorHandleDeleter {
void operator()(OakEngineColorProcessor *p) const
{
oakengine_color_processor_free(p);
}
};
using ColorProcessorHandlePtr = std::shared_ptr<OakEngineColorProcessor>;
/**
* @brief Reinterpret an engine ColorManager pointer as its borrowed facade
* handle (the same reinterpret pattern the other facade families use).
*/
inline OakEngineColorManager *oak_color_manager(ColorManager *mgr)
{
return reinterpret_cast<OakEngineColorManager *>(mgr);
}
inline const OakEngineColorManager *oak_color_manager(const ColorManager *mgr)
{
return reinterpret_cast<const OakEngineColorManager *>(mgr);
}
/**
* @brief Run a buf/size facade string getter and return the QString.
*/
template <typename Fn> QString oak_query_string(Fn &&fn)
{
const int len = fn(nullptr, 0);
if (len <= 0) {
return QString();
}
QByteArray buf(len + 1, 0);
fn(buf.data(), buf.size());
return QString::fromUtf8(buf.constData(), len);
}
/**
* @brief Run a count/at facade list getter pair and return the QStringList.
*/
template <typename CountFn, typename AtFn>
QStringList oak_query_string_list(CountFn &&count_fn, AtFn &&at_fn)
{
QStringList list;
const int count = count_fn();
list.reserve(count);
for (int i = 0; i < count; i++) {
list.append(oak_query_string(
[&](char *buf, int size) { return at_fn(i, buf, size); }));
}
return list;
}
/**
* @brief Convert an olive::ColorTransform to the facade POD. The QByteArray
* outputs back the POD's pointers and must outlive its use.
*/
inline oak_color_transform oak_to_transform(const ColorTransform &t,
QByteArray *output,
QByteArray *view,
QByteArray *look)
{
*output = t.output().toUtf8();
*view = t.view().toUtf8();
*look = t.look().toUtf8();
oak_color_transform pod;
pod.is_display = t.is_display() ? 1 : 0;
pod.output = output->constData();
pod.view = view->constData();
pod.look = look->constData();
return pod;
}
/**
* @brief ColorManager::get_compliant_color_space(ColorTransform) through
* the facade.
*/
inline ColorTransform oak_compliant_transform(ColorManager *mgr,
const ColorTransform &in,
bool force_display = false)
{
QByteArray o, v, l;
const oak_color_transform pod = oak_to_transform(in, &o, &v, &l);
int is_display = 0;
char out[256], view[256], look[256];
if (oakengine_color_manager_compliant_transform(
oak_color_manager(mgr), &pod, force_display ? 1 : 0, &is_display,
out, sizeof(out), view, sizeof(view), look, sizeof(look)) !=
OAKENGINE_OK) {
return in;
}
if (is_display) {
return ColorTransform(QString::fromUtf8(out), QString::fromUtf8(view),
QString::fromUtf8(look));
}
return ColorTransform(QString::fromUtf8(out));
}
/**
* @brief ColorManager::get_compliant_color_space(QString) through the
* facade.
*/
inline QString oak_compliant_color_space(ColorManager *mgr, const QString &s)
{
const QByteArray name = s.toUtf8();
return oak_query_string([&](char *buf, int size) {
return oakengine_color_manager_compliant_color_space(
oak_color_manager(mgr), name.constData(), buf, size);
});
}
/**
* @brief ColorProcessor::create() through the facade (never throws; an
* OCIO failure yields a handle for which IsValid() is false).
*/
inline ColorProcessorHandlePtr
oak_make_color_processor(ColorManager *mgr, const QString &input,
const ColorTransform &dest,
int direction = OAKENGINE_COLOR_PROCESSOR_NORMAL)
{
QByteArray o, v, l;
const oak_color_transform pod = oak_to_transform(dest, &o, &v, &l);
const QByteArray in = input.toUtf8();
return ColorProcessorHandlePtr(
oakengine_color_processor_create(oak_color_manager(mgr),
in.constData(), &pod, direction),
ColorProcessorHandleDeleter());
}
/**
* @brief ColorProcessor::convert_color() through the facade. A null or
* invalid processor passes the color through unchanged (matching the
* engine's behavior).
*/
inline Color oak_convert_color(const ColorProcessorHandlePtr &proc,
const Color &in)
{
double rgba[4] = { in.red(), in.green(), in.blue(), in.alpha() };
double out[4];
if (oakengine_color_processor_convert_color(proc.get(), rgba, out) ==
OAKENGINE_OK) {
return Color(out[0], out[1], out[2], out[3]);
}
return in;
}
} // namespace olive
#endif // OAK_COLORPROCESSORHANDLE_H
+116 -69
View File
@@ -25,11 +25,11 @@
#include <QMessageBox>
#include "panel/panelmanager.h"
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
#include "render/backend/dynamicrenderer.h"
#endif
#include "render/opengl/openglrenderer.h"
#include "render/rendermanager.h"
#include "oakengine/videoparams.h"
#include "oakengine/renderer.h"
#include "oakengine/display.h"
#include "widget/viewer/vieweroutpututils.h"
#include "common/configwrapper.h"
namespace olive
{
@@ -49,21 +49,24 @@ ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent)
// Create renderer
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
{
auto *dynamic_renderer = new DynamicRenderer(
RenderManager::backend_to_string(
RenderManager::instance()->requested_backend()),
this);
if (!dynamic_renderer->load()) {
const QString backend = oak_query_string([](char *buf, int sz) {
int backend = oakengine_render_manager_requested_backend();
return oakengine_render_manager_backend_to_string(backend, buf,
sz);
});
attached_renderer_ = static_cast<Renderer *>(
oakengine_display_renderer_create_dynamic(
backend.toUtf8().constData(), this));
if (!attached_renderer_) {
qWarning()
<< "Failed to load dynamic render backend for viewer, falling back to OpenGL";
delete dynamic_renderer;
attached_renderer_ = new OpenGLRenderer(this);
} else {
attached_renderer_ = dynamic_renderer;
attached_renderer_ = static_cast<Renderer *>(
oakengine_display_renderer_create_opengl(this));
}
}
#else
attached_renderer_ = new OpenGLRenderer(this);
attached_renderer_ = static_cast<Renderer *>(
oakengine_display_renderer_create_opengl(this));
#endif
if (attached_renderer_->is_open_gl()) {
@@ -120,33 +123,43 @@ ManagedDisplayWidget::~ManagedDisplayWidget()
}
}
void ManagedDisplayWidget::connect_color_manager(ColorManager *color_manager)
void ManagedDisplayWidget::connect_color_manager(OakEngineColorManager *color_manager)
{
if (color_manager_ == color_manager) {
return;
}
if (color_manager_ != nullptr) {
disconnect(color_manager_, &ColorManager::config_changed, this,
&ManagedDisplayWidget::color_config_changed);
disconnect(color_manager_, &ColorManager::reference_space_changed, this,
&ManagedDisplayWidget::color_config_changed);
for (int64_t id : color_subs_) {
oakengine_event_unsubscribe(id);
}
color_subs_.clear();
}
color_manager_ = color_manager;
if (color_manager_ != nullptr) {
connect(color_manager_, &ColorManager::config_changed, this,
&ManagedDisplayWidget::color_config_changed);
connect(color_manager_, &ColorManager::reference_space_changed, this,
&ManagedDisplayWidget::color_config_changed);
auto sub = [this](int ev) {
int64_t id = oakengine_event_subscribe(
color_manager_, ev,
[](const oakengine_event *, void *userdata) {
static_cast<ManagedDisplayWidget *>(userdata)
->color_config_changed();
},
this);
if (id > 0) {
color_subs_.append(id);
}
};
sub(OAKENGINE_EVENT_COLOR_MANAGER_CONFIG_CHANGED);
sub(OAKENGINE_EVENT_COLOR_MANAGER_REFERENCE_SPACE_CHANGED);
}
color_config_changed();
emit color_manager_changed(color_manager_);
}
ColorManager *ManagedDisplayWidget::color_manager() const
OakEngineColorManager *ManagedDisplayWidget::color_manager() const
{
return color_manager_;
}
@@ -163,7 +176,14 @@ const ColorTransform &ManagedDisplayWidget::get_color_transform() const
Menu *ManagedDisplayWidget::get_color_space_menu(QMenu *parent, bool auto_connect)
{
QStringList colorspaces = color_manager()->list_available_colorspaces();
QStringList colorspaces = oak_query_string_list(
[this]() {
return oakengine_color_manager_colorspace_count(color_manager_);
},
[this](int i, char *buf, int size) {
return oakengine_color_manager_colorspace_at(color_manager_, i, buf,
size);
});
Menu *ocio_colorspace_menu = new Menu(tr("Color Space"), parent);
@@ -195,17 +215,27 @@ void ManagedDisplayWidget::color_config_changed()
// which is usually a scene-referred space (e.g. ACEScg / Linear) and makes
// the picture look raw/wrong on a monitor.
if (color_transform_.output().isEmpty()) {
QString display = color_manager_->get_default_display();
QString view = color_manager_->get_default_view(display);
set_color_transform(color_manager_->get_compliant_color_space(
QString display = oak_query_string([this](char *buf, int size) {
return oakengine_color_manager_default_display(color_manager_, buf,
size);
});
QString view = oak_query_string([this, &display](char *buf, int size) {
QByteArray d = display.toUtf8();
return oakengine_color_manager_default_view(color_manager_,
d.constData(), buf,
size);
});
set_color_transform(oak_compliant_transform(
reinterpret_cast<olive::ColorManager *>(color_manager_),
ColorTransform(display, view, QString()), true));
} else {
set_color_transform(
color_manager_->get_compliant_color_space(color_transform_, false));
set_color_transform(oak_compliant_transform(
reinterpret_cast<olive::ColorManager *>(color_manager_),
color_transform_, false));
}
}
ColorProcessorPtr ManagedDisplayWidget::color_service()
ColorProcessorHandlePtr ManagedDisplayWidget::color_service()
{
return color_service_;
}
@@ -232,7 +262,8 @@ void ManagedDisplayWidget::menu_display_select(QAction *action)
{
const ColorTransform &old_transform = get_color_transform();
ColorTransform new_transform = color_manager()->get_compliant_color_space(
ColorTransform new_transform = oak_compliant_transform(
reinterpret_cast<olive::ColorManager *>(color_manager_),
ColorTransform(action->data().toString(), old_transform.view(),
old_transform.look()));
@@ -243,7 +274,8 @@ void ManagedDisplayWidget::menu_view_select(QAction *action)
{
const ColorTransform &old_transform = get_color_transform();
ColorTransform new_transform = color_manager()->get_compliant_color_space(
ColorTransform new_transform = oak_compliant_transform(
reinterpret_cast<olive::ColorManager *>(color_manager_),
ColorTransform(old_transform.display(), action->data().toString(),
old_transform.look()));
@@ -254,7 +286,8 @@ void ManagedDisplayWidget::menu_look_select(QAction *action)
{
const ColorTransform &old_transform = get_color_transform();
ColorTransform new_transform = color_manager()->get_compliant_color_space(
ColorTransform new_transform = oak_compliant_transform(
reinterpret_cast<olive::ColorManager *>(color_manager_),
ColorTransform(old_transform.display(), old_transform.view(),
action->data().toString()));
@@ -263,14 +296,14 @@ void ManagedDisplayWidget::menu_look_select(QAction *action)
void ManagedDisplayWidget::menu_colorspace_select(QAction *action)
{
set_color_transform(color_manager()->get_compliant_color_space(
set_color_transform(oak_compliant_transform(
reinterpret_cast<olive::ColorManager *>(color_manager_),
ColorTransform(action->data().toString())));
}
void ManagedDisplayWidget::on_destroy()
{
attached_renderer_->destroy();
attached_renderer_->post_destroy();
oakengine_display_renderer_destroy(attached_renderer_);
}
void ManagedDisplayWidget::set_color_transform(const ColorTransform &transform)
@@ -279,7 +312,7 @@ void ManagedDisplayWidget::set_color_transform(const ColorTransform &transform)
setup_color_processor();
ColorProcessorChangedEvent();
color_processor_changed_event();
}
void ManagedDisplayWidget::on_init()
@@ -287,19 +320,9 @@ void ManagedDisplayWidget::on_init()
if (!is_backend_neutral_) {
QOpenGLContext *context =
static_cast<ManagedDisplayWidgetOpenGL *>(inner_widget_)->context();
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
if (auto *dynamic_renderer =
dynamic_cast<DynamicRenderer *>(attached_renderer_)) {
dynamic_renderer->init_with_open_gl_context(context);
dynamic_renderer->post_init();
return;
}
#endif
static_cast<OpenGLRenderer *>(attached_renderer_)->init(context);
static_cast<OpenGLRenderer *>(attached_renderer_)->post_init();
oakengine_display_renderer_init(attached_renderer_, context);
} else {
attached_renderer_->init();
attached_renderer_->post_init();
oakengine_display_renderer_init(attached_renderer_, nullptr);
}
}
@@ -309,7 +332,7 @@ void ManagedDisplayWidget::enable_default_context_menu()
&ManagedDisplayWidget::show_default_context_menu);
}
void ManagedDisplayWidget::ColorProcessorChangedEvent()
void ManagedDisplayWidget::color_processor_changed_event()
{
update();
}
@@ -346,8 +369,11 @@ VideoParams ManagedDisplayWidget::get_viewport_params() const
int device_height = height() * devicePixelRatioF();
PixelFormat device_format = static_cast<PixelFormat::Format>(
OAK_CONFIG("OfflinePixelFormat").toInt());
return VideoParams(device_width, device_height, device_format,
VideoParams::k_internal_channel_count);
oak_video_params pod = {};
pod.width = device_width;
pod.height = device_height;
pod.format = device_format;
return video_params_from_pod(pod);
}
void ManagedDisplayWidget::update()
@@ -393,7 +419,14 @@ bool ManagedDisplayWidget::eventFilter(QObject *o, QEvent *e)
Menu *ManagedDisplayWidget::get_display_menu(QMenu *parent, bool auto_connect)
{
QStringList displays = color_manager()->list_available_displays();
QStringList displays = oak_query_string_list(
[this]() {
return oakengine_color_manager_display_count(color_manager_);
},
[this](int i, char *buf, int size) {
return oakengine_color_manager_display_at(color_manager_, i, buf,
size);
});
Menu *ocio_display_menu = new Menu(tr("Display"), parent);
@@ -414,8 +447,17 @@ Menu *ManagedDisplayWidget::get_display_menu(QMenu *parent, bool auto_connect)
Menu *ManagedDisplayWidget::get_view_menu(QMenu *parent, bool auto_connect)
{
QStringList views =
color_manager()->list_available_views(color_transform_.display());
QByteArray disp = color_transform_.display().toUtf8();
QStringList views = oak_query_string_list(
[this, &disp]() {
return oakengine_color_manager_view_count(color_manager_,
disp.constData());
},
[this, &disp](int i, char *buf, int size) {
return oakengine_color_manager_view_at(color_manager_,
disp.constData(), i, buf,
size);
});
Menu *ocio_view_menu = new Menu(tr("View"), parent);
@@ -436,7 +478,14 @@ Menu *ManagedDisplayWidget::get_view_menu(QMenu *parent, bool auto_connect)
Menu *ManagedDisplayWidget::get_look_menu(QMenu *parent, bool auto_connect)
{
QStringList looks = color_manager()->list_available_looks();
QStringList looks = oak_query_string_list(
[this]() {
return oakengine_color_manager_look_count(color_manager_);
},
[this](int i, char *buf, int size) {
return oakengine_color_manager_look_at(color_manager_, i, buf,
size);
});
Menu *ocio_look_menu = new Menu(tr("Look"), parent);
@@ -467,17 +516,15 @@ void ManagedDisplayWidget::setup_color_processor()
color_service_ = nullptr;
if (color_manager_) {
// (Re)create color processor
try {
color_service_ = ColorProcessor::create(
color_manager_, color_manager_->get_reference_color_space(),
color_transform_);
} catch (ocio::Exception &e) {
QMessageBox::critical(
this, tr("OpenColorIO Error"),
tr("Failed to set color configuration: %1").arg(e.what()),
QMessageBox::Ok);
}
// (Re)create color processor. The facade never throws: OCIO failures
// are caught inside the engine and surface as an invalid processor.
QString ref_cs = oak_query_string([this](char *buf, int size) {
return oakengine_color_manager_reference_color_space(
color_manager_, buf, size);
});
color_service_ = oak_make_color_processor(
reinterpret_cast<olive::ColorManager *>(color_manager_),
ref_cs, color_transform_);
} else {
color_service_ = nullptr;
}
+22 -16
View File
@@ -19,8 +19,8 @@
***/
#ifndef OAK_MANAGEDDISPLAYOBJECT_H
#define OAK_MANAGEDDISPLAYOBJECT_H
#ifndef MANAGEDDISPLAYOBJECT_H
#define MANAGEDDISPLAYOBJECT_H
//#define USE_QOPENGLWINDOW
@@ -32,8 +32,12 @@
#include <QOpenGLWidget>
#endif
#include "node/color/colormanager/colormanager.h"
#include "oakengine/color.h"
#include "oakengine/events.h"
#include "render/colorprocessor.h"
#include "render/colortransform.h"
#include "render/renderer.h"
#include "widget/manageddisplay/colorprocessorhandle.h"
#include "widget/menu/menu.h"
namespace olive
@@ -53,9 +57,9 @@ public:
virtual ~ManagedDisplayWidgetOpenGL() override
{
if (context()) {
destroy_listener();
DestroyListener();
disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this,
&ManagedDisplayWidgetOpenGL::destroy_listener);
&ManagedDisplayWidgetOpenGL::DestroyListener);
}
}
@@ -69,7 +73,7 @@ protected:
virtual void initializeGL() override
{
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this,
&ManagedDisplayWidgetOpenGL::destroy_listener,
&ManagedDisplayWidgetOpenGL::DestroyListener,
Qt::DirectConnection);
emit on_init();
@@ -81,7 +85,7 @@ protected:
}
private slots:
void destroy_listener()
void DestroyListener()
{
makeCurrent();
@@ -142,7 +146,7 @@ public:
/**
* @brief Access currently connected ColorManager (nullptr if none)
*/
ColorManager *color_manager() const;
OakEngineColorManager *color_manager() const;
/**
* @brief Get current color transform
@@ -185,18 +189,18 @@ public slots:
/**
* @brief Connect a ColorManager (ColorManagers usually belong to the Project)
*/
void connect_color_manager(ColorManager *color_manager);
void connect_color_manager(OakEngineColorManager *color_manager);
signals:
/**
* @brief Emitted when the color processor changes
*/
void color_processor_changed(ColorProcessorPtr processor);
void color_processor_changed(ColorProcessorHandlePtr processor);
/**
* @brief Emitted when a new color manager is connected
*/
void color_manager_changed(ColorManager *color_manager);
void color_manager_changed(OakEngineColorManager *color_manager);
void frame_swapped();
@@ -204,7 +208,7 @@ protected:
/**
* @brief Provides access to the color processor (nullptr if none is set)
*/
ColorProcessorPtr color_service();
ColorProcessorHandlePtr color_service();
/**
* @brief Enables a context menu that allows simple access to the DVL pipeline
@@ -216,7 +220,7 @@ protected:
*
* Default functionality is just to call update()
*/
virtual void ColorProcessorChangedEvent();
virtual void color_processor_changed_event();
Renderer *renderer() const
{
@@ -304,12 +308,12 @@ private:
/**
* @brief Connected color manager
*/
ColorManager *color_manager_;
OakEngineColorManager *color_manager_;
/**
* @brief Color management service
*/
ColorProcessorPtr color_service_;
ColorProcessorHandlePtr color_service_;
/**
* @brief Internal color transform storage
@@ -318,6 +322,8 @@ private:
bool is_backend_neutral_ = false;
QVector<int64_t> color_subs_;
private slots:
/**
* @brief Sets all color settings to the defaults pertaining to this configuration
@@ -352,4 +358,4 @@ private slots:
}
#endif // OAK_MANAGEDDISPLAYOBJECT_H
#endif // MANAGEDDISPLAYOBJECT_H