xa_tracker.c 16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/**********************************************************
 * Copyright 2009-2011 VMware, Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *********************************************************
 * Authors:
 * Thomas Hellstrom <thellstrom-at-vmware-dot-com>
 */

29
#include <unistd.h>
30 31 32 33
#include "xa_tracker.h"
#include "xa_priv.h"
#include "pipe/p_state.h"
#include "pipe/p_format.h"
34
#include "pipe-loader/pipe_loader.h"
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
#include "state_tracker/drm_driver.h"
#include "util/u_inlines.h"

/*
 * format_map [xa_surface_type][first..last in list].
 * Needs to be updated when enum xa_formats is updated.
 */

static const enum xa_formats preferred_a[] = { xa_format_a8 };

static const enum xa_formats preferred_argb[] =
    { xa_format_a8r8g8b8, xa_format_x8r8g8b8, xa_format_r5g6b5,
    xa_format_x1r5g5b5
};
static const enum xa_formats preferred_z[] =
    { xa_format_z32, xa_format_z24, xa_format_z16 };
static const enum xa_formats preferred_sz[] =
    { xa_format_x8z24, xa_format_s8z24 };
static const enum xa_formats preferred_zs[] =
    { xa_format_z24x8, xa_format_z24s8 };
static const enum xa_formats preferred_yuv[] = { xa_format_yuv8 };

static const enum xa_formats *preferred[] =
    { NULL, preferred_a, preferred_argb, NULL, NULL,
    preferred_z, preferred_zs, preferred_sz, preferred_yuv
};

static const unsigned int num_preferred[] = { 0,
    sizeof(preferred_a) / sizeof(enum xa_formats),
    sizeof(preferred_argb) / sizeof(enum xa_formats),
    0,
    0,
    sizeof(preferred_z) / sizeof(enum xa_formats),
    sizeof(preferred_zs) / sizeof(enum xa_formats),
    sizeof(preferred_sz) / sizeof(enum xa_formats),
    sizeof(preferred_yuv) / sizeof(enum xa_formats)
};

static const unsigned int stype_bind[XA_LAST_SURFACE_TYPE] = { 0,
    PIPE_BIND_SAMPLER_VIEW,
    PIPE_BIND_SAMPLER_VIEW,
    PIPE_BIND_SAMPLER_VIEW,
    PIPE_BIND_SAMPLER_VIEW,
    PIPE_BIND_DEPTH_STENCIL,
    PIPE_BIND_DEPTH_STENCIL,
    PIPE_BIND_DEPTH_STENCIL,
    PIPE_BIND_SAMPLER_VIEW
};

static struct xa_format_descriptor
85
xa_get_pipe_format(struct xa_tracker *xa, enum xa_formats xa_format)
86 87 88 89 90 91
{
    struct xa_format_descriptor fdesc;

    fdesc.xa_format = xa_format;

    switch (xa_format) {
92 93 94 95 96 97 98 99 100
    case xa_format_a8:
        if (xa->screen->is_format_supported(xa->screen, PIPE_FORMAT_R8_UNORM,
                                            PIPE_TEXTURE_2D, 0, 0,
                                            stype_bind[xa_type_a] |
                                            PIPE_BIND_RENDER_TARGET))
            fdesc.format = PIPE_FORMAT_R8_UNORM;
        else
            fdesc.format = PIPE_FORMAT_L8_UNORM;
	break;
101 102 103 104 105 106 107 108 109 110 111 112
    case xa_format_a8r8g8b8:
	fdesc.format = PIPE_FORMAT_B8G8R8A8_UNORM;
	break;
    case xa_format_x8r8g8b8:
	fdesc.format = PIPE_FORMAT_B8G8R8X8_UNORM;
	break;
    case xa_format_r5g6b5:
	fdesc.format = PIPE_FORMAT_B5G6R5_UNORM;
	break;
    case xa_format_x1r5g5b5:
	fdesc.format = PIPE_FORMAT_B5G5R5A1_UNORM;
	break;
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    case xa_format_a4r4g4b4:
        fdesc.format = PIPE_FORMAT_B4G4R4A4_UNORM;
        break;
    case xa_format_a2b10g10r10:
        fdesc.format = PIPE_FORMAT_R10G10B10A2_UNORM;
        break;
    case xa_format_x2b10g10r10:
        fdesc.format = PIPE_FORMAT_R10G10B10X2_UNORM;
        break;
    case xa_format_b8g8r8a8:
        fdesc.format = PIPE_FORMAT_A8R8G8B8_UNORM;
        break;
    case xa_format_b8g8r8x8:
        fdesc.format = PIPE_FORMAT_X8R8G8B8_UNORM;
        break;
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    case xa_format_z24:
	fdesc.format = PIPE_FORMAT_Z24X8_UNORM;
	break;
    case xa_format_z16:
	fdesc.format = PIPE_FORMAT_Z16_UNORM;
	break;
    case xa_format_z32:
	fdesc.format = PIPE_FORMAT_Z32_UNORM;
	break;
    case xa_format_x8z24:
	fdesc.format = PIPE_FORMAT_Z24X8_UNORM;
	break;
    case xa_format_z24x8:
	fdesc.format = PIPE_FORMAT_X8Z24_UNORM;
	break;
    case xa_format_s8z24:
144
	fdesc.format = PIPE_FORMAT_Z24_UNORM_S8_UINT;
145 146
	break;
    case xa_format_z24s8:
147
	fdesc.format = PIPE_FORMAT_S8_UINT_Z24_UNORM;
148 149
	break;
    case xa_format_yuv8:
150
        if (xa->screen->is_format_supported(xa->screen, PIPE_FORMAT_R8_UNORM,
151
                                            PIPE_TEXTURE_2D, 0, 0,
152 153 154 155
                                            stype_bind[xa_type_yuv_component]))
            fdesc.format = PIPE_FORMAT_R8_UNORM;
        else
            fdesc.format = PIPE_FORMAT_L8_UNORM;
156 157 158 159 160 161 162 163
	break;
    default:
	fdesc.xa_format = xa_format_unknown;
	break;
    }
    return fdesc;
}

164
XA_EXPORT struct xa_tracker *
165 166 167 168 169 170 171 172 173
xa_tracker_create(int drm_fd)
{
    struct xa_tracker *xa = calloc(1, sizeof(struct xa_tracker));
    enum xa_surface_type stype;
    unsigned int num_formats;

    if (!xa)
	return NULL;

174
    if (pipe_loader_drm_probe_fd(&xa->dev, drm_fd))
175
	xa->screen = pipe_loader_create_screen(xa->dev);
176

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    if (!xa->screen)
	goto out_no_screen;

    xa->default_ctx = xa_context_create(xa);
    if (!xa->default_ctx)
	goto out_no_pipe;

    num_formats = 0;
    for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype)
	num_formats += num_preferred[stype];

    num_formats += 1;
    xa->supported_formats = calloc(num_formats, sizeof(*xa->supported_formats));
    if (!xa->supported_formats)
	goto out_sf_alloc_fail;

    xa->supported_formats[0] = xa_format_unknown;
    num_formats = 1;
    memset(xa->format_map, 0, sizeof(xa->format_map));

    for (stype = 0; stype < XA_LAST_SURFACE_TYPE; ++stype) {
	unsigned int bind = stype_bind[stype];
	enum xa_formats xa_format;
	int i;

	for (i = 0; i < num_preferred[stype]; ++i) {
	    xa_format = preferred[stype][i];

205 206
	    struct xa_format_descriptor fdesc =
                xa_get_pipe_format(xa, xa_format);
207 208

	    if (xa->screen->is_format_supported(xa->screen, fdesc.format,
209
						PIPE_TEXTURE_2D, 0, 0, bind)) {
210 211 212 213 214 215 216 217 218 219 220 221 222 223
		if (xa->format_map[stype][0] == 0)
		    xa->format_map[stype][0] = num_formats;
		xa->format_map[stype][1] = num_formats;
		xa->supported_formats[num_formats++] = xa_format;
	    }
	}
    }
    return xa;

 out_sf_alloc_fail:
    xa_context_destroy(xa->default_ctx);
 out_no_pipe:
    xa->screen->destroy(xa->screen);
 out_no_screen:
224 225
    if (xa->dev)
	pipe_loader_release(&xa->dev, 1);
226

227 228 229 230
    free(xa);
    return NULL;
}

231
XA_EXPORT void
232 233 234 235 236
xa_tracker_destroy(struct xa_tracker *xa)
{
    free(xa->supported_formats);
    xa_context_destroy(xa->default_ctx);
    xa->screen->destroy(xa->screen);
237
    pipe_loader_release(&xa->dev, 1);
238
    /* CHECK: The XA API user preserves ownership of the original fd */
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
    free(xa);
}

static int
xa_flags_compat(unsigned int old_flags, unsigned int new_flags)
{
    unsigned int flag_diff = (old_flags ^ new_flags);

    if (flag_diff == 0)
	return 1;

    if (flag_diff & XA_FLAG_SHARED)
	return 0;
    /*
     * Don't recreate if we're dropping the render target flag.
     */
    if (flag_diff & XA_FLAG_RENDER_TARGET)
	return ((new_flags & XA_FLAG_RENDER_TARGET) == 0);

258 259 260 261 262 263
    /*
     * Don't recreate if we're dropping the scanout flag.
     */
    if (flag_diff & XA_FLAG_SCANOUT)
	return ((new_flags & XA_FLAG_SCANOUT) == 0);

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    /*
     * Always recreate for unknown / unimplemented flags.
     */
    return 0;
}

static struct xa_format_descriptor
xa_get_format_stype_depth(struct xa_tracker *xa,
			  enum xa_surface_type stype, unsigned int depth)
{
    unsigned int i;
    struct xa_format_descriptor fdesc;
    int found = 0;

    for (i = xa->format_map[stype][0]; i <= xa->format_map[stype][1]; ++i) {
279
	fdesc = xa_get_pipe_format(xa, xa->supported_formats[i]);
280 281 282 283 284 285 286 287 288 289 290 291 292
	if (fdesc.xa_format != xa_format_unknown &&
	    xa_format_depth(fdesc.xa_format) == depth) {
	    found = 1;
	    break;
	}
    }

    if (!found)
	fdesc.xa_format = xa_format_unknown;

    return fdesc;
}

293
XA_EXPORT int
294 295 296
xa_format_check_supported(struct xa_tracker *xa,
			  enum xa_formats xa_format, unsigned int flags)
{
297
    struct xa_format_descriptor fdesc = xa_get_pipe_format(xa, xa_format);
298 299 300 301 302 303 304 305 306 307
    unsigned int bind;

    if (fdesc.xa_format == xa_format_unknown)
	return -XA_ERR_INVAL;

    bind = stype_bind[xa_format_type(fdesc.xa_format)];
    if (flags & XA_FLAG_SHARED)
	bind |= PIPE_BIND_SHARED;
    if (flags & XA_FLAG_RENDER_TARGET)
	bind |= PIPE_BIND_RENDER_TARGET;
308 309
    if (flags & XA_FLAG_SCANOUT)
	bind |= PIPE_BIND_SCANOUT;
310 311

    if (!xa->screen->is_format_supported(xa->screen, fdesc.format,
312
					 PIPE_TEXTURE_2D, 0, 0, bind))
313 314 315 316 317
	return -XA_ERR_INVAL;

    return XA_ERR_NONE;
}

Rob Clark's avatar
Rob Clark committed
318 319 320 321 322
static unsigned
handle_type(enum xa_handle_type type)
{
    switch (type) {
    case xa_handle_type_kms:
323
	return WINSYS_HANDLE_TYPE_KMS;
Rob Clark's avatar
Rob Clark committed
324
    case xa_handle_type_fd:
325
        return WINSYS_HANDLE_TYPE_FD;
Rob Clark's avatar
Rob Clark committed
326 327
    case xa_handle_type_shared:
    default:
328
	return WINSYS_HANDLE_TYPE_SHARED;
Rob Clark's avatar
Rob Clark committed
329 330 331
    }
}

Rob Clark's avatar
Rob Clark committed
332 333
static struct xa_surface *
surface_create(struct xa_tracker *xa,
334 335 336 337
		  int width,
		  int height,
		  int depth,
		  enum xa_surface_type stype,
Rob Clark's avatar
Rob Clark committed
338 339
		  enum xa_formats xa_format, unsigned int flags,
		  struct winsys_handle *whandle)
340 341 342 343 344 345 346 347
{
    struct pipe_resource *template;
    struct xa_surface *srf;
    struct xa_format_descriptor fdesc;

    if (xa_format == xa_format_unknown)
	fdesc = xa_get_format_stype_depth(xa, stype, depth);
    else
348
	fdesc = xa_get_pipe_format(xa, xa_format);
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370

    if (fdesc.xa_format == xa_format_unknown)
	return NULL;

    srf = calloc(1, sizeof(*srf));
    if (!srf)
	return NULL;

    template = &srf->template;
    template->format = fdesc.format;
    template->target = PIPE_TEXTURE_2D;
    template->width0 = width;
    template->height0 = height;
    template->depth0 = 1;
    template->array_size = 1;
    template->last_level = 0;
    template->bind = stype_bind[xa_format_type(fdesc.xa_format)];

    if (flags & XA_FLAG_SHARED)
	template->bind |= PIPE_BIND_SHARED;
    if (flags & XA_FLAG_RENDER_TARGET)
	template->bind |= PIPE_BIND_RENDER_TARGET;
371 372
    if (flags & XA_FLAG_SCANOUT)
	template->bind |= PIPE_BIND_SCANOUT;
373

Rob Clark's avatar
Rob Clark committed
374
    if (whandle)
375
	srf->tex = xa->screen->resource_from_handle(xa->screen, template, whandle,
376
                                                    PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
Rob Clark's avatar
Rob Clark committed
377 378
    else
	srf->tex = xa->screen->resource_create(xa->screen, template);
379 380 381
    if (!srf->tex)
	goto out_no_tex;

382
    srf->refcount = 1;
383 384 385 386 387 388 389 390 391 392
    srf->xa = xa;
    srf->flags = flags;
    srf->fdesc = fdesc;

    return srf;
 out_no_tex:
    free(srf);
    return NULL;
}

Rob Clark's avatar
Rob Clark committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413

XA_EXPORT struct xa_surface *
xa_surface_create(struct xa_tracker *xa,
		  int width,
		  int height,
		  int depth,
		  enum xa_surface_type stype,
		  enum xa_formats xa_format, unsigned int flags)
{
    return surface_create(xa, width, height, depth, stype, xa_format, flags, NULL);
}


XA_EXPORT struct xa_surface *
xa_surface_from_handle(struct xa_tracker *xa,
		  int width,
		  int height,
		  int depth,
		  enum xa_surface_type stype,
		  enum xa_formats xa_format, unsigned int flags,
		  uint32_t handle, uint32_t stride)
Rob Clark's avatar
Rob Clark committed
414 415
{
    return xa_surface_from_handle2(xa, width, height, depth, stype, xa_format,
416
                                   WINSYS_HANDLE_TYPE_SHARED, flags, handle,
Rob Clark's avatar
Rob Clark committed
417 418 419 420 421 422 423 424 425 426 427 428
                                   stride);
}

XA_EXPORT struct xa_surface *
xa_surface_from_handle2(struct xa_tracker *xa,
                        int width,
                        int height,
                        int depth,
                        enum xa_surface_type stype,
                        enum xa_formats xa_format, unsigned int flags,
                        enum xa_handle_type type,
                        uint32_t handle, uint32_t stride)
Rob Clark's avatar
Rob Clark committed
429 430 431
{
    struct winsys_handle whandle;
    memset(&whandle, 0, sizeof(whandle));
Rob Clark's avatar
Rob Clark committed
432
    whandle.type = handle_type(type);
Rob Clark's avatar
Rob Clark committed
433 434 435 436 437
    whandle.handle = handle;
    whandle.stride = stride;
    return surface_create(xa, width, height, depth, stype, xa_format, flags, &whandle);
}

438
XA_EXPORT int
439 440 441 442 443 444
xa_surface_redefine(struct xa_surface *srf,
		    int width,
		    int height,
		    int depth,
		    enum xa_surface_type stype,
		    enum xa_formats xa_format,
445 446
		    unsigned int new_flags,
		    int copy_contents)
447 448 449 450 451 452 453
{
    struct pipe_resource *template = &srf->template;
    struct pipe_resource *texture;
    struct pipe_box src_box;
    struct xa_tracker *xa = srf->xa;
    int save_width;
    int save_height;
454
    unsigned int save_format;
455 456
    struct xa_format_descriptor fdesc;

457

458 459 460
    if (xa_format == xa_format_unknown)
	fdesc = xa_get_format_stype_depth(xa, stype, depth);
    else
461
	fdesc = xa_get_pipe_format(xa, xa_format);
462 463 464 465 466 467 468 469 470 471 472

    if (width == template->width0 && height == template->height0 &&
	template->format == fdesc.format &&
	xa_flags_compat(srf->flags, new_flags))
	return XA_ERR_NONE;

    template->bind = stype_bind[xa_format_type(fdesc.xa_format)];
    if (new_flags & XA_FLAG_SHARED)
	template->bind |= PIPE_BIND_SHARED;
    if (new_flags & XA_FLAG_RENDER_TARGET)
	template->bind |= PIPE_BIND_RENDER_TARGET;
473 474
    if (new_flags & XA_FLAG_SCANOUT)
	template->bind |= PIPE_BIND_SCANOUT;
475 476 477 478 479 480 481

    if (copy_contents) {
	if (!xa_format_type_is_color(fdesc.xa_format) ||
	    xa_format_type(fdesc.xa_format) == xa_type_a)
	    return -XA_ERR_INVAL;

	if (!xa->screen->is_format_supported(xa->screen, fdesc.format,
482
					     PIPE_TEXTURE_2D, 0, 0,
483 484 485 486 487 488 489
					     template->bind |
					     PIPE_BIND_RENDER_TARGET))
	    return -XA_ERR_INVAL;
    }

    save_width = template->width0;
    save_height = template->height0;
490
    save_format = template->format;
491 492 493

    template->width0 = width;
    template->height0 = height;
494
    template->format = fdesc.format;
495 496 497 498 499

    texture = xa->screen->resource_create(xa->screen, template);
    if (!texture) {
	template->width0 = save_width;
	template->height0 = save_height;
500
	template->format = save_format;
501 502 503 504 505 506 507 508 509 510
	return -XA_ERR_NORES;
    }

    if (copy_contents) {
	struct pipe_context *pipe = xa->default_ctx->pipe;

	u_box_origin_2d(xa_min(save_width, template->width0),
			xa_min(save_height, template->height0), &src_box);
	pipe->resource_copy_region(pipe, texture,
				   0, 0, 0, 0, srf->tex, 0, &src_box);
Rob Clark's avatar
Rob Clark committed
511
	xa_context_flush(xa->default_ctx);
512 513 514 515 516 517 518 519 520 521
    }

    pipe_resource_reference(&srf->tex, texture);
    pipe_resource_reference(&texture, NULL);
    srf->fdesc = fdesc;
    srf->flags = new_flags;

    return XA_ERR_NONE;
}

522 523 524 525 526 527 528 529 530 531
XA_EXPORT struct xa_surface*
xa_surface_ref(struct xa_surface *srf)
{
    if (srf == NULL) {
	return NULL;
    }
    srf->refcount++;
    return srf;
}

532
XA_EXPORT void
533
xa_surface_unref(struct xa_surface *srf)
534
{
535 536 537
    if (srf == NULL || --srf->refcount) {
	return;
    }
538 539 540 541
    pipe_resource_reference(&srf->tex, NULL);
    free(srf);
}

542
XA_EXPORT void
543 544 545 546 547 548 549
xa_tracker_version(int *major, int *minor, int *patch)
{
    *major = XA_TRACKER_VERSION_MAJOR;
    *minor = XA_TRACKER_VERSION_MINOR;
    *patch = XA_TRACKER_VERSION_PATCH;
}

550
XA_EXPORT int
551
xa_surface_handle(struct xa_surface *srf,
552
		  enum xa_handle_type type,
553 554 555 556 557 558 559 560
		  uint32_t * handle, unsigned int *stride)
{
    struct winsys_handle whandle;

    struct pipe_screen *screen = srf->xa->screen;
    boolean res;

    memset(&whandle, 0, sizeof(whandle));
Rob Clark's avatar
Rob Clark committed
561
    whandle.type = handle_type(type);
562 563
    res = screen->resource_get_handle(screen, srf->xa->default_ctx->pipe,
                                      srf->tex, &whandle,
564
                                      PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
565 566 567 568 569 570 571 572
    if (!res)
	return -XA_ERR_INVAL;

    *handle = whandle.handle;
    *stride = whandle.stride;

    return XA_ERR_NONE;
}
573

574
XA_EXPORT enum xa_formats
575 576
xa_surface_format(const struct xa_surface *srf)
{
577
    return srf->fdesc.xa_format;
578
}