beb8e1baa0
Что в этом коммите:
Decoration реализации:
- cpp/label_decoration.hpp/.cpp — FreeType atlas + cugrid_blit_rgba_nv12.
UTF-8 декодер, atlas в VRAM (RAII через CudaBuffer), rebuild при set_text.
- cpp/border_decoration.hpp/.cpp — 4 cugrid_fill_nv12 (top/bottom/left/right).
Cell реализации:
- cpp/camera_cell.hpp/.cpp — cfc_source_get_latest + cugrid_resize_nv12.
Non-owning указатель на cfc_source_t (pool владеет).
- cpp/widget_cell.hpp/.cpp — тёмный fill placeholder.
- cpp/blank_cell.hpp/.cpp — BT.709 black fill.
Layout и Template:
- cpp/template.hpp — LayoutTemplate { name, cells[], priority }.
8×8 микро-сетка (kGridCols=kGridRows=8). to_pixels() переводит в Rect.
- cpp/layout.hpp/.cpp — vector<unique_ptr<Cell>>, apply() создаёт
CameraCell/WidgetCell/BlankCell + Decorations (Label с "{key} prio={N}").
- cpp/template_loader.hpp/.cpp — JSON → vector<LayoutTemplate> через json-c.
builtin_templates() = { tpl_1, tpl_4 } как fallback.
SourcePool:
- cpp/source_pool.hpp/.cpp — owner cfc_source_t*, motion state атомарный,
zone-filter в motion_pulse. Pool entries — non-copyable unique_ptr.
Composer:
- cpp/composer.hpp/.cpp — owner SourcePool + templates + Layout + output.
Алгоритмы: pick_best_fit (min nb_camera_cells >= need + priority tie-break),
collect_active (drawable AND motion_within_TTL), asymmetric hysteresis
(рост сразу через std::includes, сжатие — wait shrink_hysteresis_ms).
Public C++ API: set_motion_mode / set_layout / load_templates / compose_frame.
ООП-гипотеза smoke:
- examples/grid_record_cpp.cpp — минимальный smoke без NVENC. Init composer,
compose_frame N раз, dump NV12 в файл. Проверяет что C++ модель
компилируется, линкуется с C-кодом (source.c, nvenc.c остались на C через
extern "C"), и реально рисует кадр.
Производительность сохранена:
- Один output буфер VMM, передаётся как NV12Ref (read-write reference) во все
cells/decorations — НИКАКИХ memcpy на cells boundary.
- Virtual call overhead: 1 indirect call per cell per frame. Negligible.
- Heap allocations только при apply_template (раз в N секунд при relayout).
Build:
- CMakeLists.txt: CXX language, C++17.
- src/CMakeLists.txt: COMPOSER_SOURCES_CPP добавлен в lib.
- examples/CMakeLists.txt: grid_record_cpp.
Smoke test run jammy:
[cfc/loader] docker/templates.json: loaded 7 templates
[smoke] composer 1920x1080 templates=7 sources=0 motion=0
[smoke] wrote 3317760 bytes (Y=2211840 UV=1105920) to /out/blank.nv12
Build PASS, init PASS, compose PASS, dump PASS.
Что НЕ сделано:
- extern "C" ABI shim для control.c / grid_record.c (старый C-композитор
всё ещё единственный для prod stack).
- Удаление старых composer.c / overlay.c / layouts.c.
- Live deploy в прод (Step 1-3 функциональность).
- JSON ZMQ hot-reload (был в Step 3 C-version, восстановить в C++).
Refs: #195 (Phase 11b C++ refactor).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
79 lines
2.7 KiB
C++
79 lines
2.7 KiB
C++
/* LabelDecoration — текстовая подпись поверх cell (Phase 11b).
|
||
*
|
||
* Рендерит UTF-8 строку через FreeType в RGBA-атлас (создаётся один раз
|
||
* при ctor/set_text, держится в VRAM), затем на каждом draw() блитит
|
||
* атлас в указанный угол parent_rect через cfc_cugrid_blit_rgba_nv12.
|
||
*
|
||
* Корнер: top-left (cell.x + pad, cell.y + pad). Pad по умолчанию 8 px.
|
||
* Цвет, размер шрифта, alpha-множитель задаются в ctor.
|
||
*
|
||
* Лицензия: LGPL-2.1+
|
||
*/
|
||
|
||
#ifndef CUFRAMES_COMPOSER_CPP_LABEL_DECORATION_HPP
|
||
#define CUFRAMES_COMPOSER_CPP_LABEL_DECORATION_HPP
|
||
|
||
#include "decoration.hpp"
|
||
|
||
#include <ft2build.h>
|
||
#include FT_FREETYPE_H
|
||
|
||
#include <cuda.h>
|
||
#include <string>
|
||
|
||
namespace cfc {
|
||
|
||
struct LabelStyle {
|
||
std::string font_path = "/fonts/DejaVuSans-Bold.ttf";
|
||
int pixel_size = 22;
|
||
int r = 255, g = 220, b = 64; /* жёлто-оранжевый, читается на любом фоне */
|
||
int alpha = 255; /* множитель прозрачности 0..255 */
|
||
int pad = 8; /* отступ от угла cell */
|
||
|
||
/* visible можно переключать без перерендера атласа. */
|
||
bool visible = true;
|
||
};
|
||
|
||
class LabelDecoration : public Decoration {
|
||
public:
|
||
LabelDecoration(const std::string& text, const LabelStyle& style);
|
||
~LabelDecoration() override;
|
||
|
||
LabelDecoration(const LabelDecoration&) = delete;
|
||
LabelDecoration& operator=(const LabelDecoration&) = delete;
|
||
|
||
void set_visible(bool v) noexcept { style_.visible = v; }
|
||
bool visible() const noexcept { return style_.visible; }
|
||
|
||
/* Обновить текст (re-render atlas). Передвижение/visible — без re-render. */
|
||
void set_text(const std::string& text);
|
||
|
||
void draw(CUstream stream, NV12Ref& dst, const Rect& parent_rect) override;
|
||
|
||
private:
|
||
/* Pass1: измерить bbox строки + ascent для baseline'а. */
|
||
bool measure(int& w, int& h, int& ascent) const;
|
||
/* Pass2: отрисовать строку в RGBA-буфер CPU. */
|
||
void render_to_cpu(unsigned char* rgba, int w, int h, int ascent) const;
|
||
/* Rebuild VRAM atlas из текущей строки. */
|
||
bool rebuild_atlas();
|
||
|
||
/* FreeType state. */
|
||
FT_Library ft_lib_ = nullptr;
|
||
FT_Face face_ = nullptr;
|
||
|
||
/* Текст и стиль. */
|
||
std::string text_;
|
||
LabelStyle style_;
|
||
|
||
/* VRAM atlas. */
|
||
CUdeviceptr atlas_ = 0;
|
||
int atlas_w_ = 0;
|
||
int atlas_h_ = 0;
|
||
int atlas_pitch_ = 0;
|
||
};
|
||
|
||
} // namespace cfc
|
||
|
||
#endif /* CUFRAMES_COMPOSER_CPP_LABEL_DECORATION_HPP */
|