OBS Studio 核心图形 API(graphics/graphics.h)完整参考指南
本文系统讲解 OBS Studio 底层渲染库 libobs 的 Core Graphics API——即 libobs/graphics/graphics.h 所定义的一套与具体图形后端无关的跨平台绘制接口。读完本篇后,你能完整掌握这套 API 的全部枚举类型、核心数据结构、上下文生命周期、交换链管理、渲染目标切换、纹理/顶点/索引缓冲区管理、混合与深度模板状态控制,以及各平台(Windows/macOS/Linux)专属的扩展能力(GDI 互操作、IOSurface、DMA-BUF 等),并理解其在 libobs/graphics/graphics.c 中的源码级实现方式,为开发 OBS 插件、自定义源(source)或滤镜打下坚实基础。
定位与设计:API 无关的图形子系统封装
libobs/graphics/graphics.h 开头的注释明确说明了它的设计目标:
This is an API-independent graphics subsystem wrapper. This allows the use of OpenGL and different Direct3D versions through one shared interface.
也就是说,gs_* 系列函数是 libobs 对底层图形 API 的统一抽象层。仓库中提供了三个后端实现:
- libobs-d3d11/:Direct3D 11 后端(Windows 主路径),核心入口如 d3d11-subsystem.cpp;
- libobs-opengl/:OpenGL 后端(Linux/macOS 传统路径),核心入口如 gl-subsystem.c;
- libobs-metal/:Metal 后端(macOS 新路径),核心入口如 metal-subsystem.swift。
头文件中定义了三种设备类型的常量,可用于运行时判断当前后端:
#define GS_DEVICE_OPENGL 1
#define GS_DEVICE_DIRECT3D_11 2
#define GS_DEVICE_METAL 3
同时 GS_MAX_TEXTURES 8(见 graphics.h)限定了同时可绑定的纹理单元上限。插件作者只需编写一次 gs_* 调用,即可在三种设备上运行,这是 OBS 能够跨 Windows/macOS/Linux 保持单一渲染代码路径的关键。
图形枚举类型(Graphics Enumerations)
以下是 API 参考文档 中定义的全部枚举,与 graphics.h 中的定义一一对应。
gs_draw_mode:图元绘制模式
enum gs_draw_mode {
GS_POINTS, // 绘制点
GS_LINES, // 绘制独立线段
GS_LINESTRIP, // 绘制线段条
GS_TRIS, // 绘制独立三角形
GS_TRISTRIP, // 绘制三角形条
};
该枚举是 gs_draw(draw_mode, start_vert, num_verts) 的第一个参数,决定顶点缓冲如何解释为图元。OBS 的 2D 场景合成几乎总是使用 GS_TRIS/GS_TRISTRIP。
gs_color_format:颜色格式
| 枚举值 | 含义 |
|---|---|
GS_UNKNOWN |
未知格式 |
GS_A8 |
8 位纯 Alpha 通道 |
GS_R8 |
8 位纯 Red 通道 |
GS_RGBA / GS_BGRX / GS_BGRA |
每通道 8 位 |
GS_R10G10B10A2 |
RGB 各 10 位、Alpha 2 位 |
GS_RGBA16 / GS_R16 |
16 位整数 |
GS_RGBA16F / GS_RGBA32F |
16/32 位浮点 |
GS_RG16F / GS_RG32F / GS_R16F / GS_R32F |
浮点半精度/单精度子集通道 |
GS_DXT1 / GS_DXT3 / GS_DXT5 |
BC 系列压缩格式 |
GS_RGBA_UNORM / GS_BGRX_UNORM / GS_BGRA_UNORM |
与对应 8 位格式相同,但不走 sRGB 采样别名 |
GS_RG16 |
RG 各 16 位 |
从源码结构看,头文件还额外提供了若干内联工具函数,帮助模块代码做格式判断(graphics.h):
gs_get_format_bpp(format):按格式返回每像素位数(DXT 系返回 4/8,8 位 RGBA 系返回 32,GS_RGBA32F返回 128);gs_is_compressed_format(format):判断是否为 DXT 压缩格式;gs_is_srgb_format(format):仅GS_RGBA、GS_BGRX、GS_BGRA三种 8 位格式被视为 sRGB 格式;gs_generalize_format(format):把_UNORM变体归一化为普通格式;gs_get_format_from_space(space):HDR 色彩空间统一映射到GS_RGBA16F(见下节)。
gs_color_space:色彩空间(HDR 支持的核心)
enum gs_color_space {
GS_CS_SRGB, /* SDR */
GS_CS_SRGB_16F, /* High-precision SDR */
GS_CS_709_EXTENDED, /* Canvas, Mac EDR (HDR) */
GS_CS_709_SCRGB, /* 1.0 = 80 nits, Windows/Linux HDR */
};
这组枚举驱动 OBS 的 HDR 管线:交换链创建时依据显示器 HDR 状态选择空间,gs_set_render_target_with_color_space() 则在离屏渲染时显式指定空间。GS_CS_709_SCRGB 语义为 1.0 对应 80 nits,是 Windows/Linux 下 HDR 输出的标准空间。
其他渲染状态枚举
- gs_zstencil_format:深度模板缓冲格式——
GS_ZS_NONE(无)、GS_Z16、GS_Z24_S8、GS_Z32F、GS_Z32F_S8X24; - gs_index_type:索引缓冲位宽——
GS_UNSIGNED_SHORT(16 位)、GS_UNSIGNED_LONG(32 位); - gs_cull_mode:面剔除——
GS_BACK(默认剔除背面)、GS_FRONT、GS_NEITHER; - gs_blend_type:混合因子,完整 11 项——
GS_BLEND_ZERO、GS_BLEND_ONE、GS_BLEND_SRCCOLOR、GS_BLEND_INVSRCCOLOR、GS_BLEND_SRCALPHA、GS_BLEND_INVSRCALPHA、GS_BLEND_DSTCOLOR、GS_BLEND_INVDSTCOLOR、GS_BLEND_DSTALPHA、GS_BLEND_INVDSTALPHA、GS_BLEND_SRCALPHASAT; - gs_depth_test:深度比较函数——
GS_NEVER、GS_LESS、GS_LEQUAL、GS_EQUAL、GS_GEQUAL、GS_GREATER、GS_NOTEQUAL、GS_ALWAYS; - gs_stencil_side:模板测试作用面,注意显式赋值
GS_STENCIL_FRONT=1、GS_STENCIL_BACK、GS_STENCIL_BOTH; - gs_stencil_op_type:模板操作——
GS_KEEP、GS_ZERO、GS_REPLACE、GS_INCR、GS_DECR、GS_INVERT; - gs_cube_sides:立方体贴图 6 个面——
GS_POSITIVE_X、GS_NEGATIVE_X、GS_POSITIVE_Y、GS_NEGATIVE_Y、GS_POSITIVE_Z、GS_NEGATIVE_Z; - gs_sample_filter:采样过滤——
GS_FILTER_POINT、GS_FILTER_LINEAR、GS_FILTER_ANISOTROPIC及 6 种 min/mag/mip 组合; - gs_address_mode:纹理寻址——
GS_ADDRESS_CLAMP、GS_ADDRESS_WRAP、GS_ADDRESS_MIRROR、GS_ADDRESS_BORDER、GS_ADDRESS_MIRRORONCE; - gs_texture_type:纹理维度——
GS_TEXTURE_2D、GS_TEXTURE_3D、GS_TEXTURE_CUBE。
核心数据结构(Graphics Structures)
gs_monitor_info:显示器几何信息
struct gs_monitor_info {
int rotation_degrees; // 旋转角度
long x, y; // 显示器左上角坐标
long cx, cy; // 宽/高
};
由 Windows 平台的 gs_get_duplicator_monitor_info() 填充,供显示器捕获类源使用。
gs_tvertarray 与 gs_vb_data:顶点数据描述
struct gs_tvertarray {
size_t width; // 每个顶点的纹理坐标分量数
void *array; // 纹理坐标数组
};
struct gs_vb_data {
size_t num;
struct vec3 *points; // 顶点位置
struct vec3 *normals; // 法线
struct vec3 *tangents; // 切线
uint32_t *colors; // 顶点色(ARGB 打包)
size_t num_tex;
struct gs_tvertarray *tvarray; // 多组纹理坐标
};
graphics.h 提供了两个内联配套函数:
gs_vbdata_create():bzalloc一个零初始化的gs_vb_data;gs_vbdata_destroy(data):释放points/normals/tangents/colors/每组tvarray及结构体本身。
gs_vertexbuffer_create() 对缓冲所有权的约定正是围绕这两个函数:结构体及内部缓冲用 bmalloc()/bzalloc()/brealloc() 分配后,所有权移交给创建函数,调用方不再自行释放(除非使用 GS_DUP_BUFFER 标志)。
gs_sampler_info:采样器状态
struct gs_sampler_info {
enum gs_sample_filter filter;
enum gs_address_mode address_u, address_v, address_w;
int max_anisotropy; // 各向异性级别
uint32_t border_color; // GS_ADDRESS_BORDER 时的边界色
};
其他结构
- gs_display_mode:
width/height/bits/freq,描述分辨率与刷新率; - gs_rect:
x/y/cx/cy,视口与剪裁矩形统一用它; - gs_window:跨平台的原生窗口句柄,成员按平台条件编译(graphics.h):
struct gs_window {
#if defined(_WIN32)
void *hwnd; // Windows: HWND
#elif defined(__APPLE__)
__unsafe_unretained id view; // macOS: NSView
#elif defined(__linux__) || defined(__FreeBSD__)
uint32_t id; void *display; // Linux/X11: 窗口 ID 与 Display
#endif
};
- gs_init_data:交换链初始化参数:
struct gs_init_data {
struct gs_window window; // 目标原生控件
uint32_t cx, cy; // 初始尺寸
uint32_t num_backbuffers; // 后备缓冲数量
enum gs_color_format format; // 颜色格式
enum gs_zstencil_format zsformat; // 深度模板格式
uint32_t adapter; // 适配器索引(gs_enum_adapters 得到)
};
常用标志位宏
graphics.h 还定义了若干按位或组合的标志常量,散见于纹理、缓冲创建函数:
| 宏 | 值 | 用途 |
|---|---|---|
GS_BUILD_MIPMAPS |
1 << 0 |
自动构建 mipmap(文档注明“未完全测试”) |
GS_DYNAMIC |
1 << 1 |
允许实时动态更新(纹理/顶点/索引缓冲通用) |
GS_RENDER_TARGET |
1 << 2 |
纹理可作为渲染目标 |
GS_DUP_BUFFER |
1 << 4 |
创建时不转移缓冲所有权 |
GS_FLIP_U / GS_FLIP_V |
1 << 0 / 1 << 1 |
gs_draw_sprite 系列的水平/垂直翻转 |
GS_CLEAR_COLOR / GS_CLEAR_DEPTH / GS_CLEAR_STENCIL |
1<<0/1<<1/1<<2 |
gs_clear() 的清除标志 |
gs_create() 的返回值常量:GS_SUCCESS 0、GS_ERROR_FAIL -1、GS_ERROR_MODULE_NOT_FOUND -2、GS_ERROR_NOT_SUPPORTED -3。
初始化与上下文函数(Initialization Functions)
gs_create / gs_destroy:创建与销毁图形上下文
int gs_create(graphics_t **graphics, const char *module, uint32_t adapter);
void gs_destroy(graphics_t *graphics);
第二个参数 module 是要动态加载的后端子系统模块名。查看 graphics.c 的实现可以看到完整流程:
bzalloc一个graphics_subsystem并初始化互斥锁;os_dlopen(module)加载后端模块,失败则返回GS_ERROR_MODULE_NOT_FOUND;load_graphics_imports()解析后端导出的函数表(gs_exports);- 调用后端
device_create(&device, adapter)创建设备,非GS_SUCCESS即走错误路径; graphics_init()完成子系统内部初始化。
任何一步失败都会 gs_destroy() 清理并返回对应错误码,调用方据此可尝试下一个后端或适配器。
gs_enum_adapters:枚举适配器
void gs_enum_adapters(bool (*callback)(void *param, const char *name, uint32_t id), void *param);
文档说明这主要适用于 Windows(多显卡选择)。从 graphics.c 看,当后端不支持适配器枚举时,会回退到调用一次 callback(param, "Default", 0)——因此插件不应假设枚举结果一定非平凡。
上下文锁:gs_enter_context / gs_leave_context / gs_get_context
void gs_enter_context(graphics_t *graphics);
void gs_leave_context(void);
graphics_t *gs_get_context(void);
这是线程安全模型的核心。graphics.c 中每个线程持有一个 THREAD_LOCAL graphics_t *thread_graphics,进入/离开上下文是可重入引用计数式的:
gs_enter_context()检查当前线程的thread_graphics;若已锁其他上下文则先全部退出,再pthread_mutex_lock(&graphics->mutex)、调用后端device_enter_context(),并os_atomic_inc_long(&graphics->ref);gs_leave_context()原子递减引用计数,只有降到 0 时才真正调用后端device_leave_context()并释放互斥锁(graphics.c);gs_get_context()直接返回当前线程的thread_graphics。
因此插件的典型用法是成对调用:
gs_enter_context(my_graphics);
/* 所有 gs_* 资源操作与绘制 */
gs_leave_context();
而绝大多数绘制函数内部都先走 gs_valid() 检查:未在上下文中调用只会打印 LOG_DEBUG 日志("%s: called while not in a graphics context")并静默返回,不会崩溃(graphics.c)。
子系统初始化时的内部资源
从 graphics_init() 可以看到上下文创建时自动构建的内容,理解它们有助于调试绘制类问题:
- 一个 512 顶点容量的立即模式顶点缓冲(
IMMEDIATE_COUNT 512,GS_DYNAMIC标志),供gs_render_start()/gs_vertex2f()系列使用; - 三套四边形 sprite 顶点缓冲(普通、子区域动态、UV 翻转),支撑
gs_draw_sprite()/gs_draw_sprite_subregion()的高效实现; - 矩阵栈压入单位矩阵;
- 默认混合状态设为“源 Alpha / 反源 Alpha”(RGB 用
GS_BLEND_SRCALPHA+GS_BLEND_INVSRCALPHA,Alpha 用GS_BLEND_ONE+GS_BLEND_INVSRCALPHA,操作GS_BLEND_OP_ADD),这正是文档所述gs_reset_blend_state()恢复的默认值。
矩阵栈函数(Matrix Stack Functions)
世界矩阵以栈形式管理,全部函数操作栈顶矩阵:
| 函数 | 作用 |
|---|---|
gs_matrix_push() |
压栈,复制当前矩阵 |
gs_matrix_pop() |
弹栈,恢复上一矩阵 |
gs_matrix_identity() |
置为单位矩阵 |
gs_matrix_transpose() |
转置当前矩阵 |
gs_matrix_set(const struct matrix4 *matrix) |
直接设置 |
gs_matrix_get(struct matrix4 *dst) |
读取当前矩阵 |
gs_matrix_mul(const struct matrix4 *matrix) |
右乘指定矩阵 |
gs_matrix_rotquat(const struct quat *rot) |
乘四元数旋转 |
gs_matrix_rotaa(const struct axisang *rot) / gs_matrix_rotaa4f(x, y, z, angle) |
乘轴角旋转 |
gs_matrix_translate(const struct vec3 *pos) / gs_matrix_translate3f(x, y, z) |
平移 |
gs_matrix_scale(const struct vec3 *scale) / gs_matrix_scale3f(x, y, z) |
缩放 |
每个 push/pop 必须成对,OBS 场景树(scene item 的 T 矩阵)在每帧逐层 push/translate/rotate/scale/pop 来构建合成层级。matrix4、quat、axisang、vec3 等数学类型同位于 libobs/graphics/ 目录(如 matrix4.h、quat.h),可参考 matrix4 参考页。
2D 绘制辅助函数(Draw Functions)
Sprite 系列
void gs_draw_sprite(gs_texture_t *tex, uint32_t flip, uint32_t width, uint32_t height);
void gs_draw_quadf(gs_texture_t *tex, uint32_t flip, float width, float height);
void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip,
uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
gs_draw_sprite():绘制 2D sprite,自动把当前 effect 的"image"参数设为该纹理并渲染一个四边形;tex可为NULL(配合纯色 effect 使用);width/height传 0 时使用纹理原始尺寸;flip可取0、GS_FLIP_U(水平翻转)、GS_FLIP_V(垂直翻转)或其组合;gs_draw_quadf():同上,但宽高为浮点数,适合亚像素定位;gs_draw_sprite_subregion():只绘制纹理的[x, y, cx, cy]子区域——OBS 的“裁剪区域”功能即基于此。
视口与投影模式
| 函数 | 作用 |
|---|---|
gs_reset_viewport() |
视口重置为当前交换链尺寸 |
gs_set_2d_mode() |
投影矩阵置为屏幕尺寸正交模式(2D 合成标准入口) |
gs_set_3d_mode(double fovy, double znear, double zfar) |
屏幕尺寸透视模式 |
gs_perspective(fovy, aspect, znear, zfar) |
自定义透视投影(fovy 单位:度) |
gs_ortho(left, right, top, bottom, znear, zfar) |
正交投影 |
gs_frustum(left, right, top, bottom, znear, zfar) |
视锥投影 |
gs_viewport_push() / gs_viewport_pop() |
视口保存/恢复 |
gs_projection_push() / gs_projection_pop() |
投影矩阵保存/恢复 |
gs_set_viewport(x, y, width, height) |
设置视口(相对左上角) |
gs_get_viewport(struct gs_rect *rect) |
读取视口 |
gs_set_scissor_rect(const struct gs_rect *rect) |
设置剪裁矩形,传 NULL 清除 |
混合状态栈
void gs_blend_state_push(void); // 保存当前混合状态
void gs_blend_state_pop(void); // 恢复
void gs_reset_blend_state(void); // 恢复为默认:源 Alpha + 反源 Alpha
交换链(Swap Chains)
交换链是把渲染结果呈现到原生窗口控件的载体,OBS 主预览窗口、每个显示输出各自持有一条。
| 函数 | 说明 |
|---|---|
gs_swapchain_t *gs_swapchain_create(const struct gs_init_data *data) |
创建交换链,失败返回 NULL |
void gs_swapchain_destroy(gs_swapchain_t *swapchain) |
销毁 |
void gs_resize(uint32_t cx, uint32_t cy) |
调整当前活动交换链尺寸 |
void gs_update_color_space(void) |
依据最近显示器的 HDR 状态更新交换链色彩空间 |
void gs_get_size(uint32_t *cx, uint32_t *cy) / gs_get_width() / gs_get_height() |
查询当前交换链尺寸 |
gs_swapchain_create() 接受的是上文 gs_init_data,其中 window 成员必须已按平台填好(Windows 的 HWND、macOS 的 NSView、Linux 的窗口 ID+Display)。
资源加载(Resource Loading)
“加载”指把资源绑定到当前渲染状态,而不是创建资源本身:
| 函数 | 说明 |
|---|---|
gs_load_vertexbuffer(gs_vertbuffer_t *vertbuffer) |
绑定顶点缓冲,NULL 为卸载 |
gs_load_indexbuffer(gs_indexbuffer_t *indexbuffer) |
绑定索引缓冲,NULL 为卸载 |
gs_load_texture(gs_texture_t *tex, int unit) |
绑定纹理到指定单元(一般不手动调用) |
gs_load_samplerstate(gs_samplerstate_t *samplerstate, int unit) |
绑定采样器(一般不手动调用) |
gs_load_swapchain(gs_swapchain_t *swapchain) |
绑定交换链,NULL 为卸载 |
纹理单元受 GS_MAX_TEXTURES 8 限制;effect 框架通常会自动完成纹理/采样器绑定,手动调用多出现在自定义渲染代码中。
渲染目标与逐帧绘制控制
渲染目标切换
enum gs_color_space gs_get_color_space(void);
gs_texture_t *gs_get_render_target(void);
gs_zstencil_t *gs_get_zstencil_target(void);
void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil);
void gs_set_render_target_with_color_space(gs_texture_t *tex, gs_zstencil_t *zstencil,
enum gs_color_space space);
void gs_set_cube_render_target(gs_texture_t *cubetex, int side, gs_zstencil_t *zstencil);
gs_set_render_target()等价于以隐式GS_CS_SRGB空间设置目标——OBS 的每帧画布(canvas)渲染、滤镜链每一级都是切换渲染目标 + 切换视口 + 切换 effect 的组合;- HDR 滤镜需要用
gs_set_render_target_with_color_space()显式指定GS_CS_SRGB_16F/GS_CS_709_*空间; gs_set_cube_render_target()允许渲染到立方体贴图的某个面(side取gs_cube_sides),zstencil可为NULL。
纹理拷贝与暂存
void gs_copy_texture(gs_texture_t *dst, gs_texture_t *src);
void gs_stage_texture(gs_stagesurf_t *dst, gs_texture_t *src);
gs_stage_texture() 把 GPU 纹理拷入 staging 表面再读回 RAM,文档提示“最好隔一帧处理以防阻塞(stalling)”。
场景开始/结束与 gs_draw
void gs_begin_scene(void);
void gs_end_scene(void);
void gs_draw(enum gs_draw_mode draw_mode, uint32_t start_vert, uint32_t num_verts);
文档明确 gs_begin_scene()/gs_end_scene() 由 libobs 自动调用,插件无需手动调用。gs_draw() 是最低层的绘制入口:按 draw_mode 解释从 start_vert 开始的 num_verts 个顶点。
清除、呈现与刷新
void gs_clear(uint32_t clear_flags, const struct vec4 *color, float depth, uint8_t stencil);
void gs_present(void); // 把渲染结果提交到屏幕
void gs_flush(void); // 强制刷新 GPU 命令
clear_flags 可组合 GS_CLEAR_COLOR | GS_CLEAR_DEPTH | GS_CLEAR_STENCIL。
状态开关与混合/深度/模板函数
| 函数 | 说明 |
|---|---|
gs_set_cull_mode(enum gs_cull_mode mode) / gs_get_cull_mode() |
设置/读取面剔除模式 |
gs_enable_blending(bool enable) |
开关混合 |
gs_enable_depth_test(bool enable) |
开关深度测试 |
gs_enable_stencil_test(bool enable) |
开关模板测试 |
gs_enable_stencil_write(bool enable) |
开关模板写入 |
gs_enable_color(red, green, blue, alpha) |
逐通道开关写入 |
gs_blend_function(src, dest) |
统一设置 RGB+Alpha 混合因子 |
gs_blend_function_separate(src_c, dest_c, src_a, dest_a) |
RGB 与 Alpha 分别设置 |
gs_blend_op(enum gs_blend_op_type op) |
混合方程操作(ADD/SUBTRACT/REVERSE_SUBTRACT/MIN/MAX) |
gs_depth_function(enum gs_depth_test test) |
设置深度比较函数 |
gs_stencil_function(side, test) |
模板比较函数,side 取 GS_STENCIL_FRONT/BACK/BOTH |
gs_stencil_op(side, fail, zfail, zpass) |
模板测试失败/深度失败/深度通过三态操作 |
典型 3D 源(如 3D 文本)会:开深度测试 → gs_depth_function(GS_LESS) → 绘制 → 关深度测试;2D 叠加层则通常保持混合开启、剔除关闭。
纹理函数(Texture Functions)
创建与查询
gs_texture_t *gs_texture_create(uint32_t width, uint32_t height,
enum gs_color_format color_format,
uint32_t levels, const uint8_t **data, uint32_t flags);
gs_texture_t *gs_texture_create_from_file(const char *file);
void gs_texture_destroy(gs_texture_t *tex);
uint32_t gs_texture_get_width(const gs_texture_t *tex);
uint32_t gs_texture_get_height(const gs_texture_t *tex);
enum gs_color_format gs_texture_get_color_format(const gs_texture_t *tex);
levels:总 mip 级数,1 表示无 mipmap。头文件还提供了gs_get_total_levels(width, height, depth)内联函数(graphics.h),按最大边长逐次折半计算所需级数,可直接用于正确传参;flags按位或组合GS_BUILD_MIPMAPS(文档注明“未完全测试”)、GS_DYNAMIC、GS_RENDER_TARGET;gs_texture_create_from_file()从图像文件加载;文档特别提示:动画 GIF 不建议用它,应改用 image-file 辅助器(image-file 参考页,实现位于 libobs/graphics/image-file.c)。
映射与更新
bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr, uint32_t *linesize);
void gs_texture_unmap(gs_texture_t *tex);
void gs_texture_set_image(gs_texture_t *tex, const uint8_t *data, uint32_t linesize, bool invert);
gs_texture_map()/gs_texture_unmap():把动态纹理映射到 CPU 可写内存,linesize(pitch)作为出参返回——写入时务必按返回的 pitch 而非width*bpp逐行拷贝;gs_texture_set_image():批量更新动态纹理,invert=true表示垂直翻转图像。
Linux/FreeBSD/DragonFly 专属:DMA-BUF 支持
gs_texture_t *gs_texture_create_from_dmabuf(unsigned int width, unsigned int height,
uint32_t drm_format, enum gs_color_format color_format,
uint32_t n_planes, const int *fds,
const uint32_t *strides, const uint32_t *offsets,
const uint64_t *modifiers);
文档要点:
- 交换 DMA-BUF 因多平面特性而繁琐(YUV 每个平面可作一个颜色通道,或监视器缓冲把光标放在独立平面);
- 该函数分开处理 OBS 色彩格式与 DRM 格式,因此可用着色器转换不支持的格式(如 YUV)再创建纹理;但必须确保两者匹配正确,否则纹理可能创建或渲染失败;
modifiers数组内所有值必须相等,逐平面不同 modifier 不受支持;- 各平面参数(
fds/strides/offsets/modifiers)数组长度均为n_planes。
配套的能力查询与同步对象 API(同样仅 Linux/FreeBSD/DragonFly):
| 函数 | 说明 |
|---|---|
gs_query_dmabuf_capabilities(&flags, &drm_formats, &n_formats) |
查询是否支持隐式 modifier(GS_DMABUF_FLAG_IMPLICIT_MODIFIERS_SUPPORTED)及支持的 DRM 格式;调用方需 bfree() 释放 drm_formats |
gs_query_dmabuf_modifiers_for_format(drm_format, &modifiers, &n_modifiers) |
查询某格式支持的显式 modifier;同样需 bfree() 释放 |
gs_query_sync_capabilities() |
检查是否支持同步对象 |
gs_sync_create() |
在命令流中插入 fence,创建在 fence 执行后 signal 的同步对象 |
gs_sync_create_from_syncobj_timeline_point(syncobj_fd, timeline_point) |
从 DRM syncobj 时间线点创建 |
gs_sync_destroy(sync) |
销毁;若仍在使用则标记为延迟销毁 |
gs_sync_export_syncobj_timeline_point(sync, syncobj_fd, timeline_point) |
导出为 DRM syncobj 时间线点 |
gs_sync_signal_syncobj_timeline_point(syncobj_fd, timeline_point) |
直接 signal 某时间线点 |
gs_sync_wait(sync) |
阻塞命令流直至同步对象 signal |
这套 API 支撑 OBS 在 Wayland/X11 下的零拷贝屏幕/窗口捕获:捕获插件(如 plugins/linux-capture/、plugins/linux-pipewire/)把帧的 DMA-BUF 直接交给 GPU,配合 sync 对象完成 CPU/GPU 同步。
macOS 专属:IOSurface
gs_texture_t *gs_texture_create_from_iosurface(void *iosurf);
bool gs_texture_rebind_iosurface(gs_texture_t *texture, void *iosurf);
从系统 IOSurface 创建纹理(macOS 窗口/屏幕捕获路径),以及把已有纹理重绑到另一张 IOSurface,避免重建 GPU 资源。
Windows 专属:GDI 互操作与共享纹理
gs_texture_t *gs_texture_create_gdi(uint32_t width, uint32_t height);
void *gs_texture_get_dc(gs_texture_t *gdi_tex);
void gs_texture_release_dc(gs_texture_t *gdi_tex);
gs_texture_t *gs_texture_open_shared(uint32_t handle);
bool gs_gdi_texture_available(void);
bool gs_shared_texture_available(void);
gs_texture_create_gdi()创建 GDI 可锁定的互操作纹理,gs_texture_get_dc()取出HDC绘制后必须用gs_texture_release_dc()释放;gs_texture_open_shared()从共享句柄导入纹理,配合gs_gdi_texture_available()/gs_shared_texture_available()先行探测能力。
从源码结构看,Windows 路径还有 keyed mutex 同步(gs_texture_acquire_sync()/gs_texture_release_sync())等跨设备纹理交换接口(graphics.h),供游戏/窗口捕获在多个设备间安全传递帧。
立方体贴图函数(Cube Texture Functions)
gs_texture_t *gs_cubetexture_create(uint32_t size, enum gs_color_format color_format,
uint32_t levels, const uint8_t **data, uint32_t flags);
void gs_cubetexture_destroy(gs_texture_t *cubetex);
uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex);
enum gs_color_format gs_cubetexture_get_color_format(const gs_texture_t *cubetex);
void gs_cubetexture_set_image(gs_texture_t *cubetex, uint32_t side,
const void *data, uint32_t linesize, bool invert);
size 是立方体的宽/高/深统一边长;flags 与 2D 纹理相同(GS_BUILD_MIPMAPS/GS_DYNAMIC/GS_RENDER_TARGET)。side 取 gs_cube_sides 六面之一。立方体贴图可用于 3D 环境的背景板(backdrop)渲染,头文件中还有配套的 gs_draw_cube_backdrop() 辅助函数(graphics.h)。
暂存表面函数(Staging Surface Functions)
Staging surface 用于把纹理从 VRAM 高效拷回 RAM:
| 函数 | 说明 |
|---|---|
gs_stagesurf_t *gs_stagesurface_create(width, height, color_format) |
创建 |
void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf) |
销毁 |
gs_stagesurface_get_width/height(stagesurf) |
查询尺寸 |
gs_stagesurface_get_color_format(stagesurf) |
查询格式 |
gs_stagesurface_map(stagesurf, &data, &linesize) |
映射读取;完成后必须 gs_stagesurface_unmap() |
void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf) |
解除映射 |
完整“GPU→CPU”回读流程:gs_stagesurface_create() → 每帧 gs_stage_texture(stagesurf, src_tex) → gs_stagesurface_map() 读像素 → gs_stagesurface_unmap()。OBS 的视频回放、预览截图功能依赖这条链路。
Z-Stencil、采样器、顶点与索引缓冲
Z-Stencil
gs_zstencil_t *gs_zstencil_create(uint32_t width, uint32_t height, enum gs_zstencil_format format);
void gs_zstencil_destroy(gs_zstencil_t *zstencil);
作为 gs_set_render_target() 的第二参数使用,为离屏渲染提供深度/模板缓冲。
采样器状态
gs_samplerstate_t *gs_samplerstate_create(const struct gs_sampler_info *info);
void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate);
info 即上文 gs_sampler_info;创建后可通过 effect 参数 gs_effect_set_next_sampler() 或手动 gs_load_samplerstate() 绑定。
顶点缓冲
gs_vertbuffer_t *gs_vertexbuffer_create(struct gs_vb_data *data, uint32_t flags);
void gs_vertexbuffer_destroy(gs_vertbuffer_t *vertbuffer);
void gs_vertexbuffer_flush(gs_vertbuffer_t *vertbuffer);
void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vertbuffer, const struct gs_vb_data *data);
struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vertbuffer);
关键约定(均与文档一致):
data应由gs_vbdata_create()创建,各成员用bmalloc()/bzalloc()/brealloc()分配;默认所有权移交给创建函数,调用方不得再释放;flags可组合GS_DYNAMIC(支持实时动态更新)与GS_DUP_BUFFER(不转移所有权,适合共享静态四边形等小缓冲——libobs 内部初始化 sprite 缓冲时正是这样用的,见 graphics.c);gs_vertexbuffer_flush():把内部gs_vb_data的修改刷入 GPU(仅动态缓冲);gs_vertexbuffer_flush_direct(vertbuffer, data):直接刷入指定数据,无需刷新的组件可留NULL;gs_vertexbuffer_get_data():取得内部数据以就地修改,再配flush()更新(仅动态缓冲)。
索引缓冲
gs_indexbuffer_t *gs_indexbuffer_create(enum gs_index_type type, void *indices, size_t num, uint32_t flags);
void gs_indexbuffer_destroy(gs_indexbuffer_t *indexbuffer);
void gs_indexbuffer_flush(gs_indexbuffer_t *indexbuffer);
void gs_indexbuffer_flush_direct(gs_indexbuffer_t *indexbuffer, const void *data);
void *gs_indexbuffer_get_data(const gs_indexbuffer_t *indexbuffer);
size_t gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *indexbuffer);
enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer);
indices必须用bmalloc()/bzalloc()/bralloc()分配,所有权移交给索引缓冲对象(GS_DUP_BUFFER除外);type取GS_UNSIGNED_SHORT(顶点数 ≤ 65535 时推荐,更省内存)或GS_UNSIGNED_LONG;flush/flush_direct/get_data语义与顶点缓冲完全对称,且仅限GS_DYNAMIC缓冲使用。
显示器复制器(Windows Only)与显示器函数
Display Duplicator 基于 Windows 8+ 输出复制 API,用于显示器捕获(屏幕捕获源的首选路径):
gs_duplicator_t *gs_duplicator_create(int monitor_idx);
void gs_duplicator_destroy(gs_duplicator_t *duplicator);
bool gs_duplicator_update_frame(gs_duplicator_t *duplicator);
gs_texture_t *gs_duplicator_get_texture(gs_duplicator_t *duplicator);
bool gs_get_duplicator_monitor_info(int monitor_idx, struct gs_monitor_info *monitor_info);
用法闭环:按索引创建 → 每帧 update_frame() 拉取新帧 → get_texture() 拿到 GPU 纹理直接喂给场景,全程无 CPU 拷贝。gs_get_duplicator_monitor_info() 返回 false 表示索引处无显示器。
另外,跨平台的 gs_is_monitor_hdr(void *monitor) 用于查询某显示器是否处于 HDR 模式,是 gs_update_color_space() 决策与 HDR 输出链路的基础。从源码结构看,Windows 路径还能查询复制器的色彩空间与 SDR 白点(gs_duplicator_get_color_space()/gs_duplicator_get_sdr_white_level(),graphics.h),支撑 HDR 屏幕捕获的亮度映射。
立即模式渲染辅助(Render Helper Functions)
这套函数提供 OpenGL 风格的“顶点流”接口,底层写入前文提到的 512 顶点动态立即模式缓冲(graphics.c):
void gs_render_start(bool b_new); // 开始录制顶点;b_new=true 清空已有数据
void gs_render_stop(enum gs_draw_mode mode); // 结束并按 mode 绘制
gs_vertbuffer_t *gs_render_save(void); // 结束并返回顶点缓冲对象(不立即绘制)
void gs_vertex2f(float x, float y);
void gs_vertex3f(float x, float y, float z);
void gs_normal3f(float x, float y, float z);
void gs_color(uint32_t color); // ARGB 打包顶点色
void gs_texcoord(float x, float y, int unit);
void gs_vertex2v(const struct vec2 *v);
void gs_vertex3v(const struct vec3 *v);
void gs_normal3v(const struct vec3 *v);
void gs_color4v(const struct vec4 *v);
void gs_texcoord2v(const struct vec2 *v, int unit);
一个典型的动态线条绘制片段(如自绘 UI 指示器):
gs_render_start(true);
gs_vertex2f(x0, y0); gs_color(0xFF00FF00);
gs_vertex2f(x1, y1);
gs_render_stop(GS_LINES);
gs_render_save() 与 gs_render_stop() 的区别在于前者把顶点“存成”一个 gs_vertbuffer_t 供之后反复绑定绘制,适合几何不变、位置矩阵每帧变化的图形。
不透明类型总览(Graphics Types)
文档末尾列出的 gs_* 不透明类型(graphics.h 中的 typedef)与各自的结构体名对应关系如下,供在 C++ 代码与文档间对照:
| typedef | 底层结构 |
|---|---|
gs_texture_t |
struct gs_texture |
gs_stagesurf_t |
struct gs_stage_surface |
gs_zstencil_t |
struct gs_zstencil_buffer |
gs_vertbuffer_t |
struct gs_vertex_buffer |
gs_indexbuffer_t |
struct gs_index_buffer |
gs_samplerstate_t |
struct gs_sampler_state |
gs_swapchain_t |
struct gs_swap_chain |
gs_texrender_t |
struct gs_texture_render |
gs_shader_t / gs_sparam_t |
struct gs_shader / struct gs_shader_param |
gs_effect_t |
struct gs_effect |
gs_device_t |
struct gs_device |
graphics_t |
struct graphics_subsystem |
gs_sync_t |
void(平台相关不透明类型) |
gs_duplicator_t |
struct gs_duplicator(Windows) |
实践要点小结
- 生命周期:插件获取
graphics_t后,所有资源操作必须包在gs_enter_context()/gs_leave_context()内;上下文计数归零才真正解锁,嵌套调用是安全的。 - 所有权规则:
gs_vertexbuffer_create()/gs_indexbuffer_create()默认接管bmalloc系分配的缓冲;共享静态缓冲用GS_DUP_BUFFER防止被释放。 - 2D 场景三板斧:
gs_set_2d_mode()→gs_set_viewport()→ effect 参数 +gs_draw_sprite()或gs_render_start()/gs_render_stop(),这是绝大多数 OBS 源/滤镜的合成写法。 - 格式选择:SDR 用
GS_RGBA(sRGB);HDR/高精度路径用GS_CS_*空间对应的GS_RGBA16F(gs_get_format_from_space()的映射逻辑可佐证);压缩纹理仅 DXT1/3/5 三选。 - 平台特化:Windows 用 Duplicator/GDI/共享纹理,macOS 用 IOSurface,Linux 系用 DMA-BUF + sync 对象实现零拷贝捕获——编写捕获类插件时应先用各平台的“available/capabilities”查询函数探测能力,再降级到 CPU 路径。
- 完整文档交叉引用:本主题原文档为 Core Graphics API 参考;图像文件加载见 image-file 参考;math 类型(
vec3/matrix4/quat/axisang)分别见 vec3、matrix4、quat、axisang 各参考页;整体渲染管线背景可参考 backend-design 与 graphics。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00