MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SurfaceUtils.cpp
Go to the documentation of this file.
1#include "SurfaceUtils.hpp"
2
5
9
12
14
15namespace MayaFlux::Kakshya {
16
17namespace {
18
19 /**
20 * @brief Resolve DisplayService from the backend registry.
21 * Returns nullptr and logs on failure.
22 */
23 Registry::Service::DisplayService* get_display_service()
24 {
26 .get_service<Registry::Service::DisplayService>();
27 if (!svc) {
29 "SurfaceUtils: DisplayService not available");
30 }
31 return svc;
32 }
33
34 /**
35 * @brief Resolve BufferService from the backend registry.
36 * Returns nullptr and logs on failure.
37 */
38 Registry::Service::BufferService* get_buffer_service()
39 {
41 .get_service<Registry::Service::BufferService>();
42 if (!svc) {
44 "SurfaceUtils: BufferService not available");
45 }
46 return svc;
47 }
48
49 /**
50 * @brief Build DataDimension vector for a pixel readback result.
51 * Follows IMAGE_COLOR convention: [height, width, channels].
52 */
53 std::vector<DataDimension> make_pixel_dimensions(
54 uint32_t pixel_width, uint32_t pixel_height, uint32_t channel_count)
55 {
58 { static_cast<uint64_t>(pixel_height),
59 static_cast<uint64_t>(pixel_width),
60 static_cast<uint64_t>(channel_count) },
62 }
63
64 /**
65 * @brief Reinterpret a raw byte blob as the element type matching the
66 * surface format and move it into out.
67 *
68 * The swapchain readback yields a contiguous byte blob. This function
69 * reinterprets that blob as the element type that matches the surface
70 * format, avoiding a lossy conversion to uint8_t for HDR/float formats.
71 *
72 * @param raw Pointer to the mapped staging buffer.
73 * @param byte_count Total byte count of the readback region.
74 * @param traits Format traits for the live swapchain surface.
75 * @param out DataVariant to receive the typed data.
76 */
77 void fill_variant_from_raw(
78 const void* raw,
79 size_t byte_count,
80 const Core::SurfaceFormatTraits& traits,
81 DataVariant& out)
82 {
83 if (traits.is_float && traits.bits_per_channel == 32U) {
84 const size_t n = byte_count / sizeof(float);
85 std::vector<float> v(n);
86 std::memcpy(v.data(), raw, byte_count);
87 out = std::move(v);
88 } else if (traits.bits_per_channel == 16U) {
89 const size_t n = byte_count / sizeof(uint16_t);
90 std::vector<uint16_t> v(n);
91 std::memcpy(v.data(), raw, byte_count);
92 out = std::move(v);
93 } else if (traits.is_packed) {
94 const size_t n = byte_count / sizeof(uint32_t);
95 std::vector<uint32_t> v(n);
96 std::memcpy(v.data(), raw, byte_count);
97 out = std::move(v);
98 } else {
99 std::vector<uint8_t> v(byte_count);
100 std::memcpy(v.data(), raw, byte_count);
101 out = std::move(v);
102 }
103 }
104
105} // namespace
106
107// =========================================================================
108// Public API
109// =========================================================================
110
112 const std::shared_ptr<Core::Window>& window)
113{
114 auto* svc = get_display_service();
115 if (!svc)
117
118 const int raw = svc->get_swapchain_format(std::static_pointer_cast<void>(window));
119 return Core::from_vk_format(static_cast<vk::Format>(raw));
120}
121
123 const std::shared_ptr<Core::Window>& window,
124 uint32_t x_offset,
125 uint32_t y_offset,
126 uint32_t pixel_width,
127 uint32_t pixel_height,
128 DataVariant& out_variant)
129{
130 static std::vector<DataDimension> s_empty_dims;
131 static DataVariant s_empty_var = std::vector<uint8_t> {};
132 static DataAccess s_fail { s_empty_var, s_empty_dims, DataModality::UNKNOWN };
133
134 auto* display = get_display_service();
135 auto* buf_svc = get_buffer_service();
136 if (!display || !buf_svc)
137 return s_fail;
138
139 const auto window_handle = std::static_pointer_cast<void>(window);
140
141 const int raw_fmt = display->get_swapchain_format(window_handle);
142 const auto vk_fmt = static_cast<vk::Format>(raw_fmt);
143 const auto mf_fmt = Core::from_vk_format(vk_fmt);
144 const auto traits = Core::get_surface_format_traits(mf_fmt);
145 const uint32_t bpp = Core::vk_format_bytes_per_pixel(vk_fmt);
146
147 const size_t byte_count = static_cast<size_t>(pixel_width) * pixel_height * bpp;
148
149 auto staging = Buffers::create_staging_buffer(byte_count);
150 if (!staging) {
152 "SurfaceUtils::readback_region: staging allocation failed ({} bytes) for '{}'",
153 byte_count, window->get_create_info().title);
154 return s_fail;
155 }
156
157 const auto& res = staging->get_buffer_resources();
158
159 buf_svc->invalidate_range(res.memory, 0, byte_count);
160 void* mapped = buf_svc->map_buffer(res.memory, 0, byte_count);
161 if (!mapped) {
162 buf_svc->destroy_buffer(std::static_pointer_cast<void>(staging));
164 "SurfaceUtils::readback_region: staging map failed for '{}'",
165 window->get_create_info().title);
166 return s_fail;
167 }
168
169 const bool ok = display->readback_swapchain_region(
170 window_handle,
171 mapped,
172 x_offset, y_offset,
173 pixel_width, pixel_height,
174 byte_count);
175
176 if (!ok) {
177 buf_svc->unmap_buffer(res.memory);
178 buf_svc->destroy_buffer(std::static_pointer_cast<void>(staging));
180 "SurfaceUtils::readback_region: GPU copy failed for '{}'",
181 window->get_create_info().title);
182 return s_fail;
183 }
184
185 fill_variant_from_raw(mapped, byte_count, traits, out_variant);
186 buf_svc->unmap_buffer(res.memory);
187 buf_svc->destroy_buffer(std::static_pointer_cast<void>(staging));
188
189 auto dims = make_pixel_dimensions(pixel_width, pixel_height, traits.channel_count);
190 return { out_variant, dims, DataModality::IMAGE_COLOR };
191}
192
193std::pair<uint32_t, uint32_t> query_surface_extent(
194 const std::shared_ptr<Core::Window>& window)
195{
196 auto* svc = get_display_service();
197 if (!svc)
198 return { 0U, 0U };
199
200 uint32_t w = 0, h = 0;
201 svc->get_swapchain_extent(std::static_pointer_cast<void>(window), w, h);
202 return { w, h };
203}
204
205bool is_readback_available(const std::shared_ptr<Core::Window>& window)
206{
207 auto* svc = get_display_service();
208 if (!svc)
209 return false;
210
211 uint32_t w = 0, h = 0;
212 svc->get_swapchain_extent(std::static_pointer_cast<void>(window), w, h);
213 return w > 0 && h > 0;
214}
215
216} // namespace MayaFlux::Kakshya
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
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.
std::shared_ptr< VKBuffer > create_staging_buffer(size_t size)
Create staging buffer for transfers.
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:73
@ 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