f09baed1d849539a6b5c154e8d69228e2e66b591
[mesa.git] / src / gallium / state_trackers / xa / xa_tracker.c
1 /**********************************************************
2 * Copyright 2009-2011 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 *********************************************************
25 * Authors:
26 * Thomas Hellstrom <thellstrom-at-vmware-dot-com>
27 */
28
29 #include <unistd.h>
30 #include "xa_tracker.h"
31 #include "xa_priv.h"
32 #include "pipe/p_state.h"
33 #include "pipe/p_format.h"
34 #include "pipe-loader/pipe_loader.h"
35 #include "state_tracker/drm_driver.h"
36 #include "util/u_inlines.h"
37
38 /*
39 * format_map [xa_surface_type][first..last in list].
40 * Needs to be updated when enum xa_formats is updated.
41 */
42
43 static const enum xa_formats preferred_a[] = { xa_format_a8 };
44
45 static const enum xa_formats preferred_argb[] =
46 { xa_format_a8r8g8b8, xa_format_x8r8g8b8, xa_format_r5g6b5,
47 xa_format_x1r5g5b5
48 };
49 static const enum xa_formats preferred_z[] =
50 { xa_format_z32, xa_format_z24, xa_format_z16 };
51 static const enum xa_formats preferred_sz[] =
52 { xa_format_x8z24, xa_format_s8z24 };
53 static const enum xa_formats preferred_zs[] =
54 { xa_format_z24x8, xa_format_z24s8 };
55 static const enum xa_formats preferred_yuv[] = { xa_format_yuv8 };
56
57 static const enum xa_formats *preferred[] =
58 { NULL, preferred_a, preferred_argb, NULL, NULL,
59 preferred_z, preferred_zs, preferred_sz, preferred_yuv
60 };
61
62 static const unsigned int num_preferred[] = { 0,
63 sizeof(preferred_a) / sizeof(enum xa_formats),
64 sizeof(preferred_argb) / sizeof(enum xa_formats),
65 0,
66 0,
67 sizeof(preferred_z) / sizeof(enum xa_formats),
68 sizeof(preferred_zs) / sizeof(enum xa_formats),
69 sizeof(preferred_sz) / sizeof(enum xa_formats),
70 sizeof(preferred_yuv) / sizeof(enum xa_formats)
71 };
72
73 static const unsigned int stype_bind[XA_LAST_SURFACE_TYPE] = { 0,
74 PIPE_BIND_SAMPLER_VIEW,
75 PIPE_BIND_SAMPLER_VIEW,
76 PIPE_BIND_SAMPLER_VIEW,
77 PIPE_BIND_SAMPLER_VIEW,
78 PIPE_BIND_DEPTH_STENCIL,
79 PIPE_BIND_DEPTH_STENCIL,
80 PIPE_BIND_DEPTH_STENCIL,
81 PIPE_BIND_SAMPLER_VIEW
82 };
83
84 static struct xa_format_descriptor
85 xa_get_pipe_format(struct xa_tracker *xa, enum xa_formats xa_format)
86 {
87 struct xa_format_descriptor fdesc;
88
89 fdesc.xa_format = xa_format;
90
91 switch (xa_format) {
92 case xa_format_a8r8g8b8:
93 fdesc.format = PIPE_FORMAT_B8G8R8A8_UNORM;
94 break;
95 case xa_format_x8r8g8b8:
96 fdesc.format = PIPE_FORMAT_B8G8R8X8_UNORM;
97 break;
98 case xa_format_r5g6b5:
99 fdesc.format = PIPE_FORMAT_B5G6R5_UNORM;
100 break;
101 case xa_format_x1r5g5b5:
102 fdesc.format = PIPE_FORMAT_B5G5R5A1_UNORM;
103 break;
104 case xa_format_a8:
105 if (xa->screen->is_format_supported(xa->screen, PIPE_FORMAT_R8_UNORM,
106 PIPE_TEXTURE_2D, 0,
107 stype_bind[xa_type_a] |
108 PIPE_BIND_RENDER_TARGET))
109 fdesc.format = PIPE_FORMAT_R8_UNORM;
110 else
111 fdesc.format = PIPE_FORMAT_L8_UNORM;
112 break;
113 case xa_format_z24:
114 fdesc.format = PIPE_FORMAT_Z24X8_UNORM;
115 break;
116 case xa_format_z16:
117 fdesc.format = PIPE_FORMAT_Z16_UNORM;
118 break;
119 case xa_format_z32:
120 fdesc.format = PIPE_FORMAT_Z32_UNORM;
121 break;
122 case xa_format_x8z24:
123 fdesc.format = PIPE_FORMAT_Z24X8_UNORM;
124 break;
125 case xa_format_z24x8:
126 fdesc.format = PIPE_FORMAT_X8Z24_UNORM;
127 break;
128 case xa_format_s8z24:
129 fdesc.format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
130 break;
131 case xa_format_z24s8:
132 fdesc.format = PIPE_FORMAT_S8_UINT_Z24_UNORM;
133 break;
134 case xa_format_yuv8:
135 if (xa->screen->is_format_supported(xa->screen, PIPE_FORMAT_R8_UNORM,
136 PIPE_TEXTURE_2D, 0,
137 stype_bind[xa_type_yuv_component]))
138 fdesc.format = PIPE_FORMAT_R8_UNORM;
139 else
140 fdesc.format = PIPE_FORMAT_L8_UNORM;
141 break;
142 default:
143 fdesc.xa_format = xa_format_unknown;
144 break;
145 }
146 return fdesc;
147 }
148
149 XA_EXPORT struct xa_tracker *
150 xa_tracker_create(int drm_fd)
151 {
152 struct xa_tracker *xa = calloc(1, sizeof(struct xa_tracker));
153 enum xa_surface_type stype;
154 unsigned int num_formats;
155 int fd = -1;
156
157 if (!xa)
158 return NULL;
159
160 if (drm_fd < 0 || (fd = dup(drm_fd)) < 0)
161 goto out_no_fd;
162
163 if (pipe_loader_drm_probe_fd(&xa->dev, fd))
164 xa->screen = pipe_loader_create_screen(xa->dev);
165
166 if (!xa->screen)
167 goto out_no_screen;
168
169 xa->default_ctx = xa_context_create(xa);
170 if (!xa->default_ctx)
171 goto out_no_pipe;
172
173 num_formats = 0;
174 for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype)
175 num_formats += num_preferred[stype];
176
177 num_formats += 1;
178 xa->supported_formats = calloc(num_formats, sizeof(*xa->supported_formats));
179 if (!xa->supported_formats)
180 goto out_sf_alloc_fail;
181
182 xa->supported_formats[0] = xa_format_unknown;
183 num_formats = 1;
184 memset(xa->format_map, 0, sizeof(xa->format_map));
185
186 for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype) {
187 unsigned int bind = stype_bind[stype];
188 enum xa_formats xa_format;
189 int i;
190
191 for (i = 0; i < num_preferred[stype]; ++i) {
192 xa_format = preferred[stype][i];
193
194 struct xa_format_descriptor fdesc =
195 xa_get_pipe_format(xa, xa_format);
196
197 if (xa->screen->is_format_supported(xa->screen, fdesc.format,
198 PIPE_TEXTURE_2D, 0, bind)) {
199 if (xa->format_map[stype][0] == 0)
200 xa->format_map[stype][0] = num_formats;
201 xa->format_map[stype][1] = num_formats;
202 xa->supported_formats[num_formats++] = xa_format;
203 }
204 }
205 }
206 return xa;
207
208 out_sf_alloc_fail:
209 xa_context_destroy(xa->default_ctx);
210 out_no_pipe:
211 xa->screen->destroy(xa->screen);
212 out_no_screen:
213 if (xa->dev)
214 pipe_loader_release(&xa->dev, 1);
215 fd = -1;
216 out_no_fd:
217 close(fd);
218 free(xa);
219 return NULL;
220 }
221
222 XA_EXPORT void
223 xa_tracker_destroy(struct xa_tracker *xa)
224 {
225 free(xa->supported_formats);
226 xa_context_destroy(xa->default_ctx);
227 xa->screen->destroy(xa->screen);
228 pipe_loader_release(&xa->dev, 1);
229 free(xa);
230 }
231
232 static int
233 xa_flags_compat(unsigned int old_flags, unsigned int new_flags)
234 {
235 unsigned int flag_diff = (old_flags ^ new_flags);
236
237 if (flag_diff == 0)
238 return 1;
239
240 if (flag_diff & XA_FLAG_SHARED)
241 return 0;
242 /*
243 * Don't recreate if we're dropping the render target flag.
244 */
245 if (flag_diff & XA_FLAG_RENDER_TARGET)
246 return ((new_flags & XA_FLAG_RENDER_TARGET) == 0);
247
248 /*
249 * Don't recreate if we're dropping the scanout flag.
250 */
251 if (flag_diff & XA_FLAG_SCANOUT)
252 return ((new_flags & XA_FLAG_SCANOUT) == 0);
253
254 /*
255 * Always recreate for unknown / unimplemented flags.
256 */
257 return 0;
258 }
259
260 static struct xa_format_descriptor
261 xa_get_format_stype_depth(struct xa_tracker *xa,
262 enum xa_surface_type stype, unsigned int depth)
263 {
264 unsigned int i;
265 struct xa_format_descriptor fdesc;
266 int found = 0;
267
268 for (i = xa->format_map[stype][0]; i <= xa->format_map[stype][1]; ++i) {
269 fdesc = xa_get_pipe_format(xa, xa->supported_formats[i]);
270 if (fdesc.xa_format != xa_format_unknown &&
271 xa_format_depth(fdesc.xa_format) == depth) {
272 found = 1;
273 break;
274 }
275 }
276
277 if (!found)
278 fdesc.xa_format = xa_format_unknown;
279
280 return fdesc;
281 }
282
283 XA_EXPORT int
284 xa_format_check_supported(struct xa_tracker *xa,
285 enum xa_formats xa_format, unsigned int flags)
286 {
287 struct xa_format_descriptor fdesc = xa_get_pipe_format(xa, xa_format);
288 unsigned int bind;
289
290 if (fdesc.xa_format == xa_format_unknown)
291 return -XA_ERR_INVAL;
292
293 bind = stype_bind[xa_format_type(fdesc.xa_format)];
294 if (flags & XA_FLAG_SHARED)
295 bind |= PIPE_BIND_SHARED;
296 if (flags & XA_FLAG_RENDER_TARGET)
297 bind |= PIPE_BIND_RENDER_TARGET;
298 if (flags & XA_FLAG_SCANOUT)
299 bind |= PIPE_BIND_SCANOUT;
300
301 if (!xa->screen->is_format_supported(xa->screen, fdesc.format,
302 PIPE_TEXTURE_2D, 0, bind))
303 return -XA_ERR_INVAL;
304
305 return XA_ERR_NONE;
306 }
307
308 static unsigned
309 handle_type(enum xa_handle_type type)
310 {
311 switch (type) {
312 case xa_handle_type_kms:
313 return DRM_API_HANDLE_TYPE_KMS;
314 case xa_handle_type_fd:
315 return DRM_API_HANDLE_TYPE_FD;
316 case xa_handle_type_shared:
317 default:
318 return DRM_API_HANDLE_TYPE_SHARED;
319 }
320 }
321
322 static struct xa_surface *
323 surface_create(struct xa_tracker *xa,
324 int width,
325 int height,
326 int depth,
327 enum xa_surface_type stype,
328 enum xa_formats xa_format, unsigned int flags,
329 struct winsys_handle *whandle)
330 {
331 struct pipe_resource *template;
332 struct xa_surface *srf;
333 struct xa_format_descriptor fdesc;
334
335 if (xa_format == xa_format_unknown)
336 fdesc = xa_get_format_stype_depth(xa, stype, depth);
337 else
338 fdesc = xa_get_pipe_format(xa, xa_format);
339
340 if (fdesc.xa_format == xa_format_unknown)
341 return NULL;
342
343 srf = calloc(1, sizeof(*srf));
344 if (!srf)
345 return NULL;
346
347 template = &srf->template;
348 template->format = fdesc.format;
349 template->target = PIPE_TEXTURE_2D;
350 template->width0 = width;
351 template->height0 = height;
352 template->depth0 = 1;
353 template->array_size = 1;
354 template->last_level = 0;
355 template->bind = stype_bind[xa_format_type(fdesc.xa_format)];
356
357 if (flags & XA_FLAG_SHARED)
358 template->bind |= PIPE_BIND_SHARED;
359 if (flags & XA_FLAG_RENDER_TARGET)
360 template->bind |= PIPE_BIND_RENDER_TARGET;
361 if (flags & XA_FLAG_SCANOUT)
362 template->bind |= PIPE_BIND_SCANOUT;
363
364 if (whandle)
365 srf->tex = xa->screen->resource_from_handle(xa->screen, template, whandle,
366 PIPE_HANDLE_USAGE_READ_WRITE);
367 else
368 srf->tex = xa->screen->resource_create(xa->screen, template);
369 if (!srf->tex)
370 goto out_no_tex;
371
372 srf->refcount = 1;
373 srf->xa = xa;
374 srf->flags = flags;
375 srf->fdesc = fdesc;
376
377 return srf;
378 out_no_tex:
379 free(srf);
380 return NULL;
381 }
382
383
384 XA_EXPORT struct xa_surface *
385 xa_surface_create(struct xa_tracker *xa,
386 int width,
387 int height,
388 int depth,
389 enum xa_surface_type stype,
390 enum xa_formats xa_format, unsigned int flags)
391 {
392 return surface_create(xa, width, height, depth, stype, xa_format, flags, NULL);
393 }
394
395
396 XA_EXPORT struct xa_surface *
397 xa_surface_from_handle(struct xa_tracker *xa,
398 int width,
399 int height,
400 int depth,
401 enum xa_surface_type stype,
402 enum xa_formats xa_format, unsigned int flags,
403 uint32_t handle, uint32_t stride)
404 {
405 return xa_surface_from_handle2(xa, width, height, depth, stype, xa_format,
406 DRM_API_HANDLE_TYPE_SHARED, flags, handle,
407 stride);
408 }
409
410 XA_EXPORT struct xa_surface *
411 xa_surface_from_handle2(struct xa_tracker *xa,
412 int width,
413 int height,
414 int depth,
415 enum xa_surface_type stype,
416 enum xa_formats xa_format, unsigned int flags,
417 enum xa_handle_type type,
418 uint32_t handle, uint32_t stride)
419 {
420 struct winsys_handle whandle;
421 memset(&whandle, 0, sizeof(whandle));
422 whandle.type = handle_type(type);
423 whandle.handle = handle;
424 whandle.stride = stride;
425 return surface_create(xa, width, height, depth, stype, xa_format, flags, &whandle);
426 }
427
428 XA_EXPORT int
429 xa_surface_redefine(struct xa_surface *srf,
430 int width,
431 int height,
432 int depth,
433 enum xa_surface_type stype,
434 enum xa_formats xa_format,
435 unsigned int new_flags,
436 int copy_contents)
437 {
438 struct pipe_resource *template = &srf->template;
439 struct pipe_resource *texture;
440 struct pipe_box src_box;
441 struct xa_tracker *xa = srf->xa;
442 int save_width;
443 int save_height;
444 unsigned int save_format;
445 struct xa_format_descriptor fdesc;
446
447
448 if (xa_format == xa_format_unknown)
449 fdesc = xa_get_format_stype_depth(xa, stype, depth);
450 else
451 fdesc = xa_get_pipe_format(xa, xa_format);
452
453 if (width == template->width0 && height == template->height0 &&
454 template->format == fdesc.format &&
455 xa_flags_compat(srf->flags, new_flags))
456 return XA_ERR_NONE;
457
458 template->bind = stype_bind[xa_format_type(fdesc.xa_format)];
459 if (new_flags & XA_FLAG_SHARED)
460 template->bind |= PIPE_BIND_SHARED;
461 if (new_flags & XA_FLAG_RENDER_TARGET)
462 template->bind |= PIPE_BIND_RENDER_TARGET;
463 if (new_flags & XA_FLAG_SCANOUT)
464 template->bind |= PIPE_BIND_SCANOUT;
465
466 if (copy_contents) {
467 if (!xa_format_type_is_color(fdesc.xa_format) ||
468 xa_format_type(fdesc.xa_format) == xa_type_a)
469 return -XA_ERR_INVAL;
470
471 if (!xa->screen->is_format_supported(xa->screen, fdesc.format,
472 PIPE_TEXTURE_2D, 0,
473 template->bind |
474 PIPE_BIND_RENDER_TARGET))
475 return -XA_ERR_INVAL;
476 }
477
478 save_width = template->width0;
479 save_height = template->height0;
480 save_format = template->format;
481
482 template->width0 = width;
483 template->height0 = height;
484 template->format = fdesc.format;
485
486 texture = xa->screen->resource_create(xa->screen, template);
487 if (!texture) {
488 template->width0 = save_width;
489 template->height0 = save_height;
490 template->format = save_format;
491 return -XA_ERR_NORES;
492 }
493
494 if (copy_contents) {
495 struct pipe_context *pipe = xa->default_ctx->pipe;
496
497 u_box_origin_2d(xa_min(save_width, template->width0),
498 xa_min(save_height, template->height0), &src_box);
499 pipe->resource_copy_region(pipe, texture,
500 0, 0, 0, 0, srf->tex, 0, &src_box);
501 xa_context_flush(xa->default_ctx);
502 }
503
504 pipe_resource_reference(&srf->tex, texture);
505 pipe_resource_reference(&texture, NULL);
506 srf->fdesc = fdesc;
507 srf->flags = new_flags;
508
509 return XA_ERR_NONE;
510 }
511
512 XA_EXPORT struct xa_surface*
513 xa_surface_ref(struct xa_surface *srf)
514 {
515 if (srf == NULL) {
516 return NULL;
517 }
518 srf->refcount++;
519 return srf;
520 }
521
522 XA_EXPORT void
523 xa_surface_unref(struct xa_surface *srf)
524 {
525 if (srf == NULL || --srf->refcount) {
526 return;
527 }
528 pipe_resource_reference(&srf->tex, NULL);
529 free(srf);
530 }
531
532 XA_EXPORT void
533 xa_tracker_version(int *major, int *minor, int *patch)
534 {
535 *major = XA_TRACKER_VERSION_MAJOR;
536 *minor = XA_TRACKER_VERSION_MINOR;
537 *patch = XA_TRACKER_VERSION_PATCH;
538 }
539
540 XA_EXPORT int
541 xa_surface_handle(struct xa_surface *srf,
542 enum xa_handle_type type,
543 uint32_t * handle, unsigned int *stride)
544 {
545 struct winsys_handle whandle;
546
547 struct pipe_screen *screen = srf->xa->screen;
548 boolean res;
549
550 memset(&whandle, 0, sizeof(whandle));
551 whandle.type = handle_type(type);
552 res = screen->resource_get_handle(screen, srf->tex, &whandle,
553 PIPE_HANDLE_USAGE_READ_WRITE);
554 if (!res)
555 return -XA_ERR_INVAL;
556
557 *handle = whandle.handle;
558 *stride = whandle.stride;
559
560 return XA_ERR_NONE;
561 }
562
563 XA_EXPORT enum xa_formats
564 xa_surface_format(const struct xa_surface *srf)
565 {
566 return srf->fdesc.xa_format;
567 }