2017-08-02 19:22:48 +02:00
|
|
|
/*
|
|
|
|
Simple DirectMedia Layer
|
2020-01-17 05:49:25 +01:00
|
|
|
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
2020-08-25 16:30:23 +02:00
|
|
|
Atomic KMSDRM backend by Manuel Alfayate Corchete <redwindwanderer@gmail.com>
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
2017-08-22 02:20:50 +02:00
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
#include "../../SDL_internal.h"
|
|
|
|
|
2020-12-22 14:15:33 +01:00
|
|
|
#if SDL_VIDEO_DRIVER_KMSDRM
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
#include "SDL_kmsdrmvideo.h"
|
|
|
|
#include "SDL_kmsdrmopengles.h"
|
|
|
|
#include "SDL_kmsdrmdyn.h"
|
2020-09-10 21:07:23 +02:00
|
|
|
#include "SDL_hints.h"
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
#ifndef EGL_PLATFORM_GBM_MESA
|
|
|
|
#define EGL_PLATFORM_GBM_MESA 0x31D7
|
|
|
|
#endif
|
|
|
|
|
2020-09-10 21:05:55 +02:00
|
|
|
#ifndef EGL_SYNC_NATIVE_FENCE_ANDROID
|
|
|
|
#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef EGL_SYNC_NATIVE_FENCE_FD_ANDROID
|
|
|
|
#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef EGL_NO_NATIVE_FENCE_FD_ANDROID
|
|
|
|
#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
|
|
|
|
#endif
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
/* EGL implementation of SDL OpenGL support */
|
|
|
|
|
2020-09-10 21:04:35 +02:00
|
|
|
void
|
|
|
|
KMSDRM_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor)
|
|
|
|
{
|
|
|
|
/* if SDL was _also_ built with the Raspberry Pi driver (so we're
|
|
|
|
definitely a Pi device), default to GLES2. */
|
|
|
|
#if SDL_VIDEO_DRIVER_RPI
|
|
|
|
*mask = SDL_GL_CONTEXT_PROFILE_ES;
|
|
|
|
*major = 2;
|
|
|
|
*minor = 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
int
|
|
|
|
KMSDRM_GLES_LoadLibrary(_THIS, const char *path) {
|
2020-12-18 22:53:51 +01:00
|
|
|
/* Just pretend you do this here, but don't do it until KMSDRM_CreateWindow(),
|
|
|
|
where we do the same library load we would normally do here.
|
|
|
|
because this gets called by SDL_CreateWindow() before KMSDR_CreateWindow(),
|
|
|
|
so gbm dev isn't yet created when this is called, AND we can't alter the
|
|
|
|
call order in SDL_CreateWindow(). */
|
|
|
|
#if 0
|
2020-07-20 11:42:23 +02:00
|
|
|
NativeDisplayType display = (NativeDisplayType)((SDL_VideoData *)_this->driverdata)->gbm_dev;
|
2020-02-27 17:20:34 +01:00
|
|
|
return SDL_EGL_LoadLibrary(_this, path, display, EGL_PLATFORM_GBM_MESA);
|
2020-12-18 22:53:51 +01:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KMSDRM_GLES_UnloadLibrary(_THIS) {
|
|
|
|
/* As with KMSDRM_GLES_LoadLibrary(), we define our own unloading function so
|
|
|
|
we manually unload the library whenever we want. */
|
2017-08-02 19:22:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SDL_EGL_CreateContext_impl(KMSDRM)
|
|
|
|
|
|
|
|
int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
|
|
|
|
if (!_this->egl_data) {
|
|
|
|
return SDL_SetError("EGL not initialized");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interval == 0 || interval == 1) {
|
|
|
|
_this->egl_data->egl_swapinterval = interval;
|
|
|
|
} else {
|
|
|
|
return SDL_SetError("Only swap intervals of 0 or 1 are supported");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/*********************************/
|
|
|
|
/* Atomic functions block */
|
|
|
|
/*********************************/
|
|
|
|
|
|
|
|
#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
|
|
|
|
|
|
|
|
static EGLSyncKHR create_fence(int fd, _THIS)
|
|
|
|
{
|
2020-10-22 16:01:51 +02:00
|
|
|
EGLint attrib_list[] = {
|
|
|
|
EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd,
|
|
|
|
EGL_NONE,
|
|
|
|
};
|
2020-12-18 22:53:51 +01:00
|
|
|
|
2020-10-22 16:01:51 +02:00
|
|
|
EGLSyncKHR fence = _this->egl_data->eglCreateSyncKHR
|
|
|
|
(_this->egl_data->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attrib_list);
|
|
|
|
|
|
|
|
assert(fence);
|
|
|
|
return fence;
|
2020-07-28 21:11:25 +02:00
|
|
|
}
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/***********************************************************************************/
|
|
|
|
/* Comments about buffer access protection mechanism (=fences) are the ones boxed. */
|
|
|
|
/* Also, DON'T remove the asserts: if a fence-related call fails, it's better that */
|
|
|
|
/* program exits immediately, or we could leave KMS waiting for a failed/missing */
|
|
|
|
/* fence forevever. */
|
|
|
|
/***********************************************************************************/
|
|
|
|
int
|
2020-09-10 21:07:23 +02:00
|
|
|
KMSDRM_GLES_SwapWindowFenced(_THIS, SDL_Window * window)
|
2020-08-05 02:06:59 +02:00
|
|
|
{
|
2020-02-09 20:44:22 +01:00
|
|
|
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
|
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
2020-07-28 21:11:25 +02:00
|
|
|
KMSDRM_FBInfo *fb;
|
2020-08-23 23:44:07 +02:00
|
|
|
KMSDRM_PlaneInfo info = {0};
|
2020-08-03 22:24:49 +02:00
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/******************************************************************/
|
|
|
|
/* Create the GPU-side FENCE OBJECT. It will be inserted into the */
|
|
|
|
/* GL CMDSTREAM exactly at the end of the gl commands that form a */
|
|
|
|
/* frame.(KMS will have to wait on it before doing a pageflip.) */
|
|
|
|
/******************************************************************/
|
2020-08-03 22:24:49 +02:00
|
|
|
dispdata->gpu_fence = create_fence(EGL_NO_NATIVE_FENCE_FD_ANDROID, _this);
|
|
|
|
assert(dispdata->gpu_fence);
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/******************************************************************/
|
|
|
|
/* eglSwapBuffers flushes the fence down the GL CMDSTREAM, so we */
|
|
|
|
/* know for sure it's there now. */
|
|
|
|
/* Also it marks, at EGL level, the buffer that we want to become */
|
|
|
|
/* the new front buffer. (Remember that won't really happen until */
|
|
|
|
/* we request a pageflip at the KMS level and it completes. */
|
|
|
|
/******************************************************************/
|
2020-09-06 12:08:22 +02:00
|
|
|
if (! _this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface)) {
|
2020-09-06 12:48:39 +02:00
|
|
|
return SDL_EGL_SetError("Failed to swap EGL buffers", "eglSwapBuffers");
|
2020-09-06 12:08:22 +02:00
|
|
|
}
|
2020-10-22 16:01:51 +02:00
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/******************************************************************/
|
|
|
|
/* EXPORT the GPU-side FENCE OBJECT to the fence INPUT FD, so we */
|
|
|
|
/* can pass it into the kernel. Atomic ioctl will pass the */
|
|
|
|
/* in-fence fd into the kernel, thus telling KMS that it has to */
|
|
|
|
/* wait for GPU to finish rendering the frame (remember where we */
|
|
|
|
/* put the fence in the GL CMDSTREAM) before doing the changes */
|
|
|
|
/* requested in the atomic ioct (the pageflip in this case). */
|
|
|
|
/* (We export the GPU-side FENCE OJECT to the fence INPUT FD now, */
|
|
|
|
/* not sooner, because now we are sure that the GPU-side fence is */
|
|
|
|
/* in the CMDSTREAM to be lifted when the CMDSTREAM to this point */
|
|
|
|
/* is completed). */
|
|
|
|
/******************************************************************/
|
2020-10-22 16:01:51 +02:00
|
|
|
dispdata->kms_in_fence_fd = _this->egl_data->eglDupNativeFenceFDANDROID (_this->egl_data->egl_display,
|
|
|
|
dispdata->gpu_fence);
|
2020-09-10 23:26:02 +02:00
|
|
|
|
2020-08-03 22:24:49 +02:00
|
|
|
_this->egl_data->eglDestroySyncKHR(_this->egl_data->egl_display, dispdata->gpu_fence);
|
|
|
|
assert(dispdata->kms_in_fence_fd != -1);
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/* Lock the buffer that is marked by eglSwapBuffers() to become the
|
|
|
|
next front buffer (so it can not be chosen by EGL as back buffer
|
|
|
|
to draw on), and get a handle to it to request the pageflip on it.
|
|
|
|
REMEMBER that gbm_surface_lock_front_buffer() ALWAYS has to be
|
|
|
|
called after eglSwapBuffers(). */
|
2020-08-03 22:24:49 +02:00
|
|
|
windata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(windata->gs);
|
|
|
|
if (!windata->next_bo) {
|
2020-10-22 16:01:51 +02:00
|
|
|
return SDL_SetError("Failed to lock frontbuffer");
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
fb = KMSDRM_FBFromBO(_this, windata->next_bo);
|
|
|
|
if (!fb) {
|
2020-10-22 16:01:51 +02:00
|
|
|
return SDL_SetError("Failed to get a new framebuffer from BO");
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-08-23 23:44:07 +02:00
|
|
|
/* Add the pageflip to the request list. */
|
|
|
|
info.plane = dispdata->display_plane;
|
|
|
|
info.crtc_id = dispdata->crtc->crtc->crtc_id;
|
|
|
|
info.fb_id = fb->fb_id;
|
2020-08-28 22:38:26 +02:00
|
|
|
|
2020-08-31 19:17:17 +02:00
|
|
|
info.src_w = windata->src_w;
|
|
|
|
info.src_h = windata->src_h;
|
2020-08-28 22:38:26 +02:00
|
|
|
info.crtc_w = windata->output_w;
|
|
|
|
info.crtc_h = windata->output_h;
|
|
|
|
info.crtc_x = windata->output_x;
|
2020-08-23 23:44:07 +02:00
|
|
|
|
2020-09-12 15:58:47 +02:00
|
|
|
drm_atomic_set_plane_props(&info);
|
2020-08-03 22:24:49 +02:00
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/*****************************************************************/
|
|
|
|
/* Tell the display (KMS) that it will have to wait on the fence */
|
|
|
|
/* for the GPU-side FENCE. */
|
|
|
|
/* */
|
|
|
|
/* Since KMS is a kernel thing, we have to pass an FD into */
|
|
|
|
/* the kernel, and get another FD out of the kernel. */
|
|
|
|
/* */
|
|
|
|
/* 1) To pass the GPU-side fence into the kernel, we set the */
|
|
|
|
/* INPUT FD as the IN_FENCE_FD prop of the PRIMARY PLANE. */
|
|
|
|
/* This FD tells KMS (the kernel) to wait for the GPU-side fence.*/
|
|
|
|
/* */
|
|
|
|
/* 2) To get the KMS-side fence out of the kernel, we set the */
|
|
|
|
/* OUTPUT FD as the OUT_FEWNCE_FD prop of the CRTC. */
|
|
|
|
/* This FD will be later imported as a FENCE OBJECT which will be*/
|
|
|
|
/* used to tell the GPU to wait for KMS to complete the changes */
|
|
|
|
/* requested in atomic_commit (the pageflip in this case). */
|
|
|
|
/*****************************************************************/
|
2020-08-25 16:18:49 +02:00
|
|
|
if (dispdata->kms_in_fence_fd != -1)
|
|
|
|
{
|
2020-10-22 16:01:51 +02:00
|
|
|
add_plane_property(dispdata->atomic_req, dispdata->display_plane,
|
2020-09-12 15:58:47 +02:00
|
|
|
"IN_FENCE_FD", dispdata->kms_in_fence_fd);
|
2020-10-22 16:01:51 +02:00
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc,
|
2020-09-12 15:58:47 +02:00
|
|
|
"OUT_FENCE_PTR", VOID2U64(&dispdata->kms_out_fence_fd));
|
2020-08-25 16:18:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-12 04:56:55 +02:00
|
|
|
/* Do we have a pending modesetting? If so, set the necessary
|
|
|
|
props so it's included in the incoming atomic commit. */
|
|
|
|
if (dispdata->modeset_pending) {
|
2020-10-22 16:01:51 +02:00
|
|
|
uint32_t blob_id;
|
2020-09-12 04:56:55 +02:00
|
|
|
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
|
2020-10-22 16:01:51 +02:00
|
|
|
|
2020-09-12 04:56:55 +02:00
|
|
|
dispdata->atomic_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
2020-10-22 16:01:51 +02:00
|
|
|
add_connector_property(dispdata->atomic_req, dispdata->connector, "CRTC_ID", dispdata->crtc->crtc->crtc_id);
|
2020-09-12 15:58:47 +02:00
|
|
|
KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &dispdata->mode, sizeof(dispdata->mode), &blob_id);
|
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "MODE_ID", blob_id);
|
2020-12-28 14:37:58 +01:00
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "active", 1);
|
2020-09-12 04:56:55 +02:00
|
|
|
dispdata->modeset_pending = SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/*****************************************************************/
|
|
|
|
/* Issue a non-blocking atomic commit: for triple buffering, */
|
|
|
|
/* this must not block so the game can start building another */
|
|
|
|
/* frame, even if the just-requested pageflip hasnt't completed. */
|
|
|
|
/*****************************************************************/
|
2020-09-06 12:48:39 +02:00
|
|
|
if (drm_atomic_commit(_this, SDL_FALSE)) {
|
2020-08-23 23:44:07 +02:00
|
|
|
return SDL_SetError("Failed to issue atomic commit on pageflip");
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/* Release the previous front buffer so EGL can chose it as back buffer
|
|
|
|
and render on it again. */
|
2020-08-05 02:06:59 +02:00
|
|
|
if (windata->bo) {
|
2020-10-22 16:01:51 +02:00
|
|
|
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/* Take note of the buffer about to become front buffer, so next
|
|
|
|
time we come here we can free it like we just did with the previous
|
|
|
|
front buffer. */
|
2020-08-05 02:06:59 +02:00
|
|
|
windata->bo = windata->next_bo;
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/****************************************************************/
|
|
|
|
/* Import the KMS-side FENCE OUTPUT FD from the kernel to the */
|
|
|
|
/* KMS-side FENCE OBJECT so we can use use it to fence the GPU. */
|
|
|
|
/****************************************************************/
|
2020-08-03 22:24:49 +02:00
|
|
|
dispdata->kms_fence = create_fence(dispdata->kms_out_fence_fd, _this);
|
|
|
|
assert(dispdata->kms_fence);
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/****************************************************************/
|
|
|
|
/* "Delete" the fence OUTPUT FD, because we already have the */
|
|
|
|
/* KMS FENCE OBJECT, the fence itself is away from us, on the */
|
|
|
|
/* kernel side. */
|
|
|
|
/****************************************************************/
|
2020-08-03 22:24:49 +02:00
|
|
|
dispdata->kms_out_fence_fd = -1;
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
/*****************************************************************/
|
|
|
|
/* Tell the GPU to wait on the fence for the KMS-side FENCE, */
|
|
|
|
/* which means waiting until the requested pageflip is completed.*/
|
|
|
|
/*****************************************************************/
|
2020-08-03 22:24:49 +02:00
|
|
|
_this->egl_data->eglWaitSyncKHR(_this->egl_data->egl_display, dispdata->kms_fence, 0);
|
|
|
|
|
2020-09-06 12:48:39 +02:00
|
|
|
return 0;
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-10 23:26:02 +02:00
|
|
|
int
|
2020-09-10 21:07:23 +02:00
|
|
|
KMSDRM_GLES_SwapWindowDoubleBuffered(_THIS, SDL_Window * window)
|
2020-08-05 02:06:59 +02:00
|
|
|
{
|
2020-08-03 22:24:49 +02:00
|
|
|
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
|
2020-08-17 18:35:04 +02:00
|
|
|
SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
|
2020-08-03 22:24:49 +02:00
|
|
|
KMSDRM_FBInfo *fb;
|
2020-08-23 23:44:07 +02:00
|
|
|
KMSDRM_PlaneInfo info = {0};
|
2020-08-03 22:24:49 +02:00
|
|
|
|
2020-08-25 04:05:36 +02:00
|
|
|
/****************************************************************************************************/
|
2020-09-10 23:26:02 +02:00
|
|
|
/* In double-buffer mode, atomic_commit will always be synchronous/blocking (ie: won't return until */
|
2020-08-25 04:05:36 +02:00
|
|
|
/* the requested changes are really done). */
|
|
|
|
/* Also, there's no need to fence KMS or the GPU, because we won't be entering game loop again */
|
2020-09-10 23:26:02 +02:00
|
|
|
/* (hence not building or executing a new cmdstring) until pageflip is done, so we don't need to */
|
|
|
|
/* protect the KMS/GPU access to the buffer. */
|
2020-08-25 04:05:36 +02:00
|
|
|
/****************************************************************************************************/
|
2020-08-06 01:36:56 +02:00
|
|
|
|
|
|
|
/* Mark, at EGL level, the buffer that we want to become the new front buffer.
|
2020-08-05 02:06:59 +02:00
|
|
|
However, it won't really happen until we request a pageflip at the KMS level and it completes. */
|
2020-09-06 12:08:22 +02:00
|
|
|
if (! _this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, windata->egl_surface)) {
|
2020-09-06 12:48:39 +02:00
|
|
|
return SDL_EGL_SetError("Failed to swap EGL buffers", "eglSwapBuffers");
|
2020-09-06 12:08:22 +02:00
|
|
|
}
|
2020-08-05 02:06:59 +02:00
|
|
|
|
|
|
|
/* Lock the buffer that is marked by eglSwapBuffers() to become the next front buffer (so it can not
|
|
|
|
be chosen by EGL as back buffer to draw on), and get a handle to it to request the pageflip on it. */
|
2020-08-03 22:24:49 +02:00
|
|
|
windata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(windata->gs);
|
|
|
|
if (!windata->next_bo) {
|
2020-08-07 11:53:04 +02:00
|
|
|
return SDL_SetError("Failed to lock frontbuffer");
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
fb = KMSDRM_FBFromBO(_this, windata->next_bo);
|
|
|
|
if (!fb) {
|
2020-09-06 12:48:39 +02:00
|
|
|
return SDL_SetError("Failed to get a new framebuffer BO");
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-08-23 23:44:07 +02:00
|
|
|
/* Add the pageflip to the request list. */
|
|
|
|
info.plane = dispdata->display_plane;
|
|
|
|
info.crtc_id = dispdata->crtc->crtc->crtc_id;
|
|
|
|
info.fb_id = fb->fb_id;
|
2020-08-28 22:38:26 +02:00
|
|
|
|
2020-08-31 19:17:17 +02:00
|
|
|
info.src_w = windata->src_w;
|
|
|
|
info.src_h = windata->src_h;
|
2020-08-28 22:38:26 +02:00
|
|
|
info.crtc_w = windata->output_w;
|
|
|
|
info.crtc_h = windata->output_h;
|
|
|
|
info.crtc_x = windata->output_x;
|
2020-08-23 23:44:07 +02:00
|
|
|
|
2020-09-12 15:58:47 +02:00
|
|
|
drm_atomic_set_plane_props(&info);
|
2020-08-08 14:27:55 +02:00
|
|
|
|
2020-09-12 04:56:55 +02:00
|
|
|
/* Do we have a pending modesetting? If so, set the necessary
|
|
|
|
props so it's included in the incoming atomic commit. */
|
|
|
|
if (dispdata->modeset_pending) {
|
|
|
|
SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata;
|
2020-10-22 16:01:51 +02:00
|
|
|
uint32_t blob_id;
|
2020-09-12 04:56:55 +02:00
|
|
|
dispdata->atomic_flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
2020-10-22 16:01:51 +02:00
|
|
|
add_connector_property(dispdata->atomic_req, dispdata->connector, "CRTC_ID", dispdata->crtc->crtc->crtc_id);
|
2020-09-12 15:58:47 +02:00
|
|
|
KMSDRM_drmModeCreatePropertyBlob(viddata->drm_fd, &dispdata->mode, sizeof(dispdata->mode), &blob_id);
|
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "MODE_ID", blob_id);
|
2020-12-28 14:37:58 +01:00
|
|
|
add_crtc_property(dispdata->atomic_req, dispdata->crtc, "active", 1);
|
2020-09-12 04:56:55 +02:00
|
|
|
dispdata->modeset_pending = SDL_FALSE;
|
|
|
|
}
|
|
|
|
|
2020-08-08 14:27:55 +02:00
|
|
|
/* Issue the one and only atomic commit where all changes will be requested!.
|
|
|
|
Blocking for double buffering: won't return until completed. */
|
2020-09-06 12:48:39 +02:00
|
|
|
if (drm_atomic_commit(_this, SDL_TRUE)) {
|
2020-08-23 23:44:07 +02:00
|
|
|
return SDL_SetError("Failed to issue atomic commit");
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 02:06:59 +02:00
|
|
|
/* Release last front buffer so EGL can chose it as back buffer and render on it again. */
|
|
|
|
if (windata->bo) {
|
2020-10-22 16:01:51 +02:00
|
|
|
KMSDRM_gbm_surface_release_buffer(windata->gs, windata->bo);
|
2020-08-05 02:06:59 +02:00
|
|
|
}
|
2020-08-03 22:24:49 +02:00
|
|
|
|
2020-08-05 02:06:59 +02:00
|
|
|
/* Take note of current front buffer, so we can free it next time we come here. */
|
|
|
|
windata->bo = windata->next_bo;
|
2020-08-03 22:24:49 +02:00
|
|
|
|
2020-09-06 12:48:39 +02:00
|
|
|
return 0;
|
2020-08-03 22:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-09-10 21:07:23 +02:00
|
|
|
int
|
|
|
|
KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window)
|
|
|
|
{
|
|
|
|
SDL_WindowData *windata = ((SDL_WindowData *) window->driverdata);
|
|
|
|
|
|
|
|
if (windata->swap_window == NULL) {
|
|
|
|
/* We want the fenced version by default, but it needs extensions. */
|
|
|
|
if ( (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) ||
|
2020-10-22 16:01:51 +02:00
|
|
|
(!SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_ANDROID_native_fence_sync")) )
|
|
|
|
{
|
2020-09-10 21:07:23 +02:00
|
|
|
windata->swap_window = KMSDRM_GLES_SwapWindowDoubleBuffered;
|
|
|
|
} else {
|
|
|
|
windata->swap_window = KMSDRM_GLES_SwapWindowFenced;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return windata->swap_window(_this, window);
|
|
|
|
}
|
|
|
|
|
2020-07-28 21:11:25 +02:00
|
|
|
/***************************************/
|
|
|
|
/* End of Atomic functions block */
|
|
|
|
/***************************************/
|
|
|
|
|
2017-08-02 19:22:48 +02:00
|
|
|
SDL_EGL_MakeCurrent_impl(KMSDRM)
|
|
|
|
|
2020-12-22 14:15:33 +01:00
|
|
|
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
|
2017-08-02 19:22:48 +02:00
|
|
|
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|