From 1678432d8cabef093a58e27791f68499c031dba9 Mon Sep 17 00:00:00 2001 From: Helge Norberg Date: Wed, 15 Mar 2017 19:30:12 +0100 Subject: [PATCH] [text_producer] Don't upload texture atlas to GPU every time the text or tracking changes --- core/frame/frame.cpp | 24 +++++++++++++++++++- core/frame/frame.h | 5 +++-- core/producer/text/text_producer.cpp | 17 +++++++++----- core/producer/text/utils/texture_atlas.cpp | 26 ++++++++++------------ core/producer/text/utils/texture_atlas.h | 10 ++++----- core/producer/text/utils/texture_font.cpp | 4 ++-- core/producer/text/utils/texture_font.h | 4 ++-- 7 files changed, 59 insertions(+), 31 deletions(-) diff --git a/core/frame/frame.cpp b/core/frame/frame.cpp index f2c5fa01a..2feb67ec4 100644 --- a/core/frame/frame.cpp +++ b/core/frame/frame.cpp @@ -129,6 +129,20 @@ struct const_frame::impl : boost::noncopyable recorded_age_ = 0; } + impl(const impl& other) + : future_buffers_(other.future_buffers_) + , audio_data_(other.audio_data_) + , desc_(other.desc_) + , channel_layout_(other.channel_layout_) + , tag_(other.tag_) + , geometry_(other.geometry_) + , since_created_timer_(other.since_created_timer_) + , should_record_age_(other.should_record_age_) + , key_only_on_demand_(other.key_only_on_demand_) + { + recorded_age_ = other.recorded_age_; + } + impl( std::shared_future> image, audio_buffer audio_data, @@ -237,6 +251,7 @@ const_frame& const_frame::operator=(const_frame&& other) return *this; } const_frame::const_frame(const const_frame& other) : impl_(other.impl_){} +const_frame::const_frame(const const_frame::impl& other) : impl_(new impl(other)) {} const_frame& const_frame::operator=(const const_frame& other) { impl_ = other.impl_; @@ -255,7 +270,14 @@ std::size_t const_frame::height()const{return impl_->height();} std::size_t const_frame::size()const{return impl_->size();} const void* const_frame::stream_tag()const{return impl_->tag_;} const frame_geometry& const_frame::geometry() const { return impl_->geometry_; } -void const_frame::set_geometry(const frame_geometry& g) { impl_->geometry_ = g; } +const_frame const_frame::with_geometry(const frame_geometry& g) const +{ + const_frame copy(*impl_); + + copy.impl_->geometry_ = g; + + return copy; +} int64_t const_frame::get_age_millis() const { return impl_->get_age_millis(); } const_frame const_frame::key_only() const { diff --git a/core/frame/frame.h b/core/frame/frame.h index fff5382c8..640a6589e 100644 --- a/core/frame/frame.h +++ b/core/frame/frame.h @@ -75,6 +75,7 @@ private: class const_frame final { + struct impl; public: // Static Members @@ -97,6 +98,7 @@ public: const_frame(const_frame&& other); const_frame& operator=(const_frame&& other); const_frame(const const_frame&); + const_frame(const const_frame::impl&); const_frame& operator=(const const_frame& other); const_frame key_only() const; @@ -116,7 +118,7 @@ public: const void* stream_tag() const; const core::frame_geometry& geometry() const; - void set_geometry(const frame_geometry& g); + const_frame with_geometry(const frame_geometry& g) const; int64_t get_age_millis() const; bool operator==(const const_frame& other); @@ -125,7 +127,6 @@ public: bool operator>(const const_frame& other); private: - struct impl; spl::shared_ptr impl_; }; diff --git a/core/producer/text/text_producer.cpp b/core/producer/text/text_producer.cpp index 4bcf08519..4a00b4608 100644 --- a/core/producer/text/text_producer.cpp +++ b/core/producer/text/text_producer.cpp @@ -145,6 +145,7 @@ struct text_producer::impl draw_frame frame_; text::texture_atlas atlas_ { 1024, 512, 4 }; text::texture_font font_; + const_frame atlas_frame_; public: explicit impl(const spl::shared_ptr& frame_factory, int x, int y, const std::wstring& str, text::text_info& text_info, long parent_width, long parent_height, bool standalone) @@ -159,6 +160,8 @@ public: font_.load_glyphs(text::unicode_block::Latin_1_Supplement, text_info.color); font_.load_glyphs(text::unicode_block::Latin_Extended_A, text_info.color); + atlas_frame_ = create_atlas_frame(); + tracking_.value().set(text_info.tracking); scale_x_.value().set(text_info.scale_x); scale_y_.value().set(text_info.scale_y); @@ -183,18 +186,22 @@ public: CASPAR_LOG(info) << print() << L" Initialized"; } - void generate_frame() + core::const_frame create_atlas_frame() const { core::pixel_format_desc pfd(core::pixel_format::bgra); pfd.planes.push_back(core::pixel_format_desc::plane(static_cast(atlas_.width()), static_cast(atlas_.height()), static_cast(atlas_.depth()))); + auto frame = frame_factory_->create_frame(this, pfd, core::audio_channel_layout::invalid()); + memcpy(frame.image_data().data(), atlas_.data(), frame.image_data().size()); + return frame; + } + void generate_frame() + { text::string_metrics metrics; - font_.set_tracking(static_cast(tracking_.value().get())); + font_.set_tracking(tracking_.value().get()); auto vertex_stream = font_.create_vertex_stream(text_.value().get(), x_, y_, parent_width_, parent_height_, &metrics, shear_.value().get()); - auto frame = frame_factory_->create_frame(vertex_stream.data(), pfd, core::audio_channel_layout::invalid()); - memcpy(frame.image_data().data(), atlas_.data(), frame.image_data().size()); - frame.set_geometry(frame_geometry(frame_geometry::geometry_type::quad_list, std::move(vertex_stream))); + auto frame = atlas_frame_.with_geometry(frame_geometry(frame_geometry::geometry_type::quad_list, std::move(vertex_stream))); this->constraints_.width.set(metrics.width * this->scale_x_.value().get()); this->constraints_.height.set(metrics.height * this->scale_y_.value().get()); diff --git a/core/producer/text/utils/texture_atlas.cpp b/core/producer/text/utils/texture_atlas.cpp index 0622d5858..8213f16f5 100644 --- a/core/producer/text/utils/texture_atlas.cpp +++ b/core/producer/text/utils/texture_atlas.cpp @@ -57,14 +57,12 @@ private: size_t width_; size_t height_; size_t depth_; - const unsigned char* dataptr_; - std::vector data_; + std::vector data_; size_t used_ = 0; public: impl(const size_t width, const size_t height, const size_t depth) : width_(width), height_(height), depth_(depth), data_(width*height*depth, 0) { - dataptr_ = data_.data(); // We want a one pixel border around the whole atlas to avoid any artefact when sampling texture node n = {1, 1, static_cast(width_) - 2}; nodes_.push_back(n); @@ -94,7 +92,7 @@ public: } } } - + if(best_it == nodes_.end()) { region.x = -1; @@ -165,10 +163,10 @@ public: data_.assign(width_*height_*depth_, 0); } - size_t depth() { return depth_; } - size_t width() { return width_; } - size_t height() { return height_; } - unsigned char* data() { return data_.data(); } + size_t depth() const { return depth_; } + size_t width() const { return width_; } + size_t height() const { return height_; } + const uint8_t* data() const { return data_.data(); } private: int fit(node_iterator it, const size_t width, const size_t height) @@ -215,15 +213,15 @@ private: }; texture_atlas::texture_atlas(const size_t w, const size_t h, const size_t d) : impl_(new impl(w, h, d)) {} -rect texture_atlas::get_region(int width, int height) { return impl_->get_region(width, height); } +rect texture_atlas::get_region(int width, int height) const { return impl_->get_region(width, height); } void texture_atlas::set_region(const size_t x, const size_t y, const size_t width, const size_t height, const unsigned char *src, const size_t stride, const color& col) { impl_->set_region(x, y, width, height, src, stride, col); } void texture_atlas::clear() { impl_->clear(); } -size_t texture_atlas::width() { return impl_->width(); } -size_t texture_atlas::height() { return impl_->height(); } -size_t texture_atlas::depth() { return impl_->depth(); } -unsigned char* texture_atlas::data() { return impl_->data(); } +size_t texture_atlas::width() const { return impl_->width(); } +size_t texture_atlas::height() const { return impl_->height(); } +size_t texture_atlas::depth() const { return impl_->depth(); } +const uint8_t* texture_atlas::data() const { return impl_->data(); } -}}} \ No newline at end of file +}}} diff --git a/core/producer/text/utils/texture_atlas.h b/core/producer/text/utils/texture_atlas.h index 4831158df..e3ad0462d 100644 --- a/core/producer/text/utils/texture_atlas.h +++ b/core/producer/text/utils/texture_atlas.h @@ -80,15 +80,15 @@ class texture_atlas public: texture_atlas(const size_t w, const size_t h, const size_t d); - rect get_region(int width, int height); + rect get_region(int width, int height) const; void set_region(const size_t x, const size_t y, const size_t width, const size_t height, const unsigned char *data, const size_t stride, const color& col); void clear(); - size_t depth(); - size_t width(); - size_t height(); + size_t depth() const; + size_t width() const; + size_t height() const; - unsigned char* data(); + const uint8_t* data() const; private: struct impl; diff --git a/core/producer/text/utils/texture_font.cpp b/core/producer/text/utils/texture_font.cpp index ae3858213..5a0421701 100644 --- a/core/producer/text/utils/texture_font.cpp +++ b/core/producer/text/utils/texture_font.cpp @@ -57,7 +57,7 @@ public: CASPAR_THROW_EXCEPTION(expected_freetype_exception() << msg_info("Failed to set font size")); } - void set_tracking(int tracking) + void set_tracking(double tracking) { tracking_ = size_ * tracking / 1000.0; } @@ -285,7 +285,7 @@ public: texture_font::texture_font(texture_atlas& atlas, const text_info& info, bool normalize_coordinates) : impl_(new impl(atlas, info, normalize_coordinates)) {} void texture_font::load_glyphs(unicode_block range, const color& col) { impl_->load_glyphs(range, col); } -void texture_font::set_tracking(int tracking) { impl_->set_tracking(tracking); } +void texture_font::set_tracking(double tracking) { impl_->set_tracking(tracking); } std::vector texture_font::create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics, double shear) { return impl_->create_vertex_stream(str, x, y, parent_width, parent_height, metrics, shear); } string_metrics texture_font::measure_string(const std::wstring& str) { return impl_->measure_string(str); } std::wstring texture_font::get_name() const { return impl_->get_name(); } diff --git a/core/producer/text/utils/texture_font.h b/core/producer/text/utils/texture_font.h index 89662c134..11855adfa 100644 --- a/core/producer/text/utils/texture_font.h +++ b/core/producer/text/utils/texture_font.h @@ -22,7 +22,7 @@ class texture_font public: texture_font(texture_atlas&, const text_info&, bool normalize_coordinates); void load_glyphs(unicode_block block, const color& col); - void set_tracking(int tracking); + void set_tracking(double tracking); std::vector create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height, string_metrics* metrics, double shear = 0.0); string_metrics measure_string(const std::wstring& str); std::wstring get_name() const; @@ -257,4 +257,4 @@ enum class unicode_block Supplementary_Private_Use_Area_B }; -}}} \ No newline at end of file +}}} -- 2.39.2