MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SurfaceUtils.cpp
Go to the documentation of this file.
1#include "SurfaceUtils.hpp"
2
4
8
11
13
14namespace MayaFlux::Kakshya {
15
16namespace {
17
18 /**
19 * @brief Resolve DisplayService from the backend registry.
20 * Returns nullptr and logs on failure.
21 */
22 Registry::Service::DisplayService* get_display_service()
23 {
25 .get_service<Registry::Service::DisplayService>();
26 if (!svc) {
28 "SurfaceUtils: DisplayService not available");
29 }
30 return svc;
31 }
32
33 /**
34 * @brief Resolve BufferService from the backend registry.
35 * Returns nullptr and logs on failure.
36 */
37 Registry::Service::BufferService* get_buffer_service()
38 {
40 .get_service<Registry::Service::BufferService>();
41 if (!svc) {
43 "SurfaceUtils: BufferService not available");
44 }
45 return svc;
46 }
47
48 /**
49 * @brief Build DataDimension vector for a pixel readback result.
50 * Follows IMAGE_COLOR convention: [height, width, channels].
51 */
52 std::vector<DataDimension> make_pixel_dimensions(
53 uint32_t pixel_width, uint32_t pixel_height, uint32_t channel_count)
54 {
57 { static_cast<uint64_t>(pixel_height),
58 static_cast<uint64_t>(pixel_width),
59 static_cast<uint64_t>(channel_count) },
61 }
62
63 /**
64 * @brief Reinterpret a raw byte blob as the element type matching the
65 * surface format and move it into out.
66 *
67 * The swapchain readback yields a contiguous byte blob. This function
68 * reinterprets that blob as the element type that matches the surface
69 * format, avoiding a lossy conversion to uint8_t for HDR/float formats.
70 *
71 * @param raw Pointer to the mapped staging buffer.
72 * @param byte_count Total byte count of the readback region.
73 * @param traits Format traits for the live swapchain surface.
74 * @param out DataVariant to receive the typed data.
75 */
76 void fill_variant_from_raw(
77 const void* raw,
78 size_t byte_count,
79 const Core::SurfaceFormatTraits& traits,
80 DataVariant& out)
81 {
82 if (traits.is_float && traits.bits_per_channel == 32U) {
83 const size_t n = byte_count / sizeof(float);
84 std::vector<float> v(n);
85 std::memcpy(v.data(), raw, byte_count);
86 out = std::move(v);
87 } else if (traits.bits_per_channel == 16U) {
88 const size_t n = byte_count / sizeof(uint16_t);
89 std::vector<uint16_t> v(n);
90 std::memcpy(v.data(), raw, byte_count);
91 out = std::move(v);
92 } else if (traits.is_packed) {
93 const size_t n = byte_count / sizeof(uint32_t);
94 std::vector<uint32_t> v(n);
95 std::memcpy(v.data(), raw, byte_count);
96 out = std::move(v);
97 } else {
98 std::vector<uint8_t> v(byte_count);
99 std::memcpy(v.data(), raw, byte_count);
100 out = std::move(v);
101 }
102 }
103
104} // namespace
105
106// =========================================================================
107// Public API
108// =========================================================================
109
111 const std::shared_ptr<Core::Window>& window)
112{
113 auto* svc = get_display_service();
114 if (!svc)
116
117 const int raw = svc->get_swapchain_format(std::static_pointer_cast<void>(window));
118 return Core::from_vk_format(static_cast<vk::Format>(raw));
119}
120
122 const std::shared_ptr<Core::Window>& window,
123 uint32_t x_offset,
124 uint32_t y_offset,
125 uint32_t pixel_width,
126 uint32_t pixel_height,
127 DataVariant& out_variant)
128{
129 static std::vector<DataDimension> s_empty_dims;
130 static DataVariant s_empty_var = std::vector<uint8_t> {};
131 static DataAccess s_fail { s_empty_var, s_empty_dims, DataModality::UNKNOWN };
132
133 auto* display = get_display_service();
134 if (!display)
135 return s_fail;
136
137 const auto window_handle = std::static_pointer_cast<void>(window);
138
139 const int raw_fmt = display->get_swapchain_format(window_handle);
140 const auto vk_fmt = static_cast<vk::Format>(raw_fmt);
141 const auto mf_fmt = Core::from_vk_format(vk_fmt);
142 const auto traits = Core::get_surface_format_traits(mf_fmt);
143 const uint32_t bpp = Core::vk_format_bytes_per_pixel(vk_fmt);
144
145 uint32_t full_w = 0, full_h = 0;
146 display->get_swapchain_extent(window_handle, full_w, full_h);
147 if (full_w == 0 || full_h == 0)
148 return s_fail;
149
150 auto frame = display->get_last_frame(window_handle);
151 if (!frame || frame->empty()) {
153 "SurfaceUtils::readback_region: no captured frame for '{}'",
154 window->get_create_info().title);
155 return s_fail;
156 }
157
158 if (x_offset + pixel_width > full_w || y_offset + pixel_height > full_h) {
160 "SurfaceUtils::readback_region: region {}x{} at ({},{}) exceeds surface {}x{} for '{}'",
161 pixel_width, pixel_height, x_offset, y_offset, full_w, full_h,
162 window->get_create_info().title);
163 return s_fail;
164 }
165
166 const size_t full_row = static_cast<size_t>(full_w) * bpp;
167 const size_t region_row = static_cast<size_t>(pixel_width) * bpp;
168 const size_t byte_count = region_row * pixel_height;
169
170 const size_t expected = full_row * full_h;
171 if (frame->size() < expected) {
173 "SurfaceUtils::readback_region: frame {} bytes, expected {} for '{}'",
174 frame->size(), expected, window->get_create_info().title);
175 return s_fail;
176 }
177
178 std::vector<uint8_t> region(byte_count);
179 const uint8_t* base = frame->data()
180 + static_cast<size_t>(y_offset) * full_row
181 + static_cast<size_t>(x_offset) * bpp;
182
183 for (uint32_t row = 0; row < pixel_height; ++row) {
184 std::memcpy(region.data() + row * region_row,
185 base + row * full_row,
186 region_row);
187 }
188
189 fill_variant_from_raw(region.data(), byte_count, traits, out_variant);
190
191 auto dims = make_pixel_dimensions(pixel_width, pixel_height, traits.channel_count);
192 return { out_variant, dims, DataModality::IMAGE_COLOR };
193}
194
195std::pair<uint32_t, uint32_t> query_surface_extent(
196 const std::shared_ptr<Core::Window>& window)
197{
198 auto* svc = get_display_service();
199 if (!svc)
200 return { 0U, 0U };
201
202 uint32_t w = 0, h = 0;
203 svc->get_swapchain_extent(std::static_pointer_cast<void>(window), w, h);
204 return { w, h };
205}
206
207bool is_readback_available(const std::shared_ptr<Core::Window>& window)
208{
209 auto* svc = get_display_service();
210 if (!svc)
211 return false;
212
213 uint32_t w = 0, h = 0;
214 svc->get_swapchain_extent(std::static_pointer_cast<void>(window), w, h);
215 return w > 0 && h > 0;
216}
217
218} // namespace MayaFlux::Kakshya
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
uint32_t h
Definition InkPress.cpp:28
Type-erased accessor for NDData with semantic view construction.
Interface * get_service()
Query for a backend service.
static BackendRegistry & instance()
Get the global registry instance.
GraphicsSurfaceInfo::SurfaceFormat from_vk_format(vk::Format fmt)
Reverse-map a vk::Format to the nearest GraphicsSurfaceInfo::SurfaceFormat.
SurfaceFormatTraits get_surface_format_traits(GraphicsSurfaceInfo::SurfaceFormat fmt)
Query DataVariant-dispatch traits for a surface format.
uint32_t vk_format_bytes_per_pixel(vk::Format fmt)
Byte width of a single pixel for a given Vulkan format.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
bool is_readback_available(const std::shared_ptr< Core::Window > &window)
Check whether a completed frame is currently available for readback.
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:76
@ UNKNOWN
Unknown or undefined modality.
@ IMAGE_COLOR
2D RGB/RGBA image
@ ROW_MAJOR
C/C++ style (last dimension varies fastest)
std::pair< uint32_t, uint32_t > query_surface_extent(const std::shared_ptr< Core::Window > &window)
Query the current pixel dimensions of the window's swapchain.
DataAccess readback_region(const std::shared_ptr< Core::Window > &window, uint32_t x_offset, uint32_t y_offset, uint32_t pixel_width, uint32_t pixel_height, DataVariant &out_variant)
Read a pixel rectangle from the last completed swapchain frame into a DataVariant whose element type ...
Core::GraphicsSurfaceInfo::SurfaceFormat query_surface_format(const std::shared_ptr< Core::Window > &window)
Query the actual vk::Format in use by the window's live swapchain, translated back to the MayaFlux su...
SurfaceFormat
Default pixel format for window surfaces (Vulkan-compatible)
static std::vector< DataDimension > create_dimensions(DataModality modality, const std::vector< uint64_t > &shape, MemoryLayout layout=MemoryLayout::ROW_MAJOR)
Create dimension descriptors for a data modality.
Definition NDData.cpp:108