Exemple #1
1
static int drm_egl_init(struct MPGLContext *ctx, int flags)
{
    struct priv *p = ctx->priv;
    p->kms = NULL;
    p->old_crtc = NULL;
    p->gbm.surface = NULL;
    p->gbm.device = NULL;
    p->active = false;
    p->waiting_for_flip = false;
    p->ev.version = DRM_EVENT_CONTEXT_VERSION;
    p->ev.page_flip_handler = page_flipped;

    p->vt_switcher_active = vt_switcher_init(&p->vt_switcher, ctx->vo->log);
    if (p->vt_switcher_active) {
        vt_switcher_acquire(&p->vt_switcher, acquire_vt, ctx);
        vt_switcher_release(&p->vt_switcher, release_vt, ctx);
    } else {
        MP_WARN(ctx->vo, "Failed to set up VT switcher. Terminal switching will be unavailable.\n");
    }

    MP_VERBOSE(ctx->vo, "Initializing KMS\n");
    p->kms = kms_create(ctx->vo->log);
    if (!p->kms) {
        MP_ERR(ctx->vo, "Failed to create KMS.\n");
        return -1;
    }

    // TODO: arguments should be configurable
    if (!kms_setup(p->kms, "/dev/dri/card0", -1, 0)) {
        MP_ERR(ctx->vo, "Failed to configure KMS.\n");
        return -1;
    }

    if (!init_gbm(ctx)) {
        MP_ERR(ctx->vo, "Failed to setup GBM.\n");
        return -1;
    }

    if (!init_egl(ctx, flags & VOFLAG_GLES)) {
        MP_ERR(ctx->vo, "Failed to setup EGL.\n");
        return -1;
    }

    if (!eglMakeCurrent(p->egl.display, p->egl.surface, p->egl.surface, p->egl.context)) {
        MP_ERR(ctx->vo, "Failed to make context current.\n");
        return -1;
    }

    const char *egl_exts = eglQueryString(p->egl.display, EGL_EXTENSIONS);
    void *(*gpa)(const GLubyte*) = (void *(*)(const GLubyte*))eglGetProcAddress;
    mpgl_load_functions(ctx->gl, gpa, egl_exts, ctx->vo->log);

    // required by gbm_surface_lock_front_buffer
    eglSwapBuffers(p->egl.display, p->egl.surface);

    MP_VERBOSE(ctx->vo, "Preparing framebuffer\n");
    p->gbm.bo = gbm_surface_lock_front_buffer(p->gbm.surface);
    if (!p->gbm.bo) {
        MP_ERR(ctx->vo, "Failed to lock GBM surface.\n");
        return -1;
    }
    update_framebuffer_from_bo(ctx, p->gbm.bo);
    if (!p->fb.id) {
        MP_ERR(ctx->vo, "Failed to create framebuffer.\n");
        return -1;
    }

    if (!crtc_setup(ctx)) {
        MP_ERR(
               ctx->vo,
               "Failed to set CRTC for connector %u: %s\n",
               p->kms->connector->connector_id,
               mp_strerror(errno));
        return -1;
    }

    return 0;
}
RenderingBackend::BufferExport RenderingBackendGBM::Surface::lockFrontBuffer()
{
    struct gbm_bo* bo = gbm_surface_lock_front_buffer(m_surface);
    assert(bo);

    uint32_t handle = gbm_bo_get_handle(bo).u32;
#ifndef NDEBUG
    auto result =
#endif
        m_lockedBuffers.insert({ handle, bo });
    assert(result.second);

    auto* data = static_cast<BufferDataGBM*>(gbm_bo_get_user_data(bo));
    if (data) {
        std::pair<uint32_t, uint32_t> storedSize{ data->width, data->height };
        if (m_size == storedSize)
            return RenderingBackend::BufferExport{ -1, reinterpret_cast<const uint8_t*>(data), sizeof(BufferDataGBM) };

        delete data;
    }

    data = new BufferDataGBM{ handle, m_size.first, m_size.second, gbm_bo_get_stride(bo), gbm_bo_get_format(bo), BufferDataGBM::magicValue };
    gbm_bo_set_user_data(bo, data, &destroyBOData);

    return RenderingBackend::BufferExport{ gbm_bo_get_fd(bo), reinterpret_cast<const uint8_t*>(data), sizeof(BufferDataGBM) };
}
Exemple #3
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;
    }
}
Exemple #4
0
void QKmsScreen::swapBuffers()
{
    eglSwapBuffers(m_device->eglDisplay(), m_eglWindowSurface);

    m_next_bo = gbm_surface_lock_front_buffer(m_gbmSurface);
    if (!m_next_bo)
        qFatal("kms: Failed to lock front buffer");

    performPageFlip();
}
Exemple #5
0
void
NativeStateDRM::flip()
{
    gbm_bo* next = gbm_surface_lock_front_buffer(surface_);
    fb_ = fb_get_from_bo(next);
    unsigned int waiting(1);

    if (!crtc_set_) {
        int status = drmModeSetCrtc(fd_, encoder_->crtc_id, fb_->fb_id, 0, 0,
                                    &connector_->connector_id, 1, mode_);
        if (status >= 0) {
            crtc_set_ = true;
            bo_ = next;
        }
        else {
            Log::error("Failed to set crtc: %d\n", status);
        }
        return;
    }

    int status = drmModePageFlip(fd_, encoder_->crtc_id, fb_->fb_id,
                                 DRM_MODE_PAGE_FLIP_EVENT, &waiting);
    if (status < 0) {
        Log::error("Failed to enqueue page flip: %d\n", status);
        return;
    }

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd_, &fds);
    drmEventContext evCtx;
    evCtx.version = DRM_EVENT_CONTEXT_VERSION;
    evCtx.page_flip_handler = page_flip_handler;

    while (waiting) {
        status = select(fd_ + 1, &fds, 0, 0, 0);
        if (status < 0) {
            // Most of the time, select() will return an error because the
            // user pressed Ctrl-C.  So, only print out a message in debug
            // mode, and just check for the likely condition and release
            // the current buffer object before getting out.
            Log::debug("Error in select\n");
            if (should_quit()) {
                gbm_surface_release_buffer(surface_, bo_);
                bo_ = next;
            }
            return;
        }
        drmHandleEvent(fd_, &evCtx);
    }

    gbm_surface_release_buffer(surface_, bo_);
    bo_ = next;
}
Exemple #6
0
static bool gfx_ctx_drm_queue_flip(void)
{
   struct drm_fb *fb = NULL;
   g_next_bo         = gbm_surface_lock_front_buffer(g_gbm_surface);
   fb                = (struct drm_fb*)drm_fb_get_from_bo(g_next_bo);

   if (drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id,
         DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip) == 0)
      return true;
   
   /* Failed to queue page flip. */
   return false;
}
Exemple #7
0
static void
swap(struct gbm_winsys *winsys)
{
        struct gbm_dev *dev = winsys->dev;
        struct gbm_context *context = winsys->context;
        struct gbm_bo *bo;
        uint32_t handle, stride;
        uint32_t width, height;
        uint32_t fb_id;

        eglSwapBuffers(context->edpy, context->egl_surface);

        bo = gbm_surface_lock_front_buffer(context->gbm_surface);
        width = gbm_bo_get_width(bo);
        height = gbm_bo_get_height(bo);
        stride = gbm_bo_get_stride(bo);
        handle = gbm_bo_get_handle(bo).u32;

        if (drmModeAddFB(dev->fd,
                         width, height,
                         24, /* depth */
                         32, /* bpp */
                         stride,
                         handle,
                         &fb_id)) {
                fprintf(stderr,
                        "Failed to create new back buffer handle: %m\n");
        } else {
                if (dev->saved_crtc == NULL &&
                    set_initial_crtc(dev, fb_id))
                        return;

                if (drmModePageFlip(dev->fd,
                                    dev->crtc,
                                    fb_id,
                                    DRM_MODE_PAGE_FLIP_EVENT,
                                    dev)) {
                        fprintf(stderr, "Failed to page flip: %m\n");
                        return;
                }

                dev->pending_swap = 1;

                wait_swap(dev);

                free_current_bo(context);
                context->current_bo = bo;
                context->current_fb_id = fb_id;
        }
}
Exemple #8
0
void swap_buffers(void) 
{
	eglSwapBuffers(gl.display, gl.surface);
	next_bo = gbm_surface_lock_front_buffer(gbm.surface);
	fb = drm_fb_get_from_bo(next_bo);
	
	waiting_for_flip = 1;
	
	int ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id,
			DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
	if(ret) {
		printf("failed to queue page flip: %s\n", strerror(errno));
		exit(-1);
	}
}
Exemple #9
0
static void queue_flip(void)
{
   g_next_bo = gbm_surface_lock_front_buffer(g_gbm_surface);
   struct drm_fb *fb = drm_fb_get_from_bo(g_next_bo);

   int ret = drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id,
         DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);

   if (ret < 0)
   {
      RARCH_ERR("[KMS/EGL]: Failed to queue page flip.\n");
      return;
   }

   waiting_for_flip = true;
}
Exemple #10
0
static void drm_egl_swap_buffers(MPGLContext *ctx)
{
    struct priv *p = ctx->priv;
    eglSwapBuffers(p->egl.display, p->egl.surface);
    p->gbm.next_bo = gbm_surface_lock_front_buffer(p->gbm.surface);
    p->waiting_for_flip = true;
    update_framebuffer_from_bo(ctx, p->gbm.next_bo);
    int ret = drmModePageFlip(p->kms->fd, p->kms->crtc_id, p->fb.id,
                              DRM_MODE_PAGE_FLIP_EVENT, p);
    if (ret) {
        MP_WARN(ctx->vo, "Failed to queue page flip: %s\n", mp_strerror(errno));
    }

    // poll page flip finish event
    const int timeout_ms = 3000;
    struct pollfd fds[1] = { { .events = POLLIN, .fd = p->kms->fd } };
Exemple #11
0
bool CDRMLegacy::QueueFlip()
{
  m_next_bo = gbm_surface_lock_front_buffer(m_gbm->surface);
  m_drm_fb = CDRMUtils::DrmFbGetFromBo(m_next_bo);

  auto ret = drmModePageFlip(m_drm->fd,
                             m_drm->crtc_id,
                             m_drm_fb->fb_id,
                             DRM_MODE_PAGE_FLIP_EVENT,
                             &flip_happening);

  if(ret)
  {
    CLog::Log(LOGDEBUG, "CDRMLegacy::%s - failed to queue DRM page flip", __FUNCTION__);
    return false;
  }

  return true;
}
Exemple #12
0
static void queue_flip(void)
{
   g_next_bo = gbm_surface_lock_front_buffer(g_gbm_surface);
   struct drm_fb *fb = drm_fb_get_from_bo(g_next_bo);

   int ret = drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id,
         DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);

   if (ret < 0)
   {
      RARCH_ERR("[KMS/EGL]: Failed to queue page flip.\n");
      return;
   }

   struct timeval tv;
   gettimeofday(&tv, NULL);
   flip_request_usec = (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;

   waiting_for_flip = true;
}
Exemple #13
0
static void queue_flip(void)
{
   int ret;
   struct drm_fb *fb = NULL;
   gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)
   driver.video_context_data;

   drm->g_next_bo = gbm_surface_lock_front_buffer(drm->g_gbm_surface);

   fb = (struct drm_fb*)drm_fb_get_from_bo(drm, drm->g_next_bo);

   ret = drmModePageFlip(drm->g_drm_fd, drm->g_crtc_id, fb->fb_id,
         DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);

   if (ret < 0)
   {
      RARCH_ERR("[KMS/EGL]: Failed to queue page flip.\n");
      return;
   }

   waiting_for_flip = true;
}
Exemple #14
0
int DRM_PageFlip(void){
	int ret;		
	struct gbm_bo *next_bo;
	int waiting_for_flip = 1;

	next_bo = gbm_surface_lock_front_buffer(gbm.surface);
	fb = drm_fb_get_from_bo(next_bo);

	/*
	 * Here you could also update drm plane layers if you want
	 * hw composition
	 */

	ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id,
			DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
	if (ret) {
		printf("failed to queue page flip: %s\n", strerror(errno));
		return -1;
	}

	while (waiting_for_flip) {
		//Aquí realmente no nos interesa leer el teclado. Sólo
		//hacemos el select para esperar por drm.fd
		FD_ZERO (&fds);
		
		FD_SET (0, &fds);
		FD_SET (drm.fd, &fds);

		ret = select(drm.fd+1, &fds, NULL, NULL, NULL);
		
		drmHandleEvent(drm.fd, &evctx);
	}

	/* release last buffer to render on again: */
	gbm_surface_release_buffer(gbm.surface, bo);
	bo = next_bo;
	
	return 0;
}
Exemple #15
0
bool CDRMLegacy::SetVideoMode(RESOLUTION_INFO res)
{
  gbm_surface_release_buffer(m_gbm->surface, m_bo);

  m_bo = gbm_surface_lock_front_buffer(m_gbm->surface);
  m_drm_fb = CDRMUtils::DrmFbGetFromBo(m_bo);

  auto ret = drmModeSetCrtc(m_drm->fd,
                            m_drm->crtc_id,
                            m_drm_fb->fb_id,
                            0,
                            0,
                            &m_drm->connector_id,
                            1,
                            m_drm->mode);

  if(ret < 0)
  {
    CLog::Log(LOGERROR,
              "CDRMUtils::%s - failed to set crtc mode: %dx%d%s @ %d Hz",
              __FUNCTION__,
              m_drm->mode->hdisplay,
              m_drm->mode->vdisplay,
              m_drm->mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "",
              m_drm->mode->vrefresh);

    return false;
  }

  CLog::Log(LOGDEBUG, "CDRMUtils::%s - set crtc mode: %dx%d%s @ %d Hz",
            __FUNCTION__,
            m_drm->mode->hdisplay,
            m_drm->mode->vdisplay,
            m_drm->mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "",
            m_drm->mode->vrefresh);

  return true;
}
Exemple #16
0
static bool gfx_ctx_set_video_mode(void *data,
      unsigned width, unsigned height,
      bool fullscreen)
{
   if (g_inited)
      return false;

   int i;
   int ret = 0;
   struct drm_fb *fb = NULL;

   struct sigaction sa = {{0}};
   sa.sa_handler = sighandler;
   sa.sa_flags   = SA_RESTART;
   sigemptyset(&sa.sa_mask);
   sigaction(SIGINT, &sa, NULL);
   sigaction(SIGTERM, &sa, NULL);

#define EGL_ATTRIBS_BASE \
   EGL_SURFACE_TYPE,    EGL_WINDOW_BIT, \
   EGL_RED_SIZE,        1, \
   EGL_GREEN_SIZE,      1, \
   EGL_BLUE_SIZE,       1, \
   EGL_ALPHA_SIZE,      0, \
   EGL_DEPTH_SIZE,      0

   static const EGLint egl_attribs_gl[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
      EGL_NONE,
   };

   static const EGLint egl_attribs_gles[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE,
   };

#ifdef EGL_KHR_create_context
   static const EGLint egl_attribs_gles3[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
      EGL_NONE,
   };
#endif

   static const EGLint egl_attribs_vg[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
      EGL_NONE,
   };

   const EGLint *attrib_ptr;
   switch (g_api)
   {
      case GFX_CTX_OPENGL_API:
         attrib_ptr = egl_attribs_gl;
         break;
      case GFX_CTX_OPENGL_ES_API:
#ifdef EGL_KHR_create_context
         if (g_major >= 3)
            attrib_ptr = egl_attribs_gles3;
         else
#endif
         attrib_ptr = egl_attribs_gles;
         break;
      case GFX_CTX_OPENVG_API:
         attrib_ptr = egl_attribs_vg;
         break;
      default:
         attrib_ptr = NULL;
   }

   // Find desired video mode, and use that.
   // If not fullscreen, we get desired windowed size, which is not appropriate.
   if ((width == 0 && height == 0) || !fullscreen)
      g_drm_mode = &g_connector->modes[0];
   else
   {
      // Try to match g_settings.video.refresh_rate as closely as possible.
      // Lower resolutions tend to have multiple supported refresh rates as well.
      float minimum_fps_diff = 0.0f;

      // Find best match.
      for (i = 0; i < g_connector->count_modes; i++)
      {
         if (width != g_connector->modes[i].hdisplay || height != g_connector->modes[i].vdisplay)
            continue;

         if (!g_drm_mode)
         {
            g_drm_mode = &g_connector->modes[i];
            minimum_fps_diff = g_drm_mode->vrefresh - g_settings.video.refresh_rate;
         }
         else
         {
            float diff = g_connector->modes[i].vrefresh - g_settings.video.refresh_rate;
            if (diff < minimum_fps_diff)
            {
               g_drm_mode = &g_connector->modes[i];
               minimum_fps_diff = diff;
            }
         }
      }
   }

   if (!g_drm_mode)
   {
      RARCH_ERR("[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height);
      goto error;
   }

   g_fb_width = g_drm_mode->hdisplay;
   g_fb_height = g_drm_mode->vdisplay;

   // Create GBM surface.
   g_gbm_surface = gbm_surface_create(g_gbm_dev,
         g_fb_width, g_fb_height,
         GBM_FORMAT_XRGB8888,
         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);

   if (!g_gbm_surface)
   {
      RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n");
      goto error;
   }

   g_egl_dpy = eglGetDisplay((EGLNativeDisplayType)g_gbm_dev);
   if (!g_egl_dpy)
   {
      RARCH_ERR("[KMS/EGL]: Couldn't get EGL display.\n");
      goto error;
   }

   EGLint major, minor;
   if (!eglInitialize(g_egl_dpy, &major, &minor))
      goto error;

   EGLint n;
   if (!eglChooseConfig(g_egl_dpy, attrib_ptr, &g_config, 1, &n) || n != 1)
      goto error;

   EGLint egl_attribs[16];
   EGLint *attr = egl_attribs;
   attr = egl_fill_attribs(attr);

   g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT,
         attr != egl_attribs ? egl_attribs : NULL);

   if (g_egl_ctx == EGL_NO_CONTEXT)
      goto error;

   if (g_use_hw_ctx)
   {
      g_egl_hw_ctx = eglCreateContext(g_egl_dpy, g_config, g_egl_ctx,
            attr != egl_attribs ? egl_attribs : NULL);
      RARCH_LOG("[KMS/EGL]: Created shared context: %p.\n", (void*)g_egl_hw_ctx);

      if (g_egl_hw_ctx == EGL_NO_CONTEXT)
         goto error;
   }

   g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, (EGLNativeWindowType)g_gbm_surface, NULL);
   if (!g_egl_surf)
      goto error;

   if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx))
      goto error;

   glClear(GL_COLOR_BUFFER_BIT);
   eglSwapBuffers(g_egl_dpy, g_egl_surf);

   g_bo = gbm_surface_lock_front_buffer(g_gbm_surface);
   fb = drm_fb_get_from_bo(g_bo);

   ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode);
   if (ret < 0)
      goto error;

   g_inited = true;
   return true;

error:
   gfx_ctx_destroy(data);
   return false;
}
Exemple #17
0
int init_egl(void) {

	EGLint major, minor, n;
	
	static const EGLint context_attribs[] = {
		EGL_CONTEXT_CLIENT_VERSION, 2,
		EGL_NONE
	};

	static const EGLint config_attribs[] = {
		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
		EGL_RED_SIZE, 1,
		EGL_GREEN_SIZE, 1,
		EGL_BLUE_SIZE, 1,
		EGL_ALPHA_SIZE, 0,
		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
		EGL_NONE
	};

	gl.display = eglGetDisplay(gbm.dev);

	if (!eglInitialize(gl.display, &major, &minor)) {
		printf("failed to initialize\n");
		return -1;
	}

	printf("Using display %p with EGL version %d.%d\n",
			gl.display, major, minor);

	printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
	printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
	printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));

	if (!eglBindAPI(EGL_OPENGL_ES_API)) {
		printf("failed to bind api EGL_OPENGL_ES_API\n");
		return -1;
	}

	if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
		printf("failed to choose config: %d\n", n);
		return -1;
	}

	gl.context = eglCreateContext(gl.display, gl.config,
			EGL_NO_CONTEXT, context_attribs);
	if (gl.context == NULL) {
		printf("failed to create context\n");
		return -1;
	}

	gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
	if (gl.surface == EGL_NO_SURFACE) {
		printf("failed to create egl surface\n");
		return -1;
	}

	/* connect the context to the surface */
	eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);

	//MAC Sacar esto a otra función
	int ret;

	eglSwapBuffers(gl.display, gl.surface);
	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;
	}
	//MAC Fin bloque

	return 0;
}
Exemple #18
0
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;
}
Exemple #19
0
static int drm_egl_init(struct MPGLContext *ctx, int flags)
{
    if (ctx->vo->probing) {
        MP_VERBOSE(ctx->vo, "DRM EGL backend can be activated only manually.\n");
        return -1;
    }
    struct priv *p = ctx->priv;
    p->kms = NULL;
    p->old_crtc = NULL;
    p->gbm.surface = NULL;
    p->gbm.device = NULL;
    p->active = false;
    p->waiting_for_flip = false;
    p->ev.version = DRM_EVENT_CONTEXT_VERSION;
    p->ev.page_flip_handler = page_flipped;

    p->vt_switcher_active = vt_switcher_init(&p->vt_switcher, ctx->vo->log);
    if (p->vt_switcher_active) {
        vt_switcher_acquire(&p->vt_switcher, acquire_vt, ctx);
        vt_switcher_release(&p->vt_switcher, release_vt, ctx);
    } else {
        MP_WARN(ctx->vo, "Failed to set up VT switcher. Terminal switching will be unavailable.\n");
    }

    MP_VERBOSE(ctx->vo, "Initializing KMS\n");
    p->kms = kms_create(ctx->vo->log, ctx->vo->opts->drm_connector_spec,
                        ctx->vo->opts->drm_mode_id);
    if (!p->kms) {
        MP_ERR(ctx->vo, "Failed to create KMS.\n");
        return -1;
    }

    if (!init_gbm(ctx)) {
        MP_ERR(ctx->vo, "Failed to setup GBM.\n");
        return -1;
    }

    if (!init_egl(ctx, flags)) {
        MP_ERR(ctx->vo, "Failed to setup EGL.\n");
        return -1;
    }

    if (!eglMakeCurrent(p->egl.display, p->egl.surface, p->egl.surface,
                        p->egl.context)) {
        MP_ERR(ctx->vo, "Failed to make context current.\n");
        return -1;
    }

    const char *egl_exts = eglQueryString(p->egl.display, EGL_EXTENSIONS);
    void *(*gpa)(const GLubyte*) = (void *(*)(const GLubyte*))eglGetProcAddress;
    mpgl_load_functions(ctx->gl, gpa, egl_exts, ctx->vo->log);

    ctx->native_display_type = "drm";
    ctx->native_display = (void *)(intptr_t)p->kms->fd;

    // required by gbm_surface_lock_front_buffer
    eglSwapBuffers(p->egl.display, p->egl.surface);

    MP_VERBOSE(ctx->vo, "Preparing framebuffer\n");
    p->gbm.bo = gbm_surface_lock_front_buffer(p->gbm.surface);
    if (!p->gbm.bo) {
        MP_ERR(ctx->vo, "Failed to lock GBM surface.\n");
        return -1;
    }
    update_framebuffer_from_bo(ctx, p->gbm.bo);
    if (!p->fb.id) {
        MP_ERR(ctx->vo, "Failed to create framebuffer.\n");
        return -1;
    }

    if (!crtc_setup(ctx)) {
        MP_ERR(ctx->vo, "Failed to set CRTC for connector %u: %s\n",
               p->kms->connector->connector_id, mp_strerror(errno));
        return -1;
    }

    return 0;
}
Exemple #20
0
/*!***********************************************************************
 @Function		OsRenderComplete
 @Returns		false when the app should quit
 @description	Main message loop / render loop
*************************************************************************/
void PVRShellInit::OsRenderComplete()
{
	int		ckb = 0;
	size_t  bytes_read;
	int ret, i;
	struct gbm_bo *bo;
	struct SDrmFbWrapper *fb;
	int waiting_for_flip = 1;
	fd_set fds;
	drmEventContext evctx;
	evctx.version = DRM_EVENT_CONTEXT_VERSION;
	evctx.page_flip_handler = pfnCallbackDrmPageFlip;

	bo = gbm_surface_lock_front_buffer(m_psGbmSurface);
	fb = DrmFbGetFromBo(bo);
	
	if(!m_ui32CurrentFb) 
	{
		ret = drmModeSetCrtc(m_i32DrmFile, m_ui32DrmCrtcId, fb->ui32FbId, 0, 0,
				&m_ui32DrmConnectorId, 1, m_psDrmMode);

		if (ret) 
		{
			m_pShell->PVRShellOutputDebug("display failed to set mode: %s\n", strerror(errno));
			return;
		}
	} else 
	{
		ret = drmModePageFlip(m_i32DrmFile, m_ui32DrmCrtcId, fb->ui32FbId,
				DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);

		if (ret) 
		{
			m_pShell->PVRShellOutputDebug("display failed to flip page: %s\n", strerror(errno));
			return;
		}

		FD_ZERO(&fds);
		FD_SET(m_i32DrmFile, &fds);

		while (waiting_for_flip) 
		{
			ret = select(m_i32DrmFile + 1, &fds, NULL, NULL, NULL);

			if (ret < 0) 
			{
				m_pShell->PVRShellOutputDebug("Select Error: %s\n", strerror(errno));
				return;
			} 
			else if (ret == 0) 
			{
				m_pShell->PVRShellOutputDebug("Select Timeout\n");
				return;
			} 
			else if (FD_ISSET(0, &fds)) 
			{
				continue;
			}

			drmHandleEvent(m_i32DrmFile, &evctx);
		}
	}
	// Check keyboard and keypad

	// Keyboard.
	if(devfd > 0)
	{
		while ((bytes_read = read(devfd, &ckb, 1)) == 1);

		switch(ckb)
		{
		case '0':
		case 'q':
		case 'Q':
			nLastKeyPressed = PVRShellKeyNameQUIT;
			break;
		case 13:
			nLastKeyPressed = PVRShellKeyNameSELECT;
			break;
		case ' ':
		case '1':
			nLastKeyPressed = PVRShellKeyNameACTION1;
			break;
		case '2':
			nLastKeyPressed = PVRShellKeyNameACTION2;
			break;
		case 65: // Up Arrow
			nLastKeyPressed = m_eKeyMapUP;
			break;
		case 66: // Down Arrow
			nLastKeyPressed = m_eKeyMapDOWN;
			break;
		case 68: // Left Arrow
			nLastKeyPressed = m_eKeyMapLEFT;
			break;
		case 67: // Right Arrow
			nLastKeyPressed = m_eKeyMapRIGHT;
			break;
		default:
			break;
		}

	}


}
Exemple #21
0
static bool gfx_ctx_set_video_mode(
      unsigned width, unsigned height,
      bool fullscreen)
{
   if (g_inited)
      return false;

   int ret = 0;
   struct drm_fb *fb = NULL;

   struct sigaction sa = {{0}};
   sa.sa_handler = sighandler;
   sa.sa_flags   = SA_RESTART;
   sigemptyset(&sa.sa_mask);
   sigaction(SIGINT, &sa, NULL);
   sigaction(SIGTERM, &sa, NULL);

#define EGL_ATTRIBS_BASE \
   EGL_SURFACE_TYPE,    EGL_WINDOW_BIT, \
   EGL_RED_SIZE,        1, \
   EGL_GREEN_SIZE,      1, \
   EGL_BLUE_SIZE,       1, \
   EGL_ALPHA_SIZE,      0, \
   EGL_DEPTH_SIZE,      0

   static const EGLint egl_attribs_gl[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
      EGL_NONE,
   };

   static const EGLint egl_attribs_gles[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE,
   };

   static const EGLint egl_attribs_vg[] = {
      EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
      EGL_NONE,
   };

   // GLES 2.0. Don't use for any other API.
   static const EGLint gles_context_attribs[] = {
      EGL_CONTEXT_CLIENT_VERSION, 2,
      EGL_NONE
   };

   const EGLint *attrib_ptr;
   switch (g_api)
   {
      case GFX_CTX_OPENGL_API:
         attrib_ptr = egl_attribs_gl;
         break;
      case GFX_CTX_OPENGL_ES_API:
         attrib_ptr = egl_attribs_gles;
         break;
      case GFX_CTX_OPENVG_API:
         attrib_ptr = egl_attribs_vg;
         break;
      default:
         attrib_ptr = NULL;
   }

   g_egl_dpy = eglGetDisplay((EGLNativeDisplayType)g_gbm_dev);
   if (!g_egl_dpy)
   {
      RARCH_ERR("[KMS/EGL]: Couldn't get EGL display.\n");
      goto error;
   }

   EGLint major, minor;
   if (!eglInitialize(g_egl_dpy, &major, &minor))
      goto error;

   EGLint n;
   if (!eglChooseConfig(g_egl_dpy, attrib_ptr, &g_config, 1, &n) || n != 1)
      goto error;

   g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, (g_api == GFX_CTX_OPENGL_ES_API) ? gles_context_attribs : NULL);
   if (!g_egl_ctx)
      goto error;

   g_egl_surf = eglCreateWindowSurface(g_egl_dpy, g_config, (EGLNativeWindowType)g_gbm_surface, NULL);
   if (!g_egl_surf)
      goto error;

   if (!eglMakeCurrent(g_egl_dpy, g_egl_surf, g_egl_surf, g_egl_ctx))
      goto error;

   glClear(GL_COLOR_BUFFER_BIT);
   eglSwapBuffers(g_egl_dpy, g_egl_surf);

   g_bo = gbm_surface_lock_front_buffer(g_gbm_surface);
   fb = drm_fb_get_from_bo(g_bo);

   ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode);
   if (ret < 0)
      goto error;

   g_inited = true;
   return true;

error:
   gfx_ctx_destroy();
   return false;
}
Exemple #22
0
static bool gfx_ctx_drm_set_video_mode(void *data,
      unsigned width, unsigned height,
      bool fullscreen)
{
   float refresh_mod;
   int i, ret                  = 0;
   struct drm_fb *fb           = NULL;
   settings_t *settings        = config_get_ptr();
   gfx_ctx_drm_data_t *drm     = (gfx_ctx_drm_data_t*)data;

   if (!drm)
      return false;

   frontend_driver_install_signal_handler();

   /* If we use black frame insertion, 
    * we fake a 60 Hz monitor for 120 Hz one, 
    * etc, so try to match that. */
   refresh_mod = settings->video.black_frame_insertion 
      ? 0.5f : 1.0f;

   /* Find desired video mode, and use that.
    * If not fullscreen, we get desired windowed size, 
    * which is not appropriate. */
   if ((width == 0 && height == 0) || !fullscreen)
      g_drm_mode = &g_drm_connector->modes[0];
   else
   {
      /* Try to match settings->video.refresh_rate 
       * as closely as possible.
       *
       * Lower resolutions tend to have multiple supported 
       * refresh rates as well.
       */
      float minimum_fps_diff = 0.0f;

      /* Find best match. */
      for (i = 0; i < g_drm_connector->count_modes; i++)
      {
         float diff;
         if (width != g_drm_connector->modes[i].hdisplay || 
               height != g_drm_connector->modes[i].vdisplay)
            continue;

         diff = fabsf(refresh_mod * g_drm_connector->modes[i].vrefresh
               - settings->video.refresh_rate);

         if (!g_drm_mode || diff < minimum_fps_diff)
         {
            g_drm_mode = &g_drm_connector->modes[i];
            minimum_fps_diff = diff;
         }
      }
   }

   if (!g_drm_mode)
   {
      RARCH_ERR("[KMS/EGL]: Did not find suitable video mode for %u x %u.\n",
            width, height);
      goto error;
   }

   drm->fb_width    = g_drm_mode->hdisplay;
   drm->fb_height   = g_drm_mode->vdisplay;

   /* Create GBM surface. */
   g_gbm_surface = gbm_surface_create(
         g_gbm_dev,
         drm->fb_width,
         drm->fb_height,
         GBM_FORMAT_XRGB8888,
         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);

   if (!g_gbm_surface)
   {
      RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n");
      goto error;
   }


   switch (drm_api)
   {
      case GFX_CTX_OPENGL_API:
      case GFX_CTX_OPENGL_ES_API:
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_EGL
         if (!gfx_ctx_drm_egl_set_video_mode(drm))
            goto error;
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }

   g_bo = gbm_surface_lock_front_buffer(g_gbm_surface);
   fb   = drm_fb_get_from_bo(g_bo);

   ret  = drmModeSetCrtc(g_drm_fd,
         g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode);
   if (ret < 0)
      goto error;

   return true;

error:
   gfx_ctx_drm_destroy_resources(drm);

   if (drm)
      free(drm);

   return false;
}
Exemple #23
0
static int atomic_run(const struct gbm *gbm, const struct egl *egl)
{
	struct gbm_bo *bo = NULL;
	struct drm_fb *fb;
	uint32_t i = 0;
	uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
	struct timeval timeout;
	fd_set fds;
	int ret;

	if (egl_check(egl, eglDupNativeFenceFDANDROID) ||
	    egl_check(egl, eglCreateSyncKHR) ||
	    egl_check(egl, eglDestroySyncKHR) ||
	    egl_check(egl, eglWaitSyncKHR) ||
	    egl_check(egl, eglClientWaitSyncKHR))
		return -1;

	/* Allow a modeset change for the first commit only. */
	flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;

	while (1) {
		struct gbm_bo *next_bo;
		EGLSyncKHR gpu_fence = NULL;   /* out-fence from gpu, in-fence to kms */
		EGLSyncKHR kms_fence = NULL;   /* in-fence to gpu, out-fence from kms */

		if (drm.kms_out_fence_fd != -1) {
			kms_fence = create_fence(egl, drm.kms_out_fence_fd);
			assert(kms_fence);

			/* driver now has ownership of the fence fd: */
			drm.kms_out_fence_fd = -1;

			/* wait "on the gpu" (ie. this won't necessarily block, but
			 * will block the rendering until fence is signaled), until
			 * the previous pageflip completes so we don't render into
			 * the buffer that is still on screen.
			 */
			egl->eglWaitSyncKHR(egl->display, kms_fence, 0);
		}

		egl->draw(i++);

		/* insert fence to be singled in cmdstream.. this fence will be
		 * signaled when gpu rendering done
		 */
		gpu_fence = create_fence(egl, EGL_NO_NATIVE_FENCE_FD_ANDROID);
		assert(gpu_fence);

		eglSwapBuffers(egl->display, egl->surface);

		/* after swapbuffers, gpu_fence should be flushed, so safe
		 * to get fd:
		 */
		drm.kms_in_fence_fd = egl->eglDupNativeFenceFDANDROID(egl->display, gpu_fence);
		egl->eglDestroySyncKHR(egl->display, gpu_fence);
		assert(drm.kms_in_fence_fd != -1);

		next_bo = gbm_surface_lock_front_buffer(gbm->surface);
		if (!next_bo) {
			printf("Failed to lock frontbuffer\n");
			return -1;
		}
		fb = drm_fb_get_from_bo(next_bo);
		if (!fb) {
			printf("Failed to get a new framebuffer BO\n");
			return -1;
		}

		if (kms_fence) {
			EGLint status;

			/* Wait on the CPU side for the _previous_ commit to
			 * complete before we post the flip through KMS, as
			 * atomic will reject the commit if we post a new one
			 * whilst the previous one is still pending.
			 */
			do {
				status = egl->eglClientWaitSyncKHR(egl->display,
								   kms_fence,
								   0,
								   EGL_FOREVER_KHR);
			} while (status != EGL_CONDITION_SATISFIED_KHR);

			egl->eglDestroySyncKHR(egl->display, kms_fence);
		}

		/*
		 * Here you could also update drm plane layers if you want
		 * hw composition
		 */
		ret = drm_atomic_commit(fb->fb_id, flags);
		if (ret) {
			printf("failed to commit: %s\n", strerror(errno));
			return -1;
		}

		/* release last buffer to render on again: */
		if (bo)
			gbm_surface_release_buffer(gbm->surface, bo);
		bo = next_bo;

		/* Allow a modeset change for the first commit only. */
		flags &= ~(DRM_MODE_ATOMIC_ALLOW_MODESET);

		/* watch for user interruption */
		FD_ZERO(&fds);
		FD_SET(0, &fds);
		memset(&timeout, 0, sizeof(timeout));

		ret = select(1, &fds, NULL, NULL, &timeout);
		if (ret < 0) {
			printf("select() failed: %s\n", strerror(errno));
			break;
		}

		/*
		 * select() will immediately timeout if there was no user
		 * interrupt because of the 0 timeout. However, that's an
		 * expected situation, not an error, so we just ignore it
		 * here.
		 */
		if (FD_ISSET(0, &fds)) {
			printf("user interrupted!\n");
			break;
		}
	}

	return ret;
}
static void
_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
{
  CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
  CoglDisplayEGL *egl_display = context->display->winsys;
  CoglDisplayKMS *kms_display = egl_display->platform;
  CoglRenderer *renderer = context->display->renderer;
  CoglRendererEGL *egl_renderer = renderer->winsys;
  CoglRendererKMS *kms_renderer = egl_renderer->platform;
  CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
  CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
  uint32_t handle, stride;
  CoglFlipKMS *flip;
  GList *l;

  /* If we already have a pending swap then block until it completes */
  while (kms_onscreen->next_fb_id != 0)
    handle_drm_event (kms_renderer);

  /* First chain-up. This will call eglSwapBuffers */
  parent_vtable->onscreen_swap_buffers (onscreen);

  /* Now we need to set the CRTC to whatever is the front buffer */
  kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface);

#if (COGL_VERSION_ENCODE (COGL_GBM_MAJOR, COGL_GBM_MINOR, COGL_GBM_MICRO) >= \
     COGL_VERSION_ENCODE (8, 1, 0))
  stride = gbm_bo_get_stride (kms_onscreen->next_bo);
#else
  stride = gbm_bo_get_pitch (kms_onscreen->next_bo);
#endif
  handle = gbm_bo_get_handle (kms_onscreen->next_bo).u32;

  if (drmModeAddFB (kms_renderer->fd,
                    kms_display->width,
                    kms_display->height,
                    24, /* depth */
                    32, /* bpp */
                    stride,
                    handle,
                    &kms_onscreen->next_fb_id))
    {
      g_warning ("Failed to create new back buffer handle: %m");
      gbm_surface_release_buffer (kms_onscreen->surface,
                                  kms_onscreen->next_bo);
      kms_onscreen->next_bo = NULL;
      kms_onscreen->next_fb_id = 0;
      return;
    }

  /* If this is the first framebuffer to be presented then we now setup the
   * crtc modes... */
  if (kms_display->pending_set_crtc)
    {
      setup_crtc_modes (context->display, kms_onscreen->next_fb_id);
      kms_display->pending_set_crtc = FALSE;
    }

  flip = g_slice_new0 (CoglFlipKMS);
  flip->onscreen = onscreen;

  for (l = kms_display->outputs; l; l = l->next)
    {
      CoglOutputKMS *output = l->data;

      if (drmModePageFlip (kms_renderer->fd,
                           output->encoder->crtc_id,
                           kms_onscreen->next_fb_id,
                           DRM_MODE_PAGE_FLIP_EVENT,
                           flip))
        {
          g_warning ("Failed to flip: %m");
          continue;
        }

      flip->pending++;
    }

  if (flip->pending == 0)
    {
      drmModeRmFB (kms_renderer->fd, kms_onscreen->next_fb_id);
      gbm_surface_release_buffer (kms_onscreen->surface,
                                  kms_onscreen->next_bo);
      kms_onscreen->next_bo = NULL;
      kms_onscreen->next_fb_id = 0;
      g_slice_free (CoglFlipKMS, flip);
      flip = NULL;
    }
  else
    {
      /* Ensure the onscreen remains valid while it has any pending flips... */
      cogl_object_ref (flip->onscreen);
    }
}
Exemple #25
0
static bool gfx_ctx_drm_egl_set_video_mode(void *data,
      unsigned width, unsigned height,
      bool fullscreen)
{
   static const EGLint egl_attribs_gl[] = {
      DRM_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
      EGL_NONE,
   };

   static const EGLint egl_attribs_gles[] = {
      DRM_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE,
   };

#ifdef EGL_KHR_create_context
   static const EGLint egl_attribs_gles3[] = {
      DRM_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
      EGL_NONE,
   };
#endif

   static const EGLint egl_attribs_vg[] = {
      DRM_EGL_ATTRIBS_BASE,
      EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
      EGL_NONE,
   };

   const EGLint *attrib_ptr;
   EGLint major, minor, n, egl_attribs[16], *attr;
   float refresh_mod;
   int i, ret = 0;
   struct sigaction sa = {{0}};
   struct drm_fb *fb = NULL;
   gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)
      driver.video_context_data;

   if (!drm)
      return false;

   sa.sa_handler = sighandler;
   sa.sa_flags   = SA_RESTART;
   sigemptyset(&sa.sa_mask);
   sigaction(SIGINT, &sa, NULL);
   sigaction(SIGTERM, &sa, NULL);

   switch (g_api)
   {
      case GFX_CTX_OPENGL_API:
         attrib_ptr = egl_attribs_gl;
         break;
      case GFX_CTX_OPENGL_ES_API:
#ifdef EGL_KHR_create_context
         if (g_major >= 3)
            attrib_ptr = egl_attribs_gles3;
         else
#endif
         attrib_ptr = egl_attribs_gles;
         break;
      case GFX_CTX_OPENVG_API:
         attrib_ptr = egl_attribs_vg;
         break;
      default:
         attrib_ptr = NULL;
   }

   /* If we use black frame insertion, 
    * we fake a 60 Hz monitor for 120 Hz one, etc, so try to match that. */
   refresh_mod = g_settings.video.black_frame_insertion ? 0.5f : 1.0f;

   /* Find desired video mode, and use that.
    * If not fullscreen, we get desired windowed size, 
    * which is not appropriate. */
   if ((width == 0 && height == 0) || !fullscreen)
      drm->g_drm_mode = &drm->g_connector->modes[0];
   else
   {
      /* Try to match g_settings.video.refresh_rate as closely as possible.
       * Lower resolutions tend to have multiple supported 
       * refresh rates as well.
       */
      float minimum_fps_diff = 0.0f;

      /* Find best match. */
      for (i = 0; i < drm->g_connector->count_modes; i++)
      {
         if (width != drm->g_connector->modes[i].hdisplay || 
               height != drm->g_connector->modes[i].vdisplay)
            continue;

         float diff = fabsf(refresh_mod * 
               drm->g_connector->modes[i].vrefresh - g_settings.video.refresh_rate);
         if (!drm->g_drm_mode || diff < minimum_fps_diff)
         {
            drm->g_drm_mode = &drm->g_connector->modes[i];
            minimum_fps_diff = diff;
         }
      }
   }

   if (!drm->g_drm_mode)
   {
      RARCH_ERR("[KMS/EGL]: Did not find suitable video mode for %u x %u.\n", width, height);
      goto error;
   }

   drm->g_fb_width  = drm->g_drm_mode->hdisplay;
   drm->g_fb_height = drm->g_drm_mode->vdisplay;

   /* Create GBM surface. */
   drm->g_gbm_surface = gbm_surface_create(
         drm->g_gbm_dev,
         drm->g_fb_width,
         drm->g_fb_height,
         GBM_FORMAT_XRGB8888,
         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);

   if (!drm->g_gbm_surface)
   {
      RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n");
      goto error;
   }

   drm->g_egl_dpy = eglGetDisplay((EGLNativeDisplayType)drm->g_gbm_dev);
   if (!drm->g_egl_dpy)
   {
      RARCH_ERR("[KMS/EGL]: Couldn't get EGL display.\n");
      goto error;
   }

   if (!eglInitialize(drm->g_egl_dpy, &major, &minor))
      goto error;

   if (!eglChooseConfig(drm->g_egl_dpy, attrib_ptr, &drm->g_config, 1, &n) || n != 1)
      goto error;

   attr = egl_fill_attribs(egl_attribs);

   drm->g_egl_ctx = eglCreateContext(drm->g_egl_dpy, drm->g_config, EGL_NO_CONTEXT,
         attr != egl_attribs ? egl_attribs : NULL);

   if (drm->g_egl_ctx == EGL_NO_CONTEXT)
      goto error;

   if (drm->g_use_hw_ctx)
   {
      drm->g_egl_hw_ctx = eglCreateContext(drm->g_egl_dpy, drm->g_config, drm->g_egl_ctx,
            attr != egl_attribs ? egl_attribs : NULL);
      RARCH_LOG("[KMS/EGL]: Created shared context: %p.\n", (void*)drm->g_egl_hw_ctx);

      if (drm->g_egl_hw_ctx == EGL_NO_CONTEXT)
         goto error;
   }

   drm->g_egl_surf = eglCreateWindowSurface(drm->g_egl_dpy,
         drm->g_config, (EGLNativeWindowType)drm->g_gbm_surface, NULL);
   if (!drm->g_egl_surf)
      goto error;

   if (!eglMakeCurrent(drm->g_egl_dpy,
            drm->g_egl_surf, drm->g_egl_surf, drm->g_egl_ctx))
      goto error;

   glClear(GL_COLOR_BUFFER_BIT);
   eglSwapBuffers(drm->g_egl_dpy, drm->g_egl_surf);

   drm->g_bo = gbm_surface_lock_front_buffer(drm->g_gbm_surface);
   fb = drm_fb_get_from_bo(drm, drm->g_bo);

   ret = drmModeSetCrtc(drm->g_drm_fd,
         drm->g_crtc_id, fb->fb_id, 0, 0, &drm->g_connector_id, 1, drm->g_drm_mode);
   if (ret < 0)
      goto error;

   return true;

error:
   gfx_ctx_drm_egl_destroy_resources(drm);

   if (drm)
      free(drm);

   return false;
}
Exemple #26
0
int init_egl_drm()
{
        fd_set fds;
        drmEventContext evctx = {
                        .version = DRM_EVENT_CONTEXT_VERSION,
                        .vblank_handler = 0,
                        .page_flip_handler = page_flip_handler,
        };
        struct gbm_bo *bo;
        struct drm_fb *fb;
        ret = init_drm();
        if (ret) {
                printf("failed to initialize DRM\n");
                return ret;
        }
        printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n",
                        drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay,
                        drm.mode[DISP_ID]->vdisplay);

        FD_ZERO(&fds);
        FD_SET(drm.fd, &fds);

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

	//Initialise egl regularly here
}

void egl_drm_draw_flip()
{
        /* set mode: */
        if (all_display) {
                for (i=0; i<drm.ndisp; i++) {
                        ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
                                        &drm.connector_id[i], 1, drm.mode[i]);
                        if (ret) {
                                printf("display %d failed to set mode: %s\n", i, strerror(errno));
                                return ret;
                        }
                }
        } else {
                ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
                                0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
                if (ret) {
                        printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
                        return ret;
                }
        }
	//Draw call here
	//Swapping is involved
                next_bo = gbm_surface_lock_front_buffer(gbm.surface);
                fb = drm_fb_get_from_bo(next_bo);

                /*
                 * Here you could also update drm plane layers if you want
                 * hw composition
                 */

                ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
                                DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
                if (ret) {
                        printf("failed to queue page flip: %s\n", strerror(errno));
                        return -1;
                }

                while (waiting_for_flip) {
                        ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
                        if (ret < 0) {
                                printf("select err: %s\n", strerror(errno));
                                return ret;
                        } else if (ret == 0) {
                                printf("select timeout!\n");
                                return -1;
                        } else if (FD_ISSET(0, &fds)) {
                                continue;
                        }
                        drmHandleEvent(drm.fd, &evctx);
                }
                /* release last buffer to render on again: */
                gbm_surface_release_buffer(gbm.surface, bo);
                bo = next_bo;
}
Exemple #27
0
int main(int argc, char *argv[])
{
   EGLDisplay dpy;
   EGLContext ctx;
   EGLSurface surface;
   EGLConfig config;
   EGLint major, minor, n;
   const char *ver;
   uint32_t handle, stride;
   struct kms kms;
   int ret, fd;
   struct gbm_device *gbm;
   struct gbm_bo *bo;
   drmModeCrtcPtr saved_crtc;
   struct gbm_surface *gs;

   fd = open(device_name, O_RDWR);
   if (fd < 0) {
      /* Probably permissions error */
      fprintf(stderr, "couldn't open %s, skipping\n", device_name);
      return -1;
   }

   gbm = gbm_create_device(fd);
   if (gbm == NULL) {
      fprintf(stderr, "couldn't create gbm device\n");
      ret = -1;
      goto close_fd;
   }

   dpy = eglGetDisplay(gbm);
   if (dpy == EGL_NO_DISPLAY) {
      fprintf(stderr, "eglGetDisplay() failed\n");
      ret = -1;
      goto destroy_gbm_device;
   }
	
   if (!eglInitialize(dpy, &major, &minor)) {
      printf("eglInitialize() failed\n");
      ret = -1;
      goto egl_terminate;
   }

   ver = eglQueryString(dpy, EGL_VERSION);
   printf("EGL_VERSION = %s\n", ver);

   if (!setup_kms(fd, &kms)) {
      ret = -1;
      goto egl_terminate;
   }

   eglBindAPI(EGL_OPENGL_API);

   if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) {
      fprintf(stderr, "failed to choose argb config\n");
      goto egl_terminate;
   }
   
   ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
   if (ctx == NULL) {
      fprintf(stderr, "failed to create context\n");
      ret = -1;
      goto egl_terminate;
   }

   gs = gbm_surface_create(gbm, kms.mode.hdisplay, kms.mode.vdisplay,
			   GBM_BO_FORMAT_XRGB8888,
			   GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
   surface = eglCreateWindowSurface(dpy, config, gs, NULL);

   if (!eglMakeCurrent(dpy, surface, surface, ctx)) {
      fprintf(stderr, "failed to make context current\n");
      ret = -1;
      goto destroy_context;
   }

   render_stuff(kms.mode.hdisplay, kms.mode.vdisplay);

   eglSwapBuffers(dpy, surface);

   bo = gbm_surface_lock_front_buffer(gs);
   handle = gbm_bo_get_handle(bo).u32;
   stride = gbm_bo_get_stride(bo);

   printf("handle=%d, stride=%d\n", handle, stride);

   ret = drmModeAddFB(fd,
		      kms.mode.hdisplay, kms.mode.vdisplay,
		      24, 32, stride, handle, &kms.fb_id);
   if (ret) {
      fprintf(stderr, "failed to create fb\n");
      goto rm_fb;
   }

   saved_crtc = drmModeGetCrtc(fd, kms.encoder->crtc_id);
   if (saved_crtc == NULL)
      goto rm_fb;

   ret = drmModeSetCrtc(fd, kms.encoder->crtc_id, kms.fb_id, 0, 0,
			&kms.connector->connector_id, 1, &kms.mode);
   if (ret) {
      fprintf(stderr, "failed to set mode: %m\n");
      goto free_saved_crtc;
   }

   getchar();

   ret = drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id,
                        saved_crtc->x, saved_crtc->y,
                        &kms.connector->connector_id, 1, &saved_crtc->mode);
   if (ret) {
      fprintf(stderr, "failed to restore crtc: %m\n");
   }

free_saved_crtc:
   drmModeFreeCrtc(saved_crtc);
rm_fb:
   drmModeRmFB(fd, kms.fb_id);
   eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
destroy_context:
   eglDestroyContext(dpy, ctx);
egl_terminate:
   eglTerminate(dpy);
destroy_gbm_device:
   gbm_device_destroy(gbm);
close_fd:
   close(fd);

   return ret;
}
Exemple #28
0
int main(int argc, char *argv[])
{
	EGLDisplay dpy;
	EGLContext ctx;
	EGLConfig config;
	EGLSurface surface;
	EGLint major, minor, n;
	const char *ver;
	uint32_t handle, stride;
	int ret, fd, frames = 0;
	struct gbm_device *gbm;
	drmModeCrtcPtr saved_crtc;
	time_t start, end;
	char *data;
	char j;
	int i;
	int once;
	once = 0;

	signal (SIGINT, quit_handler);

	fd = open(device_name, O_RDWR);
	if (fd < 0) {
		/* Probably permissions error */
		fprintf(stderr, "couldn't open %s, skipping\n", device_name);
		return -1;
	}

	gbm = gbm_create_device(fd);
	if (gbm == NULL) {
		fprintf(stderr, "couldn't create gbm device\n");
		ret = -1;
		goto close_fd;
	}

	dpy = eglGetDisplay(gbm);
	if (dpy == EGL_NO_DISPLAY) {
		fprintf(stderr, "eglGetDisplay() failed\n");
		ret = -1;
		goto destroy_gbm_device;
	}

	if (!eglInitialize(dpy, &major, &minor)) {
		printf("eglInitialize() failed\n");
		ret = -1;
		goto egl_terminate;
	}

	ver = eglQueryString(dpy, EGL_VERSION);
	printf("EGL_VERSION = %s\n", ver);

	if (!setup_kms(fd, &kms)) {
		ret = -1;
		goto egl_terminate;
	}

	eglBindAPI(EGL_OPENGL_API);

	if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) {
		fprintf(stderr, "failed to choose argb config\n");
		goto egl_terminate;
	}

	ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL);
	if (ctx == NULL) {
		fprintf(stderr, "failed to create context\n");
		ret = -1;
		goto egl_terminate;
	}

	gs = gbm_surface_create(gbm, kms.mode.hdisplay, kms.mode.vdisplay,
		GBM_BO_FORMAT_XRGB8888,
		GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
	if (gs == NULL) {
		fprintf(stderr, "unable to create gbm surface\n");
		ret = -1;
		goto egl_terminate;
	}


	surface = eglCreateWindowSurface(dpy, config, gs, NULL);
	if (surface == EGL_NO_SURFACE) {
		fprintf(stderr, "failed to create surface\n");
		ret = -1;
		goto destroy_gbm_surface;
	}

	if (!eglMakeCurrent(dpy, surface, surface, ctx)) {
		fprintf(stderr, "failed to make context current\n");
		ret = -1;
		goto destroy_surface;
	}

	saved_crtc = drmModeGetCrtc(fd, kms.crtc_id);
	if (saved_crtc == NULL)
	{
		fprintf(stderr, "no valid graphic configuration active (VT ?)\n");
	}
	time(&start);
	do {

		drmEventContext evctx;
		fd_set rfds;

		render_stuff(kms.mode.hdisplay, kms.mode.vdisplay);
		eglSwapBuffers(dpy, surface);
		
		if (!gbm_surface_has_free_buffers(gs))
			fprintf(stderr, "out of free buffers\n");

		next_bo = gbm_surface_lock_front_buffer(gs);
		if (!next_bo)
			fprintf(stderr, "failed to lock front buffer: %m\n");

		handle = gbm_bo_get_handle(next_bo).u32;
		stride = gbm_bo_get_stride(next_bo);
		
		ret = drmModeAddFB(fd,
				 kms.mode.hdisplay, kms.mode.vdisplay,
				 24, 32, stride, handle, &next_fb_id);
		if (ret) {
			fprintf(stderr, "failed to create fb\n");
			goto out;
		}
		  
		/* make sure to setup crtc once (fix for broken drivers) */
		if(once == 0){
			once = 1;
			drmModeSetCrtc(fd, kms.crtc_id, next_fb_id,
				0, 0,
				&kms.connector->connector_id, 1, &kms.mode);
		}
		
		ret = drmModePageFlip(fd, kms.crtc_id,
					next_fb_id,
					DRM_MODE_PAGE_FLIP_EVENT, 0);
		if (ret) {
			fprintf(stderr, "failed to page flip: %m\n");
			goto out;
		}

		FD_ZERO(&rfds);
		FD_SET(fd, &rfds);

		while (select(fd + 1, &rfds, NULL, NULL, NULL) == -1)
			NULL;

		memset(&evctx, 0, sizeof evctx);
		evctx.version = DRM_EVENT_CONTEXT_VERSION;
		evctx.page_flip_handler = page_flip_handler;

		drmHandleEvent(fd, &evctx);

		frames++;
	} while (!quit);
	time(&end);

	printf("Frames per second: %.2lf\n", frames / difftime(end, start));

out:
	if(saved_crtc){
		drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id,
			saved_crtc->x, saved_crtc->y,
			&kms.connector->connector_id, 1, &saved_crtc->mode);
		}
	drmModeFreeCrtc(saved_crtc);
	if (current_fb_id)
		drmModeRmFB(fd, current_fb_id);
	if (next_fb_id)
		drmModeRmFB(fd, next_fb_id);
	eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
destroy_context:
	eglDestroyContext(dpy, ctx);
destroy_surface:
	eglDestroySurface(dpy, surface);
destroy_gbm_surface:
	gbm_surface_destroy(gs);
egl_terminate:
	eglTerminate(dpy);
destroy_gbm_device:
	gbm_device_destroy(gbm);
close_fd:
	close(fd);

	return ret;
}