Beispiel #1
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;
}
Beispiel #2
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);
	}
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
Beispiel #11
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;
}
Beispiel #12
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;
}
Beispiel #13
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;
}
Beispiel #14
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;
}