ref: 12b7990cf9e2a448fe7d54c4f21b85483c9cf8c2
dir: /external/SDL2/src/video/kmsdrm/SDL_kmsdrmvideo.c/
/* Simple DirectMedia Layer Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 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. */ #include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_KMSDRM /* SDL internals */ #include "../SDL_sysvideo.h" #include "SDL_syswm.h" #include "SDL_log.h" #include "SDL_hints.h" #include "../../events/SDL_events_c.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_keyboard_c.h" #ifdef SDL_INPUT_LINUXEV #include "../../core/linux/SDL_evdev.h" #endif /* KMS/DRM declarations */ #include "SDL_kmsdrmvideo.h" #include "SDL_kmsdrmevents.h" #include "SDL_kmsdrmopengles.h" #include "SDL_kmsdrmmouse.h" #include "SDL_kmsdrmdyn.h" #include <sys/stat.h> #include <dirent.h> #include <errno.h> #include <poll.h> #define KMSDRM_DRI_PATH "/dev/dri/" static int check_modestting(int devindex) { SDL_bool available = SDL_FALSE; char device[512]; int drm_fd; SDL_snprintf(device, sizeof (device), "%scard%d", KMSDRM_DRI_PATH, devindex); drm_fd = open(device, O_RDWR | O_CLOEXEC); if (drm_fd >= 0) { if (SDL_KMSDRM_LoadSymbols()) { drmModeRes *resources = KMSDRM_drmModeGetResources(drm_fd); if (resources) { SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "%scard%d connector, encoder and CRTC counts are: %d %d %d", KMSDRM_DRI_PATH, devindex, resources->count_connectors, resources->count_encoders, resources->count_crtcs); if (resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0) { available = SDL_TRUE; } KMSDRM_drmModeFreeResources(resources); } SDL_KMSDRM_UnloadSymbols(); } close(drm_fd); } return available; } static int get_dricount(void) { int devcount = 0; struct dirent *res; struct stat sb; DIR *folder; if (!(stat(KMSDRM_DRI_PATH, &sb) == 0 && S_ISDIR(sb.st_mode))) { printf("The path %s cannot be opened or is not available\n", KMSDRM_DRI_PATH); return 0; } if (access(KMSDRM_DRI_PATH, F_OK) == -1) { printf("The path %s cannot be opened\n", KMSDRM_DRI_PATH); return 0; } folder = opendir(KMSDRM_DRI_PATH); if (folder) { while ((res = readdir(folder))) { int len = SDL_strlen(res->d_name); if (len > 4 && SDL_strncmp(res->d_name, "card", 4) == 0) { devcount++; } } closedir(folder); } return devcount; } static int get_driindex(void) { const int devcount = get_dricount(); int i; for (i = 0; i < devcount; i++) { if (check_modestting(i)) { return i; } } return -ENOENT; } static int KMSDRM_Available(void) { int ret = -ENOENT; ret = get_driindex(); if (ret >= 0) return 1; return ret; } static void KMSDRM_DeleteDevice(SDL_VideoDevice * device) { if (device->driverdata) { SDL_free(device->driverdata); device->driverdata = NULL; } SDL_free(device); SDL_KMSDRM_UnloadSymbols(); } static SDL_VideoDevice * KMSDRM_CreateDevice(int devindex) { SDL_VideoDevice *device; SDL_VideoData *viddata; if (!devindex || (devindex > 99)) { devindex = get_driindex(); } if (devindex < 0) { SDL_SetError("devindex (%d) must be between 0 and 99.\n", devindex); return NULL; } if (!SDL_KMSDRM_LoadSymbols()) { return NULL; } device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); if (!device) { SDL_OutOfMemory(); return NULL; } viddata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); if (!viddata) { SDL_OutOfMemory(); goto cleanup; } viddata->devindex = devindex; viddata->drm_fd = -1; device->driverdata = viddata; /* Setup all functions which we can handle */ device->VideoInit = KMSDRM_VideoInit; device->VideoQuit = KMSDRM_VideoQuit; device->GetDisplayModes = KMSDRM_GetDisplayModes; device->SetDisplayMode = KMSDRM_SetDisplayMode; device->CreateSDLWindow = KMSDRM_CreateWindow; device->CreateSDLWindowFrom = KMSDRM_CreateWindowFrom; device->SetWindowTitle = KMSDRM_SetWindowTitle; device->SetWindowIcon = KMSDRM_SetWindowIcon; device->SetWindowPosition = KMSDRM_SetWindowPosition; device->SetWindowSize = KMSDRM_SetWindowSize; device->ShowWindow = KMSDRM_ShowWindow; device->HideWindow = KMSDRM_HideWindow; device->RaiseWindow = KMSDRM_RaiseWindow; device->MaximizeWindow = KMSDRM_MaximizeWindow; device->MinimizeWindow = KMSDRM_MinimizeWindow; device->RestoreWindow = KMSDRM_RestoreWindow; device->SetWindowGrab = KMSDRM_SetWindowGrab; device->DestroyWindow = KMSDRM_DestroyWindow; device->GetWindowWMInfo = KMSDRM_GetWindowWMInfo; #if SDL_VIDEO_OPENGL_EGL device->GL_LoadLibrary = KMSDRM_GLES_LoadLibrary; device->GL_GetProcAddress = KMSDRM_GLES_GetProcAddress; device->GL_UnloadLibrary = KMSDRM_GLES_UnloadLibrary; device->GL_CreateContext = KMSDRM_GLES_CreateContext; device->GL_MakeCurrent = KMSDRM_GLES_MakeCurrent; device->GL_SetSwapInterval = KMSDRM_GLES_SetSwapInterval; device->GL_GetSwapInterval = KMSDRM_GLES_GetSwapInterval; device->GL_SwapWindow = KMSDRM_GLES_SwapWindow; device->GL_DeleteContext = KMSDRM_GLES_DeleteContext; #endif device->PumpEvents = KMSDRM_PumpEvents; device->free = KMSDRM_DeleteDevice; return device; cleanup: if (device) SDL_free(device); if (viddata) SDL_free(viddata); return NULL; } VideoBootStrap KMSDRM_bootstrap = { "KMSDRM", "KMS/DRM Video Driver", KMSDRM_Available, KMSDRM_CreateDevice }; static void KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data) { KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)data; if (fb_info && fb_info->drm_fd >= 0 && fb_info->fb_id != 0) { KMSDRM_drmModeRmFB(fb_info->drm_fd, fb_info->fb_id); SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Delete DRM FB %u", fb_info->fb_id); } SDL_free(fb_info); } KMSDRM_FBInfo * KMSDRM_FBFromBO(_THIS, struct gbm_bo *bo) { SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); unsigned w,h; int ret; Uint32 stride, handle; /* Check for an existing framebuffer */ KMSDRM_FBInfo *fb_info = (KMSDRM_FBInfo *)KMSDRM_gbm_bo_get_user_data(bo); if (fb_info) { return fb_info; } /* Create a structure that contains enough info to remove the framebuffer when the backing buffer is destroyed */ fb_info = (KMSDRM_FBInfo *)SDL_calloc(1, sizeof(KMSDRM_FBInfo)); if (!fb_info) { SDL_OutOfMemory(); return NULL; } fb_info->drm_fd = viddata->drm_fd; /* Create framebuffer object for the buffer */ w = KMSDRM_gbm_bo_get_width(bo); h = KMSDRM_gbm_bo_get_height(bo); stride = KMSDRM_gbm_bo_get_stride(bo); handle = KMSDRM_gbm_bo_get_handle(bo).u32; ret = KMSDRM_drmModeAddFB(viddata->drm_fd, w, h, 24, 32, stride, handle, &fb_info->fb_id); if (ret) { SDL_free(fb_info); return NULL; } SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "New DRM FB (%u): %ux%u, stride %u from BO %p", fb_info->fb_id, w, h, stride, (void *)bo); /* Associate our DRM framebuffer with this buffer object */ KMSDRM_gbm_bo_set_user_data(bo, fb_info, KMSDRM_FBDestroyCallback); return fb_info; } static void KMSDRM_FlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { *((SDL_bool *) data) = SDL_FALSE; } SDL_bool KMSDRM_WaitPageFlip(_THIS, SDL_WindowData *windata, int timeout) { SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); drmEventContext ev = {0}; struct pollfd pfd = {0}; ev.version = DRM_EVENT_CONTEXT_VERSION; ev.page_flip_handler = KMSDRM_FlipHandler; pfd.fd = viddata->drm_fd; pfd.events = POLLIN; while (windata->waiting_for_flip) { pfd.revents = 0; if (poll(&pfd, 1, timeout) < 0) { SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll error"); return SDL_FALSE; } if (pfd.revents & (POLLHUP | POLLERR)) { SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DRM poll hup or error"); return SDL_FALSE; } if (pfd.revents & POLLIN) { /* Page flip? If so, drmHandleEvent will unset windata->waiting_for_flip */ KMSDRM_drmHandleEvent(viddata->drm_fd, &ev); } else { /* Timed out and page flip didn't happen */ SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Dropping frame while waiting_for_flip"); return SDL_FALSE; } } return SDL_TRUE; } /*****************************************************************************/ /* SDL Video and Display initialization/handling functions */ /* _this is a SDL_VideoDevice * */ /*****************************************************************************/ static void KMSDRM_DestroySurfaces(_THIS, SDL_Window * window) { SDL_WindowData *windata = (SDL_WindowData *)window->driverdata; KMSDRM_WaitPageFlip(_this, windata, -1); if (windata->curr_bo) { KMSDRM_gbm_surface_release_buffer(windata->gs, windata->curr_bo); windata->curr_bo = NULL; } if (windata->next_bo) { KMSDRM_gbm_surface_release_buffer(windata->gs, windata->next_bo); windata->next_bo = NULL; } #if SDL_VIDEO_OPENGL_EGL SDL_EGL_MakeCurrent(_this, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (windata->egl_surface != EGL_NO_SURFACE) { SDL_EGL_DestroySurface(_this, windata->egl_surface); windata->egl_surface = EGL_NO_SURFACE; } #endif if (windata->gs) { KMSDRM_gbm_surface_destroy(windata->gs); windata->gs = NULL; } } int KMSDRM_CreateSurfaces(_THIS, SDL_Window * window) { SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); SDL_WindowData *windata = (SDL_WindowData *)window->driverdata; SDL_DisplayData *dispdata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; Uint32 width = dispdata->mode.hdisplay; Uint32 height = dispdata->mode.vdisplay; Uint32 surface_fmt = GBM_FORMAT_XRGB8888; Uint32 surface_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; EGLContext egl_context; if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm, surface_fmt, surface_flags)) { SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "GBM surface format not supported. Trying anyway."); } #if SDL_VIDEO_OPENGL_EGL SDL_EGL_SetRequiredVisualId(_this, surface_fmt); egl_context = (EGLContext)SDL_GL_GetCurrentContext(); #endif KMSDRM_DestroySurfaces(_this, window); windata->gs = KMSDRM_gbm_surface_create(viddata->gbm, width, height, surface_fmt, surface_flags); if (!windata->gs) { return SDL_SetError("Could not create GBM surface"); } #if SDL_VIDEO_OPENGL_EGL windata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType)windata->gs); if (windata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create EGL window surface"); } SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context); windata->egl_surface_dirty = 0; #endif return 0; } int KMSDRM_VideoInit(_THIS) { int ret = 0; SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); SDL_DisplayData *dispdata = NULL; drmModeRes *resources = NULL; drmModeEncoder *encoder = NULL; char devname[32]; SDL_VideoDisplay display = {0}; dispdata = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData)); if (!dispdata) { return SDL_OutOfMemory(); } SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoInit()"); /* Open /dev/dri/cardNN */ SDL_snprintf(devname, sizeof(devname), "/dev/dri/card%d", viddata->devindex); SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opening device %s", devname); viddata->drm_fd = open(devname, O_RDWR | O_CLOEXEC); if (viddata->drm_fd < 0) { ret = SDL_SetError("Could not open %s", devname); goto cleanup; } SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Opened DRM FD (%d)", viddata->drm_fd); viddata->gbm = KMSDRM_gbm_create_device(viddata->drm_fd); if (!viddata->gbm) { ret = SDL_SetError("Couldn't create gbm device."); goto cleanup; } /* Get all of the available connectors / devices / crtcs */ resources = KMSDRM_drmModeGetResources(viddata->drm_fd); if (!resources) { ret = SDL_SetError("drmModeGetResources(%d) failed", viddata->drm_fd); goto cleanup; } for (int i = 0; i < resources->count_connectors; i++) { drmModeConnector *conn = KMSDRM_drmModeGetConnector(viddata->drm_fd, resources->connectors[i]); if (!conn) { continue; } if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes) { SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found connector %d with %d modes.", conn->connector_id, conn->count_modes); dispdata->conn = conn; break; } KMSDRM_drmModeFreeConnector(conn); } if (!dispdata->conn) { ret = SDL_SetError("No currently active connector found."); goto cleanup; } /* Try to find the connector's current encoder */ for (int i = 0; i < resources->count_encoders; i++) { encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]); if (!encoder) { continue; } if (encoder->encoder_id == dispdata->conn->encoder_id) { SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id); break; } KMSDRM_drmModeFreeEncoder(encoder); encoder = NULL; } if (!encoder) { /* No encoder was connected, find the first supported one */ for (int i = 0, j; i < resources->count_encoders; i++) { encoder = KMSDRM_drmModeGetEncoder(viddata->drm_fd, resources->encoders[i]); if (!encoder) { continue; } for (j = 0; j < dispdata->conn->count_encoders; j++) { if (dispdata->conn->encoders[j] == encoder->encoder_id) { break; } } if (j != dispdata->conn->count_encoders) { break; } KMSDRM_drmModeFreeEncoder(encoder); encoder = NULL; } } if (!encoder) { ret = SDL_SetError("No connected encoder found."); goto cleanup; } SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Found encoder %d.", encoder->encoder_id); /* Try to find a CRTC connected to this encoder */ dispdata->saved_crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id); if (!dispdata->saved_crtc) { /* No CRTC was connected, find the first CRTC that can be connected */ for (int i = 0; i < resources->count_crtcs; i++) { if (encoder->possible_crtcs & (1 << i)) { encoder->crtc_id = resources->crtcs[i]; dispdata->saved_crtc = KMSDRM_drmModeGetCrtc(viddata->drm_fd, encoder->crtc_id); break; } } } if (!dispdata->saved_crtc) { ret = SDL_SetError("No CRTC found."); goto cleanup; } SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Saved crtc_id %u, fb_id %u, (%u,%u), %ux%u", dispdata->saved_crtc->crtc_id, dispdata->saved_crtc->buffer_id, dispdata->saved_crtc->x, dispdata->saved_crtc->y, dispdata->saved_crtc->width, dispdata->saved_crtc->height); dispdata->crtc_id = encoder->crtc_id; /* Figure out the default mode to be set. If the current CRTC's mode isn't valid, select the first mode supported by the connector FIXME find first mode that specifies DRM_MODE_TYPE_PREFERRED */ dispdata->mode = dispdata->saved_crtc->mode; if (dispdata->saved_crtc->mode_valid == 0) { SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Current mode is invalid, selecting connector's mode #0."); dispdata->mode = dispdata->conn->modes[0]; } /* Setup the single display that's available */ display.desktop_mode.w = dispdata->mode.hdisplay; display.desktop_mode.h = dispdata->mode.vdisplay; display.desktop_mode.refresh_rate = dispdata->mode.vrefresh; #if 1 display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888; #else /* FIXME */ drmModeFB *fb = drmModeGetFB(viddata->drm_fd, dispdata->saved_crtc->buffer_id); display.desktop_mode.format = drmToSDLPixelFormat(fb->bpp, fb->depth); drmModeFreeFB(fb); #endif display.current_mode = display.desktop_mode; display.driverdata = dispdata; SDL_AddVideoDisplay(&display); #ifdef SDL_INPUT_LINUXEV SDL_EVDEV_Init(); #endif KMSDRM_InitMouse(_this); return ret; cleanup: if (encoder) KMSDRM_drmModeFreeEncoder(encoder); if (resources) KMSDRM_drmModeFreeResources(resources); if (ret != 0) { /* Error (complete) cleanup */ if (dispdata->conn) { KMSDRM_drmModeFreeConnector(dispdata->conn); dispdata->conn = NULL; } if (dispdata->saved_crtc) { KMSDRM_drmModeFreeCrtc(dispdata->saved_crtc); dispdata->saved_crtc = NULL; } if (viddata->gbm) { KMSDRM_gbm_device_destroy(viddata->gbm); viddata->gbm = NULL; } if (viddata->drm_fd >= 0) { close(viddata->drm_fd); viddata->drm_fd = -1; } SDL_free(dispdata); } return ret; } void KMSDRM_VideoQuit(_THIS) { SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0); SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "KMSDRM_VideoQuit()"); if (_this->gl_config.driver_loaded) { SDL_GL_UnloadLibrary(); } /* Clear out the window list */ SDL_free(viddata->windows); viddata->windows = NULL; viddata->max_windows = 0; viddata->num_windows = 0; /* Restore saved CRTC settings */ if (viddata->drm_fd >= 0 && dispdata && dispdata->conn && dispdata->saved_crtc) { drmModeConnector *conn = dispdata->conn; drmModeCrtc *crtc = dispdata->saved_crtc; int ret = KMSDRM_drmModeSetCrtc(viddata->drm_fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &conn->connector_id, 1, &crtc->mode); if (ret != 0) { SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not restore original CRTC mode"); } } if (dispdata && dispdata->conn) { KMSDRM_drmModeFreeConnector(dispdata->conn); dispdata->conn = NULL; } if (dispdata && dispdata->saved_crtc) { KMSDRM_drmModeFreeCrtc(dispdata->saved_crtc); dispdata->saved_crtc = NULL; } if (viddata->gbm) { KMSDRM_gbm_device_destroy(viddata->gbm); viddata->gbm = NULL; } if (viddata->drm_fd >= 0) { close(viddata->drm_fd); SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Closed DRM FD %d", viddata->drm_fd); viddata->drm_fd = -1; } #ifdef SDL_INPUT_LINUXEV SDL_EVDEV_Quit(); #endif } void KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { SDL_DisplayData *dispdata = display->driverdata; drmModeConnector *conn = dispdata->conn; SDL_DisplayMode mode; for (int i = 0; i < conn->count_modes; i++) { SDL_DisplayModeData *modedata = SDL_calloc(1, sizeof(SDL_DisplayModeData)); if (modedata) { modedata->mode_index = i; } mode.w = conn->modes[i].hdisplay; mode.h = conn->modes[i].vdisplay; mode.refresh_rate = conn->modes[i].vrefresh; mode.format = SDL_PIXELFORMAT_ARGB8888; mode.driverdata = modedata; if (!SDL_AddDisplayMode(display, &mode)) { SDL_free(modedata); } } } int KMSDRM_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata; SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata; SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; drmModeConnector *conn = dispdata->conn; if (!modedata) { return SDL_SetError("Mode doesn't have an associated index"); } dispdata->mode = conn->modes[modedata->mode_index]; for (int i = 0; i < viddata->num_windows; i++) { SDL_Window *window = viddata->windows[i]; SDL_WindowData *windata = (SDL_WindowData *)window->driverdata; #if SDL_VIDEO_OPENGL_EGL /* Can't recreate EGL surfaces right now, need to wait until SwapWindow so the correct thread-local surface and context state are available */ windata->egl_surface_dirty = 1; #else if (KMSDRM_CreateSurfaces(_this, window)) { return -1; } #endif /* Tell app about the resize */ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode->w, mode->h); } return 0; } int KMSDRM_CreateWindow(_THIS, SDL_Window * window) { SDL_VideoData *viddata = (SDL_VideoData *)_this->driverdata; SDL_WindowData *windata; SDL_VideoDisplay *display; #if SDL_VIDEO_OPENGL_EGL if (!_this->egl_data) { if (SDL_GL_LoadLibrary(NULL) < 0) { goto error; } } #endif /* Allocate window internal data */ windata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); if (!windata) { SDL_OutOfMemory(); goto error; } /* Windows have one size for now */ display = SDL_GetDisplayForWindow(window); window->w = display->desktop_mode.w; window->h = display->desktop_mode.h; /* Maybe you didn't ask for a fullscreen OpenGL window, but that's what you get */ window->flags |= (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL); /* In case we want low-latency, double-buffer video, we take note here */ windata->double_buffer = SDL_FALSE; if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, SDL_FALSE)) { windata->double_buffer = SDL_TRUE; } /* Setup driver data for this window */ window->driverdata = windata; if (KMSDRM_CreateSurfaces(_this, window)) { goto error; } /* Add window to the internal list of tracked windows. Note, while it may seem odd to support multiple fullscreen windows, some apps create an extra window as a dummy surface when working with multiple contexts */ windata->viddata = viddata; if (viddata->num_windows >= viddata->max_windows) { int new_max_windows = viddata->max_windows + 1; viddata->windows = (SDL_Window **)SDL_realloc(viddata->windows, new_max_windows * sizeof(SDL_Window *)); viddata->max_windows = new_max_windows; if (!viddata->windows) { SDL_OutOfMemory(); goto error; } } viddata->windows[viddata->num_windows++] = window; /* Focus on the newly created window */ SDL_SetMouseFocus(window); SDL_SetKeyboardFocus(window); return 0; error: KMSDRM_DestroyWindow(_this, window); return -1; } void KMSDRM_DestroyWindow(_THIS, SDL_Window * window) { SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; SDL_VideoData *viddata; if (!windata) { return; } /* Remove from the internal window list */ viddata = windata->viddata; for (int i = 0; i < viddata->num_windows; i++) { if (viddata->windows[i] == window) { viddata->num_windows--; for (int j = i; j < viddata->num_windows; j++) { viddata->windows[j] = viddata->windows[j + 1]; } break; } } KMSDRM_DestroySurfaces(_this, window); window->driverdata = NULL; SDL_free(windata); } int KMSDRM_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) { return -1; } void KMSDRM_SetWindowTitle(_THIS, SDL_Window * window) { } void KMSDRM_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) { } void KMSDRM_SetWindowPosition(_THIS, SDL_Window * window) { } void KMSDRM_SetWindowSize(_THIS, SDL_Window * window) { } void KMSDRM_ShowWindow(_THIS, SDL_Window * window) { } void KMSDRM_HideWindow(_THIS, SDL_Window * window) { } void KMSDRM_RaiseWindow(_THIS, SDL_Window * window) { } void KMSDRM_MaximizeWindow(_THIS, SDL_Window * window) { } void KMSDRM_MinimizeWindow(_THIS, SDL_Window * window) { } void KMSDRM_RestoreWindow(_THIS, SDL_Window * window) { } void KMSDRM_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { } /*****************************************************************************/ /* SDL Window Manager function */ /*****************************************************************************/ SDL_bool KMSDRM_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) { if (info->version.major <= SDL_MAJOR_VERSION) { return SDL_TRUE; } else { SDL_SetError("application not compiled with SDL %d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION); return SDL_FALSE; } /* Failed to get window manager information */ return SDL_FALSE; } #endif /* SDL_VIDEO_DRIVER_KMSDRM */ /* vi: set ts=4 sw=4 expandtab: */