コード例 #1
0
/*
 * Queue an event to report back to the Present extension when the specified
 * MSC has past
 */
static int
intel_present_queue_vblank(RRCrtcPtr                    crtc,
                           uint64_t                     event_id,
                           uint64_t                     msc)
{
	xf86CrtcPtr                             xf86_crtc = crtc->devPrivate;
	ScreenPtr                               screen = crtc->pScreen;
	ScrnInfoPtr                             scrn = xf86ScreenToScrn(screen);
	intel_screen_private                    *intel = intel_get_screen_private(scrn);
	int                                     pipe = intel_present_crtc_pipe(screen, crtc);
	struct intel_present_vblank_event       *event;
	drmVBlank                               vbl;
	int                                     ret;
	uint32_t                                seq;

	event = calloc(sizeof(struct intel_present_vblank_event), 1);
	if (!event)
		return BadAlloc;
	event->event_id = event_id;
	seq = intel_drm_queue_alloc(scrn, xf86_crtc, event,
				    intel_present_vblank_handler,
				    intel_present_vblank_abort);
	if (!seq) {
		free(event);
		return BadAlloc;
	}

	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
	vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, xf86_crtc, msc);
	vbl.request.signal = seq;
	for (;;) {
		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
		if (!ret)
			break;
		if (errno != EBUSY || !intel_present_flush_drm_events(screen))
			return BadAlloc;
	}
	DebugPresent(("\t\tiq %lld seq %u msc %llu (hw msc %u)\n",
                      (long long) event_id, seq, (long long) msc, vbl.request.sequence));
	return Success;
}
コード例 #2
0
static int do_wait( drmVBlank * vbl, GLuint * vbl_seq, int fd )
{
   int   ret;


   ret = drmWaitVBlank( fd, vbl );
   if ( ret != 0 ) {
      static GLboolean first_time = GL_TRUE;

      if ( first_time ) {
	 fprintf(stderr, 
		 "%s: drmWaitVBlank returned %d, IRQs don't seem to be"
		 " working correctly.\nTry adjusting the vblank_mode"
		 " configuration parameter.\n", __FUNCTION__, ret);
	 first_time = GL_FALSE;
      }

      return -1;
   }

   *vbl_seq = vbl->reply.sequence;
   return 0;
}
static int
nouveau_present_ust_msc(RRCrtcPtr rrcrtc, uint64_t *ust, uint64_t *msc)
{
	xf86CrtcPtr crtc = rrcrtc->devPrivate;
	NVPtr pNv = NVPTR(crtc->scrn);
	drmVBlank args;
	int ret;

	args.request.type = DRM_VBLANK_RELATIVE;
	args.request.type |= drmmode_head(crtc) << DRM_VBLANK_HIGH_CRTC_SHIFT;
	args.request.sequence = 0,
	args.request.signal = 0,

	ret = drmWaitVBlank(pNv->dev->fd, &args);
	if (ret) {
		*ust = *msc = 0;
		return BadMatch;
	}

	*ust = (CARD64)args.reply.tval_sec * 1000000 + args.reply.tval_usec;
	*msc = args.reply.sequence;
	return Success;
}
コード例 #4
0
ファイル: drmkms_layer.c プロジェクト: Distrotech/DirectFB
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;
}
コード例 #5
0
int driWaitForMSC32( __DRIdrawablePrivate *priv,
		     int64_t target_msc, int64_t divisor, int64_t remainder,
		     int64_t * msc )
{
   drmVBlank vbl;


   if ( divisor != 0 ) {
      unsigned int target = (unsigned int)target_msc;
      unsigned int next = target;
      unsigned int r;
      int dont_wait = (target_msc == 0);

      do {
         /* dont_wait means we're using the glXWaitVideoSyncSGI() behavior.
          * The first time around, just get the current count and proceed 
          * to the test for (MSC % divisor) == remainder.
          */
         vbl.request.type = dont_wait ? DRM_VBLANK_RELATIVE :
                                        DRM_VBLANK_ABSOLUTE;
         vbl.request.sequence = next ? msc_to_vblank(priv, next) : 0;
	 if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
	    vbl.request.type |= DRM_VBLANK_SECONDARY;

	 if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) {
	    /* FIXME: This doesn't seem like the right thing to return here.
	     */
	    return GLX_BAD_CONTEXT;
	 }

	 *msc = vblank_to_msc(priv, vbl.reply.sequence);

         dont_wait = 0;
         if (target_msc != 0 && *msc == target)
            break;

         /* Assuming the wait-done test fails, the next refresh to wait for
          * will be one that satisfies (MSC % divisor) == remainder.  The
          * value (MSC - (MSC % divisor) + remainder) is the refresh value 
          * closest to the current value that would satisfy the equation.  
          * If this refresh has already happened, we add divisor to obtain 
          * the next refresh after the current one that will satisfy it.
          */
         r = (*msc % (unsigned int)divisor);
         next = (*msc - r + (unsigned int)remainder);
         if (next <= *msc) next += (unsigned int)divisor;

      } while ( r != (unsigned int)remainder );
   }
   else {
      /* If the \c divisor is zero, just wait until the MSC is greater
       * than or equal to \c target_msc.
       */

      vbl.request.type = DRM_VBLANK_ABSOLUTE;
      vbl.request.sequence = target_msc ? msc_to_vblank(priv, target_msc) : 0;

      if ( priv->vblFlags & VBLANK_FLAG_SECONDARY )
	 vbl.request.type |= DRM_VBLANK_SECONDARY;

      if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) {
	 /* FIXME: This doesn't seem like the right thing to return here.
	  */
	 return GLX_BAD_CONTEXT;
      }
   }

   *msc = vblank_to_msc(priv, vbl.reply.sequence);

   if ( *msc < target_msc ) {
      *msc += 0x0000000100000000LL;
   }

   return 0;
}
コード例 #6
0
ファイル: present.c プロジェクト: GalliumOS/xorg-server
/*
 * Flush the DRM event queue when full; makes space for new events.
 *
 * Returns a negative value on error, 0 if there was nothing to process,
 * or 1 if we handled any events.
 */
static int
ms_flush_drm_events(ScreenPtr screen)
{
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    modesettingPtr ms = modesettingPTR(scrn);

    struct pollfd p = { .fd = ms->fd, .events = POLLIN };
    int r;

    do {
            r = poll(&p, 1, 0);
    } while (r == -1 && (errno == EINTR || errno == EAGAIN));

    /* If there was an error, r will be < 0.  Return that.  If there was
     * nothing to process, r == 0.  Return that.
     */
    if (r <= 0)
        return r;

    /* Try to handle the event.  If there was an error, return it. */
    r = drmHandleEvent(ms->fd, &ms->event_context);
    if (r < 0)
        return r;

    /* Otherwise return 1 to indicate that we handled an event. */
    return 1;
}

/*
 * Called when the queued vblank event has occurred
 */
static void
ms_present_vblank_handler(uint64_t msc, uint64_t usec, void *data)
{
    struct ms_present_vblank_event *event = data;

    DebugPresent(("\t\tmh %lld msc %llu\n",
                 (long long) event->event_id, (long long) msc));

    present_event_notify(event->event_id, usec, msc);
    free(event);
}

/*
 * Called when the queued vblank is aborted
 */
static void
ms_present_vblank_abort(void *data)
{
    struct ms_present_vblank_event *event = data;

    DebugPresent(("\t\tma %lld\n", (long long) event->event_id));

    free(event);
}

/*
 * Queue an event to report back to the Present extension when the specified
 * MSC has past
 */
static int
ms_present_queue_vblank(RRCrtcPtr crtc,
                        uint64_t event_id,
                        uint64_t msc)
{
    xf86CrtcPtr xf86_crtc = crtc->devPrivate;
    ScreenPtr screen = crtc->pScreen;
    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    modesettingPtr ms = modesettingPTR(scrn);
    drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
    struct ms_present_vblank_event *event;
    drmVBlank vbl;
    int ret;
    uint32_t seq;

    event = calloc(sizeof(struct ms_present_vblank_event), 1);
    if (!event)
        return BadAlloc;
    event->event_id = event_id;
    seq = ms_drm_queue_alloc(xf86_crtc, event,
                             ms_present_vblank_handler,
                             ms_present_vblank_abort);
    if (!seq) {
        free(event);
        return BadAlloc;
    }

    vbl.request.type =
        DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe;
    vbl.request.sequence = ms_crtc_msc_to_kernel_msc(xf86_crtc, msc);
    vbl.request.signal = seq;
    for (;;) {
        ret = drmWaitVBlank(ms->fd, &vbl);
        if (!ret)
            break;
        /* If we hit EBUSY, then try to flush events.  If we can't, then
         * this is an error.
         */
        if (errno != EBUSY || ms_flush_drm_events(screen) < 0) {
	    ms_drm_abort_seq(scrn, seq);
            return BadAlloc;
        }
    }
    DebugPresent(("\t\tmq %lld seq %u msc %llu (hw msc %u)\n",
                 (long long) event_id, seq, (long long) msc,
                 vbl.request.sequence));
    return Success;
}
コード例 #7
0
ファイル: vbltest.c プロジェクト: illumsoft/libdrm
int main(int argc, char **argv)
{
	const char *device = NULL, *module = NULL;
	int c, fd, ret;
	drmVBlank vbl;
	drmEventContext evctx;
	struct vbl_info handler_info;

	opterr = 0;
	while ((c = getopt(argc, argv, optstr)) != -1) {
		switch (c) {
		case 'D':
			device = optarg;
			break;
		case 'M':
			module = optarg;
			break;
		case 's':
			secondary = 1;
			break;
		default:
			usage(argv[0]);
			break;
		}
	}

	fd = util_open(module, device);
	if (fd < 0)
		return 1;

	/* Get current count first */
	vbl.request.type = DRM_VBLANK_RELATIVE;
	if (secondary)
		vbl.request.type |= DRM_VBLANK_SECONDARY;
	vbl.request.sequence = 0;
	ret = drmWaitVBlank(fd, &vbl);
	if (ret != 0) {
		printf("drmWaitVBlank (relative) failed ret: %i\n", ret);
		return -1;
	}

	printf("starting count: %d\n", vbl.request.sequence);

	handler_info.vbl_count = 0;
	gettimeofday(&handler_info.start, NULL);

	/* Queue an event for frame + 1 */
	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
	if (secondary)
		vbl.request.type |= DRM_VBLANK_SECONDARY;
	vbl.request.sequence = 1;
	vbl.request.signal = (unsigned long)&handler_info;
	ret = drmWaitVBlank(fd, &vbl);
	if (ret != 0) {
		printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret);
		return -1;
	}

	/* Set up our event handler */
	memset(&evctx, 0, sizeof evctx);
	evctx.version = DRM_EVENT_CONTEXT_VERSION;
	evctx.vblank_handler = vblank_handler;
	evctx.page_flip_handler = NULL;

	/* Poll for events */
	while (1) {
		struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
		fd_set fds;

		FD_ZERO(&fds);
		FD_SET(0, &fds);
		FD_SET(fd, &fds);
		ret = select(fd + 1, &fds, NULL, NULL, &timeout);

		if (ret <= 0) {
			fprintf(stderr, "select timed out or error (ret %d)\n",
				ret);
			continue;
		} else if (FD_ISSET(0, &fds)) {
			break;
		}

		ret = drmHandleEvent(fd, &evctx);
		if (ret != 0) {
			printf("drmHandleEvent failed: %i\n", ret);
			return -1;
		}
	}

	return 0;
}
コード例 #8
0
ファイル: vbltest.c プロジェクト: wzyy2/libdrm-rockchip
int main(int argc, char **argv)
{
	unsigned i;
	int c, fd, ret;
	const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos", "omapdrm", "tilcdc", "msm", "tegra", "imx-drm", "rockchip", "mediatek" };
	drmVBlank vbl;
	drmEventContext evctx;
	struct vbl_info handler_info;

	opterr = 0;
	while ((c = getopt(argc, argv, optstr)) != -1) {
		switch (c) {
		case 's':
			secondary = 1;
			break;
		default:
			usage(argv[0]);
			break;
		}
	}

	for (i = 0; i < ARRAY_SIZE(modules); i++) {
		printf("trying to load module %s...", modules[i]);
		fd = drmOpen(modules[i], NULL);
		if (fd < 0) {
			printf("failed.\n");
		} else {
			printf("success.\n");
			break;
		}
	}

	if (i == ARRAY_SIZE(modules)) {
		fprintf(stderr, "failed to load any modules, aborting.\n");
		return -1;
	}

	/* Get current count first */
	vbl.request.type = DRM_VBLANK_RELATIVE;
	if (secondary)
		vbl.request.type |= DRM_VBLANK_SECONDARY;
	vbl.request.sequence = 0;
	ret = drmWaitVBlank(fd, &vbl);
	if (ret != 0) {
		printf("drmWaitVBlank (relative) failed ret: %i\n", ret);
		return -1;
	}

	printf("starting count: %d\n", vbl.request.sequence);

	handler_info.vbl_count = 0;
	gettimeofday(&handler_info.start, NULL);

	/* Queue an event for frame + 1 */
	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
	if (secondary)
		vbl.request.type |= DRM_VBLANK_SECONDARY;
	vbl.request.sequence = 1;
	vbl.request.signal = (unsigned long)&handler_info;
	ret = drmWaitVBlank(fd, &vbl);
	if (ret != 0) {
		printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret);
		return -1;
	}

	/* Set up our event handler */
	memset(&evctx, 0, sizeof evctx);
	evctx.version = DRM_EVENT_CONTEXT_VERSION;
	evctx.vblank_handler = vblank_handler;
	evctx.page_flip_handler = NULL;

	/* Poll for events */
	while (1) {
		struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
		fd_set fds;
		int ret;

		FD_ZERO(&fds);
		FD_SET(0, &fds);
		FD_SET(fd, &fds);
		ret = select(fd + 1, &fds, NULL, NULL, &timeout);

		if (ret <= 0) {
			fprintf(stderr, "select timed out or error (ret %d)\n",
				ret);
			continue;
		} else if (FD_ISSET(0, &fds)) {
			break;
		}

		ret = drmHandleEvent(fd, &evctx);
		if (ret != 0) {
			printf("drmHandleEvent failed: %i\n", ret);
			return -1;
		}
	}

	return 0;
}
コード例 #9
0
/*
 * Correct a drawablePrivate's set of vblank flags WRT the current context.
 * When considering multiple crtcs.
 */
GLuint
intelFixupVblank(struct intel_context *intel, __DRIdrawablePrivate *dPriv)
{
   if (!intel->intelScreen->driScrnPriv->dri2.enabled &&
       intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
      volatile drm_i915_sarea_t *sarea = intel->sarea;
      drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
				   .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h };
      drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y,
				     .x2 = sarea->planeA_x + sarea->planeA_w,
				     .y2 = sarea->planeA_y + sarea->planeA_h };
      drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y,
				     .x2 = sarea->planeB_x + sarea->planeB_w,
				     .y2 = sarea->planeB_y + sarea->planeB_h };
      GLint areaA = driIntersectArea( drw_rect, planeA_rect );
      GLint areaB = driIntersectArea( drw_rect, planeB_rect );
      GLuint flags = dPriv->vblFlags;

      /* Update vblank info
       */
      if (areaB > areaA || (areaA == areaB && areaB > 0)) {
	 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY;
      } else {
	 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
      }

      /* Do the stupid test: Is one of them actually disabled?
       */
      if (sarea->planeA_w == 0 || sarea->planeA_h == 0) {
	 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY;
      } else if (sarea->planeB_w == 0 || sarea->planeB_h == 0) {
	 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
      }

      return flags;
   } else {
      return dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
   }
}


/**
 * Called from driSwapBuffers()
 */
void
intelSwapBuffers(__DRIdrawablePrivate * dPriv)
{
   __DRIscreenPrivate *psp = dPriv->driScreenPriv;

   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
      GET_CURRENT_CONTEXT(ctx);
      struct intel_context *intel;

      if (ctx == NULL)
	 return;

      intel = intel_context(ctx);

      if (ctx->Visual.doubleBufferMode) {
	 GLboolean missed_target;
	 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
	 int64_t ust;
         
	 _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */

	/*
	 * The old swapping ioctl was incredibly racy, just wait for vblank
	 * and do the swap ourselves.
	 */
	 driWaitForVBlank(dPriv, &missed_target);

	 /*
	  * Update each buffer's vbl_pending so we don't get too out of
	  * sync
	  */
	 intel_get_renderbuffer(&intel_fb->Base,
		   		BUFFER_BACK_LEFT)->vbl_pending = dPriv->vblSeq;
         intel_get_renderbuffer(&intel_fb->Base,
		   		BUFFER_FRONT_LEFT)->vbl_pending = dPriv->vblSeq;

	 intelCopyBuffer(dPriv, NULL);

	 intel_fb->swap_count++;
	 (*psp->systemTime->getUST) (&ust);
	 if (missed_target) {
	    intel_fb->swap_missed_count++;
	    intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
	 }

	 intel_fb->swap_ust = ust;
      }
      drmCommandNone(intel->driFd, DRM_I915_GEM_THROTTLE);
   }
   else {
      /* XXX this shouldn't be an error but we can't handle it for now */
      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
   }
}


/**
 * Called from driCopySubBuffer()
 */
void
intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
{
   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
      struct intel_context *intel =
         (struct intel_context *) dPriv->driContextPriv->driverPrivate;
      GLcontext *ctx = &intel->ctx;

      if (ctx->Visual.doubleBufferMode) {
         drm_clip_rect_t rect;
         rect.x1 = x + dPriv->x;
         rect.y1 = (dPriv->h - y - h) + dPriv->y;
         rect.x2 = rect.x1 + w;
         rect.y2 = rect.y1 + h;
         _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */
         intelCopyBuffer(dPriv, &rect);
      }
   }
   else {
      /* XXX this shouldn't be an error but we can't handle it for now */
      fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
   }
}


/**
 * This will be called whenever the currently bound window is moved/resized.
 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
 */
void
intelWindowMoved(struct intel_context *intel)
{
   GLcontext *ctx = &intel->ctx;
   __DRIdrawablePrivate *dPriv = intel->driDrawable;
   struct intel_framebuffer *intel_fb = dPriv->driverPrivate;

   if (!intel->intelScreen->driScrnPriv->dri2.enabled &&
       intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
      GLuint flags = intelFixupVblank(intel, dPriv);

      /* Check to see if we changed pipes */
      if (flags != dPriv->vblFlags && dPriv->vblFlags &&
	  !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) {
	 int64_t count;
	 drmVBlank vbl;
	 int i;

	 /*
	  * Deal with page flipping
	  */
	 vbl.request.type = DRM_VBLANK_ABSOLUTE;

	 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) {
	    vbl.request.type |= DRM_VBLANK_SECONDARY;
	 }

	 for (i = 0; i < 2; i++) {
	    if (!intel_fb->color_rb[i] ||
		(intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <=
		(1<<23))
	       continue;

	    vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending;
	    drmWaitVBlank(intel->driFd, &vbl);
	 }

	 /*
	  * Update msc_base from old pipe
	  */
	 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count);
	 dPriv->msc_base = count;
	 /*
	  * Then get new vblank_base and vblSeq values
	  */
	 dPriv->vblFlags = flags;
	 driGetCurrentVBlank(dPriv);
	 dPriv->vblank_base = dPriv->vblSeq;

	 intel_fb->vbl_waited = dPriv->vblSeq;

	 for (i = 0; i < 2; i++) {
	    if (intel_fb->color_rb[i])
	       intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited;
	 }
      }
   } else {
      dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY;
   }

   /* Update Mesa's notion of window size */
   driUpdateFramebufferSize(ctx, dPriv);
   intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */

   /* Update hardware scissor */
   if (ctx->Driver.Scissor != NULL) {
      ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
			  ctx->Scissor.Width, ctx->Scissor.Height);
   }

   /* Re-calculate viewport related state */
   if (ctx->Driver.DepthRange != NULL)
      ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
}
コード例 #10
0
static gboolean
gst_kms_sink_sync (GstKMSSink * self)
{
  gint ret;
  gboolean waiting;
  drmEventContext evctxt = {
    .version = DRM_EVENT_CONTEXT_VERSION,
    .page_flip_handler = sync_handler,
    .vblank_handler = sync_handler,
  };
  drmVBlank vbl = {
    .request = {
          .type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
          .sequence = 1,
          .signal = (gulong) & waiting,
        },
  };

  if (self->pipe == 1)
    vbl.request.type |= DRM_VBLANK_SECONDARY;
  else if (self->pipe > 1)
    vbl.request.type |= self->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;

  waiting = TRUE;
  if (!self->has_async_page_flip) {
    ret = drmWaitVBlank (self->fd, &vbl);
    if (ret)
      goto vblank_failed;
  } else {
    ret = drmModePageFlip (self->fd, self->crtc_id, self->buffer_id,
        DRM_MODE_PAGE_FLIP_EVENT, &waiting);
    if (ret)
      goto pageflip_failed;
  }

  while (waiting) {
    do {
      ret = gst_poll_wait (self->poll, 3 * GST_SECOND);
    } while (ret == -1 && (errno == EAGAIN || errno == EINTR));

    ret = drmHandleEvent (self->fd, &evctxt);
    if (ret)
      goto event_failed;
  }

  return TRUE;

  /* ERRORS */
vblank_failed:
  {
    GST_WARNING_OBJECT (self, "drmWaitVBlank failed: %s (%d)", strerror (-ret),
        ret);
    return FALSE;
  }
pageflip_failed:
  {
    GST_WARNING_OBJECT (self, "drmModePageFlip failed: %s (%d)",
        strerror (-ret), ret);
    return FALSE;
  }
event_failed:
  {
    GST_ERROR_OBJECT (self, "drmHandleEvent failed: %s (%d)", strerror (-ret),
        ret);
    return FALSE;
  }
}
コード例 #11
0
static int
vivante_dri2_ScheduleWaitMSC(ClientPtr client, DrawablePtr draw,
	CARD64 target_msc, CARD64 divisor, CARD64 remainder)
{
	struct vivante *vivante = vivante_get_screen_priv(draw->pScreen);
	struct vivante_dri_wait *wait;
	drmVBlank vbl;
	int ret, crtc;
	CARD64 cur_msc;

	target_msc &= 0xffffffff;
	divisor &= 0xffffffff;
	remainder &= 0xffffffff;

	crtc = vivante_dri2_drawable_crtc(draw);

	/* Drawable not displayed, just complete */
	if (crtc < 0)
		goto out;

	wait = new_wait_info(client, draw, DRI2_WAITMSC);
	if (!wait)
		goto out;

	/* Get current count */
	ret = vivante_dri2_waitvblank(vivante, &vbl, crtc, __FUNCTION__);
	if (ret)
		goto out_free;

	cur_msc = vbl.reply.sequence;

	/*
	 * If the divisor is zero, or cur_msc is smaller than target_msc, we
	 * just need to make sure target_msc passes before waking up the client.
	 */
	if (divisor == 0 || cur_msc < target_msc) {
		if (cur_msc >= target_msc)
			target_msc = cur_msc;

		vbl.request.sequence = target_msc;
	} else {
		/*
		 * If we get here, target_msc has already passed or we
		 * don't have one, so queue an event that will satisfy
		 * the divisor/remainder equation.
		 */
		vbl.request.sequence = cur_msc - (cur_msc % divisor) + remainder;

		/*
		 * If calculated remainder is larger than requested
		 * remainder, it means we've passed the point where
		 * seq % divisor == remainder, so we need to wait for
		 * the next time that will happen.
		 */
		if ((cur_msc & divisor) >= remainder)
			vbl.request.sequence += divisor;
	}

	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | drm_req_crtc(crtc);
	vbl.request.signal = (unsigned long)wait;
	ret = drmWaitVBlank(vivante->drm_fd, &vbl);
	if (ret) {
		xf86DrvMsg(vivante->scrnIndex, X_WARNING,
				   "%s: get vblank counter failed: %s\n",
				   __FUNCTION__, strerror(errno));
		goto out_free;
	}

	wait->frame = vbl.reply.sequence;
	DRI2BlockClient(client, draw);
	return TRUE;

 out_free:
	del_wait_info(wait);
 out:
	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
	return TRUE;
}
コード例 #12
0
static int
vivante_dri2_ScheduleSwap(ClientPtr client, DrawablePtr draw,
	DRI2BufferPtr front, DRI2BufferPtr back, CARD64 *target_msc,
	CARD64 divisor, CARD64 remainder, DRI2SwapEventPtr func, void *data)
{
	struct vivante *vivante = vivante_get_screen_priv(draw->pScreen);
	struct vivante_dri_wait *wait;
	drmVBlank vbl;
	CARD64 cur_msc;
	int ret, crtc;

	crtc = vivante_dri2_drawable_crtc(draw);

	/* Drawable not displayed... just complete */
	if (crtc < 0)
		goto blit;

	*target_msc &= 0xffffffff;
	divisor &= 0xffffffff;
	remainder &= 0xffffffff;

	wait = new_wait_info(client, draw, DRI2_SWAP);
	if (!wait)
		goto blit;

	wait->crtc = crtc;
	wait->event_func = func;
	wait->event_data = data;
	wait->front = front;
	wait->back = back;

	vivante_dri2_buffer_reference(front);
	vivante_dri2_buffer_reference(back);

	ret = vivante_dri2_waitvblank(vivante, &vbl, crtc, __FUNCTION__);
	if (ret)
		goto blit_free;

	cur_msc = vbl.reply.sequence;

	/* Flips need to be submitted one frame before */
	if (can_exchange(draw, front, back)) {
		wait->type = DRI2_FLIP;
		if (*target_msc > 0)
			*target_msc -= 1;
	}

	if (divisor == 0 || cur_msc < *target_msc) {
		if (wait->type == DRI2_FLIP && vivante_dri2_ScheduleFlip(draw, wait))
			return TRUE;

		/*
		 * If target_msc has been reached or passed, set it to cur_msc
		 * to ensure we return a reasonable value back to the caller.
		 * This makes the swap_interval logic more robust.
		 */
		if (cur_msc >= *target_msc)
			*target_msc = cur_msc;

		vbl.request.sequence = *target_msc;
	} else {
		vbl.request.sequence = cur_msc - (cur_msc % divisor) + remainder;

		/*
		 * If the calculated deadline sequence is smaller than or equal
		 * to cur_msc, it means we've passed the point when effective
		 * onset frame seq could satisfy seq % divisor == remainder,
		 * so we need to wait for the next time this will happen.
		 *
		 * This comparison takes the 1 frame swap delay in pageflipping
		 * mode into account, as well as a potential
		 * DRM_VBLANK_NEXTONMISS delay if we are blitting/exchanging
		 * instead of flipping.
		 */
		 if (vbl.request.sequence <= cur_msc)
			 vbl.request.sequence += divisor;

		 /* Account for 1 frame extra pageflip delay if flip > 0 */
		 if (wait->type == DRI2_FLIP)
			 vbl.request.sequence -= 1;
	}

	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | drm_req_crtc(crtc);
	if (wait->type != DRI2_FLIP)
		vbl.request.type |= DRM_VBLANK_NEXTONMISS;

	vbl.request.signal = (unsigned long)wait;
	ret = drmWaitVBlank(vivante->drm_fd, &vbl);
	if (ret) {
		xf86DrvMsg(vivante->scrnIndex, X_WARNING,
			   "get vblank counter failed: %s\n",
			   strerror(errno));
		goto blit_free;
	}

	*target_msc = vbl.reply.sequence + (wait->type == DRI2_FLIP);
	wait->frame = *target_msc;

	return TRUE;

 blit_free:
	del_wait_info(wait);
 blit:
	vivante_dri2_blit(client, draw, front, back, 0, 0, 0, func, data);
	*target_msc = 0;
	return TRUE;
}
コード例 #13
0
ファイル: kmsfps.c プロジェクト: Spudd86/julia-vis
int main(int argc, char *argv[])
{
	struct opt_data opts; optproc(argc, argv, &opts);
	if(audio_init(&opts) < 0) exit(1);
	if(opts.w < 0 && opts.h < 0) opts.w = opts.h = 512;
	else if(opts.w < 0) opts.w = opts.h;
	else if(opts.h < 0) opts.h = opts.w;
	
	int ret;

	ret = init_drm(&opts, 512);
	if (ret) {
		printf("failed to initialize DRM\n");
		return ret;
	}

	ret = init_gbm();
	if (ret) {
		printf("failed to initialize GBM\n");
		return ret;
	}

	ret = init_egl();
	if (ret) {
		printf("failed to initialize EGL\n");
		return ret;
	}
	
	// call init_gl
	//init_gl(&opts, drm.mode->hdisplay, drm.mode->vdisplay);
	init_gl(&opts, opts.w, opts.h); //TODO: better dealing with our great big screen
	
	eglSwapBuffers(gl.display, gl.surface);
	struct gbm_bo *bo = gbm_surface_lock_front_buffer(gbm.surface);
	fb = drm_fb_get_from_bo(bo);

	/* set mode: */
	ret = drmModeSetCrtc(drm.fd, drm.crtc_id, fb->fb_id, 0, 0,
			&drm.connector_id, 1, drm.mode);
	if (ret) {
		printf("failed to set mode: %s\n", strerror(errno));
		return ret;
	}
	
	// turn off line buffering on input and echoing of characters
	struct termios term;
	tcgetattr(STDIN_FILENO, &save_term);
    tcgetattr(STDIN_FILENO, &term);
    term.c_lflag &= ~(ICANON|ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &term);
    
    atexit(shutdown_cleanup);
	
	drmVBlank vbl;
	/* Get current count first hopefully also sync up with blank too*/
	vbl.request.type = DRM_VBLANK_RELATIVE;
	vbl.request.sequence = 1;
	ret = drmWaitVBlank(drm.fd, &vbl);
	if (ret != 0) {
		printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret);
		return -1;
	}
	printf("starting msc: %d\n", vbl.request.sequence);
	
	/* Queue an event for frame + 1 */
	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
	vbl.request.sequence = 1;
	vbl.request.signal = NULL;
	ret = drmWaitVBlank(drm.fd, &vbl);
	if (ret != 0) {
		printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret);
		return -1;
	}
	
	struct pollfd pfds[] = {
		{drm.fd, POLLIN | POLLPRI, 0 },
		{STDIN_FILENO, POLLIN, 0 },
	};

	int debug_maxsrc = 0, debug_pal = 0, show_mandel = 0, show_fps_hist = 0;
	bool done = false;
	while (!done) {

		render_frame(debug_maxsrc, debug_pal, show_mandel, show_fps_hist);

		while (waiting_for_flip) { // TODO: input handling			
			ret = poll(pfds, 2, -1);
			if (ret < 0) {
				printf("poll err: %s\n", strerror(errno));
				return ret;
			} else if (ret == 0) {
				printf("poll timeout!\n");
				done = true;
				break;
			} 
			
			if (pfds[1].revents) {
				char buf[128];
				int cnt = read(STDIN_FILENO, buf, sizeof(buf));
				if(buf[0] == 27) done = true;
				else if(buf[0] == '1') debug_maxsrc = !debug_maxsrc;
				else if(buf[0] == '2') debug_pal = !debug_pal;
				else if(buf[0] == '3') show_mandel = !show_mandel;
				else if(buf[0] == '4') show_fps_hist = !show_fps_hist;
				//continue;
			}
			
			if(pfds[0].revents)
				drmHandleEvent(drm.fd, &evctx);
		}

		/* release last buffer to render on again: */
		gbm_surface_release_buffer(gbm.surface, bo);
		bo = next_bo;
	}
	
	audio_shutdown();

	return ret;
}
コード例 #14
0
void CVideoSyncDRM::Run(volatile bool& stop)
{
  drmVBlank vbl;
  VblInfo info;
  int ret;
  int crtc = g_Windowing.GetCrtc();

  vbl.request.type = DRM_VBLANK_RELATIVE;
  if (crtc == 1)
  {
    vbl.request.type = (drmVBlankSeqType)(vbl.request.type | DRM_VBLANK_SECONDARY);
  }
  else if (crtc > 1)
  {
    vbl.request.type = (drmVBlankSeqType)(vbl.request.type |
                       ((crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) & DRM_VBLANK_HIGH_CRTC_MASK));
  }
  vbl.request.sequence = 0;
  ret = drmWaitVBlank(m_fd, &vbl);
  if (ret != 0)
  {
    CLog::Log(LOGERROR, "CVideoSyncDRM::%s - drmWaitVBlank returned error", __FUNCTION__);
    return;
  }

  info.start = CurrentHostCounter();
  info.videoSync = this;

  vbl.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT);
  if (crtc == 1)
  {
    vbl.request.type = (drmVBlankSeqType)(vbl.request.type | DRM_VBLANK_SECONDARY);
  }
  else if (crtc > 1)
  {
    vbl.request.type = (drmVBlankSeqType)(vbl.request.type |
                       ((crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) & DRM_VBLANK_HIGH_CRTC_MASK));
  }
  vbl.request.sequence = 1;
  vbl.request.signal = (unsigned long)&info;
  ret = drmWaitVBlank(m_fd, &vbl);
  if (ret != 0)
  {
    CLog::Log(LOGERROR, "CVideoSyncDRM::%s - drmWaitVBlank returned error", __FUNCTION__);
    return;
  }

  drmEventContext evctx;
  memset(&evctx, 0, sizeof evctx);
  evctx.version = DRM_EVENT_CONTEXT_VERSION;
  evctx.vblank_handler = EventHandler;
  evctx.page_flip_handler = NULL;

  timeval timeout;
  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(m_fd, &fds);

  while (!stop && !m_abort)
  {
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    ret = select(m_fd + 1, &fds, NULL, NULL, &timeout);

    if (ret <= 0)
    {
      continue;
    }

    ret = drmHandleEvent(m_fd, &evctx);
    if (ret != 0)
    {
      CLog::Log(LOGERROR, "CVideoSyncDRM::%s - drmHandleEvent returned error", __FUNCTION__);
      break;
    }
  }
}
コード例 #15
0
static int
nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc,
		    CARD64 *pmsc, CARD64 *pust, void *data)
{
	ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
	NVPtr pNv = NVPTR(scrn);
	xf86CrtcPtr crtc;
	drmVBlank vbl;
	struct dri2_vblank *event = NULL;
	void *token = NULL;
	int ret;
	int head;

	/* Select crtc which shows the largest part of the drawable */
	crtc = nouveau_pick_best_crtc(scrn, FALSE,
                                  draw->x, draw->y, draw->width, draw->height);

	if (!crtc) {
		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
				   "Wait for VBlank failed: No valid crtc for drawable.\n");
		return -EINVAL;
	}

	if (type & DRM_VBLANK_EVENT) {
		event = drmmode_event_queue(scrn, ++dri2_sequence,
					    sizeof(*event),
					    nouveau_dri2_vblank_handler,
					    &token);
		if (!event)
			return -ENOMEM;

		event->s = data;
	}

	/* Map xf86CrtcPtr to drmWaitVBlank compatible display head index. */
	head = drmmode_head(crtc);

	if (head == 1)
		type |= DRM_VBLANK_SECONDARY;
	else if (head > 1)
#ifdef DRM_VBLANK_HIGH_CRTC_SHIFT
		type |= (head << DRM_VBLANK_HIGH_CRTC_SHIFT) &
				DRM_VBLANK_HIGH_CRTC_MASK;
#else
	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
			   "Wait for VBlank failed: Called for CRTC %d > 1, but "
			   "DRM_VBLANK_HIGH_CRTC_SHIFT not defined at build time.\n",
			   head);
#endif

	vbl.request.type = type;
	vbl.request.sequence = msc;
	vbl.request.signal = (unsigned long)token;

	ret = drmWaitVBlank(pNv->dev->fd, &vbl);
	if (ret) {
		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
			   "Wait for VBlank failed: %s\n", strerror(errno));
		if (event)
			drmmode_event_abort(scrn, dri2_sequence--, false);
		return ret;
	}

	if (pmsc)
		*pmsc = vbl.reply.sequence;
	if (pust)
		*pust = (CARD64)vbl.reply.tval_sec * 1000000 +
			vbl.reply.tval_usec;
	return 0;
}