7a0b079ffd4f6be8e75d428e8da56823346ce91a
[platform/upstream/SDL.git] / src / video / kmsdrm / SDL_kmsdrmopengles.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #include "../../SDL_internal.h"
23
24 #if SDL_VIDEO_DRIVER_KMSDRM && SDL_VIDEO_OPENGL_EGL
25
26 #include "SDL_log.h"
27
28 #include "SDL_kmsdrmvideo.h"
29 #include "SDL_kmsdrmopengles.h"
30 #include "SDL_kmsdrmdyn.h"
31
32 #ifndef EGL_PLATFORM_GBM_MESA
33 #define EGL_PLATFORM_GBM_MESA 0x31D7
34 #endif
35
36 /* EGL implementation of SDL OpenGL support */
37
38 int
39 KMSDRM_GLES_LoadLibrary(_THIS, const char *path) {
40     return SDL_EGL_LoadLibrary(_this, path, ((SDL_VideoData *)_this->driverdata)->gbm, EGL_PLATFORM_GBM_MESA);
41 }
42
43 SDL_EGL_CreateContext_impl(KMSDRM)
44
45 SDL_bool
46 KMSDRM_GLES_SetupCrtc(_THIS, SDL_Window * window) {
47     SDL_WindowData *wdata = ((SDL_WindowData *) window->driverdata);
48     SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
49     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
50     KMSDRM_FBInfo *fb_info;
51
52     if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) {
53         SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed on CRTC setup");
54         return SDL_FALSE;
55     }
56
57     wdata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(wdata->gs);
58     if (wdata->next_bo == NULL) {
59         SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not lock GBM surface front buffer on CRTC setup");
60         return SDL_FALSE;
61     }
62
63     fb_info = KMSDRM_FBFromBO(_this, wdata->next_bo);
64     if (fb_info == NULL) {
65         return SDL_FALSE;
66     }
67
68     if(KMSDRM_drmModeSetCrtc(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
69                             0, 0, &vdata->saved_conn_id, 1, &displaydata->cur_mode) != 0) {
70        SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not set up CRTC to a GBM buffer");
71        return SDL_FALSE;
72
73     }
74
75     wdata->crtc_ready = SDL_TRUE;
76     return SDL_TRUE;
77 }
78
79 int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
80     if (!_this->egl_data) {
81         return SDL_SetError("EGL not initialized");
82     }
83
84     if (interval == 0 || interval == 1) {
85         _this->egl_data->egl_swapinterval = interval;
86     } else {
87         return SDL_SetError("Only swap intervals of 0 or 1 are supported");
88     }
89
90     return 0;
91 }
92
93 int
94 KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
95     SDL_WindowData *wdata = ((SDL_WindowData *) window->driverdata);
96     SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
97     SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
98     KMSDRM_FBInfo *fb_info;
99     int ret;
100
101     /* Do we still need to wait for a flip? */
102     int timeout = 0;
103     if (_this->egl_data->egl_swapinterval == 1) {
104         timeout = -1;
105     }
106     if (!KMSDRM_WaitPageFlip(_this, wdata, timeout)) {
107         return 0;
108     }
109
110     /* Release previously displayed buffer (which is now the backbuffer) and lock a new one */
111     if (wdata->next_bo != NULL) {
112         KMSDRM_gbm_surface_release_buffer(wdata->gs, wdata->current_bo);
113         /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Released GBM surface %p", (void *)wdata->next_bo); */
114
115         wdata->current_bo = wdata->next_bo;
116         wdata->next_bo = NULL;
117     }
118
119     if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) {
120         SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed.");
121         return 0;
122     }
123
124     if (wdata->current_bo == NULL) {
125         wdata->current_bo = KMSDRM_gbm_surface_lock_front_buffer(wdata->gs);
126         if (wdata->current_bo == NULL) {
127             return 0;
128         }
129     }
130
131     wdata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(wdata->gs);
132     if (wdata->next_bo == NULL) {
133         SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not lock GBM surface front buffer");
134         return 0;
135     /* } else {
136         SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Locked GBM surface %p", (void *)wdata->next_bo); */
137     }
138
139     fb_info = KMSDRM_FBFromBO(_this, wdata->next_bo);
140     if (fb_info == NULL) {
141         return 0;
142     }
143     if (_this->egl_data->egl_swapinterval == 0) {
144         /* Swap buffers instantly, possible tearing */
145         /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModeSetCrtc(%d, %u, %u, 0, 0, &%u, 1, &%ux%u@%u)",
146             vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id, vdata->saved_conn_id,
147             displaydata->cur_mode.hdisplay, displaydata->cur_mode.vdisplay, displaydata->cur_mode.vrefresh); */
148         ret = KMSDRM_drmModeSetCrtc(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
149                                     0, 0, &vdata->saved_conn_id, 1, &displaydata->cur_mode);
150         if(ret != 0) {
151             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not pageflip with drmModeSetCrtc: %d", ret);
152         }
153     } else {
154         /* Queue page flip at vsync */
155
156         /* Have we already setup the CRTC to one of the GBM buffers? Do so if we have not,
157            or FlipPage won't work in some cases. */
158         if (!wdata->crtc_ready) {
159             if(!KMSDRM_GLES_SetupCrtc(_this, window)) {
160                 SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not set up CRTC for doing vsync-ed pageflips");
161                 return 0;
162             }
163         }
164
165         /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModePageFlip(%d, %u, %u, DRM_MODE_PAGE_FLIP_EVENT, &wdata->waiting_for_flip)",
166             vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id); */
167         ret = KMSDRM_drmModePageFlip(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
168                                      DRM_MODE_PAGE_FLIP_EVENT, &wdata->waiting_for_flip);
169         if (ret == 0) {
170             wdata->waiting_for_flip = SDL_TRUE;
171         } else {
172             SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not queue pageflip: %d", ret);
173         }
174
175         /* Wait immediately for vsync (as if we only had two buffers), for low input-lag scenarios.
176            Run your SDL2 program with "SDL_KMSDRM_DOUBLE_BUFFER=1 <program_name>" to enable this. */
177         if (wdata->double_buffer) {
178             KMSDRM_WaitPageFlip(_this, wdata, -1);
179         }
180     }
181
182     return 0;
183 }
184
185 SDL_EGL_MakeCurrent_impl(KMSDRM)
186
187 #endif /* SDL_VIDEO_DRIVER_KMSDRM && SDL_VIDEO_OPENGL_EGL */
188
189 /* vi: set ts=4 sw=4 expandtab: */