Files
cuframes-composer/include/cuframes_composer/cpp/label_decoration.hpp
T
gx beb8e1baa0 Phase 11b B-E: ООП-гипотеза проверена end-to-end
Что в этом коммите:

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>
2026-06-03 21:43:18 +01:00

79 lines
2.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 */