On Sat, Feb 01, 2014 at 12:43:48AM +0530, sagar.a.kamble@xxxxxxxxx wrote: > From: Sagar Kamble <sagar.a.kamble@xxxxxxxxx> > > This test will verify the 180 degree rotation of sprite and crtc planes. > It will allow user to control rotation separately for crtc and sprite > planes. > > Signed-off-by: Sagar Kamble <sagar.a.kamble@xxxxxxxxx> What I actually want for upstreaming is a fully automated testcase as part of our i-g-t testsuite which uses the CRC support. Having testing tools for developers is neat, but if it's not automated it's essentially untested. I don't mind merging this if there's someone else who'll ack it though. -Daniel > --- > demos/Makefile.am | 1 + > demos/intel_plane_rotate.c | 929 +++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 930 insertions(+) > create mode 100644 demos/intel_plane_rotate.c > > diff --git a/demos/Makefile.am b/demos/Makefile.am > index 49804d7..1cee2b6 100644 > --- a/demos/Makefile.am > +++ b/demos/Makefile.am > @@ -1,5 +1,6 @@ > bin_PROGRAMS = \ > intel_sprite_on \ > + intel_plane_rotate \ > $(NULL) > > AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib > diff --git a/demos/intel_plane_rotate.c b/demos/intel_plane_rotate.c > new file mode 100644 > index 0000000..b203d75 > --- /dev/null > +++ b/demos/intel_plane_rotate.c > @@ -0,0 +1,929 @@ > +/* > + * Copyright © 2014 Intel Corporation > + * > + * 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 (including the next > + * paragraph) 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. > + * > + * > + * Author: > + * Sagar Kamble <sagar.a.kamble@xxxxxxxxx> > + */ > + > +/* > + * Most of the functions are reused from intel_sprite_on test by Armeen Reese > + * <armin.c.reese@xxxxxxxxx> > + * This program is intended for testing CRTC and plane rotation 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 "i915_drm.h" > +#include "drmtest.h" > +#include "igt_kms.h" > + > +#if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY) > +#define TEST_PLANES 1 > +#include "drm_fourcc.h" > +#endif > + > +#define DRM_ROTATE_0 0 > +#define DRM_ROTATE_90 1 > +#define DRM_ROTATE_180 2 > +#define DRM_ROTATE_270 3 > +#define DRM_REFLECT_X 4 > +#define DRM_REFLECT_Y 5 > + > +#define BIT(x) (1 << x) > + > +/* > + * 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; > +}; > + > +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); > +} > + > +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, > + kmstest_connector_status_str(connector->connection), > + kmstest_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"); > +} > + > +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"); > +} > + > +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; > +} > + > +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; > +} > + > +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; > +} > + > + > +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, *stripe_ptr; > + int stripe_size; > + > + 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) > + gem_set_tiling(fd, *prim_handle, I915_TILING_X, *prim_stride); > + > + prim_fb_ptr = gem_mmap(fd, *prim_handle, *prim_size, PROT_READ | PROT_WRITE); > + > + if (prim_fb_ptr != NULL) { > + // Write primary surface with stripe of shades from black to white > + > + stripe_ptr = prim_fb_ptr; > + stripe_size = *prim_size / 4; > + for (int i = 0; i < 4; i++) > + { > + memset(stripe_ptr, i*0x32, stripe_size); //Setting shades for stripes > + stripe_ptr+=(stripe_size/4); > + } > + munmap(prim_fb_ptr, *prim_size); > + } > + return 0; > +} > + > +static void fill_sprite(int sprite_width, int sprite_height, int sprite_stride, > + void *sprite_fb_ptr) > +{ > + __u32 *pLinePat0, > + *pLinePat1, > + *pLinePtr; > + int i, > + line; > + int stripe_width; > + > + stripe_width = sprite_height/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) = 0xff; //Blue Stripe > + *(pLinePat1 + i) = 0xff0000; //Red Stripe > + } > + > + 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; > +} > + > +static int prepare_sprite_surfaces(int fd, int sprite_width, int sprite_height, > + uint32_t *sprite_handle, uint32_t *sprite_stride, uint32_t *sprite_size, > + int tiled) > +{ > + uint32_t bytes_per_pixel = sizeof(uint32_t); > + uint32_t *sprite_fb_ptr; > + > + 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; > + } > + > + // Create the sprite surface > + *sprite_handle = gem_create(fd, *sprite_size); > + > + if (tiled) > + gem_set_tiling(fd, *sprite_handle, I915_TILING_X, *sprite_stride); > + > + // Get pointer to the surface > + sprite_fb_ptr = gem_mmap(fd, > + *sprite_handle, *sprite_size, > + PROT_READ | PROT_WRITE); > + > + if (sprite_fb_ptr != NULL) { > + // Fill with stripes of colors > + fill_sprite(sprite_width, sprite_height, *sprite_stride, sprite_fb_ptr); > + > + munmap(sprite_fb_ptr, *sprite_size); > + } else { > + gem_close(fd, *sprite_handle); > + printf("\nFailed to mmap gem object for sprite"); > + } > + > + return 0; > +} > + > +void set_plane_rotation(int drm_fd, bool sprite, uint32_t plane_id, uint64_t rotation) > +{ > + int i = 0, j = 0, ret = 0; > + drmModeObjectPropertiesPtr props = NULL; > + > + props = drmModeObjectGetProperties(drm_fd, plane_id, > + sprite ? DRM_MODE_OBJECT_PLANE : DRM_MODE_OBJECT_CRTC); > + printf("\nPlane id: 0x%x, Count_props=%d ", plane_id, props->count_props); > + > + for (i = 0; i < props->count_props; i++) > + { > + drmModePropertyPtr prop = drmModeGetProperty(drm_fd, props->props[i]); > + printf("\nProp->name=%s ", prop->name); > + > + if (strcmp(prop->name, "rotation") == 0) > + { > + igt_assert(prop->flags & DRM_MODE_PROP_BITMASK); > + printf("\nRotation property enum count %d", prop->count_enums); > + printf("\nRotation type\tValue"); > + for (j = 0; j < prop->count_enums; j++) > + printf("\n%s: 0x%x", prop->enums[j].name, prop->enums[j].value); > + > + ret = drmModeObjectSetProperty(drm_fd, plane_id, sprite ? DRM_MODE_OBJECT_PLANE : DRM_MODE_OBJECT_CRTC, > + (uint32_t)prop->prop_id, rotation); > + if (ret) > + { > + printf("\nRotation setting\(0x%x\) failed !!!", rotation); > + printf("\nMappings: Bit-0:0, Bit-1:90, Bit-2:180, Bit-3:270, Bit-4:X-Reflection, Bit-5:Y-Reflection\n"); > + return; > + } > + else > + printf("\nPlane with id 0x%x is rotated with setting 0x%x", plane_id, rotation); > + } > + drmModeFreeProperty(prop); > + } > + drmModeFreeObjectProperties(props); > +} > + > +static void rotate(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; > + uint32_t sprite_handle; > + uint32_t sprite_fb_id; > + 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; > + unsigned int sprite_plane_id; > + uint32_t plane_flags = 0; > + char key; > + bool rotate_crtc = false; > + bool rotate_sprite = false; > + uint64_t rotation_crtc = BIT(DRM_ROTATE_0), > + rotation_sprite = BIT(DRM_ROTATE_0); > + > + // Open up I915 graphics device > + gfx_fd = drmOpen("i915", "pci:0000:00:02.0"); > + 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, &sprite_handle, > + &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 > + handles[0] = sprite_handle; > + 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, plane_flags); > + gem_close(gfx_fd, sprite_handle); > + > + if (ret) { > + printf("Failed to add sprite fb (%dx%d): %s\n", > + sprite_w, sprite_h, strerror(errno)); > + > + drmModeRmFB(gfx_fd, sprite_fb_id); > + 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, > + kmstest_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, > + kmstest_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)); > + assert(ret == 0); > + > + // 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; > + > + sprite_x = (prim_width / 2) - (out_w / 2); > + sprite_y = (prim_height / 2) - (out_h / 2); > + > + keep_moving = 1; > + > + // Bounce sprite off the walls > + while (keep_moving) { > + > + // Move the sprite on the screen and flip > + // the surface if the index has changed > + // NB: sprite_w and sprite_h must be 16.16 fixed point, herego << 16 > + if (drmModeSetPlane(gfx_fd, sprite_plane_id, curr_connector.crtc, > + sprite_fb_id, plane_flags, > + sprite_x, sprite_y, > + out_w, out_h, > + 0, 0, > + sprite_w << 16, sprite_h << 16)) > + printf("Failed to enable sprite plane: %s\n", strerror(errno)); > + > + if (rotate_crtc) > + set_plane_rotation(gfx_fd, false, curr_connector.crtc, rotation_crtc); > + if (rotate_sprite) > + set_plane_rotation(gfx_fd, true, sprite_plane_id, rotation_sprite); > + > + // 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 '0': > + rotation_crtc = BIT(DRM_ROTATE_0); > + rotation_sprite = rotation_crtc; > + break; > + case '1': > + rotation_crtc = BIT(DRM_ROTATE_90); > + rotation_sprite = rotation_crtc; > + break; > + case '2': > + rotation_crtc = BIT(DRM_ROTATE_180); > + rotation_sprite = rotation_crtc; > + break; > + case '3': > + rotation_crtc = BIT(DRM_ROTATE_270); > + rotation_sprite = rotation_crtc; > + break; > + case '4': > + rotation_crtc = BIT(DRM_REFLECT_X); > + rotation_sprite = rotation_crtc; > + break; > + case '5': > + rotation_crtc = BIT(DRM_REFLECT_Y); > + rotation_sprite = rotation_crtc; > + break; > + case 'c': > + rotate_crtc = true; > + rotation_crtc = BIT(DRM_ROTATE_0); > + break; > + case 'C': > + rotate_crtc = false; > + break; > + case 's': > + rotate_sprite = true; > + rotation_sprite = BIT(DRM_ROTATE_0); > + break; > + case 'S': > + rotate_sprite = false; > + break; > + case 'n': // Next connector > + case 'N': > + keep_moving = 0; > + break; > + default: > + break; > + } > + > + // Purge unread characters > + tcflush(0, TCIFLUSH); > + } > + > + usleep(500000); > + } > + } > + > +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); > +} > + > +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 and crtc rotation ...\n" > + "\t'q' or 'Q' - Quit the program\n" > + "\t'n' or 'N' - Switch to next display\n" > + "\t'c' - Enable/Disable Crtc Rotation\n" > + "\t's' - Enable/Disable Sprite Rotation\n" > + "\t'0' - 0 degree Rotation\n" > + "\t'1' - 90 degree Rotation\n" > + "\t'2' - 180 degree Rotation\n" > + "\t'3' - 270 degree Rotation\n" > + "\t'4' - X Reflection\n" > + "\t'5' - Y Reflection\n", > + name); > +} > + > +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; > + > + rotate(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); > +} > -- > 1.8.5 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx