obs_display结构体
2024-05-17
30
0
obs_display结构体用于存储需要将显卡渲染的图像输出到窗口显示的对象。
struct obs_display {
bool update_color_space;
bool enabled;
uint32_t cx, cy;
uint32_t next_cx, next_cy;
uint32_t background_color;
gs_swapchain_t *swap;
pthread_mutex_t draw_callbacks_mutex;
pthread_mutex_t draw_info_mutex;
DARRAY(struct draw_callback) draw_callbacks;
bool use_clear_workaround;
struct obs_display *next; //链表下一个
struct obs_display **prev_next;
};
创建obs_dipslay结构体时,使用结构体传递参数信息:
struct gs_window {
#if defined(_WIN32)
void *hwnd;
#elif defined(__APPLE__)
__unsafe_unretained id view;
#elif defined(__linux__) || defined(__FreeBSD__)
/* I'm not sure how portable defining id to uint32_t is. */
uint32_t id;
void *display;
#endif
};
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;
};
函数为:
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;
}
而在OBS中主窗口创建显示:
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;
// win32下获取主窗口句柄hwnd
if (!QTToGSWindow(windowHandle(), info.window))
return;
display = obs_display_create(&info, backgroundColor);
emit DisplayCreated(this);
}
初始化display
初始化结构体display,参数为graphics_data
bool obs_display_init(struct obs_display *display,
const struct gs_init_data *graphics_data)
{
pthread_mutex_init_value(&display->draw_callbacks_mutex);
pthread_mutex_init_value(&display->draw_info_mutex);
#if defined(_WIN32)
/* Conservative test for NVIDIA flickering in multi-GPU setups */
display->use_clear_workaround = gs_get_adapter_count() > 1 && !gs_can_adapter_fast_clear();
#elif defined(__APPLE__)
/* Apple Silicon GL driver doesn't seem to track SRGB clears correctly */
display->use_clear_workaround = true;
#else
display->use_clear_workaround = false;
#endif
if (graphics_data) {
display->swap = gs_swapchain_create(graphics_data);
if (!display->swap) {
blog(LOG_ERROR, "obs_display_init: Failed to "
"create swap chain");
return false;
}
const uint32_t cx = graphics_data->cx;
const uint32_t cy = graphics_data->cy;
display->cx = cx;
display->cy = cy;
display->next_cx = cx;
display->next_cy = cy;
}
if (pthread_mutex_init(&display->draw_callbacks_mutex, NULL) != 0) {
blog(LOG_ERROR, "obs_display_init: Failed to create mutex");
return false;
}
if (pthread_mutex_init(&display->draw_info_mutex, NULL) != 0) {
blog(LOG_ERROR, "obs_display_init: Failed to create mutex");
return false;
}
display->enabled = true;
return true;
}
在实始化时,会创建一个交换链,使用的函数为:gs_swapchain_create
gs_swapchain_t *gs_swapchain_create(const struct gs_init_data *data)
{
struct gs_init_data new_data = *data;
graphics_t *graphics = thread_graphics;
if (!gs_valid_p("gs_swapchain_create", data))
return NULL;
if (new_data.num_backbuffers == 0)
new_data.num_backbuffers = 1;
return graphics->exports.device_swapchain_create(graphics->device,
&new_data);
}
其本质是d3d11导出的
gs_swapchain_t *device_swapchain_create(gs_device_t *device,
const struct gs_init_data *data)
{
gs_swap_chain *swap = NULL;
try {
swap = new gs_swap_chain(device, data);
} catch (const HRError &error) {
blog(LOG_ERROR, "device_swapchain_create (D3D11): %s (%08lX)",
error.str, error.hr);
LogD3D11ErrorDetails(error, device);
}
return swap;
}
d3d11交换链
交换链是一个前台一个后台缓冲区,用于屏显防止闪屏。故有前后缓冲区。故称之为交换链。这里使用类结构体s_swap_chain的结构体来表示该对象。
交换链与窗口hwnd绑定,注意构造函数中对hwnd的初始化。
struct gs_swap_chain : gs_obj {
HWND hwnd;
gs_init_data initData;
DXGI_SWAP_CHAIN_DESC swapDesc = {};
gs_color_space space;
gs_texture_2d target;
gs_zstencil_buffer zs;
ComPtr<IDXGISwapChain> swap;
HANDLE hWaitable = NULL;
void InitTarget(uint32_t cx, uint32_t cy);
void InitZStencilBuffer(uint32_t cx, uint32_t cy);
void Resize(uint32_t cx, uint32_t cy, gs_color_format format);
void Init();
void Rebuild(ID3D11Device *dev);
inline void Release()
{
target.Release();
zs.Release();
if (hWaitable) {
CloseHandle(hWaitable);
hWaitable = NULL;
}
swap.Clear();
}
gs_swap_chain(gs_device *device, const gs_init_data *data);
virtual ~gs_swap_chain();
};
交换链的主要函数实现在libos-d3d11.cpp中.
gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data)
: gs_obj(device, gs_type::gs_swap_chain),
hwnd((HWND)data->window.hwnd),
initData(*data),
space(GS_CS_SRGB)
{
DXGI_SWAP_EFFECT effect = DXGI_SWAP_EFFECT_DISCARD;
UINT flags = 0;
ComQIPtr<IDXGIFactory5> factory5 = device->factory;
if (factory5) {
initData.num_backbuffers = max(data->num_backbuffers, 2);
effect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
}
space = make_swap_desc(device, swapDesc, &initData, effect, flags);
HRESULT hr = device->factory->CreateSwapChain(device->device, &swapDesc,
swap.Assign());
if (FAILED(hr))
throw HRError("Failed to create swap chain", hr);
/* Ignore Alt+Enter */
device->factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
if (flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) {
ComPtr<IDXGISwapChain2> swap2 = ComQIPtr<IDXGISwapChain2>(swap);
hWaitable = swap2->GetFrameLatencyWaitableObject();
if (hWaitable == NULL) {
throw HRError("Failed to GetFrameLatencyWaitableObject",
hr);
}
}
Init();
}