From: Ronag Date: Mon, 15 Aug 2011 20:25:41 +0000 (+0000) Subject: 2.0. - image_mixer: Fixed bug where amongst others mixing to alpha did not work. X-Git-Tag: 2.0.1~149 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=18c78e2930cd02e525f358d6284f0d420708641a;p=casparcg 2.0. - image_mixer: Fixed bug where amongst others mixing to alpha did not work. - misc: Added some todo comments. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1191 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- diff --git a/common/log/log.cpp b/common/log/log.cpp index d6cc96d57..607e05052 100644 --- a/common/log/log.cpp +++ b/common/log/log.cpp @@ -17,6 +17,9 @@ * along with CasparCG. If not, see . * */ +// TODO: Colors in console. +// TODO: Think through filters. + #include "../stdafx.h" #if defined(_MSC_VER) diff --git a/common/memory/safe_ptr.h b/common/memory/safe_ptr.h index f649f0e06..e4269e69b 100644 --- a/common/memory/safe_ptr.h +++ b/common/memory/safe_ptr.h @@ -154,6 +154,18 @@ bool operator==(const safe_ptr& a, const safe_ptr& b) // noexcept return a.get() == b.get(); } +template +bool operator!=(const std::shared_ptr& a, const safe_ptr& b) // noexcept +{ + return a.get() != b.get(); +} + +template +bool operator!=(const safe_ptr& a, const std::shared_ptr& b) // noexcept +{ + return a.get() != b.get(); +} + template bool operator!=(const safe_ptr& a, const safe_ptr& b) // noexcept { diff --git a/core/mixer/gpu/ogl_device.cpp b/core/mixer/gpu/ogl_device.cpp index 2d8aad35b..95c5ca3b3 100644 --- a/core/mixer/gpu/ogl_device.cpp +++ b/core/mixer/gpu/ogl_device.cpp @@ -17,6 +17,8 @@ * along with CasparCG. If not, see . * */ +// TODO: Smart GC + #include "../../stdafx.h" #include "ogl_device.h" diff --git a/core/mixer/image/image_kernel.cpp b/core/mixer/image/image_kernel.cpp index 1e3722762..31e7440ff 100644 --- a/core/mixer/image/image_kernel.cpp +++ b/core/mixer/image/image_kernel.cpp @@ -77,6 +77,12 @@ struct image_kernel::implementation : boost::noncopyable if(item.transform.get_opacity() < epsilon) return; + if(!std::all_of(item.textures.begin(), item.textures.end(), std::mem_fn(&device_buffer::ready))) + { + CASPAR_LOG(warning) << L"[image_mixer] Performance warning. Host to device transfer not complete, GPU will be stalled"; + ogl.yield(); // Try to give it some more time. + } + // Bind textures for(size_t n = 0; n < item.textures.size(); ++n) @@ -167,7 +173,7 @@ struct image_kernel::implementation : boost::noncopyable ogl.viewport(0, 0, background->width(), background->height()); - GL(glColor4d(item.transform.get_gain(), item.transform.get_gain(), item.transform.get_gain(), item.transform.get_opacity())); + GL(glColor4d(item.transform.get_gain(), item.transform.get_gain(), item.transform.get_gain(), item.transform.get_is_key() ? 1.0 : item.transform.get_opacity())); auto m_p = item.transform.get_clip_translation(); auto m_s = item.transform.get_clip_scale(); diff --git a/core/mixer/image/image_mixer.cpp b/core/mixer/image/image_mixer.cpp index c0f82f07d..9192b67f8 100644 --- a/core/mixer/image/image_mixer.cpp +++ b/core/mixer/image/image_mixer.cpp @@ -142,53 +142,35 @@ public: return host_buffer; } + // TODO: We might have more overlaps for opacity transitions + // TODO: What about blending modes, are they ok? Maybe only overlap detection is required for opacity? void draw(layer&& layer, std::shared_ptr& layer_key_buffer) - { - std::shared_ptr local_key_buffer; - - std::shared_ptr atomic_draw_buffer; - std::shared_ptr atomic_local_key_buffer; + { + if(layer.empty()) + return; - BOOST_FOREACH(auto& item, layer) + std::shared_ptr local_key_buffer; + + if(has_overlapping_items(layer, layer.front().transform.get_blend_mode())) { - //if(item.transform.get_is_atomic()) // layers need to be atomic in-order to support blend-modes properly - //{ - // if(!atomic_draw_buffer) - // { - // atomic_draw_buffer = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4); - // channel_.ogl().clear(*atomic_draw_buffer); - // } - - // draw(std::move(item), atomic_draw_buffer, atomic_local_key_buffer, nullptr); - //} - //else - //{ - // if(atomic_draw_buffer) - // { - // pixel_format_desc desc; - // desc.pix_fmt = pixel_format::bgra; - // desc.planes.push_back(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); - - // std::vector> textures; - // textures.push_back(make_safe(atomic_draw_buffer)); - // - // atomic_draw_buffer.reset(); - // atomic_local_key_buffer.reset(); - // - // render_item atomic_item(desc, std::move(textures), image_transform(), video_mode::progressive, nullptr); - // draw(std::move(atomic_item), draw_buffer_, local_key_buffer, layer_key_buffer); - // } - - // draw(std::move(item), draw_buffer_, local_key_buffer, layer_key_buffer); - //} - - draw(std::move(item), local_key_buffer, layer_key_buffer); + auto local_draw_buffer = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4); + channel_.ogl().clear(*local_draw_buffer); + + BOOST_FOREACH(auto& item, layer) + draw_item(std::move(item), local_draw_buffer, local_key_buffer, layer_key_buffer); + + kernel_.draw(channel_.ogl(), create_render_item(local_draw_buffer, layer.front().transform.get_blend_mode()), make_safe(draw_buffer_), nullptr, nullptr); } - + else // fast path + { + BOOST_FOREACH(auto& item, layer) + draw_item(std::move(item), make_safe(draw_buffer_), local_key_buffer, layer_key_buffer); + } + std::swap(local_key_buffer, layer_key_buffer); } - void draw(render_item&& item, std::shared_ptr& local_key_buffer, std::shared_ptr& layer_key_buffer) + void draw_item(render_item&& item, const safe_ptr& draw_buffer, std::shared_ptr& local_key_buffer, std::shared_ptr& layer_key_buffer) { if(item.transform.get_is_key()) { @@ -198,26 +180,60 @@ public: channel_.ogl().clear(*local_key_buffer); } - draw(std::move(item), local_key_buffer, nullptr, nullptr); + kernel_.draw(channel_.ogl(), std::move(item), make_safe(local_key_buffer), nullptr, nullptr); } else { - draw(std::move(item), draw_buffer_, local_key_buffer, layer_key_buffer); + kernel_.draw(channel_.ogl(), std::move(item), draw_buffer, local_key_buffer, layer_key_buffer); local_key_buffer.reset(); } } - - void draw(render_item&& item, std::shared_ptr& draw_buffer, const std::shared_ptr& local_key, const std::shared_ptr& layer_key) + + render_item create_render_item(const safe_ptr& buffer, image_transform::blend_mode::type blend_mode) { - if(!std::all_of(item.textures.begin(), item.textures.end(), std::mem_fn(&device_buffer::ready))) - { - CASPAR_LOG(warning) << L"[image_mixer] Performance warning. Host to device transfer not complete, GPU will be stalled"; - channel_.ogl().yield(); // Try to give it some more time. - } + CASPAR_ASSERT(buffer->stride() == 4 && "Only used for bgra textures"); - kernel_.draw(channel_.ogl(), std::move(item), make_safe(draw_buffer), local_key, layer_key); - } + pixel_format_desc desc; + desc.pix_fmt = pixel_format::bgra; + desc.planes.push_back(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); + + std::vector> textures; + textures.push_back(buffer); + image_transform transform; + transform.set_blend_mode(blend_mode); + + return render_item(desc, std::move(textures), transform, video_mode::progressive, nullptr); + } + + // TODO: Optimize + bool has_overlapping_items(const layer& layer, image_transform::blend_mode::type blend_mode) + { + if(layer.empty()) + return false; + + implementation::layer fill; + + std::copy_if(layer.begin(), layer.end(), std::back_inserter(fill), [&](const render_item& item) + { + return !item.transform.get_is_key(); + }); + + if(blend_mode == image_transform::blend_mode::normal) // Only overlap if opacity + { + return std::any_of(fill.begin(), fill.end(), [&](const render_item& item) + { + return item.transform.get_opacity() < 1.0 - 0.001; + }); + } + + // Simple solution, just check if we have differnt video streams / tags. + return std::any_of(fill.begin(), fill.end(), [&](const render_item& item) + { + return item.tag != fill.front().tag; + }); + } + safe_ptr create_frame(const void* tag, const core::pixel_format_desc& desc) { return make_safe(channel_.ogl(), tag, desc); diff --git a/core/producer/transition/transition_producer.cpp b/core/producer/transition/transition_producer.cpp index 66c79b9ee..b2f1dbafb 100644 --- a/core/producer/transition/transition_producer.cpp +++ b/core/producer/transition/transition_producer.cpp @@ -134,8 +134,8 @@ struct transition_producer : public frame_producer d_frame1->get_image_transform().set_opacity(delta1); d_frame2->get_image_transform().set_opacity(delta2); - //s_frame1->get_image_transform().set_opacity(1.0-delta1); - //s_frame2->get_image_transform().set_opacity(1.0-delta2); + s_frame1->get_image_transform().set_opacity(1.0-delta1); + s_frame2->get_image_transform().set_opacity(1.0-delta2); } else if(info_.type == transition::slide) { diff --git a/modules/image/producer/image_scroll_producer.cpp b/modules/image/producer/image_scroll_producer.cpp index 900a7ab7d..cb48246b4 100644 --- a/modules/image/producer/image_scroll_producer.cpp +++ b/modules/image/producer/image_scroll_producer.cpp @@ -17,6 +17,9 @@ * along with CasparCG. If not, see . * */ +// TODO: Refactor. +// TODO: Looping. + #include "image_scroll_producer.h" #include "../util/image_loader.h"