1 #define WANT_ARCAN_SHMIF_HELPER
2 #define AGP_ENABLE_UNPURE
3 #include "../arcan_shmif.h"
4 #include "../shmif_privext.h"
5
6 #include <X11/Xlib.h>
7 #include <X11/Xatom.h>
8 #include <X11/Xutil.h>
9
10 #include "agp/glfun.h"
11
12 #include <GL/glx.h>
13
14 struct shmif_ext_hidden_int {
15 GLXContext ctx;
16 XVisualInfo* vi;
17 Display* display;
18 struct agp_rendertarget* rtgt;
19 struct agp_vstore vstore;
20 struct agp_fenv fenv;
21 bool managed;
22 Window wnd;
23 };
24
arcan_shmifext_defaults(struct arcan_shmif_cont * con)25 struct arcan_shmifext_setup arcan_shmifext_defaults(
26 struct arcan_shmif_cont* con)
27 {
28 return (struct arcan_shmifext_setup){
29 .red = 8, .green = 8, .blue = 8,
30 .alpha = 0, .depth = 24,
31 .api = API_OPENGL,
32 .builtin_fbo = true,
33 .major = 2, .minor = 1
34 };
35 }
36
arcan_shmifext_getfenv(struct arcan_shmif_cont * con)37 struct agp_fenv* arcan_shmifext_getfenv(struct arcan_shmif_cont* con)
38 {
39 if (!con || !con->privext || !con->privext->internal)
40 return false;
41
42 struct shmif_ext_hidden_int* in = con->privext->internal;
43 return &in->fenv;
44 }
45
arcan_shmifext_import_buffer(struct arcan_shmif_cont * cont,struct shmifext_buffer_plane * planes,int format,size_t n_planes,size_t buffer_plane_sz)46 bool arcan_shmifext_import_buffer(
47 struct arcan_shmif_cont* cont,
48 struct shmifext_buffer_plane* planes,
49 int format,
50 size_t n_planes,
51 size_t buffer_plane_sz
52 )
53 {
54 return false;
55 }
56
arcan_shmifext_signal_planes(struct arcan_shmif_cont * c,int mask,size_t n_planes,struct shmifext_buffer_plane * planes)57 size_t arcan_shmifext_signal_planes(
58 struct arcan_shmif_cont* c,
59 int mask,
60 size_t n_planes,
61 struct shmifext_buffer_plane* planes
62 )
63 {
64 return 0;
65 }
66
arcan_shmifext_export_image(struct arcan_shmif_cont * con,uintptr_t display,uintptr_t tex_id,size_t plane_limit,struct shmifext_buffer_plane * planes)67 size_t arcan_shmifext_export_image(
68 struct arcan_shmif_cont* con,
69 uintptr_t display, uintptr_t tex_id,
70 size_t plane_limit, struct shmifext_buffer_plane* planes)
71 {
72 return 0;
73 }
74
x11_drop(struct arcan_shmif_cont * con)75 static void x11_drop(struct arcan_shmif_cont* con)
76 {
77 if (!con->privext->internal)
78 return;
79
80 struct shmif_ext_hidden_int* in = con->privext->internal;
81
82 if (in->managed){
83 glXDestroyContext(in->display, in->ctx);
84 XCloseDisplay(in->display);
85 }
86 if (in->rtgt){
87 agp_drop_rendertarget(in->rtgt);
88 agp_drop_vstore(&in->vstore);
89 in->rtgt = NULL;
90 }
91
92 free(con->privext->internal);
93 con->privext->internal = NULL;
94 }
95
arcan_shmifext_drop(struct arcan_shmif_cont * con)96 bool arcan_shmifext_drop(struct arcan_shmif_cont* con)
97 {
98 if (!con || !con->privext || !con->privext->internal)
99 return false;
100 x11_drop(con);
101 return true;
102 }
103
arcan_shmifext_drop_context(struct arcan_shmif_cont * con)104 bool arcan_shmifext_drop_context(struct arcan_shmif_cont* con)
105 {
106 return arcan_shmifext_drop(con);
107 }
108
arcan_shmifext_lookup(struct arcan_shmif_cont * con,const char * fun)109 void* arcan_shmifext_lookup(
110 struct arcan_shmif_cont* con, const char* fun)
111 {
112 return glXGetProcAddress((const GLubyte*) fun);
113 }
114
lookup_fun(void * tag,const char * sym,bool req)115 static void* lookup_fun(void* tag, const char* sym, bool req)
116 {
117 return glXGetProcAddress((const GLubyte*) sym);
118 }
119
arcan_shmifext_swap_context(struct arcan_shmif_cont * con,unsigned context)120 void arcan_shmifext_swap_context(
121 struct arcan_shmif_cont* con, unsigned context)
122 {
123 }
124
arcan_shmifext_add_context(struct arcan_shmif_cont * con,struct arcan_shmifext_setup arg)125 unsigned arcan_shmifext_add_context(
126 struct arcan_shmif_cont* con, struct arcan_shmifext_setup arg)
127 {
128 return 0;
129 }
130
arcan_shmifext_setup(struct arcan_shmif_cont * con,struct arcan_shmifext_setup arg)131 enum shmifext_setup_status arcan_shmifext_setup(
132 struct arcan_shmif_cont* con,
133 struct arcan_shmifext_setup arg)
134 {
135 if (con->privext->internal)
136 con->privext->cleanup(con);
137
138 struct shmif_ext_hidden_int* ctx = con->privext->internal =
139 malloc(sizeof(struct shmif_ext_hidden_int));
140 memset(ctx, '\0', sizeof(struct shmif_ext_hidden_int));
141
142 if (!con->privext->internal)
143 return SHMIFEXT_NO_DISPLAY;
144
145 int alist[] = {
146 GLX_RGBA,
147 GLX_DEPTH_SIZE,
148 arg.depth,
149 None
150 };
151
152 con->privext->cleanup = x11_drop;
153 ctx->display = XOpenDisplay(NULL);
154 if (!ctx->display){
155 free(con->privext->internal);
156 con->privext->internal = NULL;
157 return SHMIFEXT_NO_DISPLAY;
158 }
159
160 ctx->wnd = DefaultRootWindow(ctx->display);
161 ctx->vi = glXChooseVisual(ctx->display, DefaultScreen(ctx->display), alist);
162 ctx->ctx = glXCreateContext(ctx->display, ctx->vi, 0, GL_TRUE);
163 if (!ctx->ctx){
164 XCloseDisplay(con->privext->internal->display);
165 free(con->privext->internal);
166 con->privext->internal = NULL;
167 return SHMIFEXT_NO_CONTEXT;
168 }
169
170 agp_glinit_fenv(&con->privext->internal->fenv, lookup_fun, NULL);
171
172 if (!glXMakeCurrent(ctx->display, ctx->wnd, ctx->ctx))
173 XSync(ctx->display, False);
174
175 ctx->managed = true;
176 if (arg.builtin_fbo){
177 agp_empty_vstore(&ctx->vstore, con->w, con->h);
178 ctx->rtgt = agp_setup_rendertarget(
179 &ctx->vstore, arg.depth > 0 ? RENDERTARGET_COLOR_DEPTH_STENCIL :
180 RENDERTARGET_COLOR);
181 }
182
183 return SHMIFEXT_OK;
184 }
185
arcan_shmifext_bufferfail(struct arcan_shmif_cont * cont,bool fl)186 void arcan_shmifext_bufferfail(struct arcan_shmif_cont* cont, bool fl)
187 {
188 }
189
arcan_shmifext_dev(struct arcan_shmif_cont * con,uintptr_t * dev,bool clone)190 int arcan_shmifext_dev(struct arcan_shmif_cont* con,
191 uintptr_t* dev, bool clone)
192 {
193 if (dev)
194 *dev = 0;
195
196 return -1;
197 }
198
arcan_shmifext_gl_handles(struct arcan_shmif_cont * con,uintptr_t * frame,uintptr_t * color,uintptr_t * depth)199 bool arcan_shmifext_gl_handles(struct arcan_shmif_cont* con,
200 uintptr_t* frame, uintptr_t* color, uintptr_t* depth)
201 {
202 if (!con || !con->privext || !con->privext->internal ||
203 !con->privext->internal->display || !con->privext->internal->rtgt)
204 return false;
205
206 agp_rendertarget_ids(con->privext->internal->rtgt, frame, color, depth);
207 return true;
208 }
209
arcan_shmifext_egl(struct arcan_shmif_cont * con,void ** display,void * (* lookupfun)(void *,const char *),void * tag)210 bool arcan_shmifext_egl(struct arcan_shmif_cont* con,
211 void** display, void*(*lookupfun)(void*, const char*), void* tag)
212 {
213 return false;
214 }
215
arcan_shmifext_gltex_handle(struct arcan_shmif_cont * con,uintptr_t display,uintptr_t tex_id,int * dhandle,size_t * dstride,int * dfmt)216 bool arcan_shmifext_gltex_handle(struct arcan_shmif_cont* con,
217 uintptr_t display, uintptr_t tex_id,
218 int* dhandle, size_t* dstride, int* dfmt)
219 {
220 return false;
221 }
222
arcan_shmifext_free_color(struct arcan_shmif_cont * con,struct shmifext_color_buffer * out)223 void arcan_shmifext_free_color(
224 struct arcan_shmif_cont* con, struct shmifext_color_buffer* out)
225 {
226 }
227
arcan_shmifext_alloc_color(struct arcan_shmif_cont * con,struct shmifext_color_buffer * out)228 bool arcan_shmifext_alloc_color(
229 struct arcan_shmif_cont* con, struct shmifext_color_buffer* out)
230 {
231 return false;
232 }
233
arcan_shmifext_make_current(struct arcan_shmif_cont * con)234 bool arcan_shmifext_make_current(struct arcan_shmif_cont* con)
235 {
236 if (!con || !con->privext || !con->privext->internal)
237 return false;
238
239 struct shmif_ext_hidden_int* ctx = con->privext->internal;
240
241 if (!glXMakeCurrent(ctx->display, ctx->wnd, ctx->ctx)){
242 XSync(ctx->display, False);
243 return false;
244 }
245
246 if (ctx->rtgt){
247 if (ctx->vstore.w != con->w || ctx->vstore.h != con->h){
248 agp_activate_rendertarget(NULL);
249 agp_resize_rendertarget(ctx->rtgt, con->w, con->h);
250 }
251 agp_activate_rendertarget(ctx->rtgt);
252 }
253
254 return true;
255 }
256
arcan_shmifext_isext(struct arcan_shmif_cont * con)257 int arcan_shmifext_isext(struct arcan_shmif_cont* con)
258 {
259 if (con && con->privext && con->privext->internal)
260 return 2; /* we don't support handle passing via IOSurfaces yet */
261 return 0;
262 }
263
arcan_shmifext_vk(struct arcan_shmif_cont * con,void ** display,void * (* lookupfun)(void *,const char *),void * tag)264 bool arcan_shmifext_vk(struct arcan_shmif_cont* con,
265 void** display, void*(*lookupfun)(void*, const char*), void* tag)
266 {
267 return false;
268 }
269
arcan_shmifext_signal(struct arcan_shmif_cont * con,uintptr_t display,int mask,uintptr_t tex_id,...)270 int arcan_shmifext_signal(struct arcan_shmif_cont* con,
271 uintptr_t display, int mask, uintptr_t tex_id, ...)
272 {
273 if (!con || !con->privext || !con->privext->internal)
274 return -1;
275 struct shmif_ext_hidden_int* ctx = con->privext->internal;
276
277 if (tex_id == SHMIFEXT_BUILTIN){
278 if (ctx->managed)
279 tex_id = ctx->vstore.vinf.text.glid;
280 else
281 return -1;
282 }
283
284 /*
285 * There are some possible extensions for sharing resources from a GLX
286 * context between processes, but it's on the very distant research- list
287 * and would need a corresponding _map_handle etc. implementation server-side
288 *
289 * right now, juse use the slow readback method
290 */
291 struct agp_vstore vstore = {
292 .w = con->w,
293 .h = con->h,
294 .txmapped = TXSTATE_TEX2D,
295 .vinf.text = {
296 .glid = tex_id,
297 .raw = (void*) con->vidp
298 },
299 };
300
301 if (ctx->rtgt){
302 agp_activate_rendertarget(NULL);
303 agp_readback_synchronous(&vstore);
304 agp_activate_rendertarget(ctx->rtgt);
305 }
306 else
307 agp_readback_synchronous(&vstore);
308
309 unsigned res = arcan_shmif_signal(con, mask);
310 return res > INT_MAX ? INT_MAX : res;
311 }
312
platform_video_map_handle(struct agp_vstore * store,int64_t handle)313 bool platform_video_map_handle(struct agp_vstore* store, int64_t handle)
314 {
315 return false;
316 }
317