379515152e85cac6a84908aa220e14d08c43d3dc
[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 /* TODO */
278 return FALSE;
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 /* TODO */
313 if (__dri1_api_hooks)
314 return FALSE;
315
316 if (statt == ST_ATTACHMENT_FRONT_LEFT && loader->flushFrontBuffer) {
317 loader->flushFrontBuffer(drawable->dPriv,
318 drawable->dPriv->loaderPrivate);
319 }
320
321 return TRUE;
322 }
323
324 /**
325 * Create a framebuffer from the given drawable.
326 */
327 struct st_framebuffer_iface *
328 dri_create_st_framebuffer(struct dri_drawable *drawable)
329 {
330 struct st_framebuffer_iface *stfbi;
331
332 stfbi = CALLOC_STRUCT(st_framebuffer_iface);
333 if (stfbi) {
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;
338 }
339
340 return stfbi;
341 }
342
343 /**
344 * Destroy a framebuffer.
345 */
346 void
347 dri_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
348 {
349 FREE(stfbi);
350 }
351
352 /**
353 * Return the texture at an attachment. Allocate the texture if it does not
354 * exist.
355 */
356 struct pipe_texture *
357 dri_get_st_framebuffer_texture(struct st_framebuffer_iface *stfbi,
358 enum st_attachment_type statt)
359 {
360 struct dri_drawable *drawable =
361 (struct dri_drawable *) stfbi->st_manager_private;
362
363 if (!(drawable->texture_mask & (1 << statt))) {
364 enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
365 unsigned i, count = 0;
366
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)) {
370 statts[count++] = i;
371 }
372 }
373 statts[count++] = statt;
374
375 drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
376 dri_st_framebuffer_validate(stfbi, statts, count, NULL);
377 }
378
379 return drawable->textures[statt];
380 }
381
382 /**
383 * Add a reference to the st_api of the state tracker.
384 */
385 static void
386 _dri_get_st_api(void)
387 {
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();
391 }
392
393 /**
394 * Remove a reference to the st_api of the state tracker.
395 */
396 static void
397 _dri_put_st_api(void)
398 {
399 struct st_api *stapi = dri_st_api.stapi;
400
401 if (p_atomic_dec_zero(&dri_st_api.refcnt)) {
402 stapi->destroy(dri_st_api.stapi);
403 dri_st_api.stapi = NULL;
404 }
405 }
406
407 /**
408 * Create a state tracker manager from the given screen.
409 */
410 struct st_manager *
411 dri_create_st_manager(struct dri_screen *screen)
412 {
413 struct st_manager *smapi;
414
415 smapi = CALLOC_STRUCT(st_manager);
416 if (smapi) {
417 smapi->screen = screen->pipe_screen;
418 _dri_get_st_api();
419 }
420
421 return smapi;
422 }
423
424 /**
425 * Destroy a state tracker manager.
426 */
427 void
428 dri_destroy_st_manager(struct st_manager *smapi)
429 {
430 _dri_put_st_api();
431 FREE(smapi);
432 }
433
434 /**
435 * Return the st_api of OpenGL state tracker.
436 */
437 struct st_api *
438 dri_get_st_api(void)
439 {
440 assert(dri_st_api.stapi);
441 return dri_st_api.stapi;
442 }