创建逻辑
obs 在windows 下分为Opengl 和 directx 两种渲染模式,默认使用的是directx ,兼容性更好;
代码路径:
E:\opensrc\obs_studio_src\obs-studio\UI\obs-app.cpp 选择渲染模式
const char* OBSApp::GetRenderModule() const {
const char* renderer = config_get_string(appConfig, "Video", "Renderer");
return (astrcmpi(renderer, "Direct3D 11") == 0) ? DL_D3D11 : DL_OPENGL;
}
在ResetVideo中通过obs_video_info ovi 参数graphics_module 传递到底层
int OBSBasic::ResetVideo()
{
if (outputHandler && outputHandler->Active())
return OBS_VIDEO_CURRENTLY_ACTIVE;
ProfileScope("OBSBasic::ResetVideo");
struct obs_video_info ovi;
int ret;
GetConfigFPS(ovi.fps_num, ovi.fps_den);
const char *colorFormat = config_get_string(activeConfiguration, "Video", "ColorFormat");
const char *colorSpace = config_get_string(activeConfiguration, "Video", "ColorSpace");
const char *colorRange = config_get_string(activeConfiguration, "Video", "ColorRange");
ovi.graphics_module = App()->GetRenderModule();
gs_create(&video->graphics, ovi->graphics_module, ovi->adapter) 通过graphics_module load对应的动态库
static int obs_init_graphics(struct obs_video_info *ovi)
{
struct obs_core_video *video = &obs->video;
uint8_t transparent_tex_data[2 * 2 * 4] = {0};
const uint8_t *transparent_tex = transparent_tex_data;
struct gs_sampler_info point_sampler = {0};
bool success = true;
int errorcode;
profile_start(obs_init_graphics_name);
errorcode = gs_create(&video->graphics, ovi->graphics_module, ovi->adapter);
gs_create 完成设备的创建
int gs_create(graphics_t **pgraphics, const char *module, uint32_t adapter)
{
int errcode = GS_ERROR_FAIL;
graphics_t *graphics = bzalloc(sizeof(struct graphics_subsystem));
pthread_mutex_init_value(&graphics->mutex);
pthread_mutex_init_value(&graphics->effect_mutex);
//动态库 libobs-d3d11.dll
graphics->module = os_dlopen(module);
if (!graphics->module) {
errcode = GS_ERROR_MODULE_NOT_FOUND;
goto error;
}
if (!load_graphics_imports(&graphics->exports, graphics->module, module))
goto error;
//创建设备
errcode = graphics->exports.device_create(&graphics->device, adapter);
if (errcode != GS_SUCCESS)
goto error;
if (!graphics_init(graphics)) {
errcode = GS_ERROR_FAIL;
goto error;
}
*pgraphics = graphics;
return errcode;
error:
gs_destroy(graphics);
return errcode;
}
E:\opensrc\obs_studio_src\obs-studio\libobs-d3d11\d3d11-subsystem.cpp
走到d3d11 走的创建设备逻辑
int device_create(gs_device_t **p_device, uint32_t adapter)
{
gs_device *device = NULL;
int errorcode = GS_SUCCESS;
try {
blog(LOG_INFO, "---------------------------------");
blog(LOG_INFO, "Initializing D3D11...");
LogD3DAdapters();
CreateShaderCacheDirectory();
device = new gs_device(adapter);
} catch (const UnsupportedHWError &error) {
blog(LOG_ERROR, "device_create (D3D11): %s (%08lX)", error.str, error.hr);
errorcode = GS_ERROR_NOT_SUPPORTED;
} catch (const HRError &error) {
blog(LOG_ERROR, "device_create (D3D11): %s (%08lX)", error.str, error.hr);
errorcode = GS_ERROR_FAIL;
}
*p_device = device;
return errorcode;
}
gs_device::gs_device(uint32_t adapterIdx) : curToplogy(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
{
matrix4_identity(&curProjMatrix);
matrix4_identity(&curViewMatrix);
matrix4_identity(&curViewProjMatrix);
memset(&viewport, 0, sizeof(viewport));
for (size_t i = 0; i < GS_MAX_TEXTURES; i++) {
curTextures[i] = NULL;
curSamplers[i] = NULL;
}
InitFactory();
InitAdapter(adapterIdx);
InitDevice(adapterIdx);
device_set_render_target(this, NULL, NULL);
}
渲染逻辑
通过qtobsdisplay 的CreateDisplay获得到原生窗口句柄 ;并且将句柄最终设置到交换链中desc.OutputWindow = hwnd
static inline enum gs_color_space make_swap_desc(gs_device *device, DXGI_SWAP_CHAIN_DESC &desc,
const gs_init_data *data, DXGI_SWAP_EFFECT effect, UINT flags)
{
const HWND hwnd = (HWND)data->window.hwnd;
const enum gs_color_space space = get_next_space(device, hwnd, effect);
const gs_color_format format = get_swap_format_from_space(space, data->format);
memset(&desc, 0, sizeof(desc));
desc.BufferDesc.Width = data->cx;
desc.BufferDesc.Height = data->cy;
desc.BufferDesc.Format = ConvertGSTextureFormatView(format);
desc.SampleDesc.Count = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = data->num_backbuffers;
desc.OutputWindow = hwnd;
desc.Windowed = TRUE;
desc.SwapEffect = effect;
desc.Flags = flags;
return space;
}
OBSQTDisplay 中通过 OBSDisplay display;
using OBSDisplay = OBSPtr<obs_display_t *, obs_display_destroy>;
与底层沟通:
void OBSQTDisplay::CreateDisplay()
{
if (display)
return;
if (destroying)
return;
if (!windowHandle()->isExposed())
return;
QSize size = GetPixelSize(this);
gs_init_data info = {};
info.cx = size.width();
info.cy = size.height();
info.format = GS_BGRA;
info.zsformat = GS_ZS_NONE;
if (!QTToGSWindow(windowHandle(), info.window))
return;
//创建 display
display = obs_display_create(&info, backgroundColor);
emit DisplayCreated(this);
}
obs_display_t *obs_display_create(const struct gs_init_data *graphics_data, uint32_t background_color)
{
struct obs_display *display = bzalloc(sizeof(struct obs_display));
gs_enter_context(obs->video.graphics);
display->background_color = background_color;
//创建交换链
if (!obs_display_init(display, graphics_data)) {
obs_display_destroy(display);
display = NULL;
} else {
pthread_mutex_lock(&obs->data.displays_mutex);
display->prev_next = &obs->data.first_display;
display->next = obs->data.first_display;
obs->data.first_display = display;
if (display->next)
display->next->prev_next = &display->next;
pthread_mutex_unlock(&obs->data.displays_mutex);
}
gs_leave_context();
return display;
}
当发生原生创建的resizeEvent事件时:
void OBSQTDisplay::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
CreateDisplay();
if (isVisible() && display) {
QSize size = GetPixelSize(this);
obs_display_resize(display, size.width(), size.height());
}
emit DisplayResized();
}
通过obs_display_resize 接口更新渲染尺寸
void obs_display_resize(obs_display_t *display, uint32_t cx, uint32_t cy)
{
if (!display)
return;
pthread_mutex_lock(&display->draw_info_mutex);
display->next_cx = cx;
display->next_cy = cy;
pthread_mutex_unlock(&display->draw_info_mutex);
}
因此在graphics thread线程的render_display函数中
void render_display(struct obs_display *display)
{
uint32_t cx, cy;
bool update_color_space;
if (!display || !display->enabled)
return;
/* -------------------------------------------- */
pthread_mutex_lock(&display->draw_info_mutex);
//渲染尺寸
cx = display->next_cx;
cy = display->next_cy;
update_color_space = display->update_color_space;
display->update_color_space = false;
pthread_mutex_unlock(&display->draw_info_mutex);
/* -------------------------------------------- */
//d3d 渲染接口
if (render_display_begin(display, cx, cy, update_color_space)) {
GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DISPLAY, "obs_display");
pthread_mutex_lock(&display->draw_callbacks_mutex);
for (size_t i = 0; i < display->draw_callbacks.num; i++) {
struct draw_callback *callback;
callback = display->draw_callbacks.array + i;
//上层回调通知
callback->draw(callback->param, cx, cy);
}
pthread_mutex_unlock(&display->draw_callbacks_mutex);
render_display_end();
GS_DEBUG_MARKER_END();
gs_present();
}
}
最终调用到 render_display_begin 设置渲染视口
void device_set_viewport(gs_device_t *device, int x, int y, int width, int height)
{
D3D11_VIEWPORT vp;
memset(&vp, 0, sizeof(vp));
vp.MaxDepth = 1.0f;
vp.TopLeftX = (float)x;
vp.TopLeftY = (float)y;
vp.Width = (float)width;
vp.Height = (float)height;
device->context->RSSetViewports(1, &vp);
device->viewport.x = x;
device->viewport.y = y;
device->viewport.cx = width;
device->viewport.cy = height;
}