st/dri: Switch from st_public.h to st_api.h.
[mesa.git] / src / gallium / state_trackers / dri / dri_st_api.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
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 */
34
35 #include "dri_screen.h"
36 #include "dri_context.h"
37 #include "dri_drawable.h"
38 #include "dri_st_api.h"
39 #include "dri1.h"
40
41 static struct {
42 int32_t refcnt;
43 struct st_api *stapi;
44 } dri_st_api;
45
46 /**
47 * Get the format of an attachment.
48 */
49 static INLINE enum pipe_format
50 dri_drawable_get_format(struct dri_drawable *drawable,
51 enum st_attachment_type statt)
52 {
53 enum pipe_format format;
54
55 switch (statt) {
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;
61 break;
62 case ST_ATTACHMENT_DEPTH_STENCIL:
63 format = drawable->stvis.depth_stencil_format;
64 break;
65 default:
66 format = PIPE_FORMAT_NONE;
67 break;
68 }
69
70 return format;
71 }
72
73 /**
74 * Process __DRIbuffer and convert them into pipe_textures.
75 */
76 static void
77 dri_drawable_process_buffers(struct dri_drawable *drawable,
78 __DRIbuffer *buffers, unsigned count)
79 {
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;
85 unsigned i;
86
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)
91 return;
92
93 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
94 pipe_texture_reference(&drawable->textures[i], NULL);
95
96 memset(&templ, 0, sizeof(templ));
97 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
98 templ.target = PIPE_TEXTURE_2D;
99 templ.last_level = 0;
100 templ.width0 = dri_drawable->w;
101 templ.height0 = dri_drawable->h;
102 templ.depth0 = 1;
103
104 memset(&whandle, 0, sizeof(whandle));
105
106 for (i = 0; i < count; i++) {
107 __DRIbuffer *buf = &buffers[i];
108 enum st_attachment_type statt;
109 enum pipe_format format;
110
111 switch (buf->attachment) {
112 case __DRI_BUFFER_FRONT_LEFT:
113 if (!screen->auto_fake_front) {
114 statt = ST_ATTACHMENT_INVALID;
115 break;
116 }
117 /* fallthrough */
118 case __DRI_BUFFER_FAKE_FRONT_LEFT:
119 statt = ST_ATTACHMENT_FRONT_LEFT;
120 break;
121 case __DRI_BUFFER_BACK_LEFT:
122 statt = ST_ATTACHMENT_BACK_LEFT;
123 break;
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 */
129 if (have_depth)
130 statt = ST_ATTACHMENT_INVALID;
131 else
132 have_depth = TRUE;
133 break;
134 default:
135 statt = ST_ATTACHMENT_INVALID;
136 break;
137 }
138
139 format = dri_drawable_get_format(drawable, statt);
140 if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
141 continue;
142
143 templ.format = format;
144 whandle.handle = buf->name;
145 whandle.stride = buf->pitch;
146
147 drawable->textures[statt] =
148 screen->pipe_screen->texture_from_handle(screen->pipe_screen,
149 &templ, &whandle);
150 }
151
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);
156 }
157
158 /**
159 * Retrieve __DRIbuffer from the DRI loader.
160 */
161 static __DRIbuffer *
162 dri_drawable_get_buffers(struct dri_drawable *drawable,
163 const enum st_attachment_type *statts,
164 unsigned *count)
165 {
166 __DRIdrawable *dri_drawable = drawable->dPriv;
167 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
168 boolean with_format;
169 __DRIbuffer *buffers;
170 int num_buffers;
171 unsigned attachments[8];
172 unsigned num_attachments, i;
173
174 assert(loader);
175 with_format = (loader->base.version > 2 && loader->getBuffersWithFormat);
176
177 num_attachments = 0;
178 for (i = 0; i < *count; i++) {
179 enum pipe_format format;
180 int att;
181
182 format = dri_drawable_get_format(drawable, statts[i]);
183 if (format == PIPE_FORMAT_NONE)
184 continue;
185
186 switch (statts[i]) {
187 case ST_ATTACHMENT_FRONT_LEFT:
188 att = __DRI_BUFFER_FRONT_LEFT;
189 break;
190 case ST_ATTACHMENT_BACK_LEFT:
191 att = __DRI_BUFFER_BACK_LEFT;
192 break;
193 case ST_ATTACHMENT_FRONT_RIGHT:
194 att = __DRI_BUFFER_FRONT_RIGHT;
195 break;
196 case ST_ATTACHMENT_BACK_RIGHT:
197 att = __DRI_BUFFER_BACK_RIGHT;
198 break;
199 case ST_ATTACHMENT_DEPTH_STENCIL:
200 att = __DRI_BUFFER_DEPTH_STENCIL;
201 break;
202 default:
203 att = -1;
204 break;
205 }
206
207 if (att >= 0) {
208 attachments[num_attachments++] = att;
209 if (with_format) {
210 attachments[num_attachments++] =
211 util_format_get_blocksizebits(format);
212 }
213 }
214 }
215
216 if (with_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);
222 }
223 else {
224 buffers = loader->getBuffers(dri_drawable,
225 &dri_drawable->w, &dri_drawable->h,
226 attachments, num_attachments,
227 &num_buffers, dri_drawable->loaderPrivate);
228 }
229
230 if (buffers) {
231 /* set one cliprect to cover the whole dri_drawable */
232 dri_drawable->x = 0;
233 dri_drawable->y = 0;
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;
246
247 *count = num_buffers;
248 }
249
250 return buffers;
251 }
252
253 static boolean
254 dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
255 const enum st_attachment_type *statts,
256 unsigned count,
257 struct pipe_texture **out)
258 {
259 struct dri_drawable *drawable =
260 (struct dri_drawable *) stfbi->st_manager_private;
261 unsigned statt_mask, i;
262
263 statt_mask = 0x0;
264 for (i = 0; i < count; i++)
265 statt_mask |= (1 << statts[i]);
266
267 /*
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.
271 *
272 * This function updates the textures and records the stamp of the textures.
273 */
274 if (drawable->texture_stamp != drawable->dPriv->lastStamp ||
275 (statt_mask & ~drawable->texture_mask)) {
276 if (__dri1_api_hooks) {
277 dri1_allocate_textures(drawable,
278 drawable->dPriv->w, drawable->dPriv->h, statt_mask);
279 }
280 else {
281 __DRIbuffer *buffers;
282 unsigned num_buffers = count;
283
284 buffers = dri_drawable_get_buffers(drawable, statts, &num_buffers);
285 dri_drawable_process_buffers(drawable, buffers, num_buffers);
286 }
287
288 drawable->texture_stamp = drawable->dPriv->lastStamp;
289 drawable->texture_mask = statt_mask;
290 }
291
292 if (!out)
293 return TRUE;
294
295 for (i = 0; i < count; i++) {
296 out[i] = NULL;
297 pipe_texture_reference(&out[i], drawable->textures[statts[i]]);
298 }
299
300 return TRUE;
301 }
302
303 static boolean
304 dri_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
305 enum st_attachment_type statt)
306 {
307 struct dri_drawable *drawable =
308 (struct dri_drawable *) stfbi->st_manager_private;
309 struct __DRIdri2LoaderExtensionRec *loader =
310 drawable->sPriv->dri2.loader;
311
312 if (__dri1_api_hooks) {
313 struct pipe_texture *ptex = drawable->textures[statt];
314 if (ptex)
315 dri1_flush_frontbuffer(drawable, ptex);
316 return TRUE;
317 }
318
319 if (statt == ST_ATTACHMENT_FRONT_LEFT && loader->flushFrontBuffer) {
320 loader->flushFrontBuffer(drawable->dPriv,
321 drawable->dPriv->loaderPrivate);
322 }
323
324 return TRUE;
325 }
326
327 /**
328 * Create a framebuffer from the given drawable.
329 */
330 struct st_framebuffer_iface *
331 dri_create_st_framebuffer(struct dri_drawable *drawable)
332 {
333 struct st_framebuffer_iface *stfbi;
334
335 stfbi = CALLOC_STRUCT(st_framebuffer_iface);
336 if (stfbi) {
337 stfbi->visual = &drawable->stvis;
338 stfbi->flush_front = dri_st_framebuffer_flush_front;
339 stfbi->validate = dri_st_framebuffer_validate;
340 stfbi->st_manager_private = (void *) drawable;
341 }
342
343 return stfbi;
344 }
345
346 /**
347 * Destroy a framebuffer.
348 */
349 void
350 dri_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
351 {
352 FREE(stfbi);
353 }
354
355 /**
356 * Return the texture at an attachment. Allocate the texture if it does not
357 * exist.
358 */
359 struct pipe_texture *
360 dri_get_st_framebuffer_texture(struct st_framebuffer_iface *stfbi,
361 enum st_attachment_type statt)
362 {
363 struct dri_drawable *drawable =
364 (struct dri_drawable *) stfbi->st_manager_private;
365
366 if (!(drawable->texture_mask & (1 << statt))) {
367 enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
368 unsigned i, count = 0;
369
370 /* make sure DRI2 does not destroy existing buffers */
371 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
372 if (drawable->texture_mask & (1 << i)) {
373 statts[count++] = i;
374 }
375 }
376 statts[count++] = statt;
377
378 drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
379 dri_st_framebuffer_validate(stfbi, statts, count, NULL);
380 }
381
382 return drawable->textures[statt];
383 }
384
385 /**
386 * Add a reference to the st_api of the state tracker.
387 */
388 static void
389 _dri_get_st_api(void)
390 {
391 p_atomic_inc(&dri_st_api.refcnt);
392 if (p_atomic_read(&dri_st_api.refcnt) == 1)
393 dri_st_api.stapi = st_manager_create_api();
394 }
395
396 /**
397 * Remove a reference to the st_api of the state tracker.
398 */
399 static void
400 _dri_put_st_api(void)
401 {
402 struct st_api *stapi = dri_st_api.stapi;
403
404 if (p_atomic_dec_zero(&dri_st_api.refcnt)) {
405 stapi->destroy(dri_st_api.stapi);
406 dri_st_api.stapi = NULL;
407 }
408 }
409
410 /**
411 * Create a state tracker manager from the given screen.
412 */
413 struct st_manager *
414 dri_create_st_manager(struct dri_screen *screen)
415 {
416 struct st_manager *smapi;
417
418 smapi = CALLOC_STRUCT(st_manager);
419 if (smapi) {
420 smapi->screen = screen->pipe_screen;
421 _dri_get_st_api();
422 }
423
424 return smapi;
425 }
426
427 /**
428 * Destroy a state tracker manager.
429 */
430 void
431 dri_destroy_st_manager(struct st_manager *smapi)
432 {
433 _dri_put_st_api();
434 FREE(smapi);
435 }
436
437 /**
438 * Return the st_api of OpenGL state tracker.
439 */
440 struct st_api *
441 dri_get_st_api(void)
442 {
443 assert(dri_st_api.stapi);
444 return dri_st_api.stapi;
445 }