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); }
/* * 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; }