static void test(data_t *data) { igt_output_t *output = data->output; struct igt_fb *fb = &data->fb[1]; drmModeModeInfo *mode; cairo_t *cr; uint32_t caching; void *buf; igt_crc_t crc; mode = igt_output_get_mode(output); /* create a non-white fb where we can pwrite later */ igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, fb); cr = igt_get_cairo_ctx(data->drm_fd, fb); igt_paint_test_pattern(cr, fb->width, fb->height); cairo_destroy(cr); /* flip to it to make it UC/WC and fully flushed */ drmModeSetPlane(data->drm_fd, data->primary->drm_plane->plane_id, output->config.crtc->crtc_id, fb->fb_id, 0, 0, 0, fb->width, fb->height, 0, 0, fb->width << 16, fb->height << 16); /* flip back the original white buffer */ drmModeSetPlane(data->drm_fd, data->primary->drm_plane->plane_id, output->config.crtc->crtc_id, data->fb[0].fb_id, 0, 0, 0, fb->width, fb->height, 0, 0, fb->width << 16, fb->height << 16); /* make sure caching mode has become UC/WT */ caching = gem_get_caching(data->drm_fd, fb->gem_handle); igt_assert(caching == I915_CACHING_NONE || caching == I915_CACHING_DISPLAY); /* use pwrite to make the other fb all white too */ buf = malloc(fb->size); igt_assert(buf != NULL); memset(buf, 0xff, fb->size); gem_write(data->drm_fd, fb->gem_handle, 0, buf, fb->size); free(buf); /* and flip to it */ drmModeSetPlane(data->drm_fd, data->primary->drm_plane->plane_id, output->config.crtc->crtc_id, fb->fb_id, 0, 0, 0, fb->width, fb->height, 0, 0, fb->width << 16, fb->height << 16); /* check that the crc is as expected, which requires that caches got flushed */ igt_pipe_crc_collect_crc(data->pipe_crc, &crc); igt_assert_crc_equal(&crc, &data->ref_crc); }
void QEglFSKmsGbmScreen::flip() { if (!m_gbm_surface) { qWarning("Cannot sync before platform init!"); return; } m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface); if (!m_gbm_bo_next) { qWarning("Could not lock GBM surface front buffer!"); return; } FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next); QKmsOutput &op(output()); const int fd = device()->fd(); const uint32_t w = op.modes[op.mode].hdisplay; const uint32_t h = op.modes[op.mode].vdisplay; if (!op.mode_set) { int ret = drmModeSetCrtc(fd, op.crtc_id, fb->fb, 0, 0, &op.connector_id, 1, &op.modes[op.mode]); if (ret == -1) { qErrnoWarning(errno, "Could not set DRM mode!"); } else { op.mode_set = true; setPowerState(PowerStateOn); if (!op.plane_set) { op.plane_set = true; if (op.wants_plane) { int ret = drmModeSetPlane(fd, op.plane_id, op.crtc_id, uint32_t(-1), 0, 0, 0, w, h, 0 << 16, 0 << 16, w << 16, h << 16); if (ret == -1) qErrnoWarning(errno, "drmModeSetPlane failed"); } } } } int ret = drmModePageFlip(fd, op.crtc_id, fb->fb, DRM_MODE_PAGE_FLIP_EVENT, this); if (ret) { qErrnoWarning("Could not queue DRM page flip!"); gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next); m_gbm_bo_next = Q_NULLPTR; } }
static void plane_commit_legacy(struct kms_atomic_plane_state *plane, enum kms_atomic_check_relax relax) { do_or_die(drmModeSetPlane(plane->state->desc->fd, plane->obj, plane->crtc_id, plane->fb_id, 0, plane->crtc_x, plane->crtc_y, plane->crtc_w, plane->crtc_h, plane->src_x, plane->src_y, plane->src_w, plane->src_h)); plane_check_current_state(plane, relax); }
int kms_plane_set(struct kms_plane *plane, struct kms_framebuffer *fb, unsigned int x, unsigned int y) { struct kms_device *device = plane->device; int err; err = drmModeSetPlane(device->fd, plane->id, plane->crtc->id, fb->id, 0, x, y, fb->width, fb->height, 0 << 16, 0 << 16, fb->width << 16, fb->height << 16); if (err < 0) return -errno; return 0; }
void QEglFSKmsEglDeviceScreen::waitForFlip() { QKmsOutput &op(output()); const int fd = device()->fd(); const uint32_t w = op.modes[op.mode].hdisplay; const uint32_t h = op.modes[op.mode].vdisplay; if (!op.mode_set) { op.mode_set = true; drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id); const bool alreadySet = currentMode && currentMode->width == w && currentMode->height == h; if (currentMode) drmModeFreeCrtc(currentMode); if (alreadySet) { // Maybe detecting the DPMS mode could help here, but there are no properties // exposed on the connector apparently. So rely on an env var for now. static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE"); if (!alwaysDoSet) { qCDebug(qLcEglfsKmsDebug, "Mode already set"); return; } } qCDebug(qLcEglfsKmsDebug, "Setting mode"); int ret = drmModeSetCrtc(fd, op.crtc_id, uint32_t(-1), 0, 0, &op.connector_id, 1, &op.modes[op.mode]); if (ret) qErrnoWarning(errno, "drmModeSetCrtc failed"); } if (!op.plane_set) { op.plane_set = true; if (op.wants_plane) { qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.plane_id); int ret = drmModeSetPlane(fd, op.plane_id, op.crtc_id, uint32_t(-1), 0, 0, 0, w, h, 0 << 16, 0 << 16, w << 16, h << 16); if (ret == -1) qErrnoWarning(errno, "drmModeSetPlane failed"); } } }
void put_sp_plane(struct sp_plane *plane) { drmModePlanePtr p; /* Get the latest plane information (most notably the crtc_id) */ p = drmModeGetPlane(plane->dev->fd, plane->plane->plane_id); if (p) plane->plane = p; if (plane->plane->crtc_id) drmModeSetPlane(plane->dev->fd, plane->plane->plane_id, plane->plane->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (plane->bo) { free_sp_bo(plane->bo); plane->bo = NULL; } plane->in_use = 0; }
int set_sp_plane(struct sp_dev *dev, struct sp_plane *plane, struct sp_crtc *crtc, int x, int y) { int ret; uint32_t w, h; w = plane->bo->width; h = plane->bo->height; if ((w + x) > crtc->crtc->mode.hdisplay) w = crtc->crtc->mode.hdisplay - x; if ((h + y) > crtc->crtc->mode.vdisplay) h = crtc->crtc->mode.vdisplay - y; ret = drmModeSetPlane(dev->fd, plane->plane->plane_id, crtc->crtc->crtc_id, plane->bo->fb_id, 0, x, y, w, h, 0, 0, w << 16, h << 16); if (ret) { printf("failed to set plane to crtc ret=%d\n", ret); return ret; } return ret; }
static DFBResult drmkmsPlaneRemoveRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data ) { DFBResult ret; DRMKMSData *drmkms = driver_data; DRMKMSLayerData *data = layer_data; D_DEBUG_AT( DRMKMS_Layer, "%s()\n", __FUNCTION__ ); if (!data->muted) { ret = drmModeSetPlane(drmkms->fd, data->plane->plane_id, drmkms->encoder[0]->crtc_id, 0, /* plane_flags */ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0); if (ret) { D_PERROR( "DRMKMS/Layer/Remove: Failed setting plane configuration!\n" ); return ret; } } return DFB_OK; }
static DFBResult drmkmsPlaneSetRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreLayerRegionConfig *config, CoreLayerRegionConfigFlags updated, CoreSurface *surface, CorePalette *palette, CoreSurfaceBufferLock *left_lock, CoreSurfaceBufferLock *right_lock ) { int ret; bool unmute = false; DRMKMSData *drmkms = driver_data; DRMKMSLayerData *data = layer_data; D_DEBUG_AT( DRMKMS_Layer, "%s()\n", __FUNCTION__ ); if ((updated & CLRCF_OPACITY) && data->muted && config->opacity) unmute = true; if ((updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_BUFFERMODE | CLRCF_DEST | CLRCF_SOURCE)) || unmute) { ret = drmModeSetPlane(drmkms->fd, data->plane->plane_id, drmkms->encoder[0]->crtc_id, (u32)(long)left_lock->handle, /* plane_flags */ 0, config->dest.x, config->dest.y, config->dest.w, config->dest.h, config->source.x << 16, config->source.y <<16, config->source.w << 16, config->source.h << 16); if (ret) { D_INFO( "DirectFB/DRMKMS: drmModeSetPlane(plane_id=%d, fb_id=%d , dest=%d,%d-%dx%d, src=%d,%d-%dx%d) failed! (%d)\n", data->plane->plane_id, (u32)(long)left_lock->handle, DFB_RECTANGLE_VALS(&config->dest), DFB_RECTANGLE_VALS(&config->source), ret ); return DFB_FAILURE; } data->config = config; data->muted = false; } if ((updated & (CLRCF_SRCKEY | CLRCF_OPTIONS)) && data->colorkey_propid) { uint32_t drm_colorkey = config->src_key.r << 16 | config->src_key.g << 8 | config->src_key.b; if (config->options & DLOP_SRC_COLORKEY) drm_colorkey |= 0x01000000; ret = drmModeObjectSetProperty( drmkms->fd, data->plane->plane_id, DRM_MODE_OBJECT_PLANE, data->colorkey_propid, drm_colorkey ); if (ret) { D_ERROR( "DirectFB/DRMKMS: drmModeObjectSetProperty() failed setting colorkey\n"); return DFB_FAILURE; } } if (updated & CLRCF_OPACITY) { if (config->opacity == 0) { ret = drmModeSetPlane(drmkms->fd, data->plane->plane_id, drmkms->encoder[0]->crtc_id, 0, /* plane_flags */ 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0); if (ret) { D_ERROR( "DirectFB/DRMKMS: drmModeSetPlane() failed disabling plane\n"); return DFB_FAILURE; } data->muted = true; } else if (data->alpha_propid) { ret = drmModeObjectSetProperty( drmkms->fd, data->plane->plane_id, DRM_MODE_OBJECT_PLANE, data->alpha_propid, config->opacity ); if (ret) { D_ERROR( "DirectFB/DRMKMS: drmModeObjectSetProperty() failed setting alpha\n"); return DFB_FAILURE; } } } return DFB_OK; }
int main(int argc, char *argv[]) { uint64_t has_dumb; int ret, fd, opt, i; void *map; struct drm_mode_destroy_dumb dreq; struct drm_mode_create_dumb creq; struct drm_mode_map_dumb mreq; drmModePlaneRes *resources; drmModePlane *plane = NULL; uint32_t handle, stride, size; uint32_t plane_id, crtc_id; uint32_t width, height; uint32_t posx, posy; uint32_t fb; /* parse command line */ while ((opt = getopt(argc, argv, "x:y:w:v:c:p:h")) != -1) { switch (opt) { case 'x': posx = atoi(optarg); break; case 'y': posy = atoi(optarg); break; case 'w': width = atoi(optarg); break; case 'v': height = atoi(optarg); break; case 'p': plane_id = atoi(optarg); break; case 'c': crtc_id = atoi(optarg); break; case 'h': default: printf("usage: -h] -c <connector> -e <encoder> -m <mode>\n"); printf("\t-h: this help message\n"); printf("\t-c <crtc> crtc id, default is 0\n"); printf("\t-p <plane> plane id, default is 0\n"); printf("\t-x <posx> plane top left corner xpos, default is 0'\n"); printf("\t-y <posy> plane top left corner ypos, default is 0'\n"); printf("\t-w <width> plane width, default is 0'\n"); printf("\t-v <height> plane height, default is 0'\n"); exit(0); } } /* open drm device */ fd = open(device_name, O_RDWR | O_CLOEXEC); if (fd < 0) { perror("cannot open drm device"); exit(-1); } drmSetMaster(fd); /* check dumb buffer support */ if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) { perror("DRM_CAP_DUMB_BUFFER ioctl"); ret = -EFAULT; goto err_close; } if (!has_dumb) { fprintf(stderr, "driver does not support dumb buffers\n"); ret = -EFAULT; goto err_close; } /* get plane */ resources = drmModeGetPlaneResources(fd); if (!resources || resources->count_planes == 0) { fprintf(stderr, "drmModeGetPlaneResources failed\n"); ret = -ENODEV; goto err_close; } for (i = 0; i < resources->count_planes; i++) { drmModePlane *p = drmModeGetPlane(fd, resources->planes[i]); if (!p) continue; if (p->plane_id == plane_id) { plane = p; break; } drmModeFreePlane(plane); } if (!plane) { fprintf(stderr, "couldn't find specified plane\n"); ret = -ENODEV; goto err_close; } /* create dumb buffer object */ memset(&creq, 0, sizeof(creq)); creq.height = height; creq.width = width; creq.bpp = 32; ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); if (ret) { fprintf(stderr, "failed drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB)\n"); goto err_close; } handle = creq.handle; stride = creq.pitch; size = creq.size; /* create framebuffer for dumb buffer object */ ret = drmModeAddFB(fd, width, height, 24, 32, stride, handle, &fb); if (ret) { fprintf(stderr, "cannot add drm framebuffer for dumb buffer object\n"); goto err_destroy_dumb; } /* map dumb buffer object */ memset(&mreq, 0, sizeof(mreq)); mreq.handle = handle; ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); if (ret) { fprintf(stderr, "failed drmIoctl(DRM_IOCTL_MODE_MAP_DUMB)\n"); goto err_destroy_fb; } map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); if (map == MAP_FAILED) { fprintf(stderr, "cannot mmap dumb buffer\n"); goto err_destroy_fb; } /* setup new plane */ ret = drmModeSetPlane(fd, plane_id, crtc_id, fb, 0, posx, posy, width, height, 0, 0, width << 16, height << 16); if (ret) { fprintf(stderr, "cannot set plane\n"); goto err_unmap; } /* draw on the screen */ draw_test_image((uint32_t *) map, width, height); getchar(); draw_fancy_image((uint32_t *) map, width, height); getchar(); drmModeSetPlane(fd, plane_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); err_unmap: if (map) munmap(map, size); err_destroy_fb: drmModeRmFB(fd, fb); err_destroy_dumb: memset(&dreq, 0, sizeof(dreq)); dreq.handle = handle; ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); if (ret) { fprintf(stderr, "cannot destroy dumb buffer\n"); } err_close: close(fd); return ret; }
static void plane_commit(struct my_ctx *ctx, struct my_plane *p) { struct my_crtc *c = container_of(p->base.crtc, struct my_crtc, base); int r; if (!p->dirty && !c->primary->dirty && !c->dirty_mode) return; if (c->primary != p) plane_commit(ctx, c->primary); assert(p->buf == NULL); #ifndef LEGACY_API if (!ctx->set) { ctx->set = drmModePropertySetAlloc(); if (!ctx->set) return; ctx->flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK; } #endif if (p->dirty && p->enable) { p->buf = surface_get_front(ctx->fd, &p->surf.base); if (!p->buf) { if (c->primary->buf) { surface_buffer_put_fb(&c->primary->surf.base, c->primary->buf); c->primary->buf = NULL; } return; } p->buf->fence = next_fence; } #ifndef LEGACY_API if (c->dirty_mode) { r = drmModeSetCrtc(ctx->fd, c->base.crtc_id, c->primary->buf->fb_id, 0, 0, &c->base.connector_id, 1, &c->mode); if (r) printf("drmModeSetCrtc() failed %d:%s\n", errno, strerror(errno)); } if (p->dirty) { drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.fb, p->buf ? p->buf->fb_id : 0); /* note: setting CRTC but not FB angers danvet */ drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.crtc, p->buf ? p->base.crtc->crtc_id : 0); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.src_x, p->src.x1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.src_y, p->src.y1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.src_w, p->src.x2 - p->src.x1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.src_h, p->src.y2 - p->src.y1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.crtc_x, p->dst.x1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.crtc_y, p->dst.y1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.crtc_w, p->dst.x2 - p->dst.x1); drmModePropertySetAdd(ctx->set, p->base.plane_id, p->prop.crtc_h, p->dst.y2 - p->dst.y1); } #else if (c->dirty || c->dirty_mode) { r = drmModeSetCrtc(ctx->fd, c->base.crtc_id, c->buf->fb_id, 0, 0, &c->base.connector_id, 1, &c->mode); if (r) printf("drmModeSetCrtc() failed %d:%s\n", errno, strerror(errno)); } if (p->dirty) { r = drmModeSetPlane(ctx->fd, p->base.plane_id, p->base.crtc->crtc_id, p->buf ? p->buf->fb_id : 0, 0, p->dst.x1, p->dst.y1, p->dst.x2 - p->dst.x1, p->dst.y2 - p->dst.y1, p->src.x1, p->src.y1, p->src.x2 - p->src.x1, p->src.y2 - p->src.y1); if (r) printf("drmModeSetPlane() failed %d:%s\n", errno, strerror(errno)); } #endif }
/* This configures our only overlay plane to render the given surface. */ static void drm_plane_setup(struct drm_surface *surface) { int i,j; char fmt_name[5]; /* Get plane resources */ drmModePlane *plane; drmModePlaneRes *plane_resources; plane_resources = drmModeGetPlaneResources(drm.fd); if (!plane_resources) { RARCH_ERR ("DRM: No scaling planes available!\n"); } RARCH_LOG ("DRM: Number of planes on FD %d is %d\n", drm.fd, plane_resources->count_planes); /* dump_planes(drm.fd); */ /* Look for a plane/overlay we can use with the configured CRTC * Find a plane which can be connected to our CRTC. Find the * CRTC index first, then iterate over available planes. * Yes, strangely we need the in-use CRTC index to mask possible_crtc * during the planes iteration... */ unsigned int crtc_index = 0; for (i = 0; i < (unsigned int)drm.resources->count_crtcs; i++) { if (drm.crtc_id == drm.resources->crtcs[i]) { crtc_index = i; RARCH_LOG ("DRM: CRTC index found %d with ID %d\n", crtc_index, drm.crtc_id); break; } } /* Programmer!! Save your sanity!! Primary planes have to * cover the entire CRTC, and if you don't do that, you * will get dmesg error "Plane must cover entire CRTC". * * Look at linux/source/drivers/gpu/drm/drm_plane_helper.c comments for more info. * Also, primary planes can't be scaled: we need overlays for that. */ for (i = 0; i < plane_resources->count_planes; i++) { plane = drmModeGetPlane(drm.fd, plane_resources->planes[i]); if (!(plane->possible_crtcs & (1 << crtc_index))){ RARCH_LOG ("DRM: plane with ID %d can't be used with current CRTC\n", plane->plane_id); continue; } /* We are only interested in overlay planes. No overlay, no fun. * (no scaling, must cover crtc..etc) so we skip primary planes */ if (drm_plane_type(plane) != DRM_PLANE_TYPE_OVERLAY) { RARCH_LOG ("DRM: plane with ID %d is not an overlay. May be primary or cursor. Not usable.\n", plane->plane_id); continue; } if (!format_support(plane, surface->pixformat)) { RARCH_LOG ("DRM: plane with ID %d does not support framebuffer format\n", plane->plane_id); continue; } drm.plane_id = plane->plane_id; drmModeFreePlane(plane); } if (!drm.plane_id) { RARCH_LOG ("DRM: couldn't find an usable overlay plane for current CRTC and framebuffer pixel formal.\n"); deinit_drm(); exit (0); } else { RARCH_LOG ("DRM: using plane/overlay ID %d\n", drm.plane_id); } /* We are going to be changing the framebuffer ID property of the chosen overlay every time * we do a pageflip, so we get the property ID here to have it handy on the PageFlip function. */ drm.plane_fb_prop_id = get_plane_prop_id(drm.plane_id, "FB_ID"); if (!drm.plane_fb_prop_id) { RARCH_LOG("DRM: Can't get the FB property ID for plane(%u)\n", drm.plane_id); } /* Note src coords (last 4 args) are in Q16 format * crtc_w and crtc_h are the final size with applied scale/ratio. * crtc_x and crtc_y are the position of the plane * pw and ph are the input size: the size of the area we read from the fb. */ uint32_t plane_flags = 0; uint32_t plane_w = drm.current_mode->vdisplay * surface->aspect;; uint32_t plane_h = drm.current_mode->vdisplay; /* If we obtain a scaled image width that is bigger than the physical screen width, * then we keep the physical screen width as our maximun width. */ if (plane_w > drm.current_mode->hdisplay) plane_w = drm.current_mode->hdisplay; uint32_t plane_x = (drm.current_mode->hdisplay - plane_w) / 2; uint32_t plane_y = (drm.current_mode->vdisplay - plane_h) / 2; uint32_t src_w = surface->src_width; uint32_t src_h = surface->src_height; uint32_t src_x = 0; uint32_t src_y = 0; /* We have to set a buffer for the plane, whatever buffer we want, * but we must set a buffer so the plane starts reading from it now. */ if (drmModeSetPlane(drm.fd, drm.plane_id, drm.crtc_id, surface->pages[surface->flip_page].buf.fb_id, plane_flags, plane_x, plane_y, plane_w, plane_h, src_x<<16, src_y<<16, src_w<<16, src_h<<16)) { RARCH_ERR("DRM: failed to enable plane: %s\n", strerror(errno)); } RARCH_LOG("DRM: src_w %d, src_h %d, plane_w %d, plane_h %d\n", src_w, src_h, plane_w, plane_h); /* Report what plane (of overlay type) we're using. */ drm_format_name(surface->pixformat, fmt_name); RARCH_LOG("DRM: Using plane with ID %d on CRTC ID %d format %s\n", drm.plane_id, drm.crtc_id, fmt_name); }
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); }
static GstFlowReturn gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) { gint ret; GstBuffer *buffer; guint32 fb_id; GstKMSSink *self; GstVideoCropMeta *crop; GstVideoRectangle src = { 0, }; GstVideoRectangle dst = { 0, }; GstVideoRectangle result; GstFlowReturn res; self = GST_KMS_SINK (vsink); res = GST_FLOW_ERROR; buffer = gst_kms_sink_get_input_buffer (self, buf); if (!buffer) return GST_FLOW_ERROR; fb_id = gst_kms_memory_get_fb_id (gst_buffer_peek_memory (buffer, 0)); if (fb_id == 0) goto buffer_invalid; GST_TRACE_OBJECT (self, "displaying fb %d", fb_id); if (self->modesetting_enabled) { self->buffer_id = fb_id; goto sync_frame; } if ((crop = gst_buffer_get_video_crop_meta (buffer))) { GstVideoInfo vinfo = self->vinfo; vinfo.width = crop->width; vinfo.height = crop->height; if (!gst_kms_sink_calculate_display_ratio (self, &vinfo)) goto no_disp_ratio; src.x = crop->x; src.y = crop->y; } src.w = GST_VIDEO_SINK_WIDTH (self); src.h = GST_VIDEO_SINK_HEIGHT (self); dst.w = self->hdisplay; dst.h = self->vdisplay; gst_video_sink_center_rect (src, dst, &result, TRUE); if (crop) { src.w = crop->width; src.h = crop->height; } else { src.w = GST_VIDEO_INFO_WIDTH (&self->vinfo); src.h = GST_VIDEO_INFO_HEIGHT (&self->vinfo); } GST_TRACE_OBJECT (self, "drmModeSetPlane at (%i,%i) %ix%i sourcing at (%i,%i) %ix%i", result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h); ret = drmModeSetPlane (self->fd, self->plane_id, self->crtc_id, fb_id, 0, result.x, result.y, result.w, result.h, /* source/cropping coordinates are given in Q16 */ src.x << 16, src.y << 16, src.w << 16, src.h << 16); if (ret) goto set_plane_failed; sync_frame: /* Wait for the previous frame to complete redraw */ if (!gst_kms_sink_sync (self)) goto bail; gst_buffer_replace (&self->last_buffer, buffer); g_clear_pointer (&self->tmp_kmsmem, gst_memory_unref); res = GST_FLOW_OK; bail: gst_buffer_unref (buffer); return res; /* ERRORS */ buffer_invalid: { GST_ERROR_OBJECT (self, "invalid buffer: it doesn't have a fb id"); goto bail; } set_plane_failed: { GST_DEBUG_OBJECT (self, "result = { %d, %d, %d, %d} / " "src = { %d, %d, %d %d } / dst = { %d, %d, %d %d }", result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h, dst.x, dst.y, dst.w, dst.h); GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (NULL), ("drmModeSetPlane failed: %s (%d)", strerror (-ret), ret)); goto bail; } no_disp_ratio: { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video.")); goto bail; } }
// ----------------------------------------------------------------------------- bool WindowOffscreenEGL::initDrm(const char *name, EGLAttrib *layerAttribs, int &dispWidth, int &dispHeight) { // screen attached to which connector id? int conn = 0; int crtc = -1, plane = -1; int xSurfSize = 0, ySurfSize = 0; int xOffset = 0, yOffset = 0; // auto detect resolution by setting modesize to 0 //int xModeSize = dispWidth, yModeSize = dispHeight; int xModeSize = 0, yModeSize = 0; int bounce = 0; int drmFd; uint32_t drmConnId, drmEncId, drmCrtcId, drmPlaneId; uint32_t crtcMask; drmModeRes *drmResInfo = nullptr; drmModePlaneRes *drmPlaneResInfo = nullptr; drmModeCrtc *drmCrtcInfo = nullptr; drmModeConnector *drmConnInfo = nullptr; drmModeEncoder *drmEncInfo = nullptr; drmModePlane *drmPlaneInfo = nullptr; int drmModeIndex = 0; bool setMode = false; drmFd = drmOpen(name, nullptr); if (drmFd == -1) { std::cout << "Couldn't open device file " << name << std::endl; return false; } // Obtain DRM-KMS resources drmResInfo = drmModeGetResources(drmFd); if (!drmResInfo) { std::cout << "Couldn't obtain DRM-KMS resources" << std::endl; return false; } // If a specific crtc was requested, make sure it exists if (crtc >= drmResInfo->count_crtcs) { std::cout << "Requested crtc index (" << crtc << ") exceeds count (" << drmResInfo->count_crtcs << ")" << std::endl; return false; } crtcMask = (crtc >= 0) ? (1 << crtc) : ((1 << drmResInfo->count_crtcs) - 1); // If drawing to a plane is requested, obtain the plane info if (plane >= 0) { drmPlaneResInfo = drmModeGetPlaneResources(drmFd); if (!drmPlaneResInfo) { std::cout << "Unable to obtain plane resource list" << std::endl; return false; } if (plane >= (int)drmPlaneResInfo->count_planes) { std::cout << "Requested plane index (" << plane << ") exceeds count (" << drmPlaneResInfo->count_planes << ")" << std::endl; return false; } drmPlaneId = drmPlaneResInfo->planes[plane]; drmPlaneInfo = drmModeGetPlane(drmFd, drmPlaneId); if (!drmPlaneInfo) { std::cout << "Unable to obtain info for plane (" << drmPlaneId << ")" << std::endl; return false; } crtcMask &= drmPlaneInfo->possible_crtcs; if (!crtcMask) { std::cout << "Requested crtc and plane not compatible" << std::endl; return false; } std::cout << "Obtained plane information\n" << std::endl; } // Query info for requested connector if (conn >= drmResInfo->count_connectors) { std::cout << "Requested connector index (" << conn << ") exceeds count (" << drmResInfo->count_connectors << ")" << std::endl; return false; } drmConnId = drmResInfo->connectors[conn]; drmConnInfo = drmModeGetConnector(drmFd, drmConnId); if (!drmConnInfo) { std::cout << "Unable to obtain info for connector (" << drmConnId << ")" << std::endl; return false; } else if (drmConnInfo->connection != DRM_MODE_CONNECTED) { std::cout << "Requested connnector is not connected (mode=" << drmConnInfo->connection << ")" << std::endl; return false; } else if (drmConnInfo->count_modes <= 0) { std::cout << "Requested connnector has no available modes" << std::endl; return false; } // If there is already an encoder attached to the connector, choose // it unless not compatible with crtc/plane drmEncId = drmConnInfo->encoder_id; drmEncInfo = drmModeGetEncoder(drmFd, drmEncId); if (drmEncInfo) { if (!(drmEncInfo->possible_crtcs & crtcMask)) { drmModeFreeEncoder(drmEncInfo); drmEncInfo = nullptr; } } // If we didn't have a suitable encoder, find one if (!drmEncInfo) { int i; for (i = 0; i < drmConnInfo->count_encoders; ++i) { drmEncId = drmConnInfo->encoders[i]; drmEncInfo = drmModeGetEncoder(drmFd, drmEncId); if (drmEncInfo) { if (crtcMask & drmEncInfo->possible_crtcs) { crtcMask &= drmEncInfo->possible_crtcs; break; } drmModeFreeEncoder(drmEncInfo); drmEncInfo = nullptr; } } if (i == drmConnInfo->count_encoders) { std::cout << "Unable to find suitable encoder" << std::endl; return false; } } // Select a suitable crtc. Give preference to any that is already // attached to the encoder. drmCrtcId = drmEncInfo->crtc_id; for (int i = 0; i < drmResInfo->count_crtcs; ++i) { if (crtcMask & (1 << i)) { drmCrtcId = drmResInfo->crtcs[i]; if (drmResInfo->crtcs[i] == drmEncInfo->crtc_id) { break; } } } // Query info for crtc drmCrtcInfo = drmModeGetCrtc(drmFd, drmCrtcId); if (!drmCrtcInfo) { std::cout << "Unable to obtain info for crtc (" << drmCrtcId << ")" << std::endl; return false; } // If dimensions are specified and not using a plane, find closest mode if ((xModeSize || yModeSize) && (plane < 0)) { // Find best fit among available modes int best_index = 0; int best_fit = 0x7fffffff; for (int i = 0; i < drmConnInfo->count_modes; ++i) { drmModeModeInfoPtr mode = drmConnInfo->modes + i; int fit = 0; if (xModeSize) { fit += abs((int)mode->hdisplay - xModeSize) * (int)mode->vdisplay; } if (yModeSize) { fit += abs((int)mode->vdisplay - yModeSize) * (int)mode->hdisplay; } if (fit < best_fit) { best_index = i; best_fit = fit; } std::cout << i << ": " << (int)mode->hdisplay << " x " << (int)mode->vdisplay - yModeSize << std::endl; } // Choose this size/mode drmModeIndex = best_index; xModeSize = (int)drmConnInfo->modes[best_index].hdisplay; yModeSize = (int)drmConnInfo->modes[best_index].vdisplay; } // We'll only set the mode if we have to. if ((drmConnInfo->encoder_id != drmEncId) || (drmEncInfo->crtc_id != drmCrtcId) || !drmCrtcInfo->mode_valid || ((plane < 0) && xModeSize && (xModeSize != (int)drmCrtcInfo->mode.hdisplay)) || ((plane < 0) && yModeSize && (yModeSize != (int)drmCrtcInfo->mode.vdisplay))) { setMode = true; } // If dimensions haven't been specified, figure out good values to use if (!xModeSize || !yModeSize) { // If mode requires reset, just pick the first one available // from the connector if (setMode) { xModeSize = (int)drmConnInfo->modes[0].hdisplay; yModeSize = (int)drmConnInfo->modes[0].vdisplay; } // Otherwise get it from the current crtc settings else { xModeSize = (int)drmCrtcInfo->mode.hdisplay; yModeSize = (int)drmCrtcInfo->mode.vdisplay; } } // If surf size is unspecified, default to fullscreen normally // or to 1/4 fullscreen if in animated bounce mode. if (!xSurfSize || !ySurfSize) { if (bounce) { xSurfSize = xModeSize / 2; ySurfSize = yModeSize / 2; } else { xSurfSize = xModeSize; ySurfSize = yModeSize; } } // If necessary, set the mode if (setMode) { drmModeSetCrtc(drmFd, drmCrtcId, -1, 0, 0, &drmConnId, 1, drmConnInfo->modes + drmModeIndex); std::cout << "Set mode" << std::endl; } // If plane is in use, set it if (plane >= 0) { drmModeSetPlane(drmFd, drmPlaneId, drmCrtcId, -1, 0, xOffset, yOffset, xSurfSize, ySurfSize, 0, 0, xSurfSize << 16, ySurfSize << 16); std::cout << "Set plane configuration" << std::endl; } // Get the layer for this crtc/plane if (plane >= 0) { layerAttribs[0] = EGL_DRM_PLANE_EXT; layerAttribs[1] = (EGLAttrib)drmPlaneId; } else { layerAttribs[0] = EGL_DRM_CRTC_EXT; layerAttribs[1] = (EGLAttrib)drmCrtcId; } dispWidth = xSurfSize; dispHeight = ySurfSize; return true; }
static DFBResult drmkmsPlaneUpdateFlipRegion( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface, DFBSurfaceFlipFlags flags, const DFBRegion *left_update, CoreSurfaceBufferLock *left_lock, const DFBRegion *right_update, CoreSurfaceBufferLock *right_lock, bool flip ) { int ret; DRMKMSData *drmkms = driver_data; DRMKMSLayerData *data = layer_data; D_DEBUG_AT( DRMKMS_Layer, "%s()\n", __FUNCTION__ ); direct_mutex_lock( &data->lock ); while (data->flip_pending) { D_DEBUG_AT( DRMKMS_Layer, " -> waiting for pending flip (previous)\n" ); if (direct_waitqueue_wait_timeout( &data->wq_event, &data->lock, 30000 ) == DR_TIMEOUT) break; } dfb_surface_ref( surface ); data->surface = surface; data->surfacebuffer_index = left_lock->buffer->index; /* Task */ data->pending_task = left_lock->task; if (!data->muted) { ret = drmModeSetPlane(drmkms->fd, data->plane->plane_id, drmkms->encoder[0]->crtc_id, (u32)(long)left_lock->handle, /* plane_flags */ 0, data->config->dest.x, data->config->dest.y, data->config->dest.w, data->config->dest.h, data->config->source.x << 16, data->config->source.y <<16, data->config->source.w << 16, data->config->source.h << 16); if (ret) { D_PERROR( "DRMKMS/Layer/FlipRegion: Failed setting plane configuration!\n" ); direct_mutex_unlock( &data->lock ); return ret; } } if (flip) dfb_surface_flip( surface, false ); data->flip_pending = true; drmVBlank vbl; vbl.request.type = DRM_VBLANK_EVENT | DRM_VBLANK_RELATIVE; vbl.request.signal = (unsigned long)data; vbl.request.sequence = 1; drmWaitVBlank( drmkms->fd, &vbl ); if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) { while (data->flip_pending) { D_DEBUG_AT( DRMKMS_Layer, " -> waiting for pending flip (WAITFORSYNC)\n" ); if (direct_waitqueue_wait_timeout( &data->wq_event, &data->lock, 30000 ) == DR_TIMEOUT) break; } } direct_mutex_unlock( &data->lock ); return DFB_OK; }
static GstFlowReturn gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) { gint ret; GstBuffer *buffer; guint32 fb_id; GstKMSSink *self; GstVideoCropMeta *crop; GstVideoRectangle src = { 0, }; GstVideoRectangle dst = { 0, }; GstVideoRectangle result; GstFlowReturn res; self = GST_KMS_SINK (vsink); res = GST_FLOW_ERROR; buffer = gst_kms_sink_get_input_buffer (self, buf); if (!buffer) return GST_FLOW_ERROR; fb_id = gst_kms_memory_get_fb_id (gst_buffer_peek_memory (buffer, 0)); if (fb_id == 0) goto buffer_invalid; GST_TRACE_OBJECT (self, "displaying fb %d", fb_id); { if ((crop = gst_buffer_get_video_crop_meta (buffer))) { src.x = crop->x; src.y = crop->y; src.w = crop->width; src.h = crop->height; } else { src.w = GST_VIDEO_SINK_WIDTH (self); src.h = GST_VIDEO_SINK_HEIGHT (self); } } dst.w = self->hdisplay; dst.h = self->vdisplay; gst_video_sink_center_rect (src, dst, &result, FALSE); /* if the frame size is bigger than the display size, the source * must be the display size */ src.w = MIN (src.w, self->hdisplay); src.h = MIN (src.h, self->vdisplay); ret = drmModeSetPlane (self->fd, self->plane_id, self->crtc_id, fb_id, 0, result.x, result.y, result.w, result.h, /* source/cropping coordinates are given in Q16 */ src.x << 16, src.y << 16, src.w << 16, src.h << 16); if (ret) goto set_plane_failed; /* Wait for the previous frame to complete redraw */ if (!gst_kms_sink_sync (self)) goto bail; gst_buffer_replace (&self->last_buffer, buffer); res = GST_FLOW_OK; bail: gst_buffer_unref (buffer); return res; /* ERRORS */ buffer_invalid: { GST_ERROR_OBJECT (self, "invalid buffer: it doesn't have a fb id"); goto bail; } set_plane_failed: { GST_DEBUG_OBJECT (self, "result = { %d, %d, %d, %d} / " "src = { %d, %d, %d %d } / dst = { %d, %d, %d %d }", result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h, dst.x, dst.y, dst.w, dst.h); GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (NULL), ("drmModeSetPlane failed: %s (%d)", strerror (-ret), ret)); goto bail; } }