All of lore.kernel.org
 help / color / mirror / Atom feed
* SNB/IVB sprite demo
@ 2012-02-08  2:16 Reese, Armin C
  2012-02-08 15:50 ` Daniel Vetter
  2012-02-10 17:48 ` Daniel Vetter
  0 siblings, 2 replies; 9+ messages in thread
From: Reese, Armin C @ 2012-02-08  2:16 UTC (permalink / raw)
  To: intel-gfx@lists.freedesktop.org


[-- Attachment #1.1: Type: text/plain, Size: 393 bytes --]

I worked with Jesse Barnes to develop a sprite demo/test program for SNB/IVB.  It uses the new IOCTLs: GETPLANERESOURCES, GETPLANE, and SETPLANE.  I also intend on using the program as an example of how to set up a mode, display a framebuffer, and display sprite on Intel graphics.  The source is attached.  I was hoping it could be put into intel_gpu_tools for all to use.

Thanks,
Armin

[-- Attachment #1.2: Type: text/html, Size: 2101 bytes --]

[-- Attachment #2: sprite_on.c --]
[-- Type: text/plain, Size: 38832 bytes --]

/*
 * Copyright 2010 Intel Corporation
 *   Armin Reese <armin.c.reese@intel.com>
 *
 * 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.
 */

/*
 * This program is intended for testing sprite functionality.
 */
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "xf86drm.h"
#include "xf86drmMode.h"
#include "i915_drm.h"

#if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY)
#define TEST_PLANES 1
#include "drm_fourcc.h"
#endif

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

struct type_name
{
	int type;
	char *name;
};

#define type_name_fn(res) \
static char * res##_str(int type) {			\
	unsigned int i;					\
	for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
		if (res##_names[i].type == type)	\
			return res##_names[i].name;	\
	}						\
	return "(invalid)";				\
}

struct type_name encoder_type_names[] = {
	{ DRM_MODE_ENCODER_NONE, "none" },
	{ DRM_MODE_ENCODER_DAC, "DAC" },
	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
	{ DRM_MODE_ENCODER_TVDAC, "TVDAC" },
};

type_name_fn(encoder_type)

struct type_name connector_status_names[] = {
	{ DRM_MODE_CONNECTED, "connected" },
	{ DRM_MODE_DISCONNECTED, "disconnected" },
	{ DRM_MODE_UNKNOWNCONNECTION, "unknown" },
};

type_name_fn(connector_status)

struct type_name connector_type_names[] = {
	{ DRM_MODE_CONNECTOR_Unknown, "unknown" },
	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
	{ DRM_MODE_CONNECTOR_Composite, "composite" },
	{ DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
	{ DRM_MODE_CONNECTOR_Component, "component" },
	{ DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
	{ DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" },
	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
	{ DRM_MODE_CONNECTOR_TV, "TV" },
	{ DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort" },
};

type_name_fn(connector_type)

/*
 * Mode setting with the kernel interfaces is a bit of a chore.
 * First you have to find the connector in question and make sure the
 * requested mode is available.
 * Then you need to find the encoder attached to that connector so you
 * can bind it with a free crtc.
 */
struct connector
{
	uint32_t            id;
	int                 mode_valid;
	drmModeModeInfo     mode;
	drmModeEncoder      *encoder;
	drmModeConnector    *connector;
	int                 crtc;
	int                 pipe;
};

//*****************************************************************************
//
// usage
//
//*****************************************************************************
static void dump_mode(
        drmModeModeInfo             *mode)
{
	printf("  %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d\n",
	       mode->name,
	       mode->vrefresh,
	       mode->hdisplay,
	       mode->hsync_start,
	       mode->hsync_end,
	       mode->htotal,
	       mode->vdisplay,
	       mode->vsync_start,
	       mode->vsync_end,
	       mode->vtotal,
	       mode->flags,
	       mode->type,
	       mode->clock);
}

//*****************************************************************************
//
// dump_connectors
//
//*****************************************************************************
static void dump_connectors(
        int                         gfx_fd,
        drmModeRes                  *resources)
{
	int i, j;

	printf("Connectors:\n");
	printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
	for (i = 0; i < resources->count_connectors; i++) {
		drmModeConnector *connector;

		connector = drmModeGetConnector(gfx_fd, resources->connectors[i]);
		if (!connector) {
			printf("could not get connector %i: %s\n",
				resources->connectors[i], strerror(errno));
			continue;
		}

		printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
		       connector->connector_id,
		       connector->encoder_id,
		       connector_status_str(connector->connection),
		       connector_type_str(connector->connector_type),
		       connector->mmWidth, connector->mmHeight,
		       connector->count_modes);

		if (!connector->count_modes)
			continue;

		printf("  modes:\n");
		printf("  name refresh (Hz) hdisp hss hse htot vdisp "
		       "vss vse vtot flags type clock\n");
		for (j = 0; j < connector->count_modes; j++)
			dump_mode(&connector->modes[j]);

		drmModeFreeConnector(connector);
	}
	printf("\n");
}

//*****************************************************************************
//
// dump_crtcs
//
//*****************************************************************************
static void dump_crtcs(
        int                         gfx_fd,
        drmModeRes                  *resources)
{
	int i;

	printf("CRTCs:\n");
	printf("id\tfb\tpos\tsize\n");
	for (i = 0; i < resources->count_crtcs; i++) {
		drmModeCrtc *crtc;

		crtc = drmModeGetCrtc(gfx_fd, resources->crtcs[i]);
		if (!crtc) {
			printf("could not get crtc %i: %s\n",
				   resources->crtcs[i],
				   strerror(errno));
			continue;
		}
		printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
		       crtc->crtc_id,
		       crtc->buffer_id,
		       crtc->x, crtc->y,
		       crtc->width, crtc->height);
		dump_mode(&crtc->mode);

		drmModeFreeCrtc(crtc);
	}
	printf("\n");
}

//*****************************************************************************
//
// dump_planes
//
//*****************************************************************************
static void dump_planes(
        int                         gfx_fd,
        drmModeRes                  *resources)
{
	drmModePlaneRes             *plane_resources;
	drmModePlane                *ovr;
	int i;

	plane_resources = drmModeGetPlaneResources(gfx_fd);
	if (!plane_resources) {
		printf("drmModeGetPlaneResources failed: %s\n",
			   strerror(errno));
		return;
	}

	printf("Planes:\n");
	printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n");
	for (i = 0; i < plane_resources->count_planes; i++) {
		ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]);
		if (!ovr) {
			printf("drmModeGetPlane failed: %s\n",
			       strerror(errno));
			continue;
		}

		printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n",
		       ovr->plane_id, ovr->crtc_id, ovr->fb_id,
		       ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
		       ovr->gamma_size);

		drmModeFreePlane(ovr);
	}
	printf("\n");

	return;
}

//*****************************************************************************
//
// connector_find_preferred_mode
//
//*****************************************************************************
static void connector_find_preferred_mode(
        int                     gfx_fd,
        drmModeRes              *gfx_resources,
        struct connector        *c)
{
	drmModeConnector *connector;
	drmModeEncoder *encoder = NULL;
	int i, j;

	/* First, find the connector & mode */
	c->mode_valid = 0;
	connector = drmModeGetConnector(gfx_fd, c->id);
	if (!connector) {
		printf("could not get connector %d: %s\n",
			   c->id,
			   strerror(errno));
		drmModeFreeConnector(connector);
		return;
	}

	if (connector->connection != DRM_MODE_CONNECTED) {
		drmModeFreeConnector(connector);
		return;
	}

	if (!connector->count_modes) {
		printf("connector %d has no modes\n",
		       c->id);
		drmModeFreeConnector(connector);
		return;
	}

	if (connector->connector_id != c->id) {
		printf("connector id doesn't match (%d != %d)\n",
			    connector->connector_id,
			    c->id);
		drmModeFreeConnector(connector);
		return;
	}

	for (j = 0; j < connector->count_modes; j++) {
		c->mode = connector->modes[j];
		if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
			c->mode_valid = 1;
			break;
		}
	}

	if (!c->mode_valid) {
		if (connector->count_modes > 0) {
			/* use the first mode as test mode */
			c->mode = connector->modes[0];
			c->mode_valid = 1;
		} else {
			printf("failed to find any modes on connector %d\n",
				   c->id);
			return;
		}
	}

	/* Now get the encoder */
	for (i = 0; i < connector->count_encoders; i++) {
		encoder = drmModeGetEncoder(gfx_fd, connector->encoders[i]);

		if (!encoder) {
			printf("could not get encoder %i: %s\n",
				   gfx_resources->encoders[i],
				   strerror(errno));
			drmModeFreeEncoder(encoder);
			continue;
		}

		break;
	}

	c->encoder = encoder;

	if (i == gfx_resources->count_encoders) {
		printf("failed to find encoder\n");
		c->mode_valid = 0;
		return;
	}

	/* Find first CRTC not in use */
	for (i = 0; i < gfx_resources->count_crtcs; i++) {
		if (gfx_resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i)))
			break;
	}
	c->crtc = gfx_resources->crtcs[i];
	c->pipe = i;

	gfx_resources->crtcs[i] = 0;

	c->connector = connector;
}

//*****************************************************************************
//
// gem_create
//
//*****************************************************************************
static uint32_t gem_create(int fd, int size)
{
	struct drm_i915_gem_create create;

	create.handle = 0;
	create.size = (size + 4095) & -4096;
	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);

	return create.handle;
}

//*****************************************************************************
//
// gem_mmap
//
//*****************************************************************************
static void *gem_mmap(int fd, uint32_t handle, int size, int prot)
{
	struct drm_i915_gem_mmap_gtt mmap_arg;
	void *ptr;

	mmap_arg.handle = handle;
	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
		return NULL;

	ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
	if (ptr == MAP_FAILED)
		ptr = NULL;

	return ptr;
}

//*****************************************************************************
//
// gem_close
//
//*****************************************************************************
static void gem_close(int fd, uint32_t handle)
{
	struct drm_gem_close close_st;

	close_st.handle = handle;
	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_st);
}

//*****************************************************************************
//
// connector_find_plane
//
//*****************************************************************************
static int connector_find_plane(int gfx_fd, struct connector *c)
{
	drmModePlaneRes *plane_resources;
	drmModePlane *ovr;
	uint32_t id = 0;
	int i;

	plane_resources = drmModeGetPlaneResources(gfx_fd);
	if (!plane_resources) {
		printf("drmModeGetPlaneResources failed: %s\n",
		       strerror(errno));
		return 0;
	}

	for (i = 0; i < plane_resources->count_planes; i++) {
		ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]);
		if (!ovr) {
			printf("drmModeGetPlane failed: %s\n",
				   strerror(errno));
			continue;
		}

		if (ovr->possible_crtcs & (1 << c->pipe)) {
			id = ovr->plane_id;
			drmModeFreePlane(ovr);
			break;
		}
		drmModeFreePlane(ovr);
	}

	return id;
}

//*****************************************************************************
//
// disable_planes
//
//*****************************************************************************
static void disable_planes(
        int                     gfx_fd)
{
	struct                  connector *connectors;
    drmModeRes              *resources;
	int                     c;

	resources = drmModeGetResources(gfx_fd);
	if (!resources) {
		printf("drmModeGetResources failed: %s\n",
			   strerror(errno));
		return;
	}

	connectors = calloc(resources->count_connectors,
			    sizeof(struct connector));
	if (!connectors)
		return;

	/* Find any connected displays */
	for (c = 0; c < resources->count_connectors; c++) {
		uint32_t sprite_plane_id;

		sprite_plane_id = connector_find_plane(gfx_fd, &connectors[c]);
		if (!sprite_plane_id) {
			printf("failed to find plane for crtc\n");
			return;
		}
		if (drmModeSetPlane(gfx_fd, sprite_plane_id, connectors[c].crtc, 0, 0, 0,
				    0, 0, 0, 0, 0, 0, 0)) {
			printf("failed to disable plane: %s\n",
				strerror(errno));
			return;
		}
	}
	drmModeFreeResources(resources);
	return;
}

//*****************************************************************************
//
// prepare_primary_surface
//
//*****************************************************************************
static int prepare_primary_surface(
            int                     fd,
            int                     prim_width,
            int                     prim_height,
            uint32_t                *prim_handle,
            uint32_t                *prim_stride,
            uint32_t                *prim_size,
            int                     tiled)
{
    uint32_t                        bytes_per_pixel = sizeof(uint32_t);
    uint32_t                        *prim_fb_ptr;
    struct drm_i915_gem_set_tiling  set_tiling;

    if (bytes_per_pixel != sizeof(uint32_t)) {
        printf("Bad bytes_per_pixel for primary surface: %d\n",
               bytes_per_pixel);
        return -EINVAL;
    }

    if (tiled) {
        int                         v;

        /* Round the tiling up to the next power-of-two and the
         * region up to the next pot fence size so that this works
         * on all generations.
         *
         * This can still fail if the framebuffer is too large to
         * be tiled. But then that failure is expected.
         */

        v = prim_width * bytes_per_pixel;
        for (*prim_stride = 512; *prim_stride < v; *prim_stride *= 2)
            ;

        v = *prim_stride * prim_height;
        for (*prim_size = 1024*1024; *prim_size < v; *prim_size *= 2)
            ;
    } else {
        /* Scan-out has a 64 byte alignment restriction */
        *prim_stride = (prim_width * bytes_per_pixel + 63) & ~63;
        *prim_size = *prim_stride * prim_height;
    }

    *prim_handle = gem_create(fd, *prim_size);

    if (tiled) {
        set_tiling.handle = *prim_handle;
        set_tiling.tiling_mode = I915_TILING_X;
        set_tiling.stride = *prim_stride;
        if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) {
            printf("Set tiling failed: %s (stride=%d, size=%d)\n",
                    strerror(errno), *prim_stride, *prim_size);
            return -1;
        }
    }

    prim_fb_ptr = gem_mmap(fd,
                           *prim_handle, *prim_size,
                           PROT_READ | PROT_WRITE);

    if (prim_fb_ptr != NULL) {
        // Write primary surface with gray background
        memset(prim_fb_ptr, 0x3f, *prim_size);
        munmap(prim_fb_ptr, *prim_size);
    }

    return 0;
}

//*****************************************************************************
//
// fill_sprite
//
//*****************************************************************************
static void fill_sprite(
        int                             sprite_width,
        int                             sprite_height,
        int                             sprite_stride,
        int                             sprite_index,
        void                            *sprite_fb_ptr)
{
    __u32                           *pLinePat0,
                                    *pLinePat1,
                                    *pLinePtr;
    int                             i,
                                    line;
    int                             stripe_width;

    stripe_width = ((sprite_width > 64) &&
                    (sprite_height > 64)) ? (sprite_index + 1) * 8 :
                                            (sprite_index + 1) * 2;

    // Note:  sprite_stride is in bytes.  pLinePat0 and pLinePat1
    //        are both __u32 pointers
    pLinePat0 = sprite_fb_ptr;
    pLinePat1 = pLinePat0 + (stripe_width * (sprite_stride / sizeof(*pLinePat0)));

    for (i = 0; i < sprite_width; i++) {
        *(pLinePat0 + i) = ((i / stripe_width) & 0x1) ? 0 : ~0;
        *(pLinePat1 + i) = ~(*(pLinePat0 + i));
    }

    for (line = 1; line < sprite_height; line++) {
        if (line == stripe_width) {
            continue;
        }

        pLinePtr = ((line / stripe_width) & 0x1) ? pLinePat1 : pLinePat0;
        memcpy( pLinePat0 + ((sprite_stride / sizeof(*pLinePat0)) * line),
                pLinePtr,
                sprite_width * sizeof(*pLinePat0));
    }

    return;
}

//*****************************************************************************
//
// prepare_sprite_surfaces
//
//*****************************************************************************
static int prepare_sprite_surfaces(
            int                     fd,
            int                     sprite_width,
            int                     sprite_height,
            uint32_t                num_surfaces,
            uint32_t                *sprite_handles,
            uint32_t                *sprite_stride,
            uint32_t                *sprite_size,
            int                     tiled)
{
    uint32_t                        bytes_per_pixel = sizeof(uint32_t);
    uint32_t                        *sprite_fb_ptr;
    struct drm_i915_gem_set_tiling  set_tiling;
    int                             i;

    if (bytes_per_pixel != sizeof(uint32_t)) {
        printf("Bad bytes_per_pixel for sprite: %d\n", bytes_per_pixel);
        return -EINVAL;
    }

    if (tiled) {
        int                         v;

        /* Round the tiling up to the next power-of-two and the
         * region up to the next pot fence size so that this works
         * on all generations.
         *
         * This can still fail if the framebuffer is too large to
         * be tiled. But then that failure is expected.
         */

        v = sprite_width * bytes_per_pixel;
        for (*sprite_stride = 512; *sprite_stride < v; *sprite_stride *= 2)
            ;

        v = *sprite_stride * sprite_height;
        for (*sprite_size = 1024*1024; *sprite_size < v; *sprite_size *= 2)
            ;
    } else {
        /* Scan-out has a 64 byte alignment restriction */
        *sprite_stride = (sprite_width * bytes_per_pixel + 63) & ~63;
        *sprite_size = *sprite_stride * sprite_height;
    }

    for (i = 0; i < num_surfaces;  i++) {
        // Create the sprite surface
        sprite_handles[i] = gem_create(fd, *sprite_size);

        if (tiled) {
            set_tiling.handle = sprite_handles[i];
            set_tiling.tiling_mode = I915_TILING_X;
            set_tiling.stride = *sprite_stride;
            if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) {
                printf("Set tiling failed: %s (stride=%d, size=%d)\n",
                       strerror(errno), *sprite_stride, *sprite_size);
                return -1;
            }
        }

        // Get pointer to the surface
        sprite_fb_ptr = gem_mmap(fd,
                                 sprite_handles[i], *sprite_size,
                                 PROT_READ | PROT_WRITE);

        if (sprite_fb_ptr != NULL) {
            // Fill with checkerboard pattern
            fill_sprite(
                    sprite_width,
                    sprite_height,
                    *sprite_stride,
                    i, sprite_fb_ptr);

            munmap(sprite_fb_ptr, *sprite_size);
        } else {
            i--;
            while (i >= 0) {
                gem_close(fd, sprite_handles[i]);
                i--;
            }
        }
    }

    return 0;
}

//*****************************************************************************
//
// ricochet
//
//*****************************************************************************
static void ricochet(
        int                             tiled,
        int                             sprite_w,
        int                             sprite_h,
        int                             out_w,
        int                             out_h,
        int                             dump_info)
{
    int                                 ret;
    int                                 gfx_fd;
    int                                 keep_moving;
    const int                           num_surfaces = 3;
    uint32_t                            sprite_handles[num_surfaces];
    uint32_t                            sprite_fb_id[num_surfaces];
    int                                 sprite_x;
    int                                 sprite_y;
    uint32_t                            sprite_stride;
    uint32_t                            sprite_size;
    uint32_t                            handles[4],
                                        pitches[4],
                                        offsets[4]; /* we only use [0] */
    uint32_t                            prim_width,
                                        prim_height,
                                        prim_handle,
                                        prim_stride,
                                        prim_size,
                                        prim_fb_id;
    struct drm_intel_sprite_colorkey    set;
    struct connector                    curr_connector;
    drmModeRes                          *gfx_resources;
    struct termios                      orig_term,
                                        curr_term;
    int                                 c_index;
    int                                 sprite_index;
    unsigned int                        sprite_plane_id;
    uint32_t                            plane_flags = 0;
    int                                 delta_x,
                                        delta_y;
    struct timeval                      stTimeVal;
    long long                           currTime,
                                        prevFlipTime,
                                        prevMoveTime,
                                        deltaFlipTime,
                                        deltaMoveTime,
                                        SleepTime;
    char                                key;

    // Open up I915 graphics device
    gfx_fd = drmOpen("i915", NULL);
    if (gfx_fd < 0) {
        printf("Failed to load i915 driver: %s\n", strerror(errno));
        return;
    }

    // Obtain pointer to struct containing graphics resources
    gfx_resources = drmModeGetResources(gfx_fd);
    if (!gfx_resources) {
        printf("drmModeGetResources failed: %s\n", strerror(errno));
        return;
    }

    if (dump_info != 0) {
        dump_connectors(gfx_fd, gfx_resources);
        dump_crtcs(gfx_fd, gfx_resources);
        dump_planes(gfx_fd, gfx_resources);
    }

    // Save previous terminal settings
    if (tcgetattr( 0, &orig_term) != 0) {
        printf("tcgetattr failure: %s\n",
               strerror(errno));
        return;
    }

    // Set up input to return characters immediately
    curr_term = orig_term;
    curr_term.c_lflag &= ~(ICANON | ECHO | ECHONL);
    curr_term.c_cc[VMIN] = 0;       // No minimum number of characters
    curr_term.c_cc[VTIME] = 0 ;     // Return immediately, even if
                                    // nothing has been entered.
    if (tcsetattr( 0, TCSANOW, &curr_term) != 0) {
        printf("tcgetattr failure: %s\n",
               strerror(errno));
        return;
    }

    // Cycle through all connectors and display the flying sprite
    // where there are displays attached and the hardware will support it.
    for (c_index = 0; c_index < gfx_resources->count_connectors; c_index++)  {
        curr_connector.id = gfx_resources->connectors[c_index];

        // Find the native (preferred) display mode
        connector_find_preferred_mode(gfx_fd, gfx_resources, &curr_connector);
        if (curr_connector.mode_valid == 0) {
            printf("No valid preferred mode detected\n");
            goto out;
        }

        // Determine if sprite hardware is available on pipe
        // associated with this connector.
        sprite_plane_id = connector_find_plane(gfx_fd, &curr_connector);
        if (!sprite_plane_id) {
            printf("Failed to find sprite plane on crtc\n");
            goto out;
        }

        // Width and height of preferred mode
        prim_width = curr_connector.mode.hdisplay;
        prim_height = curr_connector.mode.vdisplay;

        // Allocate and fill memory for primary surface
        ret = prepare_primary_surface(
                      gfx_fd,
                      prim_width,
                      prim_height,
                      &prim_handle,
                      &prim_stride,
                      &prim_size,
                      tiled);
        if (ret != 0) {
            printf("Failed to add primary fb (%dx%d): %s\n",
                prim_width, prim_height, strerror(errno));
            goto out;
        }

        // Add the primary surface framebuffer
        ret = drmModeAddFB(
                      gfx_fd,
                      prim_width,
                      prim_height,
                      24, 32,
                      prim_stride,
                      prim_handle,
                      &prim_fb_id);
        gem_close(gfx_fd, prim_handle);

        if (ret != 0) {
            printf("Failed to add primary fb (%dx%d): %s\n",
                prim_width, prim_height, strerror(errno));
            goto out;
        }

        // Allocate and fill sprite surfaces
        ret = prepare_sprite_surfaces(
                      gfx_fd,
                      sprite_w,
                      sprite_h,
                      num_surfaces,
                      &sprite_handles[0],
                      &sprite_stride,
                      &sprite_size,
                      tiled);
        if (ret != 0) {
            printf("Preparation of sprite surfaces failed %dx%d\n",
                    sprite_w, sprite_h);
            goto out;
        }

        // Add the sprite framebuffers
        for (sprite_index = 0; sprite_index < num_surfaces; sprite_index++) {
            handles[0] = sprite_handles[sprite_index];
            handles[1] = handles[0];
            handles[2] = handles[0];
            handles[3] = handles[0];
            pitches[0] = sprite_stride;
            pitches[1] = sprite_stride;
            pitches[2] = sprite_stride;
            pitches[3] = sprite_stride;
            memset(offsets, 0, sizeof(offsets));

            ret = drmModeAddFB2(
                          gfx_fd,
                          sprite_w, sprite_h, DRM_FORMAT_XRGB8888,
                          handles, pitches, offsets, &sprite_fb_id[sprite_index],
                          plane_flags);
            gem_close(gfx_fd, sprite_handles[sprite_index]);

            if (ret) {
                printf("Failed to add sprite fb (%dx%d): %s\n",
                       sprite_w, sprite_h, strerror(errno));

                sprite_index--;
                while (sprite_index >= 0) {
                    drmModeRmFB(gfx_fd, sprite_fb_id[sprite_index]);
                    sprite_index--;
                }
                goto out;
            }
        }

        if (dump_info != 0) {
            printf("Displayed Mode Connector struct:\n"
                   "    .id = %d\n"
                   "    .mode_valid = %d\n"
                   "    .crtc = %d\n"
                   "    .pipe = %d\n"
                   "    drmModeModeInfo ...\n"
                   "        .name = %s\n"
                   "        .type = %d\n"
                   "        .flags = %08x\n"
                   "    drmModeEncoder ...\n"
                   "        .encoder_id = %d\n"
                   "        .encoder_type = %d\n"
                   "        .crtc_id = %d\n"
                   "        .possible_crtcs = %d\n"
                   "        .possible_clones = %d\n"
                   "    drmModeConnector ...\n"
                   "        .connector_id = %d\n"
                   "        .encoder_id = %d\n"
                   "        .connector_type = %d\n"
                   "        .connector_type_id = %d\n\n",
                   curr_connector.id,
                   curr_connector.mode_valid,
                   curr_connector.crtc,
                   curr_connector.pipe,
                   curr_connector.mode.name,
                   curr_connector.mode.type,
                   curr_connector.mode.flags,
                   curr_connector.encoder->encoder_id,
                   curr_connector.encoder->encoder_type,
                   curr_connector.encoder->crtc_id,
                   curr_connector.encoder->possible_crtcs,
                   curr_connector.encoder->possible_clones,
                   curr_connector.connector->connector_id,
                   curr_connector.connector->encoder_id,
                   curr_connector.connector->connector_type,
                   curr_connector.connector->connector_type_id);

            printf("Sprite surface dimensions = %dx%d\n"
                   "Sprite output dimensions = %dx%d\n"
                    "Press any key to continue >\n",
                    sprite_w,
                    sprite_h,
                    out_w,
                    out_h);

            // Wait for a key-press
            while( read(0, &key, 1) == 0);
            // Purge unread characters
            tcflush(0, TCIFLUSH);
        }

        // Set up the primary display mode
        ret = drmModeSetCrtc(
                      gfx_fd,
                      curr_connector.crtc,
                      prim_fb_id,
                      0, 0,
                      &curr_connector.id,
                      1,
                      &curr_connector.mode);
        if (ret != 0)
        {
            printf("Failed to set mode (%dx%d@%dHz): %s\n",
                prim_width, prim_height, curr_connector.mode.vrefresh,
                strerror(errno));
            continue;
        }

        // Set the sprite colorkey state
        set.plane_id = sprite_plane_id;
        set.min_value = 0;
        set.max_value = 0;
        set.flags = I915_SET_COLORKEY_NONE;
        ret = drmCommandWrite(gfx_fd, DRM_I915_SET_SPRITE_COLORKEY, &set,
                      sizeof(set));

        // Set up sprite output dimensions, initial position, etc.
        if (out_w > prim_width / 2)
            out_w = prim_width / 2;
        if (out_h > prim_height / 2)
            out_h - prim_height / 2;

        delta_x = 3;
        delta_y = 4;
        sprite_x = (prim_width / 2) - (out_w / 2);
        sprite_y = (prim_height / 2) - (out_h / 2);

        currTime = 0;
        prevFlipTime = 0;       // Will force immediate sprite flip
        prevMoveTime = 0;       // Will force immediate sprite move
        deltaFlipTime = 500000; // Flip sprite surface every 1/2 second
        deltaMoveTime = 100000; // Move sprite every 100 ms
        sprite_index = num_surfaces - 1;
        keep_moving = 1;

        // Bounce sprite off the walls
        while (keep_moving) {
            // Obtain system time in usec.
            if (gettimeofday( &stTimeVal, NULL ) != 0) {
                printf("gettimeofday error: %s\n",
                       strerror(errno));
            } else {
                currTime = ((long long)stTimeVal.tv_sec * 1000000) + stTimeVal.tv_usec;
            }

            // Check if it's time to flip the sprite surface
            if (currTime - prevFlipTime > deltaFlipTime)  {
                sprite_index = (sprite_index + 1) % num_surfaces;

                prevFlipTime = currTime;
            }

            // Move the sprite on the screen and flip
            // the surface if the index has changed
            if (drmModeSetPlane(
                        gfx_fd,
                        sprite_plane_id,
                        curr_connector.crtc,
                        sprite_fb_id[sprite_index],
                        plane_flags,
                        sprite_x, sprite_y,
                        out_w, out_h,
                        0, 0,
                        sprite_w, sprite_h)) {
                printf("Failed to enable sprite plane: %s\n",
                       strerror(errno));
            }

            // Check if it's time to move the sprite surface
            if (currTime - prevMoveTime > deltaMoveTime)  {

                // Compute the next position for sprite
                sprite_x += delta_x;
                sprite_y += delta_y;
                if (sprite_x < 0) {
                    sprite_x = 0;
                    delta_x = -delta_x;
                }
                else if (sprite_x > prim_width - out_w) {
                    sprite_x = prim_width - out_w;
                    delta_x = -delta_x;
                }

                if (sprite_y < 0) {
                    sprite_y = 0;
                    delta_y = -delta_y;
                }
                else if (sprite_y > prim_height - out_h) {
                    sprite_y = prim_height - out_h;
                    delta_y = -delta_y;
                }

                prevMoveTime = currTime;
            }

            // Fetch a key from input (non-blocking)
            if (read(0, &key, 1) == 1) {
                switch (key) {
                case 'q':       // Kill the program
                case 'Q':
                    goto out;
                    break;
                case 's':       // Slow down sprite movement;
                     deltaMoveTime = (deltaMoveTime * 100) / 90;
                   if (deltaMoveTime > 800000) {
                        deltaMoveTime = 800000;
                    }
                    break;
                case 'S':       // Speed up sprite movement;
                    deltaMoveTime = (deltaMoveTime * 100) / 110;
                    if (deltaMoveTime < 2000) {
                        deltaMoveTime = 2000;
                    }
                    break;
                case 'f':       // Slow down sprite flipping;
                    deltaFlipTime = (deltaFlipTime * 100) / 90;
                    if (deltaFlipTime > 1000000) {
                        deltaFlipTime = 1000000;
                    }
                    break;
                case 'F':       // Speed up sprite flipping;
                    deltaFlipTime = (deltaFlipTime * 100) / 110;
                    if (deltaFlipTime < 20000) {
                        deltaFlipTime = 20000;
                    }
                    break;
                case 'n':       // Next connector
                case 'N':
                    keep_moving = 0;
                    break;
                default:
                    break;
                }

                // Purge unread characters
                tcflush(0, TCIFLUSH);
            }

            // Wait for min of flip or move deltas
            SleepTime = (deltaFlipTime < deltaMoveTime) ?
                            deltaFlipTime : deltaMoveTime;
            usleep(SleepTime);
        }
    }

out:
    // Purge unread characters
    tcflush(0, TCIFLUSH);
    // Restore previous terminal settings
    if (tcsetattr( 0, TCSANOW, &orig_term) != 0) {
        printf("tcgetattr failure: %s\n",
               strerror(errno));
        return;
    }

    drmModeFreeResources(gfx_resources);
}

//*****************************************************************************
//
// usage
//
//*****************************************************************************
static void usage(char *name)
{
	printf("usage: %s -s <plane width>x<plane height> [-dhto]\n"
           "\t-d\t[optional] dump mode information\n"
           "\t-h\t[optional] output help message\n"
	       "\t-t\t[optional] enable tiling\n"
           "\t-o\t[optional] <output rect width>x<output rect height>\n\n"
           "Keyboard control for sprite movement and flip rate ...\n"
           "\t'q' or 'Q' - Quit the program\n"
           "\t'n' or 'N' - Switch to next display\n"
           "\t's'        - Slow sprite movement\n"
           "\t'S'        - Speed up sprite movement\n"
           "\t'f'        - Slow sprite surface flipping\n"
           "\t'F'        - Speed up sprite surface flipping\n",
           name);
}

//*****************************************************************************
//
// main
//
//*****************************************************************************
int main(int argc, char **argv)
{
	int                 c;
	int                 test_overlay = 0,
	                    enable_tiling = 0,
                        dump_info = 0;
    int                 plane_width = 0,
                        plane_height = 0,
                        out_width = 0,
                        out_height = 0;
	static char         optstr[] = "ds:o:th";

	opterr = 0;
	while ((c = getopt(argc, argv, optstr)) != -1) {
		switch (c) {
        case 'd':               // Dump information
            dump_info = 1;
            break;
		case 't':               // Tiling enable
			enable_tiling = 1;
			break;
		case 's':               // Surface dimensions
            if (sscanf(optarg, "%dx%d",
                       &plane_width, &plane_height) != 2)
                usage(argv[0]);
		    test_overlay = 1;
			break;
        case 'o':               // Output dimensions
            if (sscanf(optarg, "%dx%d",
                       &out_width, &out_height) != 2)
                usage(argv[0]);
            break;
		default:
			printf("unknown option %c\n", c);
			/* fall through */
		case 'h':               // Help!
			usage(argv[0]);
			goto out;
		}
	}

	if (test_overlay) {
	    if (out_width < (plane_width / 2)) {
	        out_width = plane_width;
	    }

	    if (out_height < (plane_height / 2)) {
	        out_height = plane_height;
	    }

	    ricochet(enable_tiling,
	             plane_width,
	             plane_height,
	             out_width,
	             out_height,
                 dump_info);
	} else {
	    printf("Sprite dimensions are required:\n");
	    usage(argv[0]);
	}

out:
	exit(0);
}


[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-08  2:16 SNB/IVB sprite demo Reese, Armin C
@ 2012-02-08 15:50 ` Daniel Vetter
  2012-02-08 18:14   ` Jesse Barnes
  2012-02-10 17:48 ` Daniel Vetter
  1 sibling, 1 reply; 9+ messages in thread
From: Daniel Vetter @ 2012-02-08 15:50 UTC (permalink / raw)
  To: Reese, Armin C; +Cc: intel-gfx@lists.freedesktop.org

On Wed, Feb 08, 2012 at 02:16:09AM +0000, Reese, Armin C wrote:
> I worked with Jesse Barnes to develop a sprite demo/test program for
> SNB/IVB.  It uses the new IOCTLs: GETPLANERESOURCES, GETPLANE, and
> SETPLANE.  I also intend on using the program as an example of how to
> set up a mode, display a framebuffer, and display sprite on Intel
> graphics.  The source is attached.  I was hoping it could be put into
> intel_gpu_tools for all to use.

It's a bit a duplication with the existing testdisplay stuff and imo
cleaning that up would have been nicer, but whatever. Slurped into i-g-t
under demos/

Cheers, Daniel
-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-08 15:50 ` Daniel Vetter
@ 2012-02-08 18:14   ` Jesse Barnes
  0 siblings, 0 replies; 9+ messages in thread
From: Jesse Barnes @ 2012-02-08 18:14 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx@lists.freedesktop.org


[-- Attachment #1.1: Type: text/plain, Size: 880 bytes --]

On Wed, 8 Feb 2012 16:50:13 +0100
Daniel Vetter <daniel@ffwll.ch> wrote:

> On Wed, Feb 08, 2012 at 02:16:09AM +0000, Reese, Armin C wrote:
> > I worked with Jesse Barnes to develop a sprite demo/test program for
> > SNB/IVB.  It uses the new IOCTLs: GETPLANERESOURCES, GETPLANE, and
> > SETPLANE.  I also intend on using the program as an example of how to
> > set up a mode, display a framebuffer, and display sprite on Intel
> > graphics.  The source is attached.  I was hoping it could be put into
> > intel_gpu_tools for all to use.
> 
> It's a bit a duplication with the existing testdisplay stuff and imo
> cleaning that up would have been nicer, but whatever. Slurped into i-g-t
> under demos/

That just means testdisplay needs to go on a diet. :)  I'm ok with the
duplication in the meantime...

-- 
Jesse Barnes, Intel Open Source Technology Center

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-08  2:16 SNB/IVB sprite demo Reese, Armin C
  2012-02-08 15:50 ` Daniel Vetter
@ 2012-02-10 17:48 ` Daniel Vetter
  1 sibling, 0 replies; 9+ messages in thread
From: Daniel Vetter @ 2012-02-10 17:48 UTC (permalink / raw)
  To: Reese, Armin C; +Cc: intel-gfx@lists.freedesktop.org

Hi Armin,

On Wed, Feb 08, 2012 at 02:16:09AM +0000, Reese, Armin C wrote:
> I worked with Jesse Barnes to develop a sprite demo/test program for
> SNB/IVB.  It uses the new IOCTLs: GETPLANERESOURCES, GETPLANE, and
> SETPLANE.  I also intend on using the program as an example of how to
> set up a mode, display a framebuffer, and display sprite on Intel
> graphics.  The source is attached.  I was hoping it could be put into
> intel_gpu_tools for all to use.

I've noticed that sprite_on.c spews more warnings into my build logs than
the entire rest of intel-gpu-tools. And that is mostly testdisplay.c doing
stupid and ugly things. Care to send in a patch to make building
sprite_on.c less noisy? I have gcc 4.6 here, so that's the benchmark ;-)

Cheers, Daniel
-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
@ 2012-02-11  1:11 Reese, Armin C
  2012-02-11 10:53 ` Daniel Vetter
  0 siblings, 1 reply; 9+ messages in thread
From: Reese, Armin C @ 2012-02-11  1:11 UTC (permalink / raw)
  To: intel-gfx@lists.freedesktop.org


[-- Attachment #1.1: Type: text/plain, Size: 703 bytes --]

Hi Daniel,

Thanks for letting me know about the GCC warning messages.  I did my final tweeks on the program in Android and compiled in that environment.  The compiler there is a bit blind and the build jobs generate so much output, it's easy to ignore warnings.

Anyway, I'll be more careful next time.  The GCC compiler on my Ubuntu 11.04 system is version 4.5.2.  I haven't installed 4.6.2 yet.  GCC produced no warnings after the patch was applied.  I attached both the patch and the new source code for sprite_on.c.

Thanks for taking time for this.  I intend on adding color key support into sprite_on.c to validate operation of that feature, so there will be more patches coming.

Armin

[-- Attachment #1.2: Type: text/html, Size: 2626 bytes --]

[-- Attachment #2: sprite_on.c --]
[-- Type: text/plain, Size: 37900 bytes --]

/*
 * Copyright 2010 Intel Corporation
 *   Armin Reese <armin.c.reese@intel.com>
 *
 * 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.
 */

/*
 * This program is intended for testing sprite functionality.
 */
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "xf86drm.h"
#include "xf86drmMode.h"
#include "i915_drm.h"

#if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY)
#define TEST_PLANES 1
#include "drm_fourcc.h"
#endif

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

struct type_name
{
	int                 type;
	const char          *name;
};

#define type_name_fn(res) \
static const char * res##_str(int type) {			\
	unsigned int i;					\
	for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
		if (res##_names[i].type == type)	\
			return res##_names[i].name;	\
	}						\
	return "(invalid)";				\
}

struct type_name encoder_type_names[] = {
	{ DRM_MODE_ENCODER_NONE, "none" },
	{ DRM_MODE_ENCODER_DAC, "DAC" },
	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
	{ DRM_MODE_ENCODER_TVDAC, "TVDAC" },
};

type_name_fn(encoder_type)

struct type_name connector_status_names[] = {
	{ DRM_MODE_CONNECTED, "connected" },
	{ DRM_MODE_DISCONNECTED, "disconnected" },
	{ DRM_MODE_UNKNOWNCONNECTION, "unknown" },
};

type_name_fn(connector_status)

struct type_name connector_type_names[] = {
	{ DRM_MODE_CONNECTOR_Unknown, "unknown" },
	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
	{ DRM_MODE_CONNECTOR_Composite, "composite" },
	{ DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
	{ DRM_MODE_CONNECTOR_Component, "component" },
	{ DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
	{ DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" },
	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
	{ DRM_MODE_CONNECTOR_TV, "TV" },
	{ DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort" },
};

type_name_fn(connector_type)

/*
 * Mode setting with the kernel interfaces is a bit of a chore.
 * First you have to find the connector in question and make sure the
 * requested mode is available.
 * Then you need to find the encoder attached to that connector so you
 * can bind it with a free crtc.
 */
struct connector
{
	uint32_t            id;
	int                 mode_valid;
	drmModeModeInfo     mode;
	drmModeEncoder      *encoder;
	drmModeConnector    *connector;
	int                 crtc;
	int                 pipe;
};

//*****************************************************************************
//
// usage
//
//*****************************************************************************
static void dump_mode(
        drmModeModeInfo             *mode)
{
	printf("  %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d\n",
	       mode->name,
	       mode->vrefresh,
	       mode->hdisplay,
	       mode->hsync_start,
	       mode->hsync_end,
	       mode->htotal,
	       mode->vdisplay,
	       mode->vsync_start,
	       mode->vsync_end,
	       mode->vtotal,
	       mode->flags,
	       mode->type,
	       mode->clock);
}

//*****************************************************************************
//
// dump_connectors
//
//*****************************************************************************
static void dump_connectors(
        int                         gfx_fd,
        drmModeRes                  *resources)
{
	int i, j;

	printf("Connectors:\n");
	printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
	for (i = 0; i < resources->count_connectors; i++) {
		drmModeConnector *connector;

		connector = drmModeGetConnector(gfx_fd, resources->connectors[i]);
		if (!connector) {
			printf("could not get connector %i: %s\n",
				resources->connectors[i], strerror(errno));
			continue;
		}

		printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
		       connector->connector_id,
		       connector->encoder_id,
		       connector_status_str(connector->connection),
		       connector_type_str(connector->connector_type),
		       connector->mmWidth, connector->mmHeight,
		       connector->count_modes);

		if (!connector->count_modes)
			continue;

		printf("  modes:\n");
		printf("  name refresh (Hz) hdisp hss hse htot vdisp "
		       "vss vse vtot flags type clock\n");
		for (j = 0; j < connector->count_modes; j++)
			dump_mode(&connector->modes[j]);

		drmModeFreeConnector(connector);
	}
	printf("\n");
}

//*****************************************************************************
//
// dump_crtcs
//
//*****************************************************************************
static void dump_crtcs(
        int                         gfx_fd,
        drmModeRes                  *resources)
{
	int i;

	printf("CRTCs:\n");
	printf("id\tfb\tpos\tsize\n");
	for (i = 0; i < resources->count_crtcs; i++) {
		drmModeCrtc *crtc;

		crtc = drmModeGetCrtc(gfx_fd, resources->crtcs[i]);
		if (!crtc) {
			printf("could not get crtc %i: %s\n",
				   resources->crtcs[i],
				   strerror(errno));
			continue;
		}
		printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
		       crtc->crtc_id,
		       crtc->buffer_id,
		       crtc->x, crtc->y,
		       crtc->width, crtc->height);
		dump_mode(&crtc->mode);

		drmModeFreeCrtc(crtc);
	}
	printf("\n");
}

//*****************************************************************************
//
// dump_planes
//
//*****************************************************************************
static void dump_planes(
        int                         gfx_fd,
        drmModeRes                  *resources)
{
	drmModePlaneRes             *plane_resources;
	drmModePlane                *ovr;
	int i;

	plane_resources = drmModeGetPlaneResources(gfx_fd);
	if (!plane_resources) {
		printf("drmModeGetPlaneResources failed: %s\n",
			   strerror(errno));
		return;
	}

	printf("Planes:\n");
	printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n");
	for (i = 0; i < plane_resources->count_planes; i++) {
		ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]);
		if (!ovr) {
			printf("drmModeGetPlane failed: %s\n",
			       strerror(errno));
			continue;
		}

		printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n",
		       ovr->plane_id, ovr->crtc_id, ovr->fb_id,
		       ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
		       ovr->gamma_size);

		drmModeFreePlane(ovr);
	}
	printf("\n");

	return;
}

//*****************************************************************************
//
// connector_find_preferred_mode
//
//*****************************************************************************
static void connector_find_preferred_mode(
        int                     gfx_fd,
        drmModeRes              *gfx_resources,
        struct connector        *c)
{
	drmModeConnector *connector;
	drmModeEncoder *encoder = NULL;
	int i, j;

	/* First, find the connector & mode */
	c->mode_valid = 0;
	connector = drmModeGetConnector(gfx_fd, c->id);
	if (!connector) {
		printf("could not get connector %d: %s\n",
			   c->id,
			   strerror(errno));
		drmModeFreeConnector(connector);
		return;
	}

	if (connector->connection != DRM_MODE_CONNECTED) {
		drmModeFreeConnector(connector);
		return;
	}

	if (!connector->count_modes) {
		printf("connector %d has no modes\n",
		       c->id);
		drmModeFreeConnector(connector);
		return;
	}

	if (connector->connector_id != c->id) {
		printf("connector id doesn't match (%d != %d)\n",
			    connector->connector_id,
			    c->id);
		drmModeFreeConnector(connector);
		return;
	}

	for (j = 0; j < connector->count_modes; j++) {
		c->mode = connector->modes[j];
		if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
			c->mode_valid = 1;
			break;
		}
	}

	if (!c->mode_valid) {
		if (connector->count_modes > 0) {
			/* use the first mode as test mode */
			c->mode = connector->modes[0];
			c->mode_valid = 1;
		} else {
			printf("failed to find any modes on connector %d\n",
				   c->id);
			return;
		}
	}

	/* Now get the encoder */
	for (i = 0; i < connector->count_encoders; i++) {
		encoder = drmModeGetEncoder(gfx_fd, connector->encoders[i]);

		if (!encoder) {
			printf("could not get encoder %i: %s\n",
				   gfx_resources->encoders[i],
				   strerror(errno));
			drmModeFreeEncoder(encoder);
			continue;
		}

		break;
	}

	c->encoder = encoder;

	if (i == gfx_resources->count_encoders) {
		printf("failed to find encoder\n");
		c->mode_valid = 0;
		return;
	}

	/* Find first CRTC not in use */
	for (i = 0; i < gfx_resources->count_crtcs; i++) {
		if (gfx_resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i)))
			break;
	}
	c->crtc = gfx_resources->crtcs[i];
	c->pipe = i;

	gfx_resources->crtcs[i] = 0;

	c->connector = connector;
}

//*****************************************************************************
//
// gem_create
//
//*****************************************************************************
static uint32_t gem_create(int fd, int size)
{
	struct drm_i915_gem_create create;

	create.handle = 0;
	create.size = (size + 4095) & -4096;
	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);

	return create.handle;
}

//*****************************************************************************
//
// gem_mmap
//
//*****************************************************************************
static void *gem_mmap(int fd, uint32_t handle, int size, int prot)
{
	struct drm_i915_gem_mmap_gtt mmap_arg;
	void *ptr;

	mmap_arg.handle = handle;
	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
		return NULL;

	ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
	if (ptr == MAP_FAILED)
		ptr = NULL;

	return ptr;
}

//*****************************************************************************
//
// gem_close
//
//*****************************************************************************
static void gem_close(int fd, uint32_t handle)
{
	struct drm_gem_close close_st;

	close_st.handle = handle;
	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_st);
}

//*****************************************************************************
//
// connector_find_plane
//
//*****************************************************************************
static int connector_find_plane(int gfx_fd, struct connector *c)
{
	drmModePlaneRes *plane_resources;
	drmModePlane *ovr;
	uint32_t id = 0;
	int i;

	plane_resources = drmModeGetPlaneResources(gfx_fd);
	if (!plane_resources) {
		printf("drmModeGetPlaneResources failed: %s\n",
		       strerror(errno));
		return 0;
	}

	for (i = 0; i < plane_resources->count_planes; i++) {
		ovr = drmModeGetPlane(gfx_fd, plane_resources->planes[i]);
		if (!ovr) {
			printf("drmModeGetPlane failed: %s\n",
				   strerror(errno));
			continue;
		}

		if (ovr->possible_crtcs & (1 << c->pipe)) {
			id = ovr->plane_id;
			drmModeFreePlane(ovr);
			break;
		}
		drmModeFreePlane(ovr);
	}

	return id;
}

//*****************************************************************************
//
// prepare_primary_surface
//
//*****************************************************************************
static int prepare_primary_surface(
            int                     fd,
            int                     prim_width,
            int                     prim_height,
            uint32_t                *prim_handle,
            uint32_t                *prim_stride,
            uint32_t                *prim_size,
            int                     tiled)
{
    uint32_t                        bytes_per_pixel = sizeof(uint32_t);
    uint32_t                        *prim_fb_ptr;
    struct drm_i915_gem_set_tiling  set_tiling;

    if (bytes_per_pixel != sizeof(uint32_t)) {
        printf("Bad bytes_per_pixel for primary surface: %d\n",
               bytes_per_pixel);
        return -EINVAL;
    }

    if (tiled) {
        int                         v;

        /* Round the tiling up to the next power-of-two and the
         * region up to the next pot fence size so that this works
         * on all generations.
         *
         * This can still fail if the framebuffer is too large to
         * be tiled. But then that failure is expected.
         */

        v = prim_width * bytes_per_pixel;
        for (*prim_stride = 512; *prim_stride < v; *prim_stride *= 2)
            ;

        v = *prim_stride * prim_height;
        for (*prim_size = 1024*1024; *prim_size < v; *prim_size *= 2)
            ;
    } else {
        /* Scan-out has a 64 byte alignment restriction */
        *prim_stride = (prim_width * bytes_per_pixel + 63) & ~63;
        *prim_size = *prim_stride * prim_height;
    }

    *prim_handle = gem_create(fd, *prim_size);

    if (tiled) {
        set_tiling.handle = *prim_handle;
        set_tiling.tiling_mode = I915_TILING_X;
        set_tiling.stride = *prim_stride;
        if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) {
            printf("Set tiling failed: %s (stride=%d, size=%d)\n",
                    strerror(errno), *prim_stride, *prim_size);
            return -1;
        }
    }

    prim_fb_ptr = gem_mmap(fd,
                           *prim_handle, *prim_size,
                           PROT_READ | PROT_WRITE);

    if (prim_fb_ptr != NULL) {
        // Write primary surface with gray background
        memset(prim_fb_ptr, 0x3f, *prim_size);
        munmap(prim_fb_ptr, *prim_size);
    }

    return 0;
}

//*****************************************************************************
//
// fill_sprite
//
//*****************************************************************************
static void fill_sprite(
        int                             sprite_width,
        int                             sprite_height,
        int                             sprite_stride,
        int                             sprite_index,
        void                            *sprite_fb_ptr)
{
    __u32                           *pLinePat0,
                                    *pLinePat1,
                                    *pLinePtr;
    int                             i,
                                    line;
    int                             stripe_width;

    stripe_width = ((sprite_width > 64) &&
                    (sprite_height > 64)) ? (sprite_index + 1) * 8 :
                                            (sprite_index + 1) * 2;

    // Note:  sprite_stride is in bytes.  pLinePat0 and pLinePat1
    //        are both __u32 pointers
    pLinePat0 = sprite_fb_ptr;
    pLinePat1 = pLinePat0 + (stripe_width * (sprite_stride / sizeof(*pLinePat0)));

    for (i = 0; i < sprite_width; i++) {
        *(pLinePat0 + i) = ((i / stripe_width) & 0x1) ? 0 : ~0;
        *(pLinePat1 + i) = ~(*(pLinePat0 + i));
    }

    for (line = 1; line < sprite_height; line++) {
        if (line == stripe_width) {
            continue;
        }

        pLinePtr = ((line / stripe_width) & 0x1) ? pLinePat1 : pLinePat0;
        memcpy( pLinePat0 + ((sprite_stride / sizeof(*pLinePat0)) * line),
                pLinePtr,
                sprite_width * sizeof(*pLinePat0));
    }

    return;
}

//*****************************************************************************
//
// prepare_sprite_surfaces
//
//*****************************************************************************
static int prepare_sprite_surfaces(
            int                     fd,
            int                     sprite_width,
            int                     sprite_height,
            uint32_t                num_surfaces,
            uint32_t                *sprite_handles,
            uint32_t                *sprite_stride,
            uint32_t                *sprite_size,
            int                     tiled)
{
    uint32_t                        bytes_per_pixel = sizeof(uint32_t);
    uint32_t                        *sprite_fb_ptr;
    struct drm_i915_gem_set_tiling  set_tiling;
    int                             i;

    if (bytes_per_pixel != sizeof(uint32_t)) {
        printf("Bad bytes_per_pixel for sprite: %d\n", bytes_per_pixel);
        return -EINVAL;
    }

    if (tiled) {
        int                         v;

        /* Round the tiling up to the next power-of-two and the
         * region up to the next pot fence size so that this works
         * on all generations.
         *
         * This can still fail if the framebuffer is too large to
         * be tiled. But then that failure is expected.
         */

        v = sprite_width * bytes_per_pixel;
        for (*sprite_stride = 512; *sprite_stride < v; *sprite_stride *= 2)
            ;

        v = *sprite_stride * sprite_height;
        for (*sprite_size = 1024*1024; *sprite_size < v; *sprite_size *= 2)
            ;
    } else {
        /* Scan-out has a 64 byte alignment restriction */
        *sprite_stride = (sprite_width * bytes_per_pixel + 63) & ~63;
        *sprite_size = *sprite_stride * sprite_height;
    }

    for (i = 0; i < num_surfaces;  i++) {
        // Create the sprite surface
        sprite_handles[i] = gem_create(fd, *sprite_size);

        if (tiled) {
            set_tiling.handle = sprite_handles[i];
            set_tiling.tiling_mode = I915_TILING_X;
            set_tiling.stride = *sprite_stride;
            if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) {
                printf("Set tiling failed: %s (stride=%d, size=%d)\n",
                       strerror(errno), *sprite_stride, *sprite_size);
                return -1;
            }
        }

        // Get pointer to the surface
        sprite_fb_ptr = gem_mmap(fd,
                                 sprite_handles[i], *sprite_size,
                                 PROT_READ | PROT_WRITE);

        if (sprite_fb_ptr != NULL) {
            // Fill with checkerboard pattern
            fill_sprite(
                    sprite_width,
                    sprite_height,
                    *sprite_stride,
                    i, sprite_fb_ptr);

            munmap(sprite_fb_ptr, *sprite_size);
        } else {
            i--;
            while (i >= 0) {
                gem_close(fd, sprite_handles[i]);
                i--;
            }
        }
    }

    return 0;
}

//*****************************************************************************
//
// ricochet
//
//*****************************************************************************
static void ricochet(
        int                             tiled,
        int                             sprite_w,
        int                             sprite_h,
        int                             out_w,
        int                             out_h,
        int                             dump_info)
{
    int                                 ret;
    int                                 gfx_fd;
    int                                 keep_moving;
    const int                           num_surfaces = 3;
    uint32_t                            sprite_handles[num_surfaces];
    uint32_t                            sprite_fb_id[num_surfaces];
    int                                 sprite_x;
    int                                 sprite_y;
    uint32_t                            sprite_stride;
    uint32_t                            sprite_size;
    uint32_t                            handles[4],
                                        pitches[4],
                                        offsets[4]; /* we only use [0] */
    uint32_t                            prim_width,
                                        prim_height,
                                        prim_handle,
                                        prim_stride,
                                        prim_size,
                                        prim_fb_id;
    struct drm_intel_sprite_colorkey    set;
    struct connector                    curr_connector;
    drmModeRes                          *gfx_resources;
    struct termios                      orig_term,
                                        curr_term;
    int                                 c_index;
    int                                 sprite_index;
    unsigned int                        sprite_plane_id;
    uint32_t                            plane_flags = 0;
    int                                 delta_x,
                                        delta_y;
    struct timeval                      stTimeVal;
    long long                           currTime,
                                        prevFlipTime,
                                        prevMoveTime,
                                        deltaFlipTime,
                                        deltaMoveTime,
                                        SleepTime;
    char                                key;

    // Open up I915 graphics device
    gfx_fd = drmOpen("i915", NULL);
    if (gfx_fd < 0) {
        printf("Failed to load i915 driver: %s\n", strerror(errno));
        return;
    }

    // Obtain pointer to struct containing graphics resources
    gfx_resources = drmModeGetResources(gfx_fd);
    if (!gfx_resources) {
        printf("drmModeGetResources failed: %s\n", strerror(errno));
        return;
    }

    if (dump_info != 0) {
        dump_connectors(gfx_fd, gfx_resources);
        dump_crtcs(gfx_fd, gfx_resources);
        dump_planes(gfx_fd, gfx_resources);
    }

    // Save previous terminal settings
    if (tcgetattr( 0, &orig_term) != 0) {
        printf("tcgetattr failure: %s\n",
               strerror(errno));
        return;
    }

    // Set up input to return characters immediately
    curr_term = orig_term;
    curr_term.c_lflag &= ~(ICANON | ECHO | ECHONL);
    curr_term.c_cc[VMIN] = 0;       // No minimum number of characters
    curr_term.c_cc[VTIME] = 0 ;     // Return immediately, even if
                                    // nothing has been entered.
    if (tcsetattr( 0, TCSANOW, &curr_term) != 0) {
        printf("tcgetattr failure: %s\n",
               strerror(errno));
        return;
    }

    // Cycle through all connectors and display the flying sprite
    // where there are displays attached and the hardware will support it.
    for (c_index = 0; c_index < gfx_resources->count_connectors; c_index++)  {
        curr_connector.id = gfx_resources->connectors[c_index];

        // Find the native (preferred) display mode
        connector_find_preferred_mode(gfx_fd, gfx_resources, &curr_connector);
        if (curr_connector.mode_valid == 0) {
            printf("No valid preferred mode detected\n");
            goto out;
        }

        // Determine if sprite hardware is available on pipe
        // associated with this connector.
        sprite_plane_id = connector_find_plane(gfx_fd, &curr_connector);
        if (!sprite_plane_id) {
            printf("Failed to find sprite plane on crtc\n");
            goto out;
        }

        // Width and height of preferred mode
        prim_width = curr_connector.mode.hdisplay;
        prim_height = curr_connector.mode.vdisplay;

        // Allocate and fill memory for primary surface
        ret = prepare_primary_surface(
                      gfx_fd,
                      prim_width,
                      prim_height,
                      &prim_handle,
                      &prim_stride,
                      &prim_size,
                      tiled);
        if (ret != 0) {
            printf("Failed to add primary fb (%dx%d): %s\n",
                prim_width, prim_height, strerror(errno));
            goto out;
        }

        // Add the primary surface framebuffer
        ret = drmModeAddFB(
                      gfx_fd,
                      prim_width,
                      prim_height,
                      24, 32,
                      prim_stride,
                      prim_handle,
                      &prim_fb_id);
        gem_close(gfx_fd, prim_handle);

        if (ret != 0) {
            printf("Failed to add primary fb (%dx%d): %s\n",
                prim_width, prim_height, strerror(errno));
            goto out;
        }

        // Allocate and fill sprite surfaces
        ret = prepare_sprite_surfaces(
                      gfx_fd,
                      sprite_w,
                      sprite_h,
                      num_surfaces,
                      &sprite_handles[0],
                      &sprite_stride,
                      &sprite_size,
                      tiled);
        if (ret != 0) {
            printf("Preparation of sprite surfaces failed %dx%d\n",
                    sprite_w, sprite_h);
            goto out;
        }

        // Add the sprite framebuffers
        for (sprite_index = 0; sprite_index < num_surfaces; sprite_index++) {
            handles[0] = sprite_handles[sprite_index];
            handles[1] = handles[0];
            handles[2] = handles[0];
            handles[3] = handles[0];
            pitches[0] = sprite_stride;
            pitches[1] = sprite_stride;
            pitches[2] = sprite_stride;
            pitches[3] = sprite_stride;
            memset(offsets, 0, sizeof(offsets));

            ret = drmModeAddFB2(
                          gfx_fd,
                          sprite_w, sprite_h, DRM_FORMAT_XRGB8888,
                          handles, pitches, offsets, &sprite_fb_id[sprite_index],
                          plane_flags);
            gem_close(gfx_fd, sprite_handles[sprite_index]);

            if (ret) {
                printf("Failed to add sprite fb (%dx%d): %s\n",
                       sprite_w, sprite_h, strerror(errno));

                sprite_index--;
                while (sprite_index >= 0) {
                    drmModeRmFB(gfx_fd, sprite_fb_id[sprite_index]);
                    sprite_index--;
                }
                goto out;
            }
        }

        if (dump_info != 0) {
            printf("Displayed Mode Connector struct:\n"
                   "    .id = %d\n"
                   "    .mode_valid = %d\n"
                   "    .crtc = %d\n"
                   "    .pipe = %d\n"
                   "    drmModeModeInfo ...\n"
                   "        .name = %s\n"
                   "        .type = %d\n"
                   "        .flags = %08x\n"
                   "    drmModeEncoder ...\n"
                   "        .encoder_id = %d\n"
                   "        .encoder_type = %d (%s)\n"
                   "        .crtc_id = %d\n"
                   "        .possible_crtcs = %d\n"
                   "        .possible_clones = %d\n"
                   "    drmModeConnector ...\n"
                   "        .connector_id = %d\n"
                   "        .encoder_id = %d\n"
                   "        .connector_type = %d (%s)\n"
                   "        .connector_type_id = %d\n\n",
                   curr_connector.id,
                   curr_connector.mode_valid,
                   curr_connector.crtc,
                   curr_connector.pipe,
                   curr_connector.mode.name,
                   curr_connector.mode.type,
                   curr_connector.mode.flags,
                   curr_connector.encoder->encoder_id,
                   curr_connector.encoder->encoder_type,
                   encoder_type_str(curr_connector.encoder->encoder_type),
                   curr_connector.encoder->crtc_id,
                   curr_connector.encoder->possible_crtcs,
                   curr_connector.encoder->possible_clones,
                   curr_connector.connector->connector_id,
                   curr_connector.connector->encoder_id,
                   curr_connector.connector->connector_type,
                   connector_type_str(curr_connector.connector->connector_type),
                   curr_connector.connector->connector_type_id);

            printf("Sprite surface dimensions = %dx%d\n"
                   "Sprite output dimensions = %dx%d\n"
                    "Press any key to continue >\n",
                    sprite_w,
                    sprite_h,
                    out_w,
                    out_h);

            // Wait for a key-press
            while( read(0, &key, 1) == 0);
            // Purge unread characters
            tcflush(0, TCIFLUSH);
        }

        // Set up the primary display mode
        ret = drmModeSetCrtc(
                      gfx_fd,
                      curr_connector.crtc,
                      prim_fb_id,
                      0, 0,
                      &curr_connector.id,
                      1,
                      &curr_connector.mode);
        if (ret != 0)
        {
            printf("Failed to set mode (%dx%d@%dHz): %s\n",
                prim_width, prim_height, curr_connector.mode.vrefresh,
                strerror(errno));
            continue;
        }

        // Set the sprite colorkey state
        set.plane_id = sprite_plane_id;
        set.min_value = 0;
        set.max_value = 0;
        set.flags = I915_SET_COLORKEY_NONE;
        ret = drmCommandWrite(gfx_fd, DRM_I915_SET_SPRITE_COLORKEY, &set,
                      sizeof(set));

        // Set up sprite output dimensions, initial position, etc.
        if (out_w > prim_width / 2)
            out_w = prim_width / 2;
        if (out_h > prim_height / 2)
            out_h = prim_height / 2;

        delta_x = 3;
        delta_y = 4;
        sprite_x = (prim_width / 2) - (out_w / 2);
        sprite_y = (prim_height / 2) - (out_h / 2);

        currTime = 0;
        prevFlipTime = 0;       // Will force immediate sprite flip
        prevMoveTime = 0;       // Will force immediate sprite move
        deltaFlipTime = 500000; // Flip sprite surface every 1/2 second
        deltaMoveTime = 100000; // Move sprite every 100 ms
        sprite_index = num_surfaces - 1;
        keep_moving = 1;

        // Bounce sprite off the walls
        while (keep_moving) {
            // Obtain system time in usec.
            if (gettimeofday( &stTimeVal, NULL ) != 0) {
                printf("gettimeofday error: %s\n",
                       strerror(errno));
            } else {
                currTime = ((long long)stTimeVal.tv_sec * 1000000) + stTimeVal.tv_usec;
            }

            // Check if it's time to flip the sprite surface
            if (currTime - prevFlipTime > deltaFlipTime)  {
                sprite_index = (sprite_index + 1) % num_surfaces;

                prevFlipTime = currTime;
            }

            // Move the sprite on the screen and flip
            // the surface if the index has changed
            if (drmModeSetPlane(
                        gfx_fd,
                        sprite_plane_id,
                        curr_connector.crtc,
                        sprite_fb_id[sprite_index],
                        plane_flags,
                        sprite_x, sprite_y,
                        out_w, out_h,
                        0, 0,
                        sprite_w, sprite_h)) {
                printf("Failed to enable sprite plane: %s\n",
                       strerror(errno));
            }

            // Check if it's time to move the sprite surface
            if (currTime - prevMoveTime > deltaMoveTime)  {

                // Compute the next position for sprite
                sprite_x += delta_x;
                sprite_y += delta_y;
                if (sprite_x < 0) {
                    sprite_x = 0;
                    delta_x = -delta_x;
                }
                else if (sprite_x > prim_width - out_w) {
                    sprite_x = prim_width - out_w;
                    delta_x = -delta_x;
                }

                if (sprite_y < 0) {
                    sprite_y = 0;
                    delta_y = -delta_y;
                }
                else if (sprite_y > prim_height - out_h) {
                    sprite_y = prim_height - out_h;
                    delta_y = -delta_y;
                }

                prevMoveTime = currTime;
            }

            // Fetch a key from input (non-blocking)
            if (read(0, &key, 1) == 1) {
                switch (key) {
                case 'q':       // Kill the program
                case 'Q':
                    goto out;
                    break;
                case 's':       // Slow down sprite movement;
                     deltaMoveTime = (deltaMoveTime * 100) / 90;
                   if (deltaMoveTime > 800000) {
                        deltaMoveTime = 800000;
                    }
                    break;
                case 'S':       // Speed up sprite movement;
                    deltaMoveTime = (deltaMoveTime * 100) / 110;
                    if (deltaMoveTime < 2000) {
                        deltaMoveTime = 2000;
                    }
                    break;
                case 'f':       // Slow down sprite flipping;
                    deltaFlipTime = (deltaFlipTime * 100) / 90;
                    if (deltaFlipTime > 1000000) {
                        deltaFlipTime = 1000000;
                    }
                    break;
                case 'F':       // Speed up sprite flipping;
                    deltaFlipTime = (deltaFlipTime * 100) / 110;
                    if (deltaFlipTime < 20000) {
                        deltaFlipTime = 20000;
                    }
                    break;
                case 'n':       // Next connector
                case 'N':
                    keep_moving = 0;
                    break;
                default:
                    break;
                }

                // Purge unread characters
                tcflush(0, TCIFLUSH);
            }

            // Wait for min of flip or move deltas
            SleepTime = (deltaFlipTime < deltaMoveTime) ?
                            deltaFlipTime : deltaMoveTime;
            usleep(SleepTime);
        }
    }

out:
    // Purge unread characters
    tcflush(0, TCIFLUSH);
    // Restore previous terminal settings
    if (tcsetattr( 0, TCSANOW, &orig_term) != 0) {
        printf("tcgetattr failure: %s\n",
               strerror(errno));
        return;
    }

    drmModeFreeResources(gfx_resources);
}

//*****************************************************************************
//
// usage
//
//*****************************************************************************
static void usage(char *name)
{
	printf("usage: %s -s <plane width>x<plane height> [-dhto]\n"
           "\t-d\t[optional] dump mode information\n"
           "\t-h\t[optional] output help message\n"
	       "\t-t\t[optional] enable tiling\n"
           "\t-o\t[optional] <output rect width>x<output rect height>\n\n"
           "Keyboard control for sprite movement and flip rate ...\n"
           "\t'q' or 'Q' - Quit the program\n"
           "\t'n' or 'N' - Switch to next display\n"
           "\t's'        - Slow sprite movement\n"
           "\t'S'        - Speed up sprite movement\n"
           "\t'f'        - Slow sprite surface flipping\n"
           "\t'F'        - Speed up sprite surface flipping\n",
           name);
}

//*****************************************************************************
//
// main
//
//*****************************************************************************
int main(int argc, char **argv)
{
	int                 c;
	int                 test_overlay = 0,
	                    enable_tiling = 0,
                        dump_info = 0;
    int                 plane_width = 0,
                        plane_height = 0,
                        out_width = 0,
                        out_height = 0;
	static char         optstr[] = "ds:o:th";

	opterr = 0;
	while ((c = getopt(argc, argv, optstr)) != -1) {
		switch (c) {
        case 'd':               // Dump information
            dump_info = 1;
            break;
		case 't':               // Tiling enable
			enable_tiling = 1;
			break;
		case 's':               // Surface dimensions
            if (sscanf(optarg, "%dx%d",
                       &plane_width, &plane_height) != 2)
                usage(argv[0]);
		    test_overlay = 1;
			break;
        case 'o':               // Output dimensions
            if (sscanf(optarg, "%dx%d",
                       &out_width, &out_height) != 2)
                usage(argv[0]);
            break;
		default:
			printf("unknown option %c\n", c);
			/* fall through */
		case 'h':               // Help!
			usage(argv[0]);
			goto out;
		}
	}

	if (test_overlay) {
	    if (out_width < (plane_width / 2)) {
	        out_width = plane_width;
	    }

	    if (out_height < (plane_height / 2)) {
	        out_height = plane_height;
	    }

	    ricochet(enable_tiling,
	             plane_width,
	             plane_height,
	             out_width,
	             out_height,
                 dump_info);
	} else {
	    printf("Sprite dimensions are required:\n");
	    usage(argv[0]);
	}

out:
	exit(0);
}


[-- Attachment #3: sprite_on_patch --]
[-- Type: application/octet-stream, Size: 3746 bytes --]

--- /home/acreese/PerfWS/LPIA/acreese_LPIA/gfx_Development/Source/Linux/hardware/intel/test/sprite_on.c
+++ /home/acreese/OTC/drm-overlays/intel-gpu-tools/tests/sprite_on.c
@@ -52,12 +52,12 @@
 
 struct type_name
 {
-	int type;
-	char *name;
+	int                 type;
+	const char          *name;
 };
 
 #define type_name_fn(res) \
-static char * res##_str(int type) {			\
+static const char * res##_str(int type) {			\
 	unsigned int i;					\
 	for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
 		if (res##_names[i].type == type)	\
@@ -455,50 +455,6 @@
 	}
 
 	return id;
-}
-
-//*****************************************************************************
-//
-// disable_planes
-//
-//*****************************************************************************
-static void disable_planes(
-        int                     gfx_fd)
-{
-	struct                  connector *connectors;
-    drmModeRes              *resources;
-	int                     c;
-
-	resources = drmModeGetResources(gfx_fd);
-	if (!resources) {
-		printf("drmModeGetResources failed: %s\n",
-			   strerror(errno));
-		return;
-	}
-
-	connectors = calloc(resources->count_connectors,
-			    sizeof(struct connector));
-	if (!connectors)
-		return;
-
-	/* Find any connected displays */
-	for (c = 0; c < resources->count_connectors; c++) {
-		uint32_t sprite_plane_id;
-
-		sprite_plane_id = connector_find_plane(gfx_fd, &connectors[c]);
-		if (!sprite_plane_id) {
-			printf("failed to find plane for crtc\n");
-			return;
-		}
-		if (drmModeSetPlane(gfx_fd, sprite_plane_id, connectors[c].crtc, 0, 0, 0,
-				    0, 0, 0, 0, 0, 0, 0)) {
-			printf("failed to disable plane: %s\n",
-				strerror(errno));
-			return;
-		}
-	}
-	drmModeFreeResources(resources);
-	return;
 }
 
 //*****************************************************************************
@@ -919,14 +875,14 @@
                    "        .flags = %08x\n"
                    "    drmModeEncoder ...\n"
                    "        .encoder_id = %d\n"
-                   "        .encoder_type = %d\n"
+                   "        .encoder_type = %d (%s)\n"
                    "        .crtc_id = %d\n"
                    "        .possible_crtcs = %d\n"
                    "        .possible_clones = %d\n"
                    "    drmModeConnector ...\n"
                    "        .connector_id = %d\n"
                    "        .encoder_id = %d\n"
-                   "        .connector_type = %d\n"
+                   "        .connector_type = %d (%s)\n"
                    "        .connector_type_id = %d\n\n",
                    curr_connector.id,
                    curr_connector.mode_valid,
@@ -937,12 +893,14 @@
                    curr_connector.mode.flags,
                    curr_connector.encoder->encoder_id,
                    curr_connector.encoder->encoder_type,
+                   encoder_type_str(curr_connector.encoder->encoder_type),
                    curr_connector.encoder->crtc_id,
                    curr_connector.encoder->possible_crtcs,
                    curr_connector.encoder->possible_clones,
                    curr_connector.connector->connector_id,
                    curr_connector.connector->encoder_id,
                    curr_connector.connector->connector_type,
+                   connector_type_str(curr_connector.connector->connector_type),
                    curr_connector.connector->connector_type_id);
 
             printf("Sprite surface dimensions = %dx%d\n"
@@ -988,7 +946,7 @@
         if (out_w > prim_width / 2)
             out_w = prim_width / 2;
         if (out_h > prim_height / 2)
-            out_h - prim_height / 2;
+            out_h = prim_height / 2;
 
         delta_x = 3;
         delta_y = 4;


[-- Attachment #4: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-11  1:11 Reese, Armin C
@ 2012-02-11 10:53 ` Daniel Vetter
  2012-02-17 19:22   ` Reese, Armin C
  0 siblings, 1 reply; 9+ messages in thread
From: Daniel Vetter @ 2012-02-11 10:53 UTC (permalink / raw)
  To: Reese, Armin C; +Cc: intel-gfx@lists.freedesktop.org

Hi Armin,

On Sat, Feb 11, 2012 at 01:11:16AM +0000, Reese, Armin C wrote:
> Thanks for letting me know about the GCC warning messages.  I did my
> final tweeks on the program in Android and compiled in that environment.
> The compiler there is a bit blind and the build jobs generate so much
> output, it's easy to ignore warnings.

Np. Btw I've just merged the Android build patches for i-g-t in case
that's useful for you.

> Anyway, I'll be more careful next time.  The GCC compiler on my Ubuntu
> 11.04 system is version 4.5.2.  I haven't installed 4.6.2 yet.  GCC
> produced no warnings after the patch was applied.  I attached both the
> patch and the new source code for sprite_on.c.

Thanks, patch looks nice. Can I have it as a git patch? That's much esier
to handle than your patch which contains funny paths into your own home
directory ;-)

/me is a lazy bastard

> Thanks for taking time for this.  I intend on adding color key support
> into sprite_on.c to validate operation of that feature, so there will be
> more patches coming.

Awesome, but I that case if more stuff is to show up, I _really_ prefer
git patches.

Cheers, Daniel
-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-11 10:53 ` Daniel Vetter
@ 2012-02-17 19:22   ` Reese, Armin C
  2012-02-18 16:59     ` Paul Menzel
  2012-02-22 10:00     ` Daniel Vetter
  0 siblings, 2 replies; 9+ messages in thread
From: Reese, Armin C @ 2012-02-17 19:22 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx@lists.freedesktop.org

[-- Attachment #1: Type: text/plain, Size: 1671 bytes --]

Yeah, I got lazy and just did a diff.  Sorry about that ...

Here is a real git patch made by "git diff sprite_on.c"

Thanks & have a good weekend,
Armin

-----Original Message-----
From: Daniel Vetter [mailto:daniel.vetter@ffwll.ch] On Behalf Of Daniel Vetter
Sent: Saturday, February 11, 2012 2:53 AM
To: Reese, Armin C
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [Intel-gfx] SNB/IVB sprite demo

Hi Armin,

On Sat, Feb 11, 2012 at 01:11:16AM +0000, Reese, Armin C wrote:
> Thanks for letting me know about the GCC warning messages.  I did my 
> final tweeks on the program in Android and compiled in that environment.
> The compiler there is a bit blind and the build jobs generate so much 
> output, it's easy to ignore warnings.

Np. Btw I've just merged the Android build patches for i-g-t in case that's useful for you.

> Anyway, I'll be more careful next time.  The GCC compiler on my Ubuntu
> 11.04 system is version 4.5.2.  I haven't installed 4.6.2 yet.  GCC 
> produced no warnings after the patch was applied.  I attached both the 
> patch and the new source code for sprite_on.c.

Thanks, patch looks nice. Can I have it as a git patch? That's much esier to handle than your patch which contains funny paths into your own home directory ;-)

/me is a lazy bastard

> Thanks for taking time for this.  I intend on adding color key support 
> into sprite_on.c to validate operation of that feature, so there will 
> be more patches coming.

Awesome, but I that case if more stuff is to show up, I _really_ prefer git patches.

Cheers, Daniel
--
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

[-- Attachment #2: sprite_on_patch --]
[-- Type: application/octet-stream, Size: 3927 bytes --]

diff --git a/tests/sprite_on.c b/tests/sprite_on.c
index 49ccff2..585189d 100644
--- a/tests/sprite_on.c
+++ b/tests/sprite_on.c
@@ -52,12 +52,12 @@
 
 struct type_name
 {
-	int type;
-	char *name;
+	int                 type;
+	const char          *name;
 };
 
 #define type_name_fn(res) \
-static char * res##_str(int type) {			\
+static const char * res##_str(int type) {			\
 	unsigned int i;					\
 	for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
 		if (res##_names[i].type == type)	\
@@ -459,50 +459,6 @@ static int connector_find_plane(int gfx_fd, struct connector *c)
 
 //*****************************************************************************
 //
-// disable_planes
-//
-//*****************************************************************************
-static void disable_planes(
-        int                     gfx_fd)
-{
-	struct                  connector *connectors;
-    drmModeRes              *resources;
-	int                     c;
-
-	resources = drmModeGetResources(gfx_fd);
-	if (!resources) {
-		printf("drmModeGetResources failed: %s\n",
-			   strerror(errno));
-		return;
-	}
-
-	connectors = calloc(resources->count_connectors,
-			    sizeof(struct connector));
-	if (!connectors)
-		return;
-
-	/* Find any connected displays */
-	for (c = 0; c < resources->count_connectors; c++) {
-		uint32_t sprite_plane_id;
-
-		sprite_plane_id = connector_find_plane(gfx_fd, &connectors[c]);
-		if (!sprite_plane_id) {
-			printf("failed to find plane for crtc\n");
-			return;
-		}
-		if (drmModeSetPlane(gfx_fd, sprite_plane_id, connectors[c].crtc, 0, 0, 0,
-				    0, 0, 0, 0, 0, 0, 0)) {
-			printf("failed to disable plane: %s\n",
-				strerror(errno));
-			return;
-		}
-	}
-	drmModeFreeResources(resources);
-	return;
-}
-
-//*****************************************************************************
-//
 // prepare_primary_surface
 //
 //*****************************************************************************
@@ -919,14 +875,14 @@ static void ricochet(
                    "        .flags = %08x\n"
                    "    drmModeEncoder ...\n"
                    "        .encoder_id = %d\n"
-                   "        .encoder_type = %d\n"
+                   "        .encoder_type = %d (%s)\n"
                    "        .crtc_id = %d\n"
                    "        .possible_crtcs = %d\n"
                    "        .possible_clones = %d\n"
                    "    drmModeConnector ...\n"
                    "        .connector_id = %d\n"
                    "        .encoder_id = %d\n"
-                   "        .connector_type = %d\n"
+                   "        .connector_type = %d (%s)\n"
                    "        .connector_type_id = %d\n\n",
                    curr_connector.id,
                    curr_connector.mode_valid,
@@ -937,12 +893,14 @@ static void ricochet(
                    curr_connector.mode.flags,
                    curr_connector.encoder->encoder_id,
                    curr_connector.encoder->encoder_type,
+                   encoder_type_str(curr_connector.encoder->encoder_type),
                    curr_connector.encoder->crtc_id,
                    curr_connector.encoder->possible_crtcs,
                    curr_connector.encoder->possible_clones,
                    curr_connector.connector->connector_id,
                    curr_connector.connector->encoder_id,
                    curr_connector.connector->connector_type,
+                   connector_type_str(curr_connector.connector->connector_type),
                    curr_connector.connector->connector_type_id);
 
             printf("Sprite surface dimensions = %dx%d\n"
@@ -988,7 +946,7 @@ static void ricochet(
         if (out_w > prim_width / 2)
             out_w = prim_width / 2;
         if (out_h > prim_height / 2)
-            out_h - prim_height / 2;
+            out_h = prim_height / 2;
 
         delta_x = 3;
         delta_y = 4;

[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-17 19:22   ` Reese, Armin C
@ 2012-02-18 16:59     ` Paul Menzel
  2012-02-22 10:00     ` Daniel Vetter
  1 sibling, 0 replies; 9+ messages in thread
From: Paul Menzel @ 2012-02-18 16:59 UTC (permalink / raw)
  To: Reese, Armin C; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 283 bytes --]

Am Freitag, den 17.02.2012, 19:22 +0000 schrieb Reese, Armin C:
> Yeah, I got lazy and just did a diff.  Sorry about that ...
> 
> Here is a real git patch made by "git diff sprite_on.c"

I think a real git patch is made by doing `git format-patch -1 -s`.


Thanks,

Paul

[-- Attachment #1.2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: SNB/IVB sprite demo
  2012-02-17 19:22   ` Reese, Armin C
  2012-02-18 16:59     ` Paul Menzel
@ 2012-02-22 10:00     ` Daniel Vetter
  1 sibling, 0 replies; 9+ messages in thread
From: Daniel Vetter @ 2012-02-22 10:00 UTC (permalink / raw)
  To: Reese, Armin C; +Cc: intel-gfx@lists.freedesktop.org

On Fri, Feb 17, 2012 at 07:22:19PM +0000, Reese, Armin C wrote:
> Yeah, I got lazy and just did a diff.  Sorry about that ...
> 
> Here is a real git patch made by "git diff sprite_on.c"
> 
> Thanks & have a good weekend,

Thanks for the build noise fixes, patch applied. Fyi git patches
preferred, and I've also moved around sprite_on.c a bit, so this patch was
a bit a hassle to apply ...

Yours, Daniel
-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-02-22 10:00 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-08  2:16 SNB/IVB sprite demo Reese, Armin C
2012-02-08 15:50 ` Daniel Vetter
2012-02-08 18:14   ` Jesse Barnes
2012-02-10 17:48 ` Daniel Vetter
  -- strict thread matches above, loose matches on Subject: below --
2012-02-11  1:11 Reese, Armin C
2012-02-11 10:53 ` Daniel Vetter
2012-02-17 19:22   ` Reese, Armin C
2012-02-18 16:59     ` Paul Menzel
2012-02-22 10:00     ` Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.