2 * Mesa 3-D graphics library
5 * Copyright (C) 2010 LunarG Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 * Chia-I Wu <olv@lunarg.com>
28 #include "util/u_memory.h"
29 #include "util/u_inlines.h"
30 #include "util/u_format.h"
31 #include "util/u_debug.h"
32 #include "state_tracker/drm_api.h"
33 #include "state_tracker/st_manager.h" /* for st_manager_create_api */
35 #include "dri_screen.h"
36 #include "dri_context.h"
37 #include "dri_drawable.h"
38 #include "dri_st_api.h"
47 * Get the format of an attachment.
49 static INLINE
enum pipe_format
50 dri_drawable_get_format(struct dri_drawable
*drawable
,
51 enum st_attachment_type statt
)
53 enum pipe_format format
;
56 case ST_ATTACHMENT_FRONT_LEFT
:
57 case ST_ATTACHMENT_BACK_LEFT
:
58 case ST_ATTACHMENT_FRONT_RIGHT
:
59 case ST_ATTACHMENT_BACK_RIGHT
:
60 format
= drawable
->stvis
.color_format
;
62 case ST_ATTACHMENT_DEPTH_STENCIL
:
63 format
= drawable
->stvis
.depth_stencil_format
;
66 format
= PIPE_FORMAT_NONE
;
74 * Process __DRIbuffer and convert them into pipe_textures.
77 dri_drawable_process_buffers(struct dri_drawable
*drawable
,
78 __DRIbuffer
*buffers
, unsigned count
)
80 struct dri_screen
*screen
= dri_screen(drawable
->sPriv
);
81 __DRIdrawable
*dri_drawable
= drawable
->dPriv
;
82 struct pipe_texture templ
;
83 struct winsys_handle whandle
;
84 boolean have_depth
= FALSE
;
87 if (drawable
->old_num
== count
&&
88 drawable
->old_w
== dri_drawable
->w
&&
89 drawable
->old_h
== dri_drawable
->h
&&
90 memcmp(drawable
->old
, buffers
, sizeof(__DRIbuffer
) * count
) == 0)
93 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++)
94 pipe_texture_reference(&drawable
->textures
[i
], NULL
);
96 memset(&templ
, 0, sizeof(templ
));
97 templ
.tex_usage
= PIPE_TEXTURE_USAGE_RENDER_TARGET
;
98 templ
.target
= PIPE_TEXTURE_2D
;
100 templ
.width0
= dri_drawable
->w
;
101 templ
.height0
= dri_drawable
->h
;
104 memset(&whandle
, 0, sizeof(whandle
));
106 for (i
= 0; i
< count
; i
++) {
107 __DRIbuffer
*buf
= &buffers
[i
];
108 enum st_attachment_type statt
;
109 enum pipe_format format
;
111 switch (buf
->attachment
) {
112 case __DRI_BUFFER_FRONT_LEFT
:
113 if (!screen
->auto_fake_front
) {
114 statt
= ST_ATTACHMENT_INVALID
;
118 case __DRI_BUFFER_FAKE_FRONT_LEFT
:
119 statt
= ST_ATTACHMENT_FRONT_LEFT
;
121 case __DRI_BUFFER_BACK_LEFT
:
122 statt
= ST_ATTACHMENT_BACK_LEFT
;
124 case __DRI_BUFFER_DEPTH
:
125 case __DRI_BUFFER_DEPTH_STENCIL
:
126 case __DRI_BUFFER_STENCIL
:
127 /* use only the first depth/stencil buffer */
130 statt
= ST_ATTACHMENT_DEPTH_STENCIL
;
133 statt
= ST_ATTACHMENT_INVALID
;
137 statt
= ST_ATTACHMENT_INVALID
;
141 format
= dri_drawable_get_format(drawable
, statt
);
142 if (statt
== ST_ATTACHMENT_INVALID
|| format
== PIPE_FORMAT_NONE
)
145 templ
.format
= format
;
146 whandle
.handle
= buf
->name
;
147 whandle
.stride
= buf
->pitch
;
149 drawable
->textures
[statt
] =
150 screen
->pipe_screen
->texture_from_handle(screen
->pipe_screen
,
154 drawable
->old_num
= count
;
155 drawable
->old_w
= dri_drawable
->w
;
156 drawable
->old_h
= dri_drawable
->h
;
157 memcpy(drawable
->old
, buffers
, sizeof(__DRIbuffer
) * count
);
161 * Retrieve __DRIbuffer from the DRI loader.
164 dri_drawable_get_buffers(struct dri_drawable
*drawable
,
165 const enum st_attachment_type
*statts
,
168 __DRIdrawable
*dri_drawable
= drawable
->dPriv
;
169 struct __DRIdri2LoaderExtensionRec
*loader
= drawable
->sPriv
->dri2
.loader
;
171 __DRIbuffer
*buffers
;
173 unsigned attachments
[10];
174 unsigned num_attachments
, i
;
177 with_format
= dri_with_format(drawable
->sPriv
);
181 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
183 attachments
[num_attachments
++] = __DRI_BUFFER_FRONT_LEFT
;
185 for (i
= 0; i
< *count
; i
++) {
186 enum pipe_format format
;
189 format
= dri_drawable_get_format(drawable
, statts
[i
]);
190 if (format
== PIPE_FORMAT_NONE
)
194 case ST_ATTACHMENT_FRONT_LEFT
:
198 att
= __DRI_BUFFER_FRONT_LEFT
;
200 case ST_ATTACHMENT_BACK_LEFT
:
201 att
= __DRI_BUFFER_BACK_LEFT
;
203 case ST_ATTACHMENT_FRONT_RIGHT
:
204 att
= __DRI_BUFFER_FRONT_RIGHT
;
206 case ST_ATTACHMENT_BACK_RIGHT
:
207 att
= __DRI_BUFFER_BACK_RIGHT
;
209 case ST_ATTACHMENT_DEPTH_STENCIL
:
210 att
= __DRI_BUFFER_DEPTH_STENCIL
;
217 bpp
= util_format_get_blocksizebits(format
);
220 attachments
[num_attachments
++] = att
;
222 attachments
[num_attachments
++] = bpp
;
228 num_attachments
/= 2;
229 buffers
= loader
->getBuffersWithFormat(dri_drawable
,
230 &dri_drawable
->w
, &dri_drawable
->h
,
231 attachments
, num_attachments
,
232 &num_buffers
, dri_drawable
->loaderPrivate
);
235 buffers
= loader
->getBuffers(dri_drawable
,
236 &dri_drawable
->w
, &dri_drawable
->h
,
237 attachments
, num_attachments
,
238 &num_buffers
, dri_drawable
->loaderPrivate
);
242 /* set one cliprect to cover the whole dri_drawable */
245 dri_drawable
->backX
= 0;
246 dri_drawable
->backY
= 0;
247 dri_drawable
->numClipRects
= 1;
248 dri_drawable
->pClipRects
[0].x1
= 0;
249 dri_drawable
->pClipRects
[0].y1
= 0;
250 dri_drawable
->pClipRects
[0].x2
= dri_drawable
->w
;
251 dri_drawable
->pClipRects
[0].y2
= dri_drawable
->h
;
252 dri_drawable
->numBackClipRects
= 1;
253 dri_drawable
->pBackClipRects
[0].x1
= 0;
254 dri_drawable
->pBackClipRects
[0].y1
= 0;
255 dri_drawable
->pBackClipRects
[0].x2
= dri_drawable
->w
;
256 dri_drawable
->pBackClipRects
[0].y2
= dri_drawable
->h
;
258 *count
= num_buffers
;
265 dri_st_framebuffer_validate(struct st_framebuffer_iface
*stfbi
,
266 const enum st_attachment_type
*statts
,
268 struct pipe_texture
**out
)
270 struct dri_drawable
*drawable
=
271 (struct dri_drawable
*) stfbi
->st_manager_private
;
272 unsigned statt_mask
, i
;
275 for (i
= 0; i
< count
; i
++)
276 statt_mask
|= (1 << statts
[i
]);
279 * dPriv->pStamp is the server stamp. It should be accessed with a lock, at
280 * least for DRI1. dPriv->lastStamp is the client stamp. It has the value
281 * of the server stamp when last checked.
283 * This function updates the textures and records the stamp of the textures.
285 if (drawable
->texture_stamp
!= drawable
->dPriv
->lastStamp
||
286 (statt_mask
& ~drawable
->texture_mask
)) {
287 if (__dri1_api_hooks
) {
288 dri1_allocate_textures(drawable
, statt_mask
);
291 __DRIbuffer
*buffers
;
292 unsigned num_buffers
= count
;
294 buffers
= dri_drawable_get_buffers(drawable
, statts
, &num_buffers
);
295 dri_drawable_process_buffers(drawable
, buffers
, num_buffers
);
298 /* add existing textures */
299 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++) {
300 if (drawable
->textures
[i
])
301 statt_mask
|= (1 << i
);
304 drawable
->texture_stamp
= drawable
->dPriv
->lastStamp
;
305 drawable
->texture_mask
= statt_mask
;
311 for (i
= 0; i
< count
; i
++) {
313 pipe_texture_reference(&out
[i
], drawable
->textures
[statts
[i
]]);
320 dri_st_framebuffer_flush_front(struct st_framebuffer_iface
*stfbi
,
321 enum st_attachment_type statt
)
323 struct dri_drawable
*drawable
=
324 (struct dri_drawable
*) stfbi
->st_manager_private
;
325 struct __DRIdri2LoaderExtensionRec
*loader
=
326 drawable
->sPriv
->dri2
.loader
;
328 if (__dri1_api_hooks
) {
329 dri1_flush_frontbuffer(drawable
, statt
);
333 if (statt
== ST_ATTACHMENT_FRONT_LEFT
&& loader
->flushFrontBuffer
) {
334 loader
->flushFrontBuffer(drawable
->dPriv
,
335 drawable
->dPriv
->loaderPrivate
);
342 * Create a framebuffer from the given drawable.
344 struct st_framebuffer_iface
*
345 dri_create_st_framebuffer(struct dri_drawable
*drawable
)
347 struct st_framebuffer_iface
*stfbi
;
349 stfbi
= CALLOC_STRUCT(st_framebuffer_iface
);
351 stfbi
->visual
= &drawable
->stvis
;
352 stfbi
->flush_front
= dri_st_framebuffer_flush_front
;
353 stfbi
->validate
= dri_st_framebuffer_validate
;
354 stfbi
->st_manager_private
= (void *) drawable
;
361 * Destroy a framebuffer.
364 dri_destroy_st_framebuffer(struct st_framebuffer_iface
*stfbi
)
370 * Return the texture at an attachment. Allocate the texture if it does not
373 struct pipe_texture
*
374 dri_get_st_framebuffer_texture(struct st_framebuffer_iface
*stfbi
,
375 enum st_attachment_type statt
)
377 struct dri_drawable
*drawable
=
378 (struct dri_drawable
*) stfbi
->st_manager_private
;
380 if (!(drawable
->texture_mask
& (1 << statt
))) {
381 enum st_attachment_type statts
[ST_ATTACHMENT_COUNT
];
382 unsigned i
, count
= 0;
384 /* make sure DRI2 does not destroy existing buffers */
385 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++) {
386 if (drawable
->texture_mask
& (1 << i
)) {
390 statts
[count
++] = statt
;
392 drawable
->texture_stamp
= drawable
->dPriv
->lastStamp
- 1;
393 dri_st_framebuffer_validate(stfbi
, statts
, count
, NULL
);
396 return drawable
->textures
[statt
];
400 * Add a reference to the st_api of the state tracker.
403 _dri_get_st_api(void)
405 p_atomic_inc(&dri_st_api
.refcnt
);
406 if (p_atomic_read(&dri_st_api
.refcnt
) == 1)
407 dri_st_api
.stapi
= st_manager_create_api();
411 * Remove a reference to the st_api of the state tracker.
414 _dri_put_st_api(void)
416 struct st_api
*stapi
= dri_st_api
.stapi
;
418 if (p_atomic_dec_zero(&dri_st_api
.refcnt
)) {
419 stapi
->destroy(dri_st_api
.stapi
);
420 dri_st_api
.stapi
= NULL
;
425 * Create a state tracker manager from the given screen.
428 dri_create_st_manager(struct dri_screen
*screen
)
430 struct st_manager
*smapi
;
432 smapi
= CALLOC_STRUCT(st_manager
);
434 smapi
->screen
= screen
->pipe_screen
;
442 * Destroy a state tracker manager.
445 dri_destroy_st_manager(struct st_manager
*smapi
)
452 * Return the st_api of OpenGL state tracker.
457 assert(dri_st_api
.stapi
);
458 return dri_st_api
.stapi
;