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>
70 lines
1.8 KiB
C++
70 lines
1.8 KiB
C++
/* Layout template — описание сетки в микроячейках (Phase 11b).
|
||
*
|
||
* Template — declarative описание layout'а: имя, набор CellTemplate
|
||
* (col/row/cs/rs/role/order/widget). Layout::apply_template() из template'а
|
||
* + SourcePool создаёт конкретные Cell-объекты (CameraCell/WidgetCell).
|
||
*
|
||
* Грид: 8×8 микроячейки на output W×H. Для 1920×1080 микроячейка = 240×135 (16:9).
|
||
*
|
||
* Загружается из JSON через template_loader.
|
||
*
|
||
* Лицензия: LGPL-2.1+
|
||
*/
|
||
|
||
#ifndef CUFRAMES_COMPOSER_CPP_TEMPLATE_HPP
|
||
#define CUFRAMES_COMPOSER_CPP_TEMPLATE_HPP
|
||
|
||
#include "types.hpp"
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace cfc {
|
||
|
||
constexpr int kGridCols = 8;
|
||
constexpr int kGridRows = 8;
|
||
|
||
enum class CellRole {
|
||
Camera = 0,
|
||
Widget = 1,
|
||
};
|
||
|
||
struct CellTemplate {
|
||
int col = 0, row = 0;
|
||
int cs = 1, rs = 1;
|
||
CellRole role = CellRole::Camera;
|
||
int order = 0;
|
||
std::string widget; /* имя widget'а для role=Widget */
|
||
};
|
||
|
||
struct LayoutTemplate {
|
||
std::string name;
|
||
int priority = 0;
|
||
std::vector<CellTemplate> cells;
|
||
|
||
int nb_camera_cells() const {
|
||
int n = 0;
|
||
for (auto& c : cells) if (c.role == CellRole::Camera) ++n;
|
||
return n;
|
||
}
|
||
};
|
||
|
||
/* Перевести {col,row,cs,rs} в pixel-rect для output W×H. */
|
||
inline Rect to_pixels(const CellTemplate& c, int W, int H)
|
||
{
|
||
Rect r;
|
||
r.x = (c.col * W) / kGridCols;
|
||
r.y = (c.row * H) / kGridRows;
|
||
r.w = (c.cs * W) / kGridCols;
|
||
r.h = (c.rs * H) / kGridRows;
|
||
/* NV12 4:2:0 — чётные. */
|
||
r.x &= ~1; r.y &= ~1; r.w &= ~1; r.h &= ~1;
|
||
if (r.x + r.w > W) r.w = W - r.x;
|
||
if (r.y + r.h > H) r.h = H - r.y;
|
||
return r;
|
||
}
|
||
|
||
} // namespace cfc
|
||
|
||
#endif /* CUFRAMES_COMPOSER_CPP_TEMPLATE_HPP */
|