Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/winsys/sw/xlib/xlib_sw_winsys.c
4573 views
1
/**************************************************************************
2
*
3
* Copyright 2007 VMware, Inc., Bismarck, ND., USA
4
* All Rights Reserved.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
13
*
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
* USE OR OTHER DEALINGS IN THE SOFTWARE.
21
*
22
* The above copyright notice and this permission notice (including the
23
* next paragraph) shall be included in all copies or substantial portions
24
* of the Software.
25
*
26
*
27
**************************************************************************/
28
29
/*
30
* Authors:
31
* Keith Whitwell
32
* Brian Paul
33
*/
34
35
#include "pipe/p_format.h"
36
#include "pipe/p_context.h"
37
#include "util/u_inlines.h"
38
#include "util/format/u_format.h"
39
#include "util/u_math.h"
40
#include "util/u_memory.h"
41
42
#include "frontend/xlibsw_api.h"
43
#include "xlib_sw_winsys.h"
44
45
#include <X11/Xlib.h>
46
#include <X11/Xlibint.h>
47
#include <X11/Xutil.h>
48
#include <sys/ipc.h>
49
#include <sys/shm.h>
50
#include <X11/extensions/XShm.h>
51
52
DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm, "XLIB_NO_SHM", false)
53
54
/**
55
* Display target for Xlib winsys.
56
* Low-level OS/window system memory buffer
57
*/
58
struct xlib_displaytarget
59
{
60
enum pipe_format format;
61
unsigned width;
62
unsigned height;
63
unsigned stride;
64
65
void *data;
66
void *mapped;
67
68
Display *display;
69
Visual *visual;
70
XImage *tempImage;
71
GC gc;
72
73
/* This is the last drawable that this display target was presented
74
* against. May need to recreate gc, tempImage when this changes??
75
*/
76
Drawable drawable;
77
78
XShmSegmentInfo shminfo;
79
Bool shm; /** Using shared memory images? */
80
};
81
82
83
/**
84
* Subclass of sw_winsys for Xlib winsys
85
*/
86
struct xlib_sw_winsys
87
{
88
struct sw_winsys base;
89
Display *display;
90
};
91
92
93
94
/** Cast wrapper */
95
static inline struct xlib_displaytarget *
96
xlib_displaytarget(struct sw_displaytarget *dt)
97
{
98
return (struct xlib_displaytarget *) dt;
99
}
100
101
102
/**
103
* X Shared Memory Image extension code
104
*/
105
106
static volatile int XErrorFlag = 0;
107
108
/**
109
* Catches potential Xlib errors.
110
*/
111
static int
112
handle_xerror(Display *dpy, XErrorEvent *event)
113
{
114
(void) dpy;
115
(void) event;
116
XErrorFlag = 1;
117
return 0;
118
}
119
120
121
static char *
122
alloc_shm(struct xlib_displaytarget *buf, unsigned size)
123
{
124
XShmSegmentInfo *const shminfo = & buf->shminfo;
125
126
shminfo->shmid = -1;
127
shminfo->shmaddr = (char *) -1;
128
129
/* 0600 = user read+write */
130
shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
131
if (shminfo->shmid < 0) {
132
return NULL;
133
}
134
135
shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
136
if (shminfo->shmaddr == (char *) -1) {
137
shmctl(shminfo->shmid, IPC_RMID, 0);
138
return NULL;
139
}
140
141
shminfo->readOnly = False;
142
return shminfo->shmaddr;
143
}
144
145
146
/**
147
* Allocate a shared memory XImage back buffer for the given display target.
148
*/
149
static void
150
alloc_shm_ximage(struct xlib_displaytarget *xlib_dt,
151
struct xlib_drawable *xmb,
152
unsigned width, unsigned height)
153
{
154
/*
155
* We have to do a _lot_ of error checking here to be sure we can
156
* really use the XSHM extension. It seems different servers trigger
157
* errors at different points if the extension won't work. Therefore
158
* we have to be very careful...
159
*/
160
int (*old_handler)(Display *, XErrorEvent *);
161
162
xlib_dt->tempImage = XShmCreateImage(xlib_dt->display,
163
xmb->visual,
164
xmb->depth,
165
ZPixmap,
166
NULL,
167
&xlib_dt->shminfo,
168
width, height);
169
if (xlib_dt->tempImage == NULL) {
170
shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
171
xlib_dt->shm = False;
172
return;
173
}
174
175
176
XErrorFlag = 0;
177
old_handler = XSetErrorHandler(handle_xerror);
178
/* This may trigger the X protocol error we're ready to catch: */
179
XShmAttach(xlib_dt->display, &xlib_dt->shminfo);
180
XSync(xlib_dt->display, False);
181
182
/* Mark the segment to be destroyed, so that it is automatically destroyed
183
* when this process dies. Needs to be after XShmAttach() for *BSD.
184
*/
185
shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
186
187
if (XErrorFlag) {
188
/* we are on a remote display, this error is normal, don't print it */
189
XFlush(xlib_dt->display);
190
XErrorFlag = 0;
191
XDestroyImage(xlib_dt->tempImage);
192
xlib_dt->tempImage = NULL;
193
xlib_dt->shm = False;
194
(void) XSetErrorHandler(old_handler);
195
return;
196
}
197
198
xlib_dt->shm = True;
199
}
200
201
202
static void
203
alloc_ximage(struct xlib_displaytarget *xlib_dt,
204
struct xlib_drawable *xmb,
205
unsigned width, unsigned height)
206
{
207
/* try allocating a shared memory image first */
208
if (xlib_dt->shm) {
209
alloc_shm_ximage(xlib_dt, xmb, width, height);
210
if (xlib_dt->tempImage)
211
return; /* success */
212
}
213
214
/* try regular (non-shared memory) image */
215
xlib_dt->tempImage = XCreateImage(xlib_dt->display,
216
xmb->visual,
217
xmb->depth,
218
ZPixmap, 0,
219
NULL, width, height,
220
8, 0);
221
}
222
223
static bool
224
xlib_is_displaytarget_format_supported(struct sw_winsys *ws,
225
unsigned tex_usage,
226
enum pipe_format format)
227
{
228
/* TODO: check visuals or other sensible thing here */
229
return true;
230
}
231
232
233
static void *
234
xlib_displaytarget_map(struct sw_winsys *ws,
235
struct sw_displaytarget *dt,
236
unsigned flags)
237
{
238
struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
239
xlib_dt->mapped = xlib_dt->data;
240
return xlib_dt->mapped;
241
}
242
243
244
static void
245
xlib_displaytarget_unmap(struct sw_winsys *ws,
246
struct sw_displaytarget *dt)
247
{
248
struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
249
xlib_dt->mapped = NULL;
250
}
251
252
253
static void
254
xlib_displaytarget_destroy(struct sw_winsys *ws,
255
struct sw_displaytarget *dt)
256
{
257
struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
258
259
if (xlib_dt->data) {
260
if (xlib_dt->shminfo.shmid >= 0) {
261
shmdt(xlib_dt->shminfo.shmaddr);
262
shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
263
264
xlib_dt->shminfo.shmid = -1;
265
xlib_dt->shminfo.shmaddr = (char *) -1;
266
267
xlib_dt->data = NULL;
268
if (xlib_dt->tempImage)
269
xlib_dt->tempImage->data = NULL;
270
}
271
else {
272
align_free(xlib_dt->data);
273
if (xlib_dt->tempImage && xlib_dt->tempImage->data == xlib_dt->data) {
274
xlib_dt->tempImage->data = NULL;
275
}
276
xlib_dt->data = NULL;
277
}
278
}
279
280
if (xlib_dt->tempImage) {
281
XDestroyImage(xlib_dt->tempImage);
282
xlib_dt->tempImage = NULL;
283
}
284
285
if (xlib_dt->gc)
286
XFreeGC(xlib_dt->display, xlib_dt->gc);
287
288
FREE(xlib_dt);
289
}
290
291
292
/**
293
* Display/copy the image in the surface into the X window specified
294
* by the display target.
295
*/
296
static void
297
xlib_sw_display(struct xlib_drawable *xlib_drawable,
298
struct sw_displaytarget *dt,
299
struct pipe_box *box)
300
{
301
static bool no_swap = false;
302
static bool firsttime = true;
303
struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
304
Display *display = xlib_dt->display;
305
XImage *ximage;
306
struct pipe_box _box = {};
307
308
if (firsttime) {
309
no_swap = getenv("SP_NO_RAST") != NULL;
310
firsttime = 0;
311
}
312
313
if (no_swap)
314
return;
315
316
if (!box) {
317
_box.width = xlib_dt->width;
318
_box.height = xlib_dt->height;
319
box = &_box;
320
}
321
322
if (xlib_dt->drawable != xlib_drawable->drawable) {
323
if (xlib_dt->gc) {
324
XFreeGC(display, xlib_dt->gc);
325
xlib_dt->gc = NULL;
326
}
327
328
if (xlib_dt->tempImage) {
329
XDestroyImage(xlib_dt->tempImage);
330
xlib_dt->tempImage = NULL;
331
}
332
333
xlib_dt->drawable = xlib_drawable->drawable;
334
}
335
336
if (xlib_dt->tempImage == NULL) {
337
assert(util_format_get_blockwidth(xlib_dt->format) == 1);
338
assert(util_format_get_blockheight(xlib_dt->format) == 1);
339
alloc_ximage(xlib_dt, xlib_drawable,
340
xlib_dt->stride / util_format_get_blocksize(xlib_dt->format),
341
xlib_dt->height);
342
if (!xlib_dt->tempImage)
343
return;
344
}
345
346
if (xlib_dt->gc == NULL) {
347
xlib_dt->gc = XCreateGC(display, xlib_drawable->drawable, 0, NULL);
348
XSetFunction(display, xlib_dt->gc, GXcopy);
349
}
350
351
if (xlib_dt->shm) {
352
ximage = xlib_dt->tempImage;
353
ximage->data = xlib_dt->data;
354
355
/* _debug_printf("XSHM\n"); */
356
XShmPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,
357
ximage, box->x, box->y, box->x, box->y,
358
box->width, box->height, False);
359
}
360
else {
361
/* display image in Window */
362
ximage = xlib_dt->tempImage;
363
ximage->data = xlib_dt->data;
364
365
/* check that the XImage has been previously initialized */
366
assert(ximage->format);
367
assert(ximage->bitmap_unit);
368
369
/* update XImage's fields */
370
ximage->width = xlib_dt->width;
371
ximage->height = xlib_dt->height;
372
ximage->bytes_per_line = xlib_dt->stride;
373
374
/* _debug_printf("XPUT\n"); */
375
XPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,
376
ximage, box->x, box->y, box->x, box->y,
377
box->width, box->height);
378
}
379
380
XFlush(xlib_dt->display);
381
}
382
383
384
/**
385
* Display/copy the image in the surface into the X window specified
386
* by the display target.
387
*/
388
static void
389
xlib_displaytarget_display(struct sw_winsys *ws,
390
struct sw_displaytarget *dt,
391
void *context_private,
392
struct pipe_box *box)
393
{
394
struct xlib_drawable *xlib_drawable = (struct xlib_drawable *)context_private;
395
xlib_sw_display(xlib_drawable, dt, box);
396
}
397
398
399
static struct sw_displaytarget *
400
xlib_displaytarget_create(struct sw_winsys *winsys,
401
unsigned tex_usage,
402
enum pipe_format format,
403
unsigned width, unsigned height,
404
unsigned alignment,
405
const void *front_private,
406
unsigned *stride)
407
{
408
struct xlib_displaytarget *xlib_dt;
409
unsigned nblocksy, size;
410
int ignore;
411
412
xlib_dt = CALLOC_STRUCT(xlib_displaytarget);
413
if (!xlib_dt)
414
goto no_xlib_dt;
415
416
xlib_dt->display = ((struct xlib_sw_winsys *)winsys)->display;
417
xlib_dt->format = format;
418
xlib_dt->width = width;
419
xlib_dt->height = height;
420
421
nblocksy = util_format_get_nblocksy(format, height);
422
xlib_dt->stride = align(util_format_get_stride(format, width), alignment);
423
size = xlib_dt->stride * nblocksy;
424
425
if (!debug_get_option_xlib_no_shm() &&
426
XQueryExtension(xlib_dt->display, "MIT-SHM", &ignore, &ignore, &ignore)) {
427
xlib_dt->data = alloc_shm(xlib_dt, size);
428
if (xlib_dt->data) {
429
xlib_dt->shm = True;
430
}
431
}
432
433
if (!xlib_dt->data) {
434
xlib_dt->data = align_malloc(size, alignment);
435
if (!xlib_dt->data)
436
goto no_data;
437
}
438
439
*stride = xlib_dt->stride;
440
return (struct sw_displaytarget *)xlib_dt;
441
442
no_data:
443
FREE(xlib_dt);
444
no_xlib_dt:
445
return NULL;
446
}
447
448
449
static struct sw_displaytarget *
450
xlib_displaytarget_from_handle(struct sw_winsys *winsys,
451
const struct pipe_resource *templet,
452
struct winsys_handle *whandle,
453
unsigned *stride)
454
{
455
assert(0);
456
return NULL;
457
}
458
459
460
static bool
461
xlib_displaytarget_get_handle(struct sw_winsys *winsys,
462
struct sw_displaytarget *dt,
463
struct winsys_handle *whandle)
464
{
465
assert(0);
466
return false;
467
}
468
469
470
static void
471
xlib_destroy(struct sw_winsys *ws)
472
{
473
FREE(ws);
474
}
475
476
477
struct sw_winsys *
478
xlib_create_sw_winsys(Display *display)
479
{
480
struct xlib_sw_winsys *ws;
481
482
ws = CALLOC_STRUCT(xlib_sw_winsys);
483
if (!ws)
484
return NULL;
485
486
ws->display = display;
487
ws->base.destroy = xlib_destroy;
488
489
ws->base.is_displaytarget_format_supported = xlib_is_displaytarget_format_supported;
490
491
ws->base.displaytarget_create = xlib_displaytarget_create;
492
ws->base.displaytarget_from_handle = xlib_displaytarget_from_handle;
493
ws->base.displaytarget_get_handle = xlib_displaytarget_get_handle;
494
ws->base.displaytarget_map = xlib_displaytarget_map;
495
ws->base.displaytarget_unmap = xlib_displaytarget_unmap;
496
ws->base.displaytarget_destroy = xlib_displaytarget_destroy;
497
498
ws->base.displaytarget_display = xlib_displaytarget_display;
499
500
return &ws->base;
501
}
502
503