-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathgraphics.h
More file actions
803 lines (695 loc) · 25 KB
/
Copy pathgraphics.h
File metadata and controls
803 lines (695 loc) · 25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
/**
* @file src/platform/linux/graphics.h
* @brief Declarations for graphics related functions.
*/
#pragma once
// standard includes
#include <exception>
#include <functional>
#include <optional>
#include <string_view>
#include <utility>
// lib includes
#include <glad/egl.h>
#include <glad/gl.h>
// local includes
#include "misc.h"
#include "src/logging.h"
#include "src/platform/common.h"
#include "src/utility.h"
#include "src/video_colorspace.h"
/**
* @def SUNSHINE_STRINGIFY_HELPER(x)
* @brief Macro for SUNSHINE STRINGIFY HELPER.
*/
#define SUNSHINE_STRINGIFY_HELPER(x) #x
/**
* @def SUNSHINE_STRINGIFY(x)
* @brief Macro for SUNSHINE STRINGIFY.
*/
#define SUNSHINE_STRINGIFY(x) SUNSHINE_STRINGIFY_HELPER(x)
/**
* @def gl_drain_errors_helper(x)
* @brief Macro for gl drain errors helper.
*/
#define gl_drain_errors_helper(x) gl::drain_errors(x)
/**
* @def gl_drain_errors
* @brief Macro for gl drain errors.
*/
#define gl_drain_errors gl_drain_errors_helper(__FILE__ ":" SUNSHINE_STRINGIFY(__LINE__))
/**
* @brief Release the native resource held by the RAII wrapper.
*
* @param __fd File descriptor owned by the RAII wrapper.
* @return 0 on success, or -1 with errno set by the system close call.
*/
extern "C" int close(int __fd);
// X11 Display
extern "C" struct _XDisplay;
struct AVFrame;
/**
* @brief Release an FFmpeg frame allocated by the capture or conversion backend.
*
* @param frame Video or graphics frame being processed.
*/
void free_frame(AVFrame *frame);
/**
* @brief Owning pointer for an EGL frame object.
*/
using frame_t = util::safe_ptr<AVFrame, free_frame>;
namespace gl {
extern GladGLContext ctx;
// glEGLImageTargetTexture2DOES (GL_OES_EGL_image) is not part of desktop GL —
// it is a GLES extension that must be loaded manually via eglGetProcAddress.
// GLeglImageOES is typedef void* per the Khronos spec (gl.xml).
/**
* @brief Function pointer type for glEGLImageTargetTexture2DOES.
*/
using PFNGLEGLIMAGETARGETTEXTURE2DOESPROC = void (*)(GLenum target, void *image);
/**
* @brief Resolve the GLES extension used to bind EGL images as textures.
*
* @return Extension function pointer, or nullptr when the driver does not expose it.
*/
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC egl_image_target_texture_2d();
/**
* @brief Drain and log pending OpenGL errors.
*
* @param prefix Text prefix used when formatting the message.
*/
void drain_errors(const std::string_view &prefix);
/**
* @brief OpenGL texture handle wrapper.
*/
class tex_t: public util::buffer_t<GLuint> {
using util::buffer_t<GLuint>::buffer_t;
public:
/**
* @brief Move ownership of OpenGL texture object names.
*/
tex_t(tex_t &&) = default;
/**
* @brief Assign state from another instance while preserving ownership semantics.
*
* @return Reference or value produced by the operator.
*/
tex_t &operator=(tex_t &&) = default;
~tex_t();
/**
* @brief Allocate the underlying object and wrap it in the owning handle.
*
* @param count Number of objects or handles to create.
* @return Created backend object, or null when creation fails.
*/
static tex_t make(std::size_t count);
};
/**
* @brief OpenGL framebuffer handle wrapper.
*/
class frame_buf_t: public util::buffer_t<GLuint> {
using util::buffer_t<GLuint>::buffer_t;
public:
/**
* @brief Move ownership of OpenGL framebuffer object names.
*/
frame_buf_t(frame_buf_t &&) = default;
/**
* @brief Assign state from another instance while preserving ownership semantics.
*
* @return Reference or value produced by the operator.
*/
frame_buf_t &operator=(frame_buf_t &&) = default;
~frame_buf_t();
/**
* @brief Allocate the underlying object and wrap it in the owning handle.
*
* @param count Number of objects or handles to create.
* @return Created backend object, or null when creation fails.
*/
static frame_buf_t make(std::size_t count);
/**
* @brief Bind each framebuffer and clear its color attachment.
*/
inline void bind(std::nullptr_t, std::nullptr_t) {
int x = 0;
for (auto fb : (*this)) {
ctx.BindFramebuffer(GL_FRAMEBUFFER, fb);
ctx.FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, 0, 0);
++x;
}
return;
}
/**
* @brief Bind textures to this object's framebuffers as color attachments.
*
* @param it_begin First texture object to attach.
* @param it_end One-past-the-end iterator for texture objects to attach.
*/
template<class It>
void bind(It it_begin, It it_end) {
using namespace std::literals;
if (std::distance(it_begin, it_end) > size()) {
BOOST_LOG(warning) << "To many elements to bind"sv;
return;
}
int x = 0;
std::for_each(it_begin, it_end, [&](auto tex) {
ctx.BindFramebuffer(GL_FRAMEBUFFER, (*this)[x]);
ctx.BindTexture(GL_TEXTURE_2D, tex);
ctx.FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, tex, 0);
++x;
});
}
/**
* Copies a part of the framebuffer to texture
*
* @param id Framebuffer index to copy from.
* @param texture Destination texture receiving the copied pixels.
* @param offset_x Source X offset in pixels.
* @param offset_y Source Y offset in pixels.
* @param width Frame or display width in pixels.
* @param height Frame or display height in pixels.
*/
void copy(int id, int texture, int offset_x, int offset_y, int width, int height);
};
/**
* @brief OpenGL shader object that compiles GLSL source.
*/
class shader_t {
KITTY_USING_MOVE_T(shader_internal_t, GLuint, std::numeric_limits<GLuint>::max(), {
if (el != std::numeric_limits<GLuint>::max()) {
ctx.DeleteShader(el);
}
});
public:
/**
* @brief Read the shader compiler log.
*
* @return Shader compiler error log.
*/
std::string err_str();
/**
* @brief Compile an OpenGL shader and report compiler errors.
*
* @param source Shader source code to compile.
* @param type OpenGL shader type, such as GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
* @return Compiled shader object, or compiler log on failure.
*/
static util::Either<shader_t, std::string> compile(const std::string_view &source, GLenum type);
/**
* @brief Return the native handle owned by the wrapper.
*
* @return OpenGL shader object name.
*/
GLuint handle() const;
private:
shader_internal_t _shader;
};
/**
* @brief EGL image buffer with plane descriptors and imported GL textures.
*/
class buffer_t {
KITTY_USING_MOVE_T(buffer_internal_t, GLuint, std::numeric_limits<GLuint>::max(), {
if (el != std::numeric_limits<GLuint>::max()) {
ctx.DeleteBuffers(1, &el);
}
});
public:
/**
* @brief Allocate the underlying object and wrap it in the owning handle.
*
* @param offsets Byte offsets for each uniform member in the block.
* @param block Uniform block name used for diagnostics and updates.
* @param data Initial bytes copied into the uniform buffer.
* @return Created backend object, or null when creation fails.
*/
static buffer_t make(util::buffer_t<GLint> &&offsets, const char *block, const std::string_view &data);
/**
* @brief Return the native handle owned by the wrapper.
*
* @return OpenGL buffer object name.
*/
GLuint handle() const;
/**
* @brief Query a uniform block index from an OpenGL program.
*
* @return Uniform block name associated with the buffer.
*/
const char *block() const;
/**
* @brief Update one uniform member in the block buffer.
*
* @param view Raw bytes to copy into the uniform block.
* @param offset Uniform-member index whose offset is used as the destination.
*/
void update(const std::string_view &view, std::size_t offset = 0);
/**
* @brief Update multiple uniform members in the block buffer.
*
* @param members Uniform members to query within the block.
* @param count Number of members in the array.
* @param offset First uniform-member index to update.
*/
void update(std::string_view *members, std::size_t count, std::size_t offset = 0);
private:
const char *_block;
std::size_t _size;
util::buffer_t<GLint> _offsets;
buffer_internal_t _buffer;
};
/**
* @brief OpenGL shader program with attached shader stages.
*/
class program_t {
KITTY_USING_MOVE_T(program_internal_t, GLuint, std::numeric_limits<GLuint>::max(), {
if (el != std::numeric_limits<GLuint>::max()) {
ctx.DeleteProgram(el);
}
});
public:
/**
* @brief Read the program linker log.
*
* @return OpenGL program link error log.
*/
std::string err_str();
/**
* @brief Link an OpenGL program from compiled shaders.
*
* @param vert Compiled vertex shader object.
* @param frag Compiled fragment shader object.
* @return Linked program object, or linker log on failure.
*/
static util::Either<program_t, std::string> link(const shader_t &vert, const shader_t &frag);
/**
* @brief Bind this program and attach a uniform buffer block.
*
* @param buffer Uniform buffer block used by the program.
*/
void bind(const buffer_t &buffer);
/**
* @brief Query a uniform location from an OpenGL program.
*
* @param block Uniform block name to bind.
* @param members Uniform members to query within the block.
* @param count Number of uniform members to resolve.
* @return Uniform buffer wrapper, or std::nullopt when lookup/allocation fails.
*/
std::optional<buffer_t> uniform(const char *block, std::pair<const char *, std::string_view> *members, std::size_t count);
/**
* @brief Return the native handle owned by the wrapper.
*
* @return OpenGL program object name.
*/
GLuint handle() const;
private:
program_internal_t _program;
};
} // namespace gl
namespace gbm {
struct device;
/**
* @brief Function pointer used to destroy a GBM device.
*/
typedef void (*device_destroy_fn)(device *gbm);
/**
* @brief Function pointer used to create a GBM device from a file descriptor.
*/
typedef device *(*create_device_fn)(int fd);
extern device_destroy_fn device_destroy;
extern create_device_fn create_device;
/**
* @brief Owning GBM device pointer released with the GBM destroy callback.
*/
using gbm_t = util::dyn_safe_ptr<device, &device_destroy>;
/**
* @brief Load GBM symbols required for EGL device creation.
*
* @return 0 on success; nonzero or negative platform status on failure.
*/
int init();
} // namespace gbm
namespace egl {
/**
* @brief Owning pointer for an EGL display connection.
*/
using display_t = util::dyn_safe_ptr_v2<void, EGLBoolean, &eglTerminate>;
/**
* @brief RGB capture image backed by EGL and OpenGL resources.
*/
struct rgb_img_t {
display_t::pointer display; ///< EGL display that owns the imported image.
EGLImage xrgb8; ///< EGL image for the imported XRGB plane.
gl::tex_t tex; ///< Texture containing the imported RGB plane.
};
/**
* @brief NV12 capture image backed by EGL and OpenGL resources.
*/
struct nv12_img_t {
display_t::pointer display; ///< EGL display that owns the imported planes.
EGLImage r8; ///< EGL image for the NV12 luma plane.
EGLImage bg88; ///< EGL image for the NV12 interleaved chroma plane.
gl::tex_t tex; ///< Textures containing the imported Y and UV planes.
gl::frame_buf_t buf; ///< OpenGL framebuffer object used for rendering.
// sizeof(va::DRMPRIMESurfaceDescriptor::objects) / sizeof(va::DRMPRIMESurfaceDescriptor::objects[0]);
static constexpr std::size_t num_fds = 4; ///< Maximum number of DMA-BUF plane file descriptors exported by VAAPI.
std::array<file_t, num_fds> fds; ///< DMA-BUF file descriptors for each exported plane.
};
/**
* @brief YUV 4:4:4 capture image backed by EGL and OpenGL resources.
*/
struct yuv444_img_t {
display_t::pointer display; ///< EGL display that owns the imported planes.
EGLImage r8; ///< EGL image for the Y plane.
EGLImage g8; ///< EGL image for the U plane.
EGLImage b8; ///< EGL image for the V plane.
gl::tex_t tex; ///< Textures containing the imported Y, U, and V planes.
gl::frame_buf_t buf; ///< OpenGL framebuffer object used for rendering.
static constexpr std::size_t num_fds = 4; ///< Num fds.
std::array<file_t, num_fds> fds; ///< DMA-BUF file descriptors for each exported plane.
};
#ifndef DOXYGEN
KITTY_USING_MOVE_T(rgb_t, rgb_img_t, , {
if (el.xrgb8) {
eglDestroyImage(el.display, el.xrgb8);
}
});
KITTY_USING_MOVE_T(nv12_t, nv12_img_t, , {
if (el.r8) {
eglDestroyImage(el.display, el.r8);
}
if (el.bg88) {
eglDestroyImage(el.display, el.bg88);
}
});
KITTY_USING_MOVE_T(yuv444_t, yuv444_img_t, , {
if (el.r8) {
eglDestroyImage(el.display, el.r8);
}
if (el.g8) {
eglDestroyImage(el.display, el.g8);
}
if (el.b8) {
eglDestroyImage(el.display, el.b8);
}
});
KITTY_USING_MOVE_T(ctx_t, (std::tuple<display_t::pointer, EGLContext>), , {
TUPLE_2D_REF(disp, ctx, el);
if (ctx) {
eglMakeCurrent(disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(disp, ctx);
}
});
#else
/**
* @brief Move-only wrapper for RGB EGL image resources.
*/
class rgb_t;
/**
* @brief Move-only wrapper for NV12 EGL image resources.
*/
class nv12_t;
/**
* @brief Move-only wrapper for YUV444 EGL image resources.
*/
class yuv444_t;
/**
* @brief Move-only wrapper for an EGL context.
*/
class ctx_t;
#endif
/**
* @brief EGL surface descriptor used to import a captured DMA-BUF.
*/
struct surface_descriptor_t {
int width; ///< Frame or display width in pixels.
int height; ///< Frame or display height in pixels.
int fds[4]; ///< DMA-BUF file descriptors for up to four planes.
std::uint32_t fourcc; ///< DRM fourcc pixel format for the buffer.
std::uint64_t modifier; ///< DRM format modifier describing the buffer layout.
std::uint32_t pitches[4]; ///< Row stride in bytes for each DMA-BUF plane.
std::uint32_t offsets[4]; ///< Byte offset to the first pixel for each DMA-BUF plane.
};
/**
* @brief Open and initialize the display connection used for capture.
*
* @param native_display Native display.
* @return Constructed display object.
*/
display_t make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display);
/**
* @brief Create an EGL/OpenGL context for capture or conversion.
*
* @param display Display object or identifier associated with the operation.
* @return EGL context wrapper, or std::nullopt when context creation fails.
*/
std::optional<ctx_t> make_ctx(display_t::pointer display);
/**
* @brief Import an RGB source surface.
*
* @return Imported RGB image, or std::nullopt on failure.
*/
std::optional<rgb_t> import_source(display_t::pointer egl_display, const surface_descriptor_t &xrgb);
/**
* @brief Create a blank RGB texture for an image.
*
* @return Blank RGB image.
*/
rgb_t create_blank(platf::img_t &img);
/**
* @brief Import an NV12 target surface.
*
* @return Imported NV12 image, or std::nullopt on failure.
*/
std::optional<nv12_t> import_target(
display_t::pointer egl_display,
std::array<file_t, nv12_img_t::num_fds> &&fds,
const surface_descriptor_t &y,
const surface_descriptor_t &uv
);
/**
* @brief Import a YUV444 target surface.
*
* @param egl_display EGL display.
* @param fds Target plane file descriptors.
* @param y Y plane descriptor.
* @param u U plane descriptor.
* @param v V plane descriptor.
* @return Imported YUV444 image, or std::nullopt on failure.
*/
std::optional<yuv444_t> import_target(
display_t::pointer egl_display,
std::array<file_t, yuv444_img_t::num_fds> &&fds,
const surface_descriptor_t &y,
const surface_descriptor_t &u,
const surface_descriptor_t &v
);
/**
* @brief Creates biplanar YUV textures to render into.
* @param width Width of the target frame.
* @param height Height of the target frame.
* @param format Format of the target frame.
* @return The new RGB texture.
*/
std::optional<nv12_t> create_nv12_target(int width, int height, AVPixelFormat format);
/**
* @brief Create YUV444 target.
*
* @param width Frame or display width in pixels.
* @param height Frame or display height in pixels.
* @param format Pixel, audio, or protocol format being converted.
* @return Created YUV444 target object or status.
*/
std::optional<yuv444_t> create_yuv444_target(int width, int height, AVPixelFormat format);
/**
* @brief Cursor image and hotspot metadata captured from the window system.
*/
class cursor_t: public platf::img_t {
public:
int x; ///< Cursor hotspot or surface X coordinate.
int y; ///< Cursor hotspot or surface Y coordinate.
int src_w; ///< Cursor source image width in pixels.
int src_h; ///< Cursor source image height in pixels.
unsigned long serial; ///< X11 cursor serial used to detect cursor image changes.
std::vector<std::uint8_t> buffer; ///< Cursor image pixels.
};
// Allow cursor and the underlying image to be kept together
/**
* @brief Captured image descriptor shared by EGL conversion paths.
*/
class img_descriptor_t: public cursor_t {
public:
~img_descriptor_t() noexcept {
reset();
}
/**
* @brief Reset the object to its initial empty state.
*/
void reset() noexcept {
mark_capture_buffer_consumed();
for (auto x = 0; x < 4; ++x) {
if (sd.fds[x] >= 0) {
close(sd.fds[x]);
sd.fds[x] = -1;
}
}
}
/**
* @brief Notify the capture backend that the imported source buffer is no
* longer needed by conversion and can be returned to its producer.
*/
void mark_capture_buffer_consumed() noexcept {
auto callback = std::exchange(capture_buffer_consumed_cb, {});
if (callback) {
try {
callback();
} catch (const std::exception &e) {
BOOST_LOG(error) << "Failed to release capture buffer: " << e.what();
} catch (...) {
BOOST_LOG(error) << "Failed to release capture buffer: unknown exception";
}
}
}
surface_descriptor_t sd; ///< DMA-BUF surface descriptor for the captured image.
// Increment sequence when new rgb_t needs to be created
std::uint64_t sequence; ///< Monotonic value used to detect when GL resources must be recreated.
// Frame is vertically flipped (GL convention)
bool y_invert {false}; ///< Whether the shader should invert the Y axis.
// PipeWire metadata
std::optional<uint64_t> pts; ///< PipeWire presentation timestamp.
std::optional<uint64_t> seq; ///< PipeWire frame sequence number.
std::optional<bool> pw_damage; ///< Whether PipeWire damage tracking should be used.
std::optional<uint32_t> pw_flags; ///< PipeWire frame flags reported with the buffer.
std::function<void()> capture_buffer_consumed_cb; ///< Releases a producer-owned capture buffer after import/conversion.
};
/**
* @brief EGL/OpenGL scaler and colorspace conversion pipeline.
*/
class sws_t {
public:
/**
* @brief Create a software-scaling pipeline that renders to NV12 planes.
*
* @param in_width Source frame width in pixels.
* @param in_height Source frame height in pixels.
* @param out_width Destination frame width in pixels.
* @param out_height Destination frame height in pixels.
* @param tex Texture resource used by the converter.
* @return Constructed NV12 object.
*/
static std::optional<sws_t> make_nv12(int in_width, int in_height, int out_width, int out_height, gl::tex_t &&tex);
/**
* @brief Create a software-scaling pipeline that renders to YUV444 planes.
*
* @param in_width Source frame width in pixels.
* @param in_height Source frame height in pixels.
* @param out_width Destination frame width in pixels.
* @param out_height Destination frame height in pixels.
* @param tex Texture resource used by the converter.
* @return Constructed YUV444 object.
*/
static std::optional<sws_t> make_yuv444(int in_width, int in_height, int out_width, int out_height, gl::tex_t &&tex);
/**
* @brief Allocate the underlying object and wrap it in the owning handle.
*
* @param in_width Source frame width in pixels.
* @param in_height Source frame height in pixels.
* @param out_width Destination frame width in pixels.
* @param out_height Destination frame height in pixels.
* @param format Destination FFmpeg pixel format.
* @param is_yuv444 Whether the destination uses three full-resolution planes.
* @return Created backend object, or null when creation fails.
*/
static std::optional<sws_t> make(int in_width, int in_height, int out_width, int out_height, AVPixelFormat format, bool is_yuv444);
// Convert the loaded image into the first two framebuffers
/**
* @brief Convert the loaded source image into NV12 output planes.
*
* @param fb Framebuffer object to bind or update.
* @return Conversion status.
*/
int convert_nv12(gl::frame_buf_t &fb);
// Convert the loaded image into the first three framebuffers
/**
* @brief Convert the loaded source image into YUV444 output planes.
*
* @param fb Framebuffer object to bind or update.
* @return Conversion status.
*/
int convert_yuv444(gl::frame_buf_t &fb);
// Draw loaded image by programs to frame buffers
/**
* @brief Render the loaded source texture into output framebuffers.
*
* @param attachments Framebuffer attachments to bind.
* @param fb Framebuffer object to bind or update.
* @param count Number of output planes to draw.
* @param is_yuv444 Whether to render three YUV444 planes instead of NV12 planes.
* @return 0 when all draw calls complete; nonzero on OpenGL failure.
*/
int draw_programs_to_buffers(GLenum attachments[], gl::frame_buf_t &fb, int count, bool is_yuv444);
// Make an area of the image black
/**
* @brief Clear the render target to a blank frame.
*
* @param fb Framebuffer object to bind or update.
* @param offsetX_ Offset x.
* @param offsetY_ Offset y.
* @param width Frame or display width in pixels.
* @param height Frame or display height in pixels.
* @param is_yuv444 Is YUV444.
* @return 0 when the target area is cleared; nonzero on OpenGL failure.
*/
int blank(gl::frame_buf_t &fb, int offsetX_, int offsetY_, int width, int height, bool is_yuv444);
/**
* @brief Load ram data from the backing API or store.
*
* @param img Image or frame object to read from or populate.
*/
void load_ram(platf::img_t &img);
/**
* @brief Load vram data from the backing API or store.
*
* @param img Image or frame object to read from or populate.
* @param offset_x Offset x.
* @param offset_y Offset y.
* @param texture Texture resource to bind, update, or attach.
* @param is_yuv444 Is YUV444.
*/
void load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture, bool is_yuv444);
/**
* @brief Apply the configured colorspace metadata to the active frame.
*
* @param colorspace Colorimetry information used for conversion or encoding.
* @param is_yuv444 Is YUV444.
*/
void apply_colorspace(const video::sunshine_colorspace_t &colorspace, bool is_yuv444);
// The first texture is the monitor image.
// The second texture is the cursor image
gl::tex_t tex; ///< Source and cursor textures used by the conversion pipeline.
// The cursor image will be blended into this framebuffer
gl::frame_buf_t cursor_framebuffer; ///< Cursor framebuffer.
gl::frame_buf_t copy_framebuffer; ///< Copy framebuffer.
// Y - shader, UV - shader, Cursor - shader : for nv12
// Y - shader, U - shader, V - shader, Cursor - shader : for yuv444
std::array<gl::program_t, 4> program; ///< Program.
gl::buffer_t color_matrix; ///< Color matrix.
int out_width; ///< Out width.
int out_height; ///< Out height.
int in_width; ///< In width.
int in_height; ///< In height.
int offsetX; ///< Offset x.
int offsetY; ///< Offset y.
// Pointer to the texture to be converted to nv12
int loaded_texture; ///< Loaded texture.
// Store latest cursor for load_vram
std::uint64_t serial; ///< Serial.
};
/**
* @brief Log EGL failure details and return an error code.
*
* @return False after logging the EGL failure.
*/
bool fail();
} // namespace egl