render_main_texture
2024-07-01
17
0
render_main_texture函数中比较重要的是:
static inline void render_main_texture(struct obs_core_video_mix *video)
{
...
//设置背景颜色
struct vec4 clear_color;
vec4_set(&clear_color, 0.0f, 0.0f, 0.0f, 0.0f);
//设置颜色空间
gs_set_render_target_with_color_space(video->render_texture, NULL, video->render_space);
//使用颜色清除背景空间
gs_clear(GS_CLEAR_COLOR, &clear_color, 1.0f, 0);
//设置尺寸
set_render_size(base_width, base_height);
//draw_callbacks
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
for (size_t i = obs->data.draw_callbacks.num; i > 0; i--)
{
struct draw_callback *const callback = obs->data.draw_callbacks.array + (i - 1);
callback->draw(callback->param, base_width, base_height);
}
pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
/* In some cases we can reuse a previous mix's texture and save re-rendering everything */
size_t reuse_idx;
if (can_reuse_mix_texture(video, &reuse_idx))
draw_mix_texture(reuse_idx);
else
obs_view_render(video->view);
video->texture_rendered = true;
//rendered_callbacks
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
for (size_t i = 0; i < obs->data.rendered_callbacks.num; ++i)
{
struct rendered_callback *const callback = &obs->data.rendered_callbacks.array[i];
callback->rendered(callback->param);
}
pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
}
gs_set_render_target_with_color_space
gs_set_render_target_with_color_space其实是调用device_set_render_target_internal函数,设置当前的texture为video->render_texture,并设置基本的信息。所以这一步其实是渲染的条件准备。
static void device_set_render_target_internal(gs_device_t *device,
gs_texture_t *tex,
gs_zstencil_t *zstencil,
enum gs_color_space space)
{
if (device->curSwapChain) {
if (!tex)
tex = &device->curSwapChain->target;
if (!zstencil)
zstencil = &device->curSwapChain->zs;
}
if (device->curRenderTarget == tex && device->curZStencilBuffer == zstencil)
{
device->curColorSpace = space;
}
if (tex && tex->type != GS_TEXTURE_2D) {
blog(LOG_ERROR, "device_set_render_target_internal (D3D11): texture is not a 2D texture");
return;
}
gs_texture_2d *const tex2d = static_cast<gs_texture_2d *>(tex);
if (device->curRenderTarget != tex2d || device->curRenderSide != 0 ||
device->curZStencilBuffer != zstencil)
{
device->curRenderTarget = tex2d; //当前渲染纹理
device->curZStencilBuffer = zstencil; //为NULL
device->curRenderSide = 0;
device->curColorSpace = space;
device->curFramebufferInvalidate = true;
}
}
所以对于gs_clear使用背景色清除背景,就是针对当前的curRenderTarget。
void device_clear(gs_device_t *device, uint32_t clear_flags,
const struct vec4 *color, float depth, uint8_t stencil)
{
if (clear_flags & GS_CLEAR_COLOR)
{
gs_texture_2d *const tex = device->curRenderTarget;
if (tex)
{
const int side = device->curRenderSide;
ID3D11RenderTargetView *const rtv = device->curFramebufferSrgb ? tex->renderTargetLinear[side] : tex->renderTarget[side];
device->context->ClearRenderTargetView(rtv, color->ptr);
}
}
//深度模版为NULL
if (device->curZStencilBuffer)
{
uint32_t flags = 0;
if ((clear_flags & GS_CLEAR_DEPTH) != 0)
flags |= D3D11_CLEAR_DEPTH;
if ((clear_flags & GS_CLEAR_STENCIL) != 0)
flags |= D3D11_CLEAR_STENCIL;
if (flags && device->curZStencilBuffer->view)
device->context->ClearDepthStencilView(device->curZStencilBuffer->view, flags, depth,stencil);
}
}
set_render_size
用于设置窗口及矩阵
static inline void set_render_size(uint32_t width, uint32_t height)
{
gs_enable_depth_test(false);
gs_set_cull_mode(GS_NEITHER);
gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f);
gs_set_viewport(0, 0, width, height);
}
void device_ortho(gs_device_t *device, float left, float right, float top,
float bottom, float zNear, float zFar)
{
matrix4 *dst = &device->curProjMatrix;
float rml = right - left;
float bmt = bottom - top;
float fmn = zFar - zNear;
vec4_zero(&dst->x);
vec4_zero(&dst->y);
vec4_zero(&dst->z);
vec4_zero(&dst->t);
dst->x.x = 2.0f / rml;
dst->t.x = (left + right) / -rml;
dst->y.y = 2.0f / -bmt;
dst->t.y = (bottom + top) / bmt;
dst->z.z = 1.0f / fmn;
dst->t.z = zNear / -fmn;
dst->t.w = 1.0f;
}
draw_callbacks和rendered_callbacks
这两个分别使用obs_add_main_render_callback和obs_add_main_rendered_callback添加的回调函数。
//draw_callbacks
void obs_add_main_render_callback(void (*draw)(void *param, uint32_t cx,uint32_t cy), void *param)
{
struct draw_callback data = {draw, param};
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
da_insert(obs->data.draw_callbacks, 0, &data);
pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
}
//rendered_callbacks
void obs_add_main_rendered_callback(void (*rendered)(void *param), void *param)
{
struct rendered_callback data = {rendered, param};
pthread_mutex_lock(&obs->data.draw_callbacks_mutex);
da_insert(obs->data.rendered_callbacks, 0, &data);
pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
}
从名字和先顺序序来看,一个是渲染前的渲染,一个是渲染后的渲染,都是进行渲染。
而中间的就是obs_view_render。
obs_view_render
obs_view_render是对当前view中所有通道的源进行渲染。
void obs_view_render(obs_view_t *view)
{
if (!view)
return;
pthread_mutex_lock(&view->channels_mutex);
for (size_t i = 0; i < MAX_CHANNELS; i++)
{
struct obs_source *source = view->channels[i];
if (source)
{
if (source->removed)
{
obs_source_release(source);
view->channels[i] = NULL;
}
else
{
obs_source_video_render(source);
}
}
}
pthread_mutex_unloc
当需要与其它obs_core_video_mixs混合时,则不会使用本obs_core_video_mixs,使用can_reuse_mix_texture函数返回它的索引之后,调用draw_mix_texture进行混合。