1 /**************************************************************************
3 * Copyright 2009, VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 * Author: Keith Whitwell <keithw@vmware.com>
29 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
32 #include "dri_screen.h"
33 #include "dri_context.h"
34 #include "dri_drawable.h"
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"
41 static uint32_t drifb_ID
= 0;
44 dri_st_framebuffer_validate(struct st_context_iface
*stctx
,
45 struct st_framebuffer_iface
*stfbi
,
46 const enum st_attachment_type
*statts
,
48 struct pipe_resource
**out
)
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
;
57 unsigned int lastStamp
;
58 struct pipe_resource
**textures
=
59 drawable
->stvis
.samples
> 1 ? drawable
->msaa_textures
63 for (i
= 0; i
< count
; i
++)
64 statt_mask
|= (1 << statts
[i
]);
66 /* record newly allocated textures */
67 new_mask
= (statt_mask
& ~drawable
->texture_mask
);
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
75 lastStamp
= drawable
->dPriv
->lastStamp
;
76 new_stamp
= (drawable
->texture_stamp
!= lastStamp
);
78 if (new_stamp
|| new_mask
|| screen
->broken_invalidate
) {
79 if (new_stamp
&& drawable
->update_drawable_info
)
80 drawable
->update_drawable_info(drawable
);
82 drawable
->allocate_textures(ctx
, drawable
, statts
, count
);
84 /* add existing textures */
85 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++) {
87 statt_mask
|= (1 << i
);
90 drawable
->texture_stamp
= lastStamp
;
91 drawable
->texture_mask
= statt_mask
;
93 } while (lastStamp
!= drawable
->dPriv
->lastStamp
);
95 /* Flush the pending set_damage_region request. */
96 struct pipe_screen
*pscreen
= screen
->base
.screen
;
98 if (new_mask
& (1 << ST_ATTACHMENT_BACK_LEFT
) &&
99 pscreen
->set_damage_region
) {
100 struct pipe_resource
*resource
= textures
[ST_ATTACHMENT_BACK_LEFT
];
102 pscreen
->set_damage_region(pscreen
, resource
,
103 drawable
->num_damage_rects
,
104 drawable
->damage_rects
);
110 /* Set the window-system buffers for the state tracker. */
111 for (i
= 0; i
< count
; i
++)
112 pipe_resource_reference(&out
[i
], textures
[statts
[i
]]);
118 dri_st_framebuffer_flush_front(struct st_context_iface
*stctx
,
119 struct st_framebuffer_iface
*stfbi
,
120 enum st_attachment_type statt
)
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
;
126 /* XXX remove this and just set the correct one on the framebuffer */
127 drawable
->flush_frontbuffer(ctx
, drawable
, statt
);
133 * The state tracker framebuffer interface flush_swapbuffers callback
136 dri_st_framebuffer_flush_swapbuffers(struct st_context_iface
*stctx
,
137 struct st_framebuffer_iface
*stfbi
)
139 struct dri_context
*ctx
= (struct dri_context
*)stctx
->st_manager_private
;
140 struct dri_drawable
*drawable
=
141 (struct dri_drawable
*) stfbi
->st_manager_private
;
143 if (drawable
->flush_swapbuffers
)
144 drawable
->flush_swapbuffers(ctx
, drawable
);
150 * This is called when we need to set up GL rendering to a new X window.
153 dri_create_buffer(__DRIscreen
* sPriv
,
154 __DRIdrawable
* dPriv
,
155 const struct gl_config
* visual
, bool isPixmap
)
157 struct dri_screen
*screen
= sPriv
->driverPrivate
;
158 struct dri_drawable
*drawable
= NULL
;
161 goto fail
; /* not implemented */
163 drawable
= CALLOC_STRUCT(dri_drawable
);
164 if (drawable
== NULL
)
167 dri_fill_st_visual(&drawable
->stvis
, screen
, visual
);
169 /* setup the st_framebuffer_iface */
170 drawable
->base
.visual
= &drawable
->stvis
;
171 drawable
->base
.flush_front
= dri_st_framebuffer_flush_front
;
172 drawable
->base
.validate
= dri_st_framebuffer_validate
;
173 drawable
->base
.flush_swapbuffers
= dri_st_framebuffer_flush_swapbuffers
;
174 drawable
->base
.st_manager_private
= (void *) drawable
;
176 drawable
->screen
= screen
;
177 drawable
->sPriv
= sPriv
;
178 drawable
->dPriv
= dPriv
;
180 dPriv
->driverPrivate
= (void *)drawable
;
181 p_atomic_set(&drawable
->base
.stamp
, 1);
182 drawable
->base
.ID
= p_atomic_inc_return(&drifb_ID
);
183 drawable
->base
.state_manager
= &screen
->base
;
192 dri_destroy_buffer(__DRIdrawable
* dPriv
)
194 struct dri_drawable
*drawable
= dri_drawable(dPriv
);
195 struct dri_screen
*screen
= drawable
->screen
;
196 struct st_api
*stapi
= screen
->st_api
;
199 pipe_surface_reference(&drawable
->drisw_surface
, NULL
);
201 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++)
202 pipe_resource_reference(&drawable
->textures
[i
], NULL
);
203 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++)
204 pipe_resource_reference(&drawable
->msaa_textures
[i
], NULL
);
206 screen
->base
.screen
->fence_reference(screen
->base
.screen
,
207 &drawable
->throttle_fence
, NULL
);
209 /* Notify the st manager that this drawable is no longer valid */
210 stapi
->destroy_drawable(stapi
, &drawable
->base
);
212 FREE(drawable
->damage_rects
);
217 * Validate the texture at an attachment. Allocate the texture if it does not
218 * exist. Used by the TFP extension.
221 dri_drawable_validate_att(struct dri_context
*ctx
,
222 struct dri_drawable
*drawable
,
223 enum st_attachment_type statt
)
225 enum st_attachment_type statts
[ST_ATTACHMENT_COUNT
];
226 unsigned i
, count
= 0;
228 /* check if buffer already exists */
229 if (drawable
->texture_mask
& (1 << statt
))
232 /* make sure DRI2 does not destroy existing buffers */
233 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++) {
234 if (drawable
->texture_mask
& (1 << i
)) {
238 statts
[count
++] = statt
;
240 drawable
->texture_stamp
= drawable
->dPriv
->lastStamp
- 1;
242 drawable
->base
.validate(ctx
->st
, &drawable
->base
, statts
, count
, NULL
);
246 * These are used for GLX_EXT_texture_from_pixmap
249 dri_set_tex_buffer2(__DRIcontext
*pDRICtx
, GLint target
,
250 GLint format
, __DRIdrawable
*dPriv
)
252 struct dri_context
*ctx
= dri_context(pDRICtx
);
253 struct st_context_iface
*st
= ctx
->st
;
254 struct dri_drawable
*drawable
= dri_drawable(dPriv
);
255 struct pipe_resource
*pt
;
257 if (st
->thread_finish
)
258 st
->thread_finish(st
);
260 dri_drawable_validate_att(ctx
, drawable
, ST_ATTACHMENT_FRONT_LEFT
);
262 /* Use the pipe resource associated with the X drawable */
263 pt
= drawable
->textures
[ST_ATTACHMENT_FRONT_LEFT
];
266 enum pipe_format internal_format
= pt
->format
;
268 if (format
== __DRI_TEXTURE_FORMAT_RGB
) {
269 /* only need to cover the formats recognized by dri_fill_st_visual */
270 switch (internal_format
) {
271 case PIPE_FORMAT_R16G16B16A16_FLOAT
:
272 internal_format
= PIPE_FORMAT_R16G16B16X16_FLOAT
;
274 case PIPE_FORMAT_B10G10R10A2_UNORM
:
275 internal_format
= PIPE_FORMAT_B10G10R10X2_UNORM
;
277 case PIPE_FORMAT_R10G10B10A2_UNORM
:
278 internal_format
= PIPE_FORMAT_R10G10B10X2_UNORM
;
280 case PIPE_FORMAT_BGRA8888_UNORM
:
281 internal_format
= PIPE_FORMAT_BGRX8888_UNORM
;
283 case PIPE_FORMAT_ARGB8888_UNORM
:
284 internal_format
= PIPE_FORMAT_XRGB8888_UNORM
;
291 drawable
->update_tex_buffer(drawable
, ctx
, pt
);
293 ctx
->st
->teximage(ctx
->st
,
294 (target
== GL_TEXTURE_2D
) ? ST_TEXTURE_2D
: ST_TEXTURE_RECT
,
295 0, internal_format
, pt
, false);
300 dri_set_tex_buffer(__DRIcontext
*pDRICtx
, GLint target
,
301 __DRIdrawable
*dPriv
)
303 dri_set_tex_buffer2(pDRICtx
, target
, __DRI_TEXTURE_FORMAT_RGBA
, dPriv
);
306 const __DRItexBufferExtension driTexBufferExtension
= {
307 .base
= { __DRI_TEX_BUFFER
, 2 },
309 .setTexBuffer
= dri_set_tex_buffer
,
310 .setTexBuffer2
= dri_set_tex_buffer2
,
311 .releaseTexBuffer
= NULL
,
315 * Get the format and binding of an attachment.
318 dri_drawable_get_format(struct dri_drawable
*drawable
,
319 enum st_attachment_type statt
,
320 enum pipe_format
*format
,
324 case ST_ATTACHMENT_FRONT_LEFT
:
325 case ST_ATTACHMENT_BACK_LEFT
:
326 case ST_ATTACHMENT_FRONT_RIGHT
:
327 case ST_ATTACHMENT_BACK_RIGHT
:
328 /* Other pieces of the driver stack get confused and behave incorrectly
329 * when they get an sRGB drawable. st/mesa receives "drawable->stvis"
330 * though other means and handles it correctly, so we don't really need
331 * to use an sRGB format here.
333 *format
= util_format_linear(drawable
->stvis
.color_format
);
334 *bind
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
336 case ST_ATTACHMENT_DEPTH_STENCIL
:
337 *format
= drawable
->stvis
.depth_stencil_format
;
338 *bind
= PIPE_BIND_DEPTH_STENCIL
; /* XXX sampler? */
341 *format
= PIPE_FORMAT_NONE
;
348 dri_pipe_blit(struct pipe_context
*pipe
,
349 struct pipe_resource
*dst
,
350 struct pipe_resource
*src
)
352 struct pipe_blit_info blit
;
357 /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
358 * Fragment Operations):
360 * If a framebuffer object is not bound, after all operations have
361 * been completed on the multisample buffer, the sample values for
362 * each color in the multisample buffer are combined to produce a
363 * single color value, and that value is written into the
364 * corresponding color buffers selected by DrawBuffer or
365 * DrawBuffers. An implementation may defer the writing of the color
366 * buffers until a later time, but the state of the framebuffer must
367 * behave as if the color buffers were updated as each fragment was
368 * processed. The method of combination is not specified. If the
369 * framebuffer contains sRGB values, then it is recommended that the
370 * an average of sample values is computed in a linearized space, as
371 * for blending (see section 4.1.7).
373 * In other words, to do a resolve operation in a linear space, we have
374 * to set sRGB formats if the original resources were sRGB, so don't use
375 * util_format_linear.
378 memset(&blit
, 0, sizeof(blit
));
379 blit
.dst
.resource
= dst
;
380 blit
.dst
.box
.width
= dst
->width0
;
381 blit
.dst
.box
.height
= dst
->height0
;
382 blit
.dst
.box
.depth
= 1;
383 blit
.dst
.format
= dst
->format
;
384 blit
.src
.resource
= src
;
385 blit
.src
.box
.width
= src
->width0
;
386 blit
.src
.box
.height
= src
->height0
;
387 blit
.src
.box
.depth
= 1;
388 blit
.src
.format
= src
->format
;
389 blit
.mask
= PIPE_MASK_RGBA
;
390 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
392 pipe
->blit(pipe
, &blit
);
396 dri_postprocessing(struct dri_context
*ctx
,
397 struct dri_drawable
*drawable
,
398 enum st_attachment_type att
)
400 struct pipe_resource
*src
= drawable
->textures
[att
];
401 struct pipe_resource
*zsbuf
= drawable
->textures
[ST_ATTACHMENT_DEPTH_STENCIL
];
404 pp_run(ctx
->pp
, src
, src
, zsbuf
);
407 struct notify_before_flush_cb_args
{
408 struct dri_context
*ctx
;
409 struct dri_drawable
*drawable
;
411 enum __DRI2throttleReason reason
;
412 bool swap_msaa_buffers
;
416 notify_before_flush_cb(void* _args
)
418 struct notify_before_flush_cb_args
*args
= (struct notify_before_flush_cb_args
*) _args
;
419 struct st_context_iface
*st
= args
->ctx
->st
;
420 struct pipe_context
*pipe
= st
->pipe
;
422 if (args
->drawable
->stvis
.samples
> 1 &&
423 (args
->reason
== __DRI2_THROTTLE_SWAPBUFFER
||
424 args
->reason
== __DRI2_THROTTLE_COPYSUBBUFFER
)) {
425 /* Resolve the MSAA back buffer. */
426 dri_pipe_blit(st
->pipe
,
427 args
->drawable
->textures
[ST_ATTACHMENT_BACK_LEFT
],
428 args
->drawable
->msaa_textures
[ST_ATTACHMENT_BACK_LEFT
]);
430 if (args
->reason
== __DRI2_THROTTLE_SWAPBUFFER
&&
431 args
->drawable
->msaa_textures
[ST_ATTACHMENT_FRONT_LEFT
] &&
432 args
->drawable
->msaa_textures
[ST_ATTACHMENT_BACK_LEFT
]) {
433 args
->swap_msaa_buffers
= true;
436 /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
439 dri_postprocessing(args
->ctx
, args
->drawable
, ST_ATTACHMENT_BACK_LEFT
);
441 if (pipe
->invalidate_resource
&&
442 (args
->flags
& __DRI2_FLUSH_INVALIDATE_ANCILLARY
)) {
443 if (args
->drawable
->textures
[ST_ATTACHMENT_DEPTH_STENCIL
])
444 pipe
->invalidate_resource(pipe
, args
->drawable
->textures
[ST_ATTACHMENT_DEPTH_STENCIL
]);
445 if (args
->drawable
->msaa_textures
[ST_ATTACHMENT_DEPTH_STENCIL
])
446 pipe
->invalidate_resource(pipe
, args
->drawable
->msaa_textures
[ST_ATTACHMENT_DEPTH_STENCIL
]);
449 if (args
->ctx
->hud
) {
450 hud_run(args
->ctx
->hud
, args
->ctx
->st
->cso_context
,
451 args
->drawable
->textures
[ST_ATTACHMENT_BACK_LEFT
]);
454 pipe
->flush_resource(pipe
, args
->drawable
->textures
[ST_ATTACHMENT_BACK_LEFT
]);
458 * DRI2 flush extension, the flush_with_flags function.
460 * \param context the context
461 * \param drawable the drawable to flush
462 * \param flags a combination of _DRI2_FLUSH_xxx flags
463 * \param throttle_reason the reason for throttling, 0 = no throttling
466 dri_flush(__DRIcontext
*cPriv
,
467 __DRIdrawable
*dPriv
,
469 enum __DRI2throttleReason reason
)
471 struct dri_context
*ctx
= dri_context(cPriv
);
472 struct dri_drawable
*drawable
= dri_drawable(dPriv
);
473 struct st_context_iface
*st
;
474 unsigned flush_flags
;
475 struct notify_before_flush_cb_args args
= { 0 };
483 if (st
->thread_finish
)
484 st
->thread_finish(st
);
487 /* prevent recursion */
488 if (drawable
->flushing
)
491 drawable
->flushing
= true;
494 flags
&= ~__DRI2_FLUSH_DRAWABLE
;
497 if ((flags
& __DRI2_FLUSH_DRAWABLE
) &&
498 drawable
->textures
[ST_ATTACHMENT_BACK_LEFT
]) {
499 /* We can't do operations on the back buffer here, because there
500 * may be some pending operations that will get flushed by the
501 * call to st->flush (eg: FLUSH_VERTICES).
502 * Instead we register a callback to be notified when all operations
503 * have been submitted but before the call to st_flush.
506 args
.drawable
= drawable
;
508 args
.reason
= reason
;
512 if (flags
& __DRI2_FLUSH_CONTEXT
)
513 flush_flags
|= ST_FLUSH_FRONT
;
514 if (reason
== __DRI2_THROTTLE_SWAPBUFFER
)
515 flush_flags
|= ST_FLUSH_END_OF_FRAME
;
517 /* Flush the context and throttle if needed. */
518 if (dri_screen(ctx
->sPriv
)->throttle
&&
520 (reason
== __DRI2_THROTTLE_SWAPBUFFER
||
521 reason
== __DRI2_THROTTLE_FLUSHFRONT
)) {
523 struct pipe_screen
*screen
= drawable
->screen
->base
.screen
;
524 struct pipe_fence_handle
*new_fence
= NULL
;
526 st
->flush(st
, flush_flags
, &new_fence
, args
.ctx
? notify_before_flush_cb
: NULL
, &args
);
528 /* throttle on the previous fence */
529 if (drawable
->throttle_fence
) {
530 screen
->fence_finish(screen
, NULL
, drawable
->throttle_fence
, PIPE_TIMEOUT_INFINITE
);
531 screen
->fence_reference(screen
, &drawable
->throttle_fence
, NULL
);
533 drawable
->throttle_fence
= new_fence
;
535 else if (flags
& (__DRI2_FLUSH_DRAWABLE
| __DRI2_FLUSH_CONTEXT
)) {
536 st
->flush(st
, flush_flags
, NULL
, args
.ctx
? notify_before_flush_cb
: NULL
, &args
);
540 drawable
->flushing
= false;
543 /* Swap the MSAA front and back buffers, so that reading
544 * from the front buffer after SwapBuffers returns what was
545 * in the back buffer.
547 if (args
.swap_msaa_buffers
) {
548 struct pipe_resource
*tmp
=
549 drawable
->msaa_textures
[ST_ATTACHMENT_FRONT_LEFT
];
551 drawable
->msaa_textures
[ST_ATTACHMENT_FRONT_LEFT
] =
552 drawable
->msaa_textures
[ST_ATTACHMENT_BACK_LEFT
];
553 drawable
->msaa_textures
[ST_ATTACHMENT_BACK_LEFT
] = tmp
;
555 /* Now that we have swapped the buffers, this tells the state
556 * tracker to revalidate the framebuffer.
558 p_atomic_inc(&drawable
->base
.stamp
);
563 * dri_throttle - A DRI2ThrottleExtension throttling function.
566 dri_throttle(__DRIcontext
*cPriv
, __DRIdrawable
*dPriv
,
567 enum __DRI2throttleReason reason
)
569 dri_flush(cPriv
, dPriv
, 0, reason
);
573 const __DRI2throttleExtension dri2ThrottleExtension
= {
574 .base
= { __DRI2_THROTTLE
, 1 },
576 .throttle
= dri_throttle
,
580 /* vim: set sw=3 ts=8 sts=3 expandtab: */