Add render backend capability info ABI

This commit is contained in:
2026-07-13 10:19:29 +08:00
parent 38c5afb13d
commit 5fc8232671
8 changed files with 97 additions and 1 deletions
+11 -1
View File
@@ -148,6 +148,16 @@ target_link_libraries(oakgl-cabi-check PRIVATE ${OLIVE_LIBRARIES} OfxHost)
target_compile_definitions(oakgl-cabi-check PRIVATE ${OLIVE_DEFINITIONS})
target_compile_options(oakgl-cabi-check PRIVATE ${OLIVE_COMPILE_OPTIONS})
add_library(oakvulkan-cabi-check OBJECT
render/vulkan/vulkanbackend_c.cpp
)
target_include_directories(oakvulkan-cabi-check PRIVATE
${CMAKE_SOURCE_DIR}/app
)
target_link_libraries(oakvulkan-cabi-check PRIVATE Qt${QT_VERSION_MAJOR}::Core)
target_compile_definitions(oakvulkan-cabi-check PRIVATE ${OLIVE_DEFINITIONS})
target_compile_options(oakvulkan-cabi-check PRIVATE ${OLIVE_COMPILE_OPTIONS})
# Add application
add_executable(olive-editor
main.cpp
@@ -156,7 +166,7 @@ add_executable(olive-editor
)
target_include_directories(olive-editor PUBLIC pluginSupport)
target_link_libraries(olive-editor PUBLIC OfxHost)
add_dependencies(olive-editor oakgl-cabi-check)
add_dependencies(olive-editor oakgl-cabi-check oakvulkan-cabi-check)
if (OAK_ENABLE_DYNAMIC_RENDER_BACKEND)
add_dependencies(olive-editor oakgl oakvulkan)
endif()
+8
View File
@@ -142,6 +142,8 @@ bool DynamicRenderer::ResolveFunctions()
RESOLVE(opengl_context_, OakBackendOpenGLContextFn,
"oak_renderer_opengl_context");
#undef RESOLVE
get_info_ = reinterpret_cast<OakBackendGetInfoFn>(
library_.resolve("oak_renderer_get_info"));
is_available_ = reinterpret_cast<OakBackendIsAvailableFn>(
library_.resolve("oak_renderer_is_available"));
return true;
@@ -165,6 +167,7 @@ void DynamicRenderer::ResetFunctions()
{
create_ = nullptr;
destroy_ = nullptr;
get_info_ = nullptr;
is_available_ = nullptr;
init_ = nullptr;
init_with_context_ = nullptr;
@@ -184,6 +187,11 @@ void DynamicRenderer::ResetFunctions()
opengl_context_ = nullptr;
}
bool DynamicRenderer::GetBackendInfo(OakRenderBackendInfo *out_info) const
{
return handle_ && get_info_ && out_info && get_info_(handle_, out_info);
}
bool DynamicRenderer::Init()
{
return Load() && init_(handle_);
+6
View File
@@ -19,6 +19,11 @@ public:
bool Load();
bool InitWithOpenGLContext(QOpenGLContext *context);
bool GetBackendInfo(OakRenderBackendInfo *out_info) const;
QString backend_name() const
{
return backend_;
}
virtual bool Init() override;
virtual void PostDestroy() override;
@@ -62,6 +67,7 @@ private:
OakBackendCreateFn create_ = nullptr;
OakBackendDestroyFn destroy_ = nullptr;
OakBackendGetInfoFn get_info_ = nullptr;
OakBackendIsAvailableFn is_available_ = nullptr;
OakBackendInitFn init_ = nullptr;
OakBackendInitWithContextFn init_with_context_ = nullptr;
+25
View File
@@ -2,6 +2,7 @@
#define RENDERBACKEND_C_H
#include <stdbool.h>
#include <stdint.h>
#ifdef _WIN32
#define OAK_RENDER_BACKEND_EXPORT extern "C" __declspec(dllexport)
@@ -15,8 +16,32 @@ extern "C" {
typedef void *OakRenderBackendHandle;
enum OakRenderBackendKind {
OAK_RENDER_BACKEND_UNKNOWN = 0,
OAK_RENDER_BACKEND_OPENGL = 1,
OAK_RENDER_BACKEND_VULKAN = 2
};
enum OakRenderBackendCapability {
OAK_RENDER_BACKEND_CAP_TEXTURES = 1ULL << 0,
OAK_RENDER_BACKEND_CAP_SHADERS = 1ULL << 1,
OAK_RENDER_BACKEND_CAP_BLIT = 1ULL << 2,
OAK_RENDER_BACKEND_CAP_READBACK = 1ULL << 3,
OAK_RENDER_BACKEND_CAP_VIEWER_CONTEXT = 1ULL << 4
};
struct OakRenderBackendInfo {
uint32_t abi_version;
uint32_t kind;
uint64_t capabilities;
const char *name;
const char *status;
};
typedef OakRenderBackendHandle (*OakBackendCreateFn)(void *parent);
typedef void (*OakBackendDestroyFn)(OakRenderBackendHandle handle);
typedef bool (*OakBackendGetInfoFn)(OakRenderBackendHandle handle,
struct OakRenderBackendInfo *out_info);
typedef bool (*OakBackendIsAvailableFn)(OakRenderBackendHandle handle);
typedef bool (*OakBackendInitFn)(OakRenderBackendHandle handle);
typedef void (*OakBackendInitWithContextFn)(OakRenderBackendHandle handle,
+17
View File
@@ -43,6 +43,23 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy(OakRenderBackendHandle handl
delete Renderer(handle);
}
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
OakRenderBackendHandle handle, OakRenderBackendInfo *out_info)
{
if (!handle || !out_info) {
return false;
}
out_info->abi_version = 1;
out_info->kind = OAK_RENDER_BACKEND_OPENGL;
out_info->capabilities = OAK_RENDER_BACKEND_CAP_TEXTURES |
OAK_RENDER_BACKEND_CAP_SHADERS | OAK_RENDER_BACKEND_CAP_BLIT |
OAK_RENDER_BACKEND_CAP_READBACK |
OAK_RENDER_BACKEND_CAP_VIEWER_CONTEXT;
out_info->name = "opengl";
out_info->status = "available";
return true;
}
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_is_available(
OakRenderBackendHandle handle)
{
+14
View File
@@ -38,6 +38,20 @@ OAK_RENDER_BACKEND_EXPORT void oak_renderer_destroy(OakRenderBackendHandle handl
delete Backend(handle);
}
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_get_info(
OakRenderBackendHandle handle, OakRenderBackendInfo *out_info)
{
if (!handle || !out_info) {
return false;
}
out_info->abi_version = 1;
out_info->kind = OAK_RENDER_BACKEND_VULKAN;
out_info->capabilities = 0;
out_info->name = "vulkan";
out_info->status = "placeholder-unavailable";
return true;
}
OAK_RENDER_BACKEND_EXPORT bool oak_renderer_is_available(
OakRenderBackendHandle handle)
{
+2
View File
@@ -61,6 +61,8 @@
已新增可选 `oak_renderer_is_available` C ABI:后端库可以在被加载和 create 后报告自身是否可用。OpenGL 后端返回可用;Vulkan 占位后端返回不可用,适配器随后卸载它并回退 OpenGL。这把“后端存在”和“后端可用于渲染”分开,避免后续最小化链接边界时把不可用实现误接入渲染路径。
已新增 `oak_renderer_get_info` C ABI:后端库可以报告 ABI 版本、后端类型、能力位和状态字符串。默认构建也会编译检查 OpenGL/Vulkan 两个 C wrapper,避免只在实验构建中发现 C ABI 破损。
因此动态后端成为默认路径前,仍需要把 OpenGL 后端库的链接边界收敛到最小集合:
- 后端库只拥有 OpenGL/Vulkan native 操作和必要的后端私有状态。
@@ -10,6 +10,15 @@ TEST(DynamicRenderBackend, LoadsExperimentalOpenGLBackend)
olive::DynamicRenderer renderer(QStringLiteral("opengl"));
ASSERT_TRUE(renderer.Load());
EXPECT_EQ(renderer.OpenGLContext(), nullptr);
OakRenderBackendInfo info = {};
ASSERT_TRUE(renderer.GetBackendInfo(&info));
EXPECT_EQ(info.abi_version, 1U);
EXPECT_EQ(info.kind, OAK_RENDER_BACKEND_OPENGL);
EXPECT_STREQ(info.name, "opengl");
EXPECT_TRUE(info.capabilities & OAK_RENDER_BACKEND_CAP_TEXTURES);
EXPECT_TRUE(info.capabilities & OAK_RENDER_BACKEND_CAP_SHADERS);
EXPECT_TRUE(info.capabilities & OAK_RENDER_BACKEND_CAP_BLIT);
EXPECT_TRUE(info.capabilities & OAK_RENDER_BACKEND_CAP_READBACK);
#endif
}
@@ -20,6 +29,11 @@ TEST(DynamicRenderBackend, FallsBackWhenExperimentalVulkanUnavailable)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
ASSERT_TRUE(renderer.Load());
EXPECT_EQ(renderer.backend_name(), QStringLiteral("opengl"));
EXPECT_EQ(renderer.OpenGLContext(), nullptr);
OakRenderBackendInfo info = {};
ASSERT_TRUE(renderer.GetBackendInfo(&info));
EXPECT_EQ(info.kind, OAK_RENDER_BACKEND_OPENGL);
EXPECT_STREQ(info.name, "opengl");
#endif
}