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 = NULL;
	int                                 *sprite_y = NULL;
	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 = NULL;
	uint32_t                            plane_flags = 0;
	int                                 *delta_x = NULL,
					    *delta_y = NULL;
	struct timeval                      stTimeVal;
	long long                           currTime,
	     prevFlipTime,
	     prevMoveTime,
	     deltaFlipTime,
	     deltaMoveTime,
	     SleepTime;
	char                                key;
	int				    sprite_plane_count = 0;
	int 				    i;
	// 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_count = connector_find_plane(gfx_fd, &curr_connector,
							  &sprite_plane_id);
		if (!sprite_plane_count) {
			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,
				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
		for(i = 0; i < sprite_plane_count; i++) {
			set.plane_id = sprite_plane_id[i];
			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;

		delta_x = (int *) malloc(sprite_plane_count * sizeof(int));
		delta_y = (int *) malloc(sprite_plane_count * sizeof(int));
		sprite_x = (int *) malloc(sprite_plane_count * sizeof(int));
		sprite_y = (int *) malloc(sprite_plane_count * sizeof(int));

		/* Initializing the coordinates (x,y) of the available sprites on the
		 * connector, equally spaced along the diagonal of the rectangle
		 * {(0,0),(prim_width/2, prim_height/2)}.
		 */
		for(i = 0; i < sprite_plane_count; i++) {
			delta_x[i] = 3;
			delta_y[i] = 4;
			sprite_x[i] = i * (prim_width / (2 * sprite_plane_count));
			sprite_y[i] = i * (prim_height / (2 * sprite_plane_count));
		}

		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
			// NB: sprite_w and sprite_h must be 16.16 fixed point, herego << 16
			for(i = 0; i < sprite_plane_count; i++) {
				if (drmModeSetPlane(gfx_fd, sprite_plane_id[i],
						    curr_connector.crtc,
						    sprite_fb_id[sprite_index],
						    plane_flags,
						    sprite_x[i], sprite_y[i],
						    out_w, out_h,
						    0, 0,
						    sprite_w << 16, sprite_h << 16))
					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
				for(i = 0; i < sprite_plane_count; i++) {
					sprite_x[i] += delta_x[i];
					sprite_y[i] += delta_y[i];
					if (sprite_x[i] < 0) {
						sprite_x[i] = 0;
						delta_x[i] = -delta_x[i];
					}
					else if (sprite_x[i] > prim_width - out_w) {
						sprite_x[i] = prim_width - out_w;
						delta_x[i] = -delta_x[i];
					}

					if (sprite_y[i] < 0) {
						sprite_y[i] = 0;
						delta_y[i] = -delta_y[i];
					}
					else if (sprite_y[i] > prim_height - out_h) {
						sprite_y[i] = prim_height - out_h;
						delta_y[i] = -delta_y[i];
					}
				}
				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);
		}

		free(sprite_plane_id);
		free(sprite_x);
		free(sprite_y);
		free(delta_x);
		free(delta_y);
		sprite_plane_id = NULL;
		sprite_plane_count = 0;
		sprite_x = sprite_y = delta_x = delta_y = NULL;
	}

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);
}
예제 #2
0
/*
 * Re-probe outputs and light up as many as possible.
 *
 * On Intel, we have two CRTCs that we can drive independently with
 * different timings and scanout buffers.
 *
 * Each connector has a corresponding encoder, except in the SDVO case
 * where an encoder may have multiple connectors.
 */
int update_display(void)
{
	struct connector *connectors;
	int c;

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

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

	if (test_preferred_mode || test_all_modes ||
	    force_mode || specified_disp_id != -1) {
		unsigned long crtc_idx_mask = -1UL;

		/* Find any connected displays */
		for (c = 0; c < resources->count_connectors; c++) {
			struct connector *connector = &connectors[c];

			connector->id = resources->connectors[c];
			if (specified_disp_id != -1 &&
			    connector->id != specified_disp_id)
				continue;

			connector_find_preferred_mode(connector->id,
						      crtc_idx_mask,
						      specified_mode_num,
						      connector);
			if (!connector->mode_valid)
				continue;

			set_mode(connector);

			if (test_preferred_mode || force_mode ||
			    specified_mode_num != -1)
				crtc_idx_mask &= ~(1 << connector->crtc_idx);

		}
	}

	if (test_stereo_modes) {
		for (c = 0; c < resources->count_connectors; c++) {
			struct connector *connector = &connectors[c];

			connector->id = resources->connectors[c];
			if (specified_disp_id != -1 &&
			    connector->id != specified_disp_id)
				continue;

			connector_find_preferred_mode(connector->id,
						      -1UL,
						      specified_mode_num,
						      connector);
			if (!connector->mode_valid)
				continue;

			set_stereo_mode(connector);
		}
	}

	free(connectors);
	drmModeFreeResources(resources);
	return 1;
}