Example #1
0
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);
}
Example #2
0
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;
    }
}
Example #3
0
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);
}
Example #4
0
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;
}
Example #5
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");
        }
    }
}
Example #6
0
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;
}
Example #7
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
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
}
Example #12
0
/* 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;
  }
}
Example #15
0
// -----------------------------------------------------------------------------
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;
}
Example #16
0
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;
}
Example #17
0
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;
  }
}