filter-transform: Optimize rendering, fix bad property names

The Transform filter will now no longer render the child source more than once per tick(), resulting in an overall speed up for heavy sources. This also applies to mipmapping and shape rendering. Any other calls to video_render will instead just use the cached texture.

Additionally the crash on exit has been fixed which was caused by strings.hpp containing static const char*s and using these directly in obs calls. Instead we now use #define for those property names
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2019-01-24 20:18:04 +01:00
parent e28334d27b
commit 0ae120835a
3 changed files with 206 additions and 179 deletions

View file

@ -126,8 +126,7 @@ void filter::TransformAddon::get_defaults(obs_data_t* data)
obs_data_set_default_double(data, ST_SHEAR_X, 0);
obs_data_set_default_double(data, ST_SHEAR_Y, 0);
obs_data_set_default_bool(data, S_ADVANCED, false);
obs_data_set_default_int(data, ST_ROTATION_ORDER,
RotationOrder::ZXY); //ZXY
obs_data_set_default_int(data, ST_ROTATION_ORDER, RotationOrder::ZXY);
}
obs_properties_t* filter::TransformAddon::get_properties(void*)
@ -135,17 +134,20 @@ obs_properties_t* filter::TransformAddon::get_properties(void*)
obs_properties_t* pr = obs_properties_create();
obs_property_t* p = NULL;
// Camera
/// Projection Mode
p = obs_properties_add_list(pr, ST_CAMERA, P_TRANSLATE(ST_CAMERA), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(ST_CAMERA)));
obs_property_list_add_int(p, P_TRANSLATE(ST_CAMERA_ORTHOGRAPHIC), (int64_t)CameraMode::Orthographic);
obs_property_list_add_int(p, P_TRANSLATE(ST_CAMERA_PERSPECTIVE), (int64_t)CameraMode::Perspective);
obs_property_set_modified_callback(p, modified_properties);
/// Field Of View
p = obs_properties_add_float_slider(pr, ST_CAMERA_FIELDOFVIEW, P_TRANSLATE(ST_CAMERA_FIELDOFVIEW), 1.0, 179.0,
0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(ST_CAMERA_FIELDOFVIEW)));
// Position, Scale, Rotation
// Mesh
/// Position
{
std::pair<const char*, const char*> entries[] = {
std::make_pair(ST_POSITION_X, P_DESC(ST_POSITION_X)),
@ -157,6 +159,7 @@ obs_properties_t* filter::TransformAddon::get_properties(void*)
obs_property_set_long_description(p, P_TRANSLATE(kv.second));
}
}
/// Rotation
{
std::pair<const char*, const char*> entries[] = {
std::make_pair(ST_ROTATION_X, P_DESC(ST_ROTATION_X)),
@ -168,6 +171,7 @@ obs_properties_t* filter::TransformAddon::get_properties(void*)
obs_property_set_long_description(p, P_TRANSLATE(kv.second));
}
}
/// Scale
{
std::pair<const char*, const char*> entries[] = {
std::make_pair(ST_SCALE_X, P_DESC(ST_SCALE_X)),
@ -178,6 +182,7 @@ obs_properties_t* filter::TransformAddon::get_properties(void*)
obs_property_set_long_description(p, P_TRANSLATE(kv.second));
}
}
/// Shear
{
std::pair<const char*, const char*> entries[] = {
std::make_pair(ST_SHEAR_X, P_DESC(ST_SHEAR_X)),
@ -206,24 +211,25 @@ obs_properties_t* filter::TransformAddon::get_properties(void*)
obs_property_set_modified_callback(p, modified_properties);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(ST_MIPMAPPING)));
p = obs_properties_add_list(pr, strings::MipGenerator::Name, P_TRANSLATE(strings::MipGenerator::Name),
p = obs_properties_add_list(pr, S_MIPGENERATOR, P_TRANSLATE(S_MIPGENERATOR),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, P_TRANSLATE(strings::MipGenerator::Description));
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_MIPGENERATOR)));
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Point), (long long)gs::mipmapper::generator::Point);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Linear),
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Point);
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
(long long)gs::mipmapper::generator::Linear);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Sharpen),
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
(long long)gs::mipmapper::generator::Sharpen);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Smoothen),
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
(long long)gs::mipmapper::generator::Smoothen);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Bicubic),
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
(long long)gs::mipmapper::generator::Bicubic);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Lanczos),
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
(long long)gs::mipmapper::generator::Lanczos);
p = obs_properties_add_float(pr, strings::MipGenerator::Strength, P_TRANSLATE(strings::MipGenerator::Strength), 0.0,
100.0, 0.01);
p = obs_properties_add_float_slider(pr, S_MIPGENERATOR_STRENGTH, P_TRANSLATE(S_MIPGENERATOR_STRENGTH), 0.0,
1000.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_MIPGENERATOR_STRENGTH)));
return pr;
}
@ -246,8 +252,8 @@ bool filter::TransformAddon::modified_properties(obs_properties_t* pr, obs_prope
obs_property_set_visible(obs_properties_get(pr, ST_MIPMAPPING), advancedVisible);
bool mipmappingVisible = obs_data_get_bool(d, ST_MIPMAPPING) && advancedVisible;
obs_property_set_visible(obs_properties_get(pr, strings::MipGenerator::Name), mipmappingVisible);
obs_property_set_visible(obs_properties_get(pr, strings::MipGenerator::Strength), mipmappingVisible);
obs_property_set_visible(obs_properties_get(pr, S_MIPGENERATOR), mipmappingVisible);
obs_property_set_visible(obs_properties_get(pr, S_MIPGENERATOR_STRENGTH), mipmappingVisible);
return true;
}
@ -299,17 +305,26 @@ void filter::TransformAddon::video_render(void* ptr, gs_effect_t* effect)
filter::Transform::~Transform()
{
obs_enter_graphics();
m_shape_rendertarget.reset();
m_source_rendertarget.reset();
m_shear.reset();
m_scale.reset();
m_rotation.reset();
m_position.reset();
m_vertex_buffer.reset();
obs_leave_graphics();
m_shape_texture.reset();
m_shape_rendertarget.reset();
m_source_texture.reset();
m_source_rendertarget.reset();
}
filter::Transform::Transform(obs_data_t* data, obs_source_t* context)
: m_active(true), m_self(context), m_camera_orthographic(true), m_camera_fov(90.0), m_update_mesh(false),
m_rotation_order(RotationOrder::ZXY)
: m_active(true), m_self(context), m_source_rendered(false), m_mipmap_enabled(false), m_mipmap_strength(50.0),
m_mipmap_generator(gs::mipmapper::generator::Linear), m_update_mesh(false), m_rotation_order(RotationOrder::ZXY),
m_camera_orthographic(true), m_camera_fov(90.0)
{
m_source_rendertarget = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
m_shape_rendertarget = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
m_vertex_buffer = std::make_shared<gs::vertex_buffer>(4u, 1u);
m_position = std::make_unique<util::vec3a>();
m_rotation = std::make_unique<util::vec3a>();
m_scale = std::make_unique<util::vec3a>();
@ -319,16 +334,6 @@ filter::Transform::Transform(obs_data_t* data, obs_source_t* context)
vec3_set(m_rotation.get(), 0, 0, 0);
vec3_set(m_scale.get(), 1, 1, 1);
m_mipmap_enabled = false;
m_mipmap_generator = gs::mipmapper::generator::Linear;
m_mipmap_strength = 50.0;
obs_enter_graphics();
m_source_rendertarget = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
m_shape_rendertarget = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
m_vertex_buffer = std::make_shared<gs::vertex_buffer>(4u, 1u);
obs_leave_graphics();
update(data);
}
@ -365,8 +370,8 @@ void filter::Transform::update(obs_data_t* data)
// Mipmapping
m_mipmap_enabled = obs_data_get_bool(data, ST_MIPMAPPING);
m_mipmap_strength = obs_data_get_double(data, strings::MipGenerator::Strength);
m_mipmap_generator = (gs::mipmapper::generator)obs_data_get_int(data, strings::MipGenerator::Name);
m_mipmap_strength = obs_data_get_double(data, S_MIPGENERATOR_STRENGTH);
m_mipmap_generator = (gs::mipmapper::generator)obs_data_get_int(data, S_MIPGENERATOR);
m_update_mesh = true;
}
@ -381,39 +386,28 @@ void filter::Transform::deactivate()
m_active = false;
}
void filter::Transform::video_tick(float) {}
void filter::Transform::video_render(gs_effect_t* paramEffect)
void filter::Transform::video_tick(float)
{
if (!m_active) {
obs_source_skip_video_filter(m_self);
return;
}
// Grab parent and target.
obs_source_t* parent = obs_filter_get_parent(m_self);
obs_source_t* target = obs_filter_get_target(m_self);
if (!parent || !target) {
obs_source_skip_video_filter(m_self);
return;
}
// Grab width an height of the target source (child filter or source).
uint32_t width = obs_source_get_base_width(target);
uint32_t height = obs_source_get_base_height(target);
if ((width == 0) || (height == 0)) {
obs_source_skip_video_filter(m_self);
return;
}
std::shared_ptr<gs::texture> source_tex;
std::shared_ptr<gs::texture> shape_tex;
uint32_t real_width = width;
uint32_t real_height = height;
gs_effect_t* default_effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
// Update Mesh
if (m_update_mesh) {
uint32_t width = 0;
uint32_t height = 0;
// Grab parent and target.
obs_source_t* target = obs_filter_get_target(m_self);
if (target) {
// Grab width an height of the target source (child filter or source).
width = obs_source_get_base_width(target);
height = obs_source_get_base_height(target);
}
if (width == 0) {
width = 1;
}
if (height == 0) {
height = 1;
}
// Calculate Aspect Ratio
float_t aspectRatioX = float_t(width) / float_t(height);
if (m_camera_orthographic)
aspectRatioX = 1.0;
@ -493,7 +487,41 @@ void filter::Transform::video_render(gs_effect_t* paramEffect)
m_update_mesh = false;
}
// Make texture a power of two compatible texture if mipmapping is enabled.
this->m_source_rendered = false;
}
void filter::Transform::video_render(gs_effect_t* paramEffect)
{
if (!m_active) {
obs_source_skip_video_filter(m_self);
return;
}
// Grab parent and target.
obs_source_t* parent = obs_filter_get_parent(m_self);
obs_source_t* target = obs_filter_get_target(m_self);
if (!parent || !target) {
obs_source_skip_video_filter(m_self);
return;
}
// Grab width an height of the target source (child filter or source).
uint32_t width = obs_source_get_base_width(target);
uint32_t height = obs_source_get_base_height(target);
if ((width == 0) || (height == 0)) {
obs_source_skip_video_filter(m_self);
return;
}
gs_effect_t* default_effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
// Only render if we didn't already render.
if (!this->m_source_rendered) {
std::shared_ptr<gs::texture> source_tex;
uint32_t real_width = width;
uint32_t real_height = height;
// If MipMapping is enabled, resize Render Target to be a Power of Two.
if (m_mipmap_enabled) {
real_width = uint32_t(pow(2, util::math::get_power_of_two_exponent_ceil(width)));
real_height = uint32_t(pow(2, util::math::get_power_of_two_exponent_ceil(height)));
@ -554,8 +582,9 @@ void filter::Transform::video_render(gs_effect_t* paramEffect)
}
}
m_source_texture = std::make_shared<gs::texture>(
real_width, real_height, GS_RGBA, uint32_t(1u + mip_levels), nullptr, gs::texture::flags::BuildMipMaps);
m_source_texture =
std::make_shared<gs::texture>(real_width, real_height, GS_RGBA, uint32_t(1u + mip_levels), nullptr,
gs::texture::flags::BuildMipMaps);
}
m_mipmapper.rebuild(source_tex, m_source_texture, m_mipmap_generator, float_t(m_mipmap_strength));
@ -598,13 +627,16 @@ void filter::Transform::video_render(gs_effect_t* paramEffect)
obs_source_skip_video_filter(m_self);
return;
}
m_shape_rendertarget->get_texture(shape_tex);
m_shape_rendertarget->get_texture(m_shape_texture);
this->m_source_rendered = true;
}
// Draw final shape
gs_reset_blend_state();
gs_enable_depth_test(false);
while (gs_effect_loop(default_effect, "Draw")) {
gs_effect_set_texture(gs_effect_get_param_by_name(default_effect, "image"), shape_tex->get_object());
gs_draw_sprite(shape_tex->get_object(), 0, 0, 0);
gs_effect_set_texture(gs_effect_get_param_by_name(default_effect, "image"), m_shape_texture->get_object());
gs_draw_sprite(m_shape_texture->get_object(), 0, 0, 0);
}
}

View file

@ -59,6 +59,7 @@ namespace filter {
// Input
std::shared_ptr<gs::rendertarget> m_source_rendertarget;
std::shared_ptr<gs::texture> m_source_texture;
bool m_source_rendered;
// Mipmapping
bool m_mipmap_enabled;
@ -68,6 +69,7 @@ namespace filter {
// Rendering
std::shared_ptr<gs::rendertarget> m_shape_rendertarget;
std::shared_ptr<gs::texture> m_shape_texture;
// Mesh
bool m_update_mesh;

View file

@ -26,18 +26,11 @@
#define S_ADVANCED "Advanced"
#define S_FILEFILTERS_IMAGES "FileFilters.Images"
namespace strings {
static const char* Advanced = "Advanced";
namespace MipGenerator {
static const char* Name = "MipGenerator";
static const char* Description = "MipGenerator.Description";
static const char* Point = "MipGenerator.Point";
static const char* Linear = "MipGenerator.Linear";
static const char* Sharpen = "MipGenerator.Sharpen";
static const char* Smoothen = "MipGenerator.Smoothen";
static const char* Bicubic = "MipGenerator.Bicubic";
static const char* Lanczos = "MipGenerator.Lanczos";
static const char* Strength = "MipGenerator.Strength";
} // namespace MipGenerator
} // namespace strings
#define S_MIPGENERATOR "MipGenerator"
#define S_MIPGENERATOR_POINT "MipGenerator.Point"
#define S_MIPGENERATOR_LINEAR "MipGenerator.Linear"
#define S_MIPGENERATOR_SHARPEN "MipGenerator.Sharpen"
#define S_MIPGENERATOR_SMOOTHEN "MipGenerator.Smoothen"
#define S_MIPGENERATOR_BICUBIC "MipGenerator.Bicubic"
#define S_MIPGENERATOR_LANCZOS "MipGenerator.Lanczos"
#define S_MIPGENERATOR_STRENGTH "MipGenerator.Strength"