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 statt
= ST_ATTACHMENT_DEPTH_STENCIL
;
128 /* use only the first depth/stencil buffer */
130 statt
= ST_ATTACHMENT_INVALID
;
135 statt
= ST_ATTACHMENT_INVALID
;
139 format
= dri_drawable_get_format(drawable
, statt
);
140 if (statt
== ST_ATTACHMENT_INVALID
|| format
== PIPE_FORMAT_NONE
)
143 templ
.format
= format
;
144 whandle
.handle
= buf
->name
;
145 whandle
.stride
= buf
->pitch
;
147 drawable
->textures
[statt
] =
148 screen
->pipe_screen
->texture_from_handle(screen
->pipe_screen
,
152 drawable
->old_num
= count
;
153 drawable
->old_w
= dri_drawable
->w
;
154 drawable
->old_h
= dri_drawable
->h
;
155 memcpy(drawable
->old
, buffers
, sizeof(__DRIbuffer
) * count
);
159 * Retrieve __DRIbuffer from the DRI loader.
162 dri_drawable_get_buffers(struct dri_drawable
*drawable
,
163 const enum st_attachment_type
*statts
,
166 __DRIdrawable
*dri_drawable
= drawable
->dPriv
;
167 struct __DRIdri2LoaderExtensionRec
*loader
= drawable
->sPriv
->dri2
.loader
;
169 __DRIbuffer
*buffers
;
171 unsigned attachments
[8];
172 unsigned num_attachments
, i
;
175 with_format
= (loader
->base
.version
> 2 && loader
->getBuffersWithFormat
);
178 for (i
= 0; i
< *count
; i
++) {
179 enum pipe_format format
;
182 format
= dri_drawable_get_format(drawable
, statts
[i
]);
183 if (format
== PIPE_FORMAT_NONE
)
187 case ST_ATTACHMENT_FRONT_LEFT
:
188 att
= __DRI_BUFFER_FRONT_LEFT
;
190 case ST_ATTACHMENT_BACK_LEFT
:
191 att
= __DRI_BUFFER_BACK_LEFT
;
193 case ST_ATTACHMENT_FRONT_RIGHT
:
194 att
= __DRI_BUFFER_FRONT_RIGHT
;
196 case ST_ATTACHMENT_BACK_RIGHT
:
197 att
= __DRI_BUFFER_BACK_RIGHT
;
199 case ST_ATTACHMENT_DEPTH_STENCIL
:
200 att
= __DRI_BUFFER_DEPTH_STENCIL
;
208 attachments
[num_attachments
++] = att
;
210 attachments
[num_attachments
++] =
211 util_format_get_blocksizebits(format
);
217 num_attachments
/= 2;
218 buffers
= loader
->getBuffersWithFormat(dri_drawable
,
219 &dri_drawable
->w
, &dri_drawable
->h
,
220 attachments
, num_attachments
,
221 &num_buffers
, dri_drawable
->loaderPrivate
);
224 buffers
= loader
->getBuffers(dri_drawable
,
225 &dri_drawable
->w
, &dri_drawable
->h
,
226 attachments
, num_attachments
,
227 &num_buffers
, dri_drawable
->loaderPrivate
);
231 /* set one cliprect to cover the whole dri_drawable */
234 dri_drawable
->backX
= 0;
235 dri_drawable
->backY
= 0;
236 dri_drawable
->numClipRects
= 1;
237 dri_drawable
->pClipRects
[0].x1
= 0;
238 dri_drawable
->pClipRects
[0].y1
= 0;
239 dri_drawable
->pClipRects
[0].x2
= dri_drawable
->w
;
240 dri_drawable
->pClipRects
[0].y2
= dri_drawable
->h
;
241 dri_drawable
->numBackClipRects
= 1;
242 dri_drawable
->pBackClipRects
[0].x1
= 0;
243 dri_drawable
->pBackClipRects
[0].y1
= 0;
244 dri_drawable
->pBackClipRects
[0].x2
= dri_drawable
->w
;
245 dri_drawable
->pBackClipRects
[0].y2
= dri_drawable
->h
;
247 *count
= num_buffers
;
254 dri_st_framebuffer_validate(struct st_framebuffer_iface
*stfbi
,
255 const enum st_attachment_type
*statts
,
257 struct pipe_texture
**out
)
259 struct dri_drawable
*drawable
=
260 (struct dri_drawable
*) stfbi
->st_manager_private
;
261 unsigned statt_mask
, i
;
264 for (i
= 0; i
< count
; i
++)
265 statt_mask
|= (1 << statts
[i
]);
268 * dPriv->pStamp is the server stamp. It should be accessed with a lock, at
269 * least for DRI1. dPriv->lastStamp is the client stamp. It has the value
270 * of the server stamp when last checked.
272 * This function updates the textures and records the stamp of the textures.
274 if (drawable
->texture_stamp
!= drawable
->dPriv
->lastStamp
||
275 (statt_mask
& ~drawable
->texture_mask
)) {
276 if (__dri1_api_hooks
) {
281 __DRIbuffer
*buffers
;
282 unsigned num_buffers
= count
;
284 buffers
= dri_drawable_get_buffers(drawable
, statts
, &num_buffers
);
285 dri_drawable_process_buffers(drawable
, buffers
, num_buffers
);
288 drawable
->texture_stamp
= drawable
->dPriv
->lastStamp
;
289 drawable
->texture_mask
= statt_mask
;
295 for (i
= 0; i
< count
; i
++) {
297 pipe_texture_reference(&out
[i
], drawable
->textures
[statts
[i
]]);
304 dri_st_framebuffer_flush_front(struct st_framebuffer_iface
*stfbi
,
305 enum st_attachment_type statt
)
307 struct dri_drawable
*drawable
=
308 (struct dri_drawable
*) stfbi
->st_manager_private
;
309 struct __DRIdri2LoaderExtensionRec
*loader
=
310 drawable
->sPriv
->dri2
.loader
;
313 if (__dri1_api_hooks
)
316 if (statt
== ST_ATTACHMENT_FRONT_LEFT
&& loader
->flushFrontBuffer
) {
317 loader
->flushFrontBuffer(drawable
->dPriv
,
318 drawable
->dPriv
->loaderPrivate
);
325 * Create a framebuffer from the given drawable.
327 struct st_framebuffer_iface
*
328 dri_create_st_framebuffer(struct dri_drawable
*drawable
)
330 struct st_framebuffer_iface
*stfbi
;
332 stfbi
= CALLOC_STRUCT(st_framebuffer_iface
);
334 stfbi
->visual
= &drawable
->stvis
;
335 stfbi
->flush_front
= dri_st_framebuffer_flush_front
;
336 stfbi
->validate
= dri_st_framebuffer_validate
;
337 stfbi
->st_manager_private
= (void *) drawable
;
344 * Destroy a framebuffer.
347 dri_destroy_st_framebuffer(struct st_framebuffer_iface
*stfbi
)
353 * Return the texture at an attachment. Allocate the texture if it does not
356 struct pipe_texture
*
357 dri_get_st_framebuffer_texture(struct st_framebuffer_iface
*stfbi
,
358 enum st_attachment_type statt
)
360 struct dri_drawable
*drawable
=
361 (struct dri_drawable
*) stfbi
->st_manager_private
;
363 if (!(drawable
->texture_mask
& (1 << statt
))) {
364 enum st_attachment_type statts
[ST_ATTACHMENT_COUNT
];
365 unsigned i
, count
= 0;
367 /* make sure DRI2 does not destroy existing buffers */
368 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++) {
369 if (drawable
->texture_mask
& (1 << i
)) {
373 statts
[count
++] = statt
;
375 drawable
->texture_stamp
= drawable
->dPriv
->lastStamp
- 1;
376 dri_st_framebuffer_validate(stfbi
, statts
, count
, NULL
);
379 return drawable
->textures
[statt
];
383 * Add a reference to the st_api of the state tracker.
386 _dri_get_st_api(void)
388 p_atomic_inc(&dri_st_api
.refcnt
);
389 if (p_atomic_read(&dri_st_api
.refcnt
) == 1)
390 dri_st_api
.stapi
= st_manager_create_api();
394 * Remove a reference to the st_api of the state tracker.
397 _dri_put_st_api(void)
399 struct st_api
*stapi
= dri_st_api
.stapi
;
401 if (p_atomic_dec_zero(&dri_st_api
.refcnt
)) {
402 stapi
->destroy(dri_st_api
.stapi
);
403 dri_st_api
.stapi
= NULL
;
408 * Create a state tracker manager from the given screen.
411 dri_create_st_manager(struct dri_screen
*screen
)
413 struct st_manager
*smapi
;
415 smapi
= CALLOC_STRUCT(st_manager
);
417 smapi
->screen
= screen
->pipe_screen
;
425 * Destroy a state tracker manager.
428 dri_destroy_st_manager(struct st_manager
*smapi
)
435 * Return the st_api of OpenGL state tracker.
440 assert(dri_st_api
.stapi
);
441 return dri_st_api
.stapi
;