Sunshine latest
Self-hosted game stream host for Moonlight.
graphics.h
Go to the documentation of this file.
1
5#pragma once
6
7// standard includes
8#include <optional>
9#include <string_view>
10
11// lib includes
12#include <glad/egl.h>
13#include <glad/gl.h>
14
15// local includes
16#include "misc.h"
17#include "src/logging.h"
18#include "src/platform/common.h"
19#include "src/utility.h"
21
22#define SUNSHINE_STRINGIFY_HELPER(x) #x
23#define SUNSHINE_STRINGIFY(x) SUNSHINE_STRINGIFY_HELPER(x)
24#define gl_drain_errors_helper(x) gl::drain_errors(x)
25#define gl_drain_errors gl_drain_errors_helper(__FILE__ ":" SUNSHINE_STRINGIFY(__LINE__))
26
27extern "C" int close(int __fd);
28
29// X11 Display
30extern "C" struct _XDisplay;
31
32struct AVFrame;
33void free_frame(AVFrame *frame);
34
36
37namespace gl {
38 extern GladGLContext ctx;
39 void drain_errors(const std::string_view &prefix);
40
41 class tex_t: public util::buffer_t<GLuint> {
42 using util::buffer_t<GLuint>::buffer_t;
43
44 public:
45 tex_t(tex_t &&) = default;
46 tex_t &operator=(tex_t &&) = default;
47
48 ~tex_t();
49
50 static tex_t make(std::size_t count);
51 };
52
53 class frame_buf_t: public util::buffer_t<GLuint> {
54 using util::buffer_t<GLuint>::buffer_t;
55
56 public:
57 frame_buf_t(frame_buf_t &&) = default;
58 frame_buf_t &operator=(frame_buf_t &&) = default;
59
61
62 static frame_buf_t make(std::size_t count);
63
64 inline void bind(std::nullptr_t, std::nullptr_t) {
65 int x = 0;
66 for (auto fb : (*this)) {
67 ctx.BindFramebuffer(GL_FRAMEBUFFER, fb);
68 ctx.FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, 0, 0);
69
70 ++x;
71 }
72 return;
73 }
74
75 template<class It>
76 void bind(It it_begin, It it_end) {
77 using namespace std::literals;
78 if (std::distance(it_begin, it_end) > size()) {
79 BOOST_LOG(warning) << "To many elements to bind"sv;
80 return;
81 }
82
83 int x = 0;
84 std::for_each(it_begin, it_end, [&](auto tex) {
85 ctx.BindFramebuffer(GL_FRAMEBUFFER, (*this)[x]);
86 ctx.BindTexture(GL_TEXTURE_2D, tex);
87
88 ctx.FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + x, tex, 0);
89
90 ++x;
91 });
92 }
93
97 void copy(int id, int texture, int offset_x, int offset_y, int width, int height);
98 };
99
100 class shader_t {
101 KITTY_USING_MOVE_T(shader_internal_t, GLuint, std::numeric_limits<GLuint>::max(), {
102 if (el != std::numeric_limits<GLuint>::max()) {
103 ctx.DeleteShader(el);
104 }
105 });
106
107 public:
108 std::string err_str();
109
110 static util::Either<shader_t, std::string> compile(const std::string_view &source, GLenum type);
111
112 GLuint handle() const;
113
114 private:
115 shader_internal_t _shader;
116 };
117
118 class buffer_t {
119 KITTY_USING_MOVE_T(buffer_internal_t, GLuint, std::numeric_limits<GLuint>::max(), {
120 if (el != std::numeric_limits<GLuint>::max()) {
121 ctx.DeleteBuffers(1, &el);
122 }
123 });
124
125 public:
126 static buffer_t make(util::buffer_t<GLint> &&offsets, const char *block, const std::string_view &data);
127
128 GLuint handle() const;
129
130 const char *block() const;
131
132 void update(const std::string_view &view, std::size_t offset = 0);
133 void update(std::string_view *members, std::size_t count, std::size_t offset = 0);
134
135 private:
136 const char *_block;
137
138 std::size_t _size;
139
140 util::buffer_t<GLint> _offsets;
141
142 buffer_internal_t _buffer;
143 };
144
145 class program_t {
146 KITTY_USING_MOVE_T(program_internal_t, GLuint, std::numeric_limits<GLuint>::max(), {
147 if (el != std::numeric_limits<GLuint>::max()) {
148 ctx.DeleteProgram(el);
149 }
150 });
151
152 public:
153 std::string err_str();
154
155 static util::Either<program_t, std::string> link(const shader_t &vert, const shader_t &frag);
156
157 void bind(const buffer_t &buffer);
158
159 std::optional<buffer_t> uniform(const char *block, std::pair<const char *, std::string_view> *members, std::size_t count);
160
161 GLuint handle() const;
162
163 private:
164 program_internal_t _program;
165 };
166} // namespace gl
167
168namespace gbm {
169 struct device;
170 typedef void (*device_destroy_fn)(device *gbm);
171 typedef device *(*create_device_fn)(int fd);
172
173 extern device_destroy_fn device_destroy;
174 extern create_device_fn create_device;
175
177
178 int init();
179
180} // namespace gbm
181
182namespace egl {
184
185 struct rgb_img_t {
186 display_t::pointer display;
187 EGLImage xrgb8;
188
189 gl::tex_t tex;
190 };
191
192 struct nv12_img_t {
193 display_t::pointer display;
194 EGLImage r8;
195 EGLImage bg88;
196
197 gl::tex_t tex;
198 gl::frame_buf_t buf;
199
200 // sizeof(va::DRMPRIMESurfaceDescriptor::objects) / sizeof(va::DRMPRIMESurfaceDescriptor::objects[0]);
201 static constexpr std::size_t num_fds = 4;
202
203 std::array<file_t, num_fds> fds;
204 };
205
206 KITTY_USING_MOVE_T(rgb_t, rgb_img_t, , {
207 if (el.xrgb8) {
208 eglDestroyImage(el.display, el.xrgb8);
209 }
210 });
211
212 KITTY_USING_MOVE_T(nv12_t, nv12_img_t, , {
213 if (el.r8) {
214 eglDestroyImage(el.display, el.r8);
215 }
216
217 if (el.bg88) {
218 eglDestroyImage(el.display, el.bg88);
219 }
220 });
221
222 KITTY_USING_MOVE_T(ctx_t, (std::tuple<display_t::pointer, EGLContext>), , {
223 TUPLE_2D_REF(disp, ctx, el);
224 if (ctx) {
225 eglMakeCurrent(disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
226 eglDestroyContext(disp, ctx);
227 }
228 });
229
231 int width;
232 int height;
233 int fds[4];
234 std::uint32_t fourcc;
235 std::uint64_t modifier;
236 std::uint32_t pitches[4];
237 std::uint32_t offsets[4];
238 };
239
240 display_t make_display(std::variant<gbm::gbm_t::pointer, wl_display *, _XDisplay *> native_display);
241 std::optional<ctx_t> make_ctx(display_t::pointer display);
242
243 std::optional<rgb_t>
244 import_source(
245 display_t::pointer egl_display,
246 const surface_descriptor_t &xrgb
247 );
248
249 rgb_t create_blank(platf::img_t &img);
250
251 std::optional<nv12_t> import_target(
252 display_t::pointer egl_display,
253 std::array<file_t, nv12_img_t::num_fds> &&fds,
254 const surface_descriptor_t &y,
255 const surface_descriptor_t &uv
256 );
257
265 std::optional<nv12_t> create_target(int width, int height, AVPixelFormat format);
266
267 class cursor_t: public platf::img_t {
268 public:
269 int x, y;
270 int src_w, src_h;
271
272 unsigned long serial;
273
274 std::vector<std::uint8_t> buffer;
275 };
276
277 // Allow cursor and the underlying image to be kept together
279 public:
281 reset();
282 }
283
284 void reset() {
285 for (auto x = 0; x < 4; ++x) {
286 if (sd.fds[x] >= 0) {
287 close(sd.fds[x]);
288
289 sd.fds[x] = -1;
290 }
291 }
292 }
293
295
296 // Increment sequence when new rgb_t needs to be created
297 std::uint64_t sequence;
298 };
299
300 class sws_t {
301 public:
302 static std::optional<sws_t> make(int in_width, int in_height, int out_width, int out_height, gl::tex_t &&tex);
303 static std::optional<sws_t> make(int in_width, int in_height, int out_width, int out_height, AVPixelFormat format);
304
305 // Convert the loaded image into the first two framebuffers
306 int convert(gl::frame_buf_t &fb);
307
308 // Make an area of the image black
309 int blank(gl::frame_buf_t &fb, int offsetX, int offsetY, int width, int height);
310
311 void load_ram(platf::img_t &img);
312 void load_vram(img_descriptor_t &img, int offset_x, int offset_y, int texture);
313
314 void apply_colorspace(const video::sunshine_colorspace_t &colorspace);
315
316 // The first texture is the monitor image.
317 // The second texture is the cursor image
318 gl::tex_t tex;
319
320 // The cursor image will be blended into this framebuffer
321 gl::frame_buf_t cursor_framebuffer;
322 gl::frame_buf_t copy_framebuffer;
323
324 // Y - shader, UV - shader, Cursor - shader
325 gl::program_t program[3];
326 gl::buffer_t color_matrix;
327
328 int out_width, out_height;
329 int in_width, in_height;
330 int offsetX, offsetY;
331
332 // Pointer to the texture to be converted to nv12
333 int loaded_texture;
334
335 // Store latest cursor for load_vram
336 std::uint64_t serial;
337 };
338
339 bool fail();
340} // namespace egl
Definition graphics.h:267
Definition graphics.h:278
Definition graphics.h:300
Definition graphics.h:118
Definition graphics.h:53
void copy(int id, int texture, int offset_x, int offset_y, int width, int height)
Definition graphics.cpp:81
Definition graphics.h:145
Definition graphics.h:100
Definition graphics.h:41
Definition utility.h:499
Definition utility.h:835
Definition utility.h:530
Declarations for common platform specific utilities.
rgb_t create_blank(platf::img_t &img)
Create a black RGB texture of the specified image size.
Definition graphics.cpp:567
std::optional< nv12_t > create_target(int width, int height, AVPixelFormat format)
Create biplanar YUV textures to render into.
Definition graphics.cpp:646
Miscellaneous declarations for Linux.
Declarations for logging related functions.
Definition graphics.h:192
Definition graphics.h:185
Definition graphics.h:230
Definition common.h:347
Definition video_colorspace.h:20
Declarations for utility functions.
Declarations for colorspace functions.