mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-13 07:15:06 +00:00
filters/color-grade: Fix support for translucent Inputs
Additionally also document some of the code and enforce certain GPU states for rendering.
This commit is contained in:
parent
d7d34028a0
commit
4c082ad3a9
1 changed files with 105 additions and 7 deletions
|
@ -328,6 +328,7 @@ void color_grade_instance::video_render(gs_effect_t*)
|
||||||
obs_source_t* target = obs_filter_get_target(_self);
|
obs_source_t* target = obs_filter_get_target(_self);
|
||||||
uint32_t width = obs_source_get_base_width(target);
|
uint32_t width = obs_source_get_base_width(target);
|
||||||
uint32_t height = obs_source_get_base_height(target);
|
uint32_t height = obs_source_get_base_height(target);
|
||||||
|
vec4 blank = vec4{0, 0, 0, 0};
|
||||||
|
|
||||||
// Skip filter if anything is wrong.
|
// Skip filter if anything is wrong.
|
||||||
if (!parent || !target || !width || !height) {
|
if (!parent || !target || !width || !height) {
|
||||||
|
@ -343,10 +344,11 @@ void color_grade_instance::video_render(gs_effect_t*)
|
||||||
// - We can skip the original capture and reduce the overall impact of this.
|
// - We can skip the original capture and reduce the overall impact of this.
|
||||||
|
|
||||||
// 1. Capture the filter/source rendered above this.
|
// 1. Capture the filter/source rendered above this.
|
||||||
if (!_ccache_fresh) {
|
if (!_ccache_fresh || !_ccache_texture) {
|
||||||
#ifdef ENABLE_PROFILING
|
#ifdef ENABLE_PROFILING
|
||||||
gs::debug_marker gdmp{gs::debug_color_cache, "Cache '%s'", obs_source_get_name(target)};
|
gs::debug_marker gdmp{gs::debug_color_cache, "Cache '%s'", obs_source_get_name(target)};
|
||||||
#endif
|
#endif
|
||||||
|
// If the input cache render target doesn't exist, create it.
|
||||||
if (!_ccache_rt) {
|
if (!_ccache_rt) {
|
||||||
_ccache_rt = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
_ccache_rt = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||||
}
|
}
|
||||||
|
@ -355,45 +357,108 @@ void color_grade_instance::video_render(gs_effect_t*)
|
||||||
auto op = _ccache_rt->render(width, height);
|
auto op = _ccache_rt->render(width, height);
|
||||||
gs_ortho(0, static_cast<float_t>(width), 0, static_cast<float_t>(height), 0, 1);
|
gs_ortho(0, static_cast<float_t>(width), 0, static_cast<float_t>(height), 0, 1);
|
||||||
|
|
||||||
|
// Blank out the input cache.
|
||||||
|
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &blank, 0., 0);
|
||||||
|
|
||||||
|
// Begin rendering the actual input source.
|
||||||
obs_source_process_filter_begin(_self, GS_RGBA, OBS_ALLOW_DIRECT_RENDERING);
|
obs_source_process_filter_begin(_self, GS_RGBA, OBS_ALLOW_DIRECT_RENDERING);
|
||||||
|
|
||||||
|
// Enable all colors for rendering.
|
||||||
|
gs_enable_color(true, true, true, true);
|
||||||
|
|
||||||
|
// Prevent blending with existing content, even if it is cleared.
|
||||||
|
gs_blend_state_push();
|
||||||
|
gs_enable_blending(false);
|
||||||
|
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
|
||||||
|
|
||||||
|
// Disable depth testing.
|
||||||
|
gs_enable_depth_test(false);
|
||||||
|
|
||||||
|
// Disable stencil testing.
|
||||||
|
gs_enable_stencil_test(false);
|
||||||
|
|
||||||
|
// Disable culling.
|
||||||
|
gs_set_cull_mode(GS_NEITHER);
|
||||||
|
|
||||||
|
// End rendering the actual input source.
|
||||||
obs_source_process_filter_end(_self, obs_get_base_effect(OBS_EFFECT_DEFAULT), width, height);
|
obs_source_process_filter_end(_self, obs_get_base_effect(OBS_EFFECT_DEFAULT), width, height);
|
||||||
|
|
||||||
|
// Restore original blend mode.
|
||||||
|
gs_blend_state_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try and retrieve the input cache as a texture for later use.
|
||||||
_ccache_rt->get_texture(_ccache_texture);
|
_ccache_rt->get_texture(_ccache_texture);
|
||||||
if (!_ccache_texture) {
|
if (!_ccache_texture) {
|
||||||
throw std::runtime_error("Failed to cache original source.");
|
throw std::runtime_error("Failed to cache original source.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the input cache as valid.
|
||||||
_ccache_fresh = true;
|
_ccache_fresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Apply one of the two rendering methods (LUT or Direct).
|
// 2. Apply one of the two rendering methods (LUT or Direct).
|
||||||
if (_lut_initialized && _lut_enabled) {
|
if (_lut_initialized && _lut_enabled) { // Try to apply with the LUT based method.
|
||||||
try {
|
try {
|
||||||
#ifdef ENABLE_PROFILING
|
#ifdef ENABLE_PROFILING
|
||||||
gs::debug_marker gdm{gs::debug_color_convert, "LUT Rendering"};
|
gs::debug_marker gdm{gs::debug_color_convert, "LUT Rendering"};
|
||||||
#endif
|
#endif
|
||||||
|
// If the LUT was changed, rebuild the LUT first.
|
||||||
if (_lut_dirty) {
|
if (_lut_dirty) {
|
||||||
rebuild_lut();
|
rebuild_lut();
|
||||||
|
|
||||||
|
// Mark the cache as invalid, since the LUT has been changed.
|
||||||
_cache_fresh = false;
|
_cache_fresh = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reallocate the rendertarget if necessary.
|
||||||
|
if (_cache_rt->get_color_format() != GS_RGBA) {
|
||||||
|
allocate_rendertarget(GS_RGBA);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_cache_fresh) {
|
if (!_cache_fresh) {
|
||||||
{ // Render the source to the cache.
|
{ // Render the source to the cache.
|
||||||
auto op = _cache_rt->render(width, height);
|
auto op = _cache_rt->render(width, height);
|
||||||
gs_ortho(0, 1., 0, 1., 0, 1);
|
gs_ortho(0, 1., 0, 1., 0, 1);
|
||||||
|
|
||||||
|
// Blank out the input cache.
|
||||||
|
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &blank, 0., 0);
|
||||||
|
|
||||||
|
// Enable all colors for rendering.
|
||||||
|
gs_enable_color(true, true, true, true);
|
||||||
|
|
||||||
|
// Prevent blending with existing content, even if it is cleared.
|
||||||
|
gs_blend_state_push();
|
||||||
|
gs_enable_blending(false);
|
||||||
|
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
|
||||||
|
|
||||||
|
// Disable depth testing.
|
||||||
|
gs_enable_depth_test(false);
|
||||||
|
|
||||||
|
// Disable stencil testing.
|
||||||
|
gs_enable_stencil_test(false);
|
||||||
|
|
||||||
|
// Disable culling.
|
||||||
|
gs_set_cull_mode(GS_NEITHER);
|
||||||
|
|
||||||
auto effect = _lut_consumer->prepare(_lut_depth, _lut_texture);
|
auto effect = _lut_consumer->prepare(_lut_depth, _lut_texture);
|
||||||
effect->get_parameter("image").set_texture(_ccache_texture);
|
effect->get_parameter("image").set_texture(_ccache_texture);
|
||||||
while (gs_effect_loop(effect->get_object(), "Draw")) {
|
while (gs_effect_loop(effect->get_object(), "Draw")) {
|
||||||
streamfx::gs_draw_fullscreen_tri();
|
streamfx::gs_draw_fullscreen_tri();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore original blend mode.
|
||||||
|
gs_blend_state_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try and retrieve the render cache as a texture.
|
||||||
_cache_rt->get_texture(_cache_texture);
|
_cache_rt->get_texture(_cache_texture);
|
||||||
|
|
||||||
|
// Mark the render cache as valid.
|
||||||
_cache_fresh = true;
|
_cache_fresh = true;
|
||||||
}
|
}
|
||||||
} catch (std::exception const& ex) {
|
} catch (std::exception const& ex) {
|
||||||
|
// If anything happened, revert to direct rendering.
|
||||||
_lut_rt.reset();
|
_lut_rt.reset();
|
||||||
_lut_texture.reset();
|
_lut_texture.reset();
|
||||||
_lut_enabled = false;
|
_lut_enabled = false;
|
||||||
|
@ -411,18 +476,46 @@ void color_grade_instance::video_render(gs_effect_t*)
|
||||||
|
|
||||||
{ // Render the source to the cache.
|
{ // Render the source to the cache.
|
||||||
auto op = _cache_rt->render(width, height);
|
auto op = _cache_rt->render(width, height);
|
||||||
gs_ortho(0, static_cast<float_t>(width), 0, static_cast<float_t>(height), 0, 1);
|
gs_ortho(0, 1, 0, 1, 0, 1);
|
||||||
// TODO: Check if clearing things is required.
|
|
||||||
|
|
||||||
prepare_effect();
|
prepare_effect();
|
||||||
obs_source_process_filter_begin(_self, GS_RGBA, OBS_ALLOW_DIRECT_RENDERING);
|
|
||||||
obs_source_process_filter_end(_self, _effect.get_object(), width, height);
|
// Blank out the input cache.
|
||||||
|
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &blank, 0., 0);
|
||||||
|
|
||||||
|
// Enable all colors for rendering.
|
||||||
|
gs_enable_color(true, true, true, true);
|
||||||
|
|
||||||
|
// Prevent blending with existing content, even if it is cleared.
|
||||||
|
gs_blend_state_push();
|
||||||
|
gs_enable_blending(false);
|
||||||
|
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
|
||||||
|
|
||||||
|
// Disable depth testing.
|
||||||
|
gs_enable_depth_test(false);
|
||||||
|
|
||||||
|
// Disable stencil testing.
|
||||||
|
gs_enable_stencil_test(false);
|
||||||
|
|
||||||
|
// Disable culling.
|
||||||
|
gs_set_cull_mode(GS_NEITHER);
|
||||||
|
|
||||||
|
// Render the effect.
|
||||||
|
_effect.get_parameter("image").set_texture(_ccache_texture);
|
||||||
|
while (gs_effect_loop(_effect.get_object(), "Draw")) {
|
||||||
|
streamfx::gs_draw_fullscreen_tri();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore original blend mode.
|
||||||
|
gs_blend_state_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try and retrieve the render cache as a texture.
|
||||||
_cache_rt->get_texture(_cache_texture);
|
_cache_rt->get_texture(_cache_texture);
|
||||||
|
|
||||||
|
// Mark the render cache as valid.
|
||||||
_cache_fresh = true;
|
_cache_fresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_cache_texture) {
|
if (!_cache_texture) {
|
||||||
throw std::runtime_error("Failed to cache processed source.");
|
throw std::runtime_error("Failed to cache processed source.");
|
||||||
}
|
}
|
||||||
|
@ -434,7 +527,12 @@ void color_grade_instance::video_render(gs_effect_t*)
|
||||||
#endif
|
#endif
|
||||||
auto shader = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
auto shader = obs_get_base_effect(OBS_EFFECT_DEFAULT);
|
||||||
|
|
||||||
|
// Revert GPU status to what OBS Studio expects.
|
||||||
gs_enable_depth_test(false);
|
gs_enable_depth_test(false);
|
||||||
|
gs_enable_color(true, true, true, true);
|
||||||
|
gs_set_cull_mode(GS_NEITHER);
|
||||||
|
|
||||||
|
// Draw the render cache.
|
||||||
while (gs_effect_loop(shader, "Draw")) {
|
while (gs_effect_loop(shader, "Draw")) {
|
||||||
gs_effect_set_texture(gs_effect_get_param_by_name(shader, "image"),
|
gs_effect_set_texture(gs_effect_get_param_by_name(shader, "image"),
|
||||||
_cache_texture ? _cache_texture->get_object() : nullptr);
|
_cache_texture ? _cache_texture->get_object() : nullptr);
|
||||||
|
|
Loading…
Reference in a new issue