Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/frontends/dri/dri_drawable.c
4565 views
1
/**************************************************************************
2
*
3
* Copyright 2009, VMware, Inc.
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 above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
16
* of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
/*
28
* Author: Keith Whitwell <[email protected]>
29
* Author: Jakob Bornecrantz <[email protected]>
30
*/
31
32
#include "dri_screen.h"
33
#include "dri_context.h"
34
#include "dri_drawable.h"
35
36
#include "pipe/p_screen.h"
37
#include "util/format/u_format.h"
38
#include "util/u_memory.h"
39
#include "util/u_inlines.h"
40
41
static uint32_t drifb_ID = 0;
42
43
static bool
44
dri_st_framebuffer_validate(struct st_context_iface *stctx,
45
struct st_framebuffer_iface *stfbi,
46
const enum st_attachment_type *statts,
47
unsigned count,
48
struct pipe_resource **out)
49
{
50
struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
51
struct dri_drawable *drawable =
52
(struct dri_drawable *) stfbi->st_manager_private;
53
struct dri_screen *screen = dri_screen(drawable->sPriv);
54
unsigned statt_mask, new_mask;
55
bool new_stamp;
56
int i;
57
unsigned int lastStamp;
58
struct pipe_resource **textures =
59
drawable->stvis.samples > 1 ? drawable->msaa_textures
60
: drawable->textures;
61
62
statt_mask = 0x0;
63
for (i = 0; i < count; i++)
64
statt_mask |= (1 << statts[i]);
65
66
/* record newly allocated textures */
67
new_mask = (statt_mask & ~drawable->texture_mask);
68
69
/*
70
* dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the
71
* client stamp. It has the value of the server stamp when last
72
* checked.
73
*/
74
do {
75
lastStamp = drawable->dPriv->lastStamp;
76
new_stamp = (drawable->texture_stamp != lastStamp);
77
78
if (new_stamp || new_mask || screen->broken_invalidate) {
79
if (new_stamp && drawable->update_drawable_info)
80
drawable->update_drawable_info(drawable);
81
82
drawable->allocate_textures(ctx, drawable, statts, count);
83
84
/* add existing textures */
85
for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
86
if (textures[i])
87
statt_mask |= (1 << i);
88
}
89
90
drawable->texture_stamp = lastStamp;
91
drawable->texture_mask = statt_mask;
92
}
93
} while (lastStamp != drawable->dPriv->lastStamp);
94
95
/* Flush the pending set_damage_region request. */
96
struct pipe_screen *pscreen = screen->base.screen;
97
98
if (new_mask & (1 << ST_ATTACHMENT_BACK_LEFT) &&
99
pscreen->set_damage_region) {
100
struct pipe_resource *resource = textures[ST_ATTACHMENT_BACK_LEFT];
101
102
pscreen->set_damage_region(pscreen, resource,
103
drawable->num_damage_rects,
104
drawable->damage_rects);
105
}
106
107
if (!out)
108
return true;
109
110
/* Set the window-system buffers for the gallium frontend. */
111
for (i = 0; i < count; i++)
112
pipe_resource_reference(&out[i], textures[statts[i]]);
113
114
return true;
115
}
116
117
static bool
118
dri_st_framebuffer_flush_front(struct st_context_iface *stctx,
119
struct st_framebuffer_iface *stfbi,
120
enum st_attachment_type statt)
121
{
122
struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
123
struct dri_drawable *drawable =
124
(struct dri_drawable *) stfbi->st_manager_private;
125
126
/* XXX remove this and just set the correct one on the framebuffer */
127
return drawable->flush_frontbuffer(ctx, drawable, statt);
128
}
129
130
/**
131
* The gallium frontend framebuffer interface flush_swapbuffers callback
132
*/
133
static bool
134
dri_st_framebuffer_flush_swapbuffers(struct st_context_iface *stctx,
135
struct st_framebuffer_iface *stfbi)
136
{
137
struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
138
struct dri_drawable *drawable =
139
(struct dri_drawable *) stfbi->st_manager_private;
140
141
if (drawable->flush_swapbuffers)
142
drawable->flush_swapbuffers(ctx, drawable);
143
144
return true;
145
}
146
147
/**
148
* This is called when we need to set up GL rendering to a new X window.
149
*/
150
bool
151
dri_create_buffer(__DRIscreen * sPriv,
152
__DRIdrawable * dPriv,
153
const struct gl_config * visual, bool isPixmap)
154
{
155
struct dri_screen *screen = sPriv->driverPrivate;
156
struct dri_drawable *drawable = NULL;
157
158
if (isPixmap)
159
goto fail; /* not implemented */
160
161
drawable = CALLOC_STRUCT(dri_drawable);
162
if (drawable == NULL)
163
goto fail;
164
165
dri_fill_st_visual(&drawable->stvis, screen, visual);
166
167
/* setup the st_framebuffer_iface */
168
drawable->base.visual = &drawable->stvis;
169
drawable->base.flush_front = dri_st_framebuffer_flush_front;
170
drawable->base.validate = dri_st_framebuffer_validate;
171
drawable->base.flush_swapbuffers = dri_st_framebuffer_flush_swapbuffers;
172
drawable->base.st_manager_private = (void *) drawable;
173
174
drawable->screen = screen;
175
drawable->sPriv = sPriv;
176
drawable->dPriv = dPriv;
177
178
dPriv->driverPrivate = (void *)drawable;
179
p_atomic_set(&drawable->base.stamp, 1);
180
drawable->base.ID = p_atomic_inc_return(&drifb_ID);
181
drawable->base.state_manager = &screen->base;
182
183
return true;
184
fail:
185
FREE(drawable);
186
return false;
187
}
188
189
void
190
dri_destroy_buffer(__DRIdrawable * dPriv)
191
{
192
struct dri_drawable *drawable = dri_drawable(dPriv);
193
struct dri_screen *screen = drawable->screen;
194
struct st_api *stapi = screen->st_api;
195
int i;
196
197
for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
198
pipe_resource_reference(&drawable->textures[i], NULL);
199
for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
200
pipe_resource_reference(&drawable->msaa_textures[i], NULL);
201
202
screen->base.screen->fence_reference(screen->base.screen,
203
&drawable->throttle_fence, NULL);
204
205
/* Notify the st manager that this drawable is no longer valid */
206
stapi->destroy_drawable(stapi, &drawable->base);
207
208
FREE(drawable->damage_rects);
209
FREE(drawable);
210
}
211
212
/**
213
* Validate the texture at an attachment. Allocate the texture if it does not
214
* exist. Used by the TFP extension.
215
*/
216
static void
217
dri_drawable_validate_att(struct dri_context *ctx,
218
struct dri_drawable *drawable,
219
enum st_attachment_type statt)
220
{
221
enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
222
unsigned i, count = 0;
223
224
/* check if buffer already exists */
225
if (drawable->texture_mask & (1 << statt))
226
return;
227
228
/* make sure DRI2 does not destroy existing buffers */
229
for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
230
if (drawable->texture_mask & (1 << i)) {
231
statts[count++] = i;
232
}
233
}
234
statts[count++] = statt;
235
236
drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
237
238
drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL);
239
}
240
241
/**
242
* These are used for GLX_EXT_texture_from_pixmap
243
*/
244
static void
245
dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
246
GLint format, __DRIdrawable *dPriv)
247
{
248
struct dri_context *ctx = dri_context(pDRICtx);
249
struct st_context_iface *st = ctx->st;
250
struct dri_drawable *drawable = dri_drawable(dPriv);
251
struct pipe_resource *pt;
252
253
if (st->thread_finish)
254
st->thread_finish(st);
255
256
dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
257
258
/* Use the pipe resource associated with the X drawable */
259
pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
260
261
if (pt) {
262
enum pipe_format internal_format = pt->format;
263
264
if (format == __DRI_TEXTURE_FORMAT_RGB) {
265
/* only need to cover the formats recognized by dri_fill_st_visual */
266
switch (internal_format) {
267
case PIPE_FORMAT_R16G16B16A16_FLOAT:
268
internal_format = PIPE_FORMAT_R16G16B16X16_FLOAT;
269
break;
270
case PIPE_FORMAT_B10G10R10A2_UNORM:
271
internal_format = PIPE_FORMAT_B10G10R10X2_UNORM;
272
break;
273
case PIPE_FORMAT_R10G10B10A2_UNORM:
274
internal_format = PIPE_FORMAT_R10G10B10X2_UNORM;
275
break;
276
case PIPE_FORMAT_BGRA8888_UNORM:
277
internal_format = PIPE_FORMAT_BGRX8888_UNORM;
278
break;
279
case PIPE_FORMAT_ARGB8888_UNORM:
280
internal_format = PIPE_FORMAT_XRGB8888_UNORM;
281
break;
282
default:
283
break;
284
}
285
}
286
287
drawable->update_tex_buffer(drawable, ctx, pt);
288
289
ctx->st->teximage(ctx->st,
290
(target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
291
0, internal_format, pt, false);
292
}
293
}
294
295
static void
296
dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
297
__DRIdrawable *dPriv)
298
{
299
dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
300
}
301
302
const __DRItexBufferExtension driTexBufferExtension = {
303
.base = { __DRI_TEX_BUFFER, 2 },
304
305
.setTexBuffer = dri_set_tex_buffer,
306
.setTexBuffer2 = dri_set_tex_buffer2,
307
.releaseTexBuffer = NULL,
308
};
309
310
/**
311
* Get the format and binding of an attachment.
312
*/
313
void
314
dri_drawable_get_format(struct dri_drawable *drawable,
315
enum st_attachment_type statt,
316
enum pipe_format *format,
317
unsigned *bind)
318
{
319
switch (statt) {
320
case ST_ATTACHMENT_FRONT_LEFT:
321
case ST_ATTACHMENT_BACK_LEFT:
322
case ST_ATTACHMENT_FRONT_RIGHT:
323
case ST_ATTACHMENT_BACK_RIGHT:
324
/* Other pieces of the driver stack get confused and behave incorrectly
325
* when they get an sRGB drawable. st/mesa receives "drawable->stvis"
326
* though other means and handles it correctly, so we don't really need
327
* to use an sRGB format here.
328
*/
329
*format = util_format_linear(drawable->stvis.color_format);
330
*bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
331
break;
332
case ST_ATTACHMENT_DEPTH_STENCIL:
333
*format = drawable->stvis.depth_stencil_format;
334
*bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
335
break;
336
default:
337
*format = PIPE_FORMAT_NONE;
338
*bind = 0;
339
break;
340
}
341
}
342
343
void
344
dri_pipe_blit(struct pipe_context *pipe,
345
struct pipe_resource *dst,
346
struct pipe_resource *src)
347
{
348
struct pipe_blit_info blit;
349
350
if (!dst || !src)
351
return;
352
353
/* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
354
* Fragment Operations):
355
*
356
* If a framebuffer object is not bound, after all operations have
357
* been completed on the multisample buffer, the sample values for
358
* each color in the multisample buffer are combined to produce a
359
* single color value, and that value is written into the
360
* corresponding color buffers selected by DrawBuffer or
361
* DrawBuffers. An implementation may defer the writing of the color
362
* buffers until a later time, but the state of the framebuffer must
363
* behave as if the color buffers were updated as each fragment was
364
* processed. The method of combination is not specified. If the
365
* framebuffer contains sRGB values, then it is recommended that the
366
* an average of sample values is computed in a linearized space, as
367
* for blending (see section 4.1.7).
368
*
369
* In other words, to do a resolve operation in a linear space, we have
370
* to set sRGB formats if the original resources were sRGB, so don't use
371
* util_format_linear.
372
*/
373
374
memset(&blit, 0, sizeof(blit));
375
blit.dst.resource = dst;
376
blit.dst.box.width = dst->width0;
377
blit.dst.box.height = dst->height0;
378
blit.dst.box.depth = 1;
379
blit.dst.format = dst->format;
380
blit.src.resource = src;
381
blit.src.box.width = src->width0;
382
blit.src.box.height = src->height0;
383
blit.src.box.depth = 1;
384
blit.src.format = src->format;
385
blit.mask = PIPE_MASK_RGBA;
386
blit.filter = PIPE_TEX_FILTER_NEAREST;
387
388
pipe->blit(pipe, &blit);
389
}
390
391
static void
392
dri_postprocessing(struct dri_context *ctx,
393
struct dri_drawable *drawable,
394
enum st_attachment_type att)
395
{
396
struct pipe_resource *src = drawable->textures[att];
397
struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
398
399
if (ctx->pp && src)
400
pp_run(ctx->pp, src, src, zsbuf);
401
}
402
403
struct notify_before_flush_cb_args {
404
struct dri_context *ctx;
405
struct dri_drawable *drawable;
406
unsigned flags;
407
enum __DRI2throttleReason reason;
408
bool swap_msaa_buffers;
409
};
410
411
static void
412
notify_before_flush_cb(void* _args)
413
{
414
struct notify_before_flush_cb_args *args = (struct notify_before_flush_cb_args *) _args;
415
struct st_context_iface *st = args->ctx->st;
416
struct pipe_context *pipe = st->pipe;
417
418
if (args->drawable->stvis.samples > 1 &&
419
(args->reason == __DRI2_THROTTLE_SWAPBUFFER ||
420
args->reason == __DRI2_THROTTLE_COPYSUBBUFFER)) {
421
/* Resolve the MSAA back buffer. */
422
dri_pipe_blit(st->pipe,
423
args->drawable->textures[ST_ATTACHMENT_BACK_LEFT],
424
args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
425
426
if (args->reason == __DRI2_THROTTLE_SWAPBUFFER &&
427
args->drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&
428
args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {
429
args->swap_msaa_buffers = true;
430
}
431
432
/* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
433
}
434
435
dri_postprocessing(args->ctx, args->drawable, ST_ATTACHMENT_BACK_LEFT);
436
437
if (pipe->invalidate_resource &&
438
(args->flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) {
439
if (args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
440
pipe->invalidate_resource(pipe, args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
441
if (args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL])
442
pipe->invalidate_resource(pipe, args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);
443
}
444
445
if (args->ctx->hud) {
446
hud_run(args->ctx->hud, args->ctx->st->cso_context,
447
args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
448
}
449
450
pipe->flush_resource(pipe, args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
451
}
452
453
/**
454
* DRI2 flush extension, the flush_with_flags function.
455
*
456
* \param context the context
457
* \param drawable the drawable to flush
458
* \param flags a combination of _DRI2_FLUSH_xxx flags
459
* \param throttle_reason the reason for throttling, 0 = no throttling
460
*/
461
void
462
dri_flush(__DRIcontext *cPriv,
463
__DRIdrawable *dPriv,
464
unsigned flags,
465
enum __DRI2throttleReason reason)
466
{
467
struct dri_context *ctx = dri_context(cPriv);
468
struct dri_drawable *drawable = dri_drawable(dPriv);
469
struct st_context_iface *st;
470
unsigned flush_flags;
471
struct notify_before_flush_cb_args args = { 0 };
472
473
if (!ctx) {
474
assert(0);
475
return;
476
}
477
478
st = ctx->st;
479
if (st->thread_finish)
480
st->thread_finish(st);
481
482
if (drawable) {
483
/* prevent recursion */
484
if (drawable->flushing)
485
return;
486
487
drawable->flushing = true;
488
}
489
else {
490
flags &= ~__DRI2_FLUSH_DRAWABLE;
491
}
492
493
if ((flags & __DRI2_FLUSH_DRAWABLE) &&
494
drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {
495
/* We can't do operations on the back buffer here, because there
496
* may be some pending operations that will get flushed by the
497
* call to st->flush (eg: FLUSH_VERTICES).
498
* Instead we register a callback to be notified when all operations
499
* have been submitted but before the call to st_flush.
500
*/
501
args.ctx = ctx;
502
args.drawable = drawable;
503
args.flags = flags;
504
args.reason = reason;
505
}
506
507
flush_flags = 0;
508
if (flags & __DRI2_FLUSH_CONTEXT)
509
flush_flags |= ST_FLUSH_FRONT;
510
if (reason == __DRI2_THROTTLE_SWAPBUFFER)
511
flush_flags |= ST_FLUSH_END_OF_FRAME;
512
513
/* Flush the context and throttle if needed. */
514
if (dri_screen(ctx->sPriv)->throttle &&
515
drawable &&
516
(reason == __DRI2_THROTTLE_SWAPBUFFER ||
517
reason == __DRI2_THROTTLE_FLUSHFRONT)) {
518
519
struct pipe_screen *screen = drawable->screen->base.screen;
520
struct pipe_fence_handle *new_fence = NULL;
521
522
st->flush(st, flush_flags, &new_fence, args.ctx ? notify_before_flush_cb : NULL, &args);
523
524
/* throttle on the previous fence */
525
if (drawable->throttle_fence) {
526
screen->fence_finish(screen, NULL, drawable->throttle_fence, PIPE_TIMEOUT_INFINITE);
527
screen->fence_reference(screen, &drawable->throttle_fence, NULL);
528
}
529
drawable->throttle_fence = new_fence;
530
}
531
else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {
532
st->flush(st, flush_flags, NULL, args.ctx ? notify_before_flush_cb : NULL, &args);
533
}
534
535
if (drawable) {
536
drawable->flushing = false;
537
}
538
539
/* Swap the MSAA front and back buffers, so that reading
540
* from the front buffer after SwapBuffers returns what was
541
* in the back buffer.
542
*/
543
if (args.swap_msaa_buffers) {
544
struct pipe_resource *tmp =
545
drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];
546
547
drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =
548
drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
549
drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;
550
551
/* Now that we have swapped the buffers, this tells the gallium
552
* frontend to revalidate the framebuffer.
553
*/
554
p_atomic_inc(&drawable->base.stamp);
555
}
556
}
557
558
/**
559
* dri_throttle - A DRI2ThrottleExtension throttling function.
560
*/
561
static void
562
dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,
563
enum __DRI2throttleReason reason)
564
{
565
dri_flush(cPriv, dPriv, 0, reason);
566
}
567
568
569
const __DRI2throttleExtension dri2ThrottleExtension = {
570
.base = { __DRI2_THROTTLE, 1 },
571
572
.throttle = dri_throttle,
573
};
574
575
576
/* vim: set sw=3 ts=8 sts=3 expandtab: */
577
578