blob: 630b80180adfae3ff7e1a7857c1e3b9c176935be [file] [log] [blame]
Stéphane Marchesin1a92c442015-06-29 20:05:48 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Tao Bao557fa1f2017-02-07 12:51:00 -080017#include "graphics_drm.h"
18
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070019#include <fcntl.h>
Jeremy Compostella955da1e2018-06-07 10:51:33 -070020#include <poll.h>
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070021#include <stdio.h>
22#include <stdlib.h>
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070023#include <sys/mman.h>
24#include <sys/types.h>
25#include <unistd.h>
Tao Bao76be34c2017-02-07 13:30:19 -080026
27#include <drm_fourcc.h>
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070028#include <xf86drm.h>
29#include <xf86drmMode.h>
30
Tao Bao0ecbd762017-01-16 21:16:58 -080031#include "minui/minui.h"
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070032
33#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
34
Tao Bao557fa1f2017-02-07 12:51:00 -080035MinuiBackendDrm::MinuiBackendDrm()
36 : GRSurfaceDrms(), main_monitor_crtc(nullptr), main_monitor_connector(nullptr), drm_fd(-1) {}
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070037
Tao Bao557fa1f2017-02-07 12:51:00 -080038void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) {
Tao Bao76be34c2017-02-07 13:30:19 -080039 if (crtc) {
40 drmModeSetCrtc(drm_fd, crtc->crtc_id,
41 0, // fb_id
42 0, 0, // x,y
43 nullptr, // connectors
44 0, // connector_count
45 nullptr); // mode
46 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070047}
48
Tianjie Xuccf00a22018-06-05 17:10:23 -070049int MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface) {
50 int ret = drmModeSetCrtc(drm_fd, crtc->crtc_id, surface->fb_id, 0, 0, // x,y
51 &main_monitor_connector->connector_id,
52 1, // connector_count
53 &main_monitor_crtc->mode);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070054
Tao Bao76be34c2017-02-07 13:30:19 -080055 if (ret) {
56 printf("drmModeSetCrtc failed ret=%d\n", ret);
57 }
Tianjie Xuccf00a22018-06-05 17:10:23 -070058
59 return ret;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070060}
61
Tao Bao557fa1f2017-02-07 12:51:00 -080062void MinuiBackendDrm::Blank(bool blank) {
Tao Bao76be34c2017-02-07 13:30:19 -080063 if (blank) {
Tao Bao557fa1f2017-02-07 12:51:00 -080064 DrmDisableCrtc(drm_fd, main_monitor_crtc);
Tao Bao76be34c2017-02-07 13:30:19 -080065 } else {
Tao Bao557fa1f2017-02-07 12:51:00 -080066 DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]);
Tao Bao76be34c2017-02-07 13:30:19 -080067 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070068}
69
Tao Bao557fa1f2017-02-07 12:51:00 -080070void MinuiBackendDrm::DrmDestroySurface(GRSurfaceDrm* surface) {
Tao Bao76be34c2017-02-07 13:30:19 -080071 if (!surface) return;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070072
Tao Bao557fa1f2017-02-07 12:51:00 -080073 if (surface->data) {
74 munmap(surface->data, surface->row_bytes * surface->height);
Tao Bao76be34c2017-02-07 13:30:19 -080075 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070076
Tao Bao76be34c2017-02-07 13:30:19 -080077 if (surface->fb_id) {
78 int ret = drmModeRmFB(drm_fd, surface->fb_id);
79 if (ret) {
80 printf("drmModeRmFB failed ret=%d\n", ret);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070081 }
Tao Bao76be34c2017-02-07 13:30:19 -080082 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070083
Tao Bao76be34c2017-02-07 13:30:19 -080084 if (surface->handle) {
85 drm_gem_close gem_close = {};
86 gem_close.handle = surface->handle;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070087
Tao Bao76be34c2017-02-07 13:30:19 -080088 int ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
89 if (ret) {
90 printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070091 }
Tao Bao76be34c2017-02-07 13:30:19 -080092 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070093
Tao Bao557fa1f2017-02-07 12:51:00 -080094 delete surface;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -070095}
96
97static int drm_format_to_bpp(uint32_t format) {
Tao Bao76be34c2017-02-07 13:30:19 -080098 switch (format) {
99 case DRM_FORMAT_ABGR8888:
100 case DRM_FORMAT_BGRA8888:
101 case DRM_FORMAT_RGBX8888:
102 case DRM_FORMAT_BGRX8888:
103 case DRM_FORMAT_XBGR8888:
104 case DRM_FORMAT_XRGB8888:
105 return 32;
106 case DRM_FORMAT_RGB565:
107 return 16;
108 default:
109 printf("Unknown format %d\n", format);
110 return 32;
111 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700112}
113
Tao Bao557fa1f2017-02-07 12:51:00 -0800114GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) {
115 GRSurfaceDrm* surface = new GRSurfaceDrm;
116 *surface = {};
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700117
Tao Bao76be34c2017-02-07 13:30:19 -0800118 uint32_t format;
Tao Baoed876a72018-07-31 21:32:50 -0700119 PixelFormat pixel_format = gr_pixel_format();
tangrobin13bec762018-08-07 17:23:31 +0800120 // PixelFormat comes in byte order, whereas DRM_FORMAT_* uses little-endian
121 // (external/libdrm/include/drm/drm_fourcc.h). Note that although drm_fourcc.h also defines a
122 // macro of DRM_FORMAT_BIG_ENDIAN, it doesn't seem to be actually supported (see the discussion
123 // in https://lists.freedesktop.org/archives/amd-gfx/2017-May/008560.html).
Tao Baoed876a72018-07-31 21:32:50 -0700124 if (pixel_format == PixelFormat::ABGR) {
tangrobin13bec762018-08-07 17:23:31 +0800125 format = DRM_FORMAT_RGBA8888;
Tao Baoed876a72018-07-31 21:32:50 -0700126 } else if (pixel_format == PixelFormat::BGRA) {
tangrobin13bec762018-08-07 17:23:31 +0800127 format = DRM_FORMAT_ARGB8888;
Tao Baoed876a72018-07-31 21:32:50 -0700128 } else if (pixel_format == PixelFormat::RGBX) {
tangrobin13bec762018-08-07 17:23:31 +0800129 format = DRM_FORMAT_XBGR8888;
Tao Baoed876a72018-07-31 21:32:50 -0700130 } else {
131 format = DRM_FORMAT_RGB565;
132 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700133
Tao Bao76be34c2017-02-07 13:30:19 -0800134 drm_mode_create_dumb create_dumb = {};
135 create_dumb.height = height;
136 create_dumb.width = width;
137 create_dumb.bpp = drm_format_to_bpp(format);
138 create_dumb.flags = 0;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700139
Tao Bao76be34c2017-02-07 13:30:19 -0800140 int ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
141 if (ret) {
142 printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n", ret);
Tao Bao557fa1f2017-02-07 12:51:00 -0800143 DrmDestroySurface(surface);
Tao Bao76be34c2017-02-07 13:30:19 -0800144 return nullptr;
145 }
146 surface->handle = create_dumb.handle;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700147
Tao Bao76be34c2017-02-07 13:30:19 -0800148 uint32_t handles[4], pitches[4], offsets[4];
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700149
Tao Bao76be34c2017-02-07 13:30:19 -0800150 handles[0] = surface->handle;
151 pitches[0] = create_dumb.pitch;
152 offsets[0] = 0;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700153
Tao Bao76be34c2017-02-07 13:30:19 -0800154 ret =
155 drmModeAddFB2(drm_fd, width, height, format, handles, pitches, offsets, &(surface->fb_id), 0);
156 if (ret) {
157 printf("drmModeAddFB2 failed ret=%d\n", ret);
Tao Bao557fa1f2017-02-07 12:51:00 -0800158 DrmDestroySurface(surface);
Tao Bao76be34c2017-02-07 13:30:19 -0800159 return nullptr;
160 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700161
Tao Bao76be34c2017-02-07 13:30:19 -0800162 drm_mode_map_dumb map_dumb = {};
163 map_dumb.handle = create_dumb.handle;
164 ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
165 if (ret) {
166 printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n", ret);
Tao Bao557fa1f2017-02-07 12:51:00 -0800167 DrmDestroySurface(surface);
Tao Bao76be34c2017-02-07 13:30:19 -0800168 return nullptr;
169 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700170
Tao Bao557fa1f2017-02-07 12:51:00 -0800171 surface->height = height;
172 surface->width = width;
173 surface->row_bytes = create_dumb.pitch;
174 surface->pixel_bytes = create_dumb.bpp / 8;
175 surface->data = static_cast<unsigned char*>(mmap(nullptr, surface->height * surface->row_bytes,
176 PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd,
177 map_dumb.offset));
178 if (surface->data == MAP_FAILED) {
Tao Bao76be34c2017-02-07 13:30:19 -0800179 perror("mmap() failed");
Tao Bao557fa1f2017-02-07 12:51:00 -0800180 DrmDestroySurface(surface);
Tao Bao76be34c2017-02-07 13:30:19 -0800181 return nullptr;
182 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700183
Tao Bao76be34c2017-02-07 13:30:19 -0800184 return surface;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700185}
186
Tao Bao76be34c2017-02-07 13:30:19 -0800187static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources,
188 drmModeConnector* connector) {
189 // Find the encoder. If we already have one, just use it.
190 drmModeEncoder* encoder;
191 if (connector->encoder_id) {
192 encoder = drmModeGetEncoder(fd, connector->encoder_id);
193 } else {
194 encoder = nullptr;
195 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700196
Tao Bao76be34c2017-02-07 13:30:19 -0800197 int32_t crtc;
198 if (encoder && encoder->crtc_id) {
199 crtc = encoder->crtc_id;
200 drmModeFreeEncoder(encoder);
201 return drmModeGetCrtc(fd, crtc);
202 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700203
Tao Bao76be34c2017-02-07 13:30:19 -0800204 // Didn't find anything, try to find a crtc and encoder combo.
205 crtc = -1;
206 for (int i = 0; i < connector->count_encoders; i++) {
207 encoder = drmModeGetEncoder(fd, connector->encoders[i]);
208
209 if (encoder) {
210 for (int j = 0; j < resources->count_crtcs; j++) {
211 if (!(encoder->possible_crtcs & (1 << j))) continue;
212 crtc = resources->crtcs[j];
213 break;
214 }
215 if (crtc >= 0) {
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700216 drmModeFreeEncoder(encoder);
217 return drmModeGetCrtc(fd, crtc);
Tao Bao76be34c2017-02-07 13:30:19 -0800218 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700219 }
Tao Bao76be34c2017-02-07 13:30:19 -0800220 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700221
Tao Bao76be34c2017-02-07 13:30:19 -0800222 return nullptr;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700223}
224
Tao Bao76be34c2017-02-07 13:30:19 -0800225static drmModeConnector* find_used_connector_by_type(int fd, drmModeRes* resources, unsigned type) {
226 for (int i = 0; i < resources->count_connectors; i++) {
227 drmModeConnector* connector = drmModeGetConnector(fd, resources->connectors[i]);
228 if (connector) {
229 if ((connector->connector_type == type) && (connector->connection == DRM_MODE_CONNECTED) &&
230 (connector->count_modes > 0)) {
231 return connector;
232 }
233 drmModeFreeConnector(connector);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700234 }
Tao Bao76be34c2017-02-07 13:30:19 -0800235 }
236 return nullptr;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700237}
238
Tao Bao76be34c2017-02-07 13:30:19 -0800239static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* resources) {
240 for (int i = 0; i < resources->count_connectors; i++) {
241 drmModeConnector* connector;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700242
Tao Bao76be34c2017-02-07 13:30:19 -0800243 connector = drmModeGetConnector(fd, resources->connectors[i]);
244 if (connector) {
245 if ((connector->count_modes > 0) && (connector->connection == DRM_MODE_CONNECTED))
246 return connector;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700247
Tao Bao76be34c2017-02-07 13:30:19 -0800248 drmModeFreeConnector(connector);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700249 }
Tao Bao76be34c2017-02-07 13:30:19 -0800250 }
251 return nullptr;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700252}
253
Tao Bao557fa1f2017-02-07 12:51:00 -0800254drmModeConnector* MinuiBackendDrm::FindMainMonitor(int fd, drmModeRes* resources,
255 uint32_t* mode_index) {
Tao Bao76be34c2017-02-07 13:30:19 -0800256 /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */
257 static constexpr unsigned kConnectorPriority[] = {
258 DRM_MODE_CONNECTOR_LVDS,
259 DRM_MODE_CONNECTOR_eDP,
260 DRM_MODE_CONNECTOR_DSI,
261 };
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700262
Tao Bao76be34c2017-02-07 13:30:19 -0800263 drmModeConnector* main_monitor_connector = nullptr;
264 unsigned i = 0;
265 do {
266 main_monitor_connector = find_used_connector_by_type(fd, resources, kConnectorPriority[i]);
267 i++;
268 } while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority));
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700269
Tao Bao76be34c2017-02-07 13:30:19 -0800270 /* If we didn't find a connector, grab the first one that is connected. */
271 if (!main_monitor_connector) {
272 main_monitor_connector = find_first_connected_connector(fd, resources);
273 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700274
Tao Bao76be34c2017-02-07 13:30:19 -0800275 /* If we still didn't find a connector, give up and return. */
276 if (!main_monitor_connector) return nullptr;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700277
Tao Bao76be34c2017-02-07 13:30:19 -0800278 *mode_index = 0;
279 for (int modes = 0; modes < main_monitor_connector->count_modes; modes++) {
280 if (main_monitor_connector->modes[modes].type & DRM_MODE_TYPE_PREFERRED) {
281 *mode_index = modes;
282 break;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700283 }
Tao Bao76be34c2017-02-07 13:30:19 -0800284 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700285
Tao Bao76be34c2017-02-07 13:30:19 -0800286 return main_monitor_connector;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700287}
288
Tao Bao557fa1f2017-02-07 12:51:00 -0800289void MinuiBackendDrm::DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc) {
Tao Bao76be34c2017-02-07 13:30:19 -0800290 for (int i = 0; i < resources->count_connectors; i++) {
291 drmModeConnector* connector = drmModeGetConnector(fd, resources->connectors[i]);
292 drmModeCrtc* crtc = find_crtc_for_connector(fd, resources, connector);
293 if (crtc->crtc_id != main_crtc->crtc_id) {
Tao Bao557fa1f2017-02-07 12:51:00 -0800294 DrmDisableCrtc(fd, crtc);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700295 }
Tao Bao76be34c2017-02-07 13:30:19 -0800296 drmModeFreeCrtc(crtc);
297 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700298}
299
Tao Bao557fa1f2017-02-07 12:51:00 -0800300GRSurface* MinuiBackendDrm::Init() {
Tao Bao76be34c2017-02-07 13:30:19 -0800301 drmModeRes* res = nullptr;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700302
Tao Bao76be34c2017-02-07 13:30:19 -0800303 /* Consider DRM devices in order. */
304 for (int i = 0; i < DRM_MAX_MINOR; i++) {
305 char* dev_name;
306 int ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
307 if (ret < 0) continue;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700308
Tao Bao76be34c2017-02-07 13:30:19 -0800309 drm_fd = open(dev_name, O_RDWR, 0);
310 free(dev_name);
311 if (drm_fd < 0) continue;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700312
Tao Bao76be34c2017-02-07 13:30:19 -0800313 uint64_t cap = 0;
314 /* We need dumb buffers. */
315 ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
316 if (ret || cap == 0) {
317 close(drm_fd);
318 continue;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700319 }
320
Tao Bao76be34c2017-02-07 13:30:19 -0800321 res = drmModeGetResources(drm_fd);
322 if (!res) {
323 close(drm_fd);
324 continue;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700325 }
326
Tao Bao76be34c2017-02-07 13:30:19 -0800327 /* Use this device if it has at least one connected monitor. */
328 if (res->count_crtcs > 0 && res->count_connectors > 0) {
329 if (find_first_connected_connector(drm_fd, res)) break;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700330 }
331
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700332 drmModeFreeResources(res);
Tao Bao76be34c2017-02-07 13:30:19 -0800333 close(drm_fd);
334 res = nullptr;
335 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700336
Tao Bao76be34c2017-02-07 13:30:19 -0800337 if (drm_fd < 0 || res == nullptr) {
338 perror("cannot find/open a drm device");
339 return nullptr;
340 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700341
Tao Bao76be34c2017-02-07 13:30:19 -0800342 uint32_t selected_mode;
Tao Bao557fa1f2017-02-07 12:51:00 -0800343 main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode);
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700344
Tao Bao76be34c2017-02-07 13:30:19 -0800345 if (!main_monitor_connector) {
346 printf("main_monitor_connector not found\n");
347 drmModeFreeResources(res);
348 close(drm_fd);
349 return nullptr;
350 }
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700351
Tao Bao76be34c2017-02-07 13:30:19 -0800352 main_monitor_crtc = find_crtc_for_connector(drm_fd, res, main_monitor_connector);
353
354 if (!main_monitor_crtc) {
355 printf("main_monitor_crtc not found\n");
356 drmModeFreeResources(res);
357 close(drm_fd);
358 return nullptr;
359 }
360
Tao Bao557fa1f2017-02-07 12:51:00 -0800361 DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc);
Tao Bao76be34c2017-02-07 13:30:19 -0800362
363 main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode];
364
365 int width = main_monitor_crtc->mode.hdisplay;
366 int height = main_monitor_crtc->mode.vdisplay;
367
368 drmModeFreeResources(res);
369
Tao Bao557fa1f2017-02-07 12:51:00 -0800370 GRSurfaceDrms[0] = DrmCreateSurface(width, height);
371 GRSurfaceDrms[1] = DrmCreateSurface(width, height);
372 if (!GRSurfaceDrms[0] || !GRSurfaceDrms[1]) {
373 // GRSurfaceDrms and drm_fd should be freed in d'tor.
Tao Bao76be34c2017-02-07 13:30:19 -0800374 return nullptr;
375 }
376
377 current_buffer = 0;
378
Tianjie Xuccf00a22018-06-05 17:10:23 -0700379 // We will likely encounter errors in the backend functions (i.e. Flip) if EnableCrtc fails.
380 if (DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]) != 0) {
381 return nullptr;
382 }
Tao Bao76be34c2017-02-07 13:30:19 -0800383
Tao Bao557fa1f2017-02-07 12:51:00 -0800384 return GRSurfaceDrms[0];
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700385}
386
Jeremy Compostella955da1e2018-06-07 10:51:33 -0700387static void page_flip_complete(__unused int fd,
388 __unused unsigned int sequence,
389 __unused unsigned int tv_sec,
390 __unused unsigned int tv_usec,
391 void *user_data) {
392 *static_cast<bool*>(user_data) = false;
393}
394
Tao Bao557fa1f2017-02-07 12:51:00 -0800395GRSurface* MinuiBackendDrm::Flip() {
Jeremy Compostella955da1e2018-06-07 10:51:33 -0700396 bool ongoing_flip = true;
397
Tao Bao557fa1f2017-02-07 12:51:00 -0800398 int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id,
Jeremy Compostella955da1e2018-06-07 10:51:33 -0700399 GRSurfaceDrms[current_buffer]->fb_id,
400 DRM_MODE_PAGE_FLIP_EVENT, &ongoing_flip);
Tao Bao76be34c2017-02-07 13:30:19 -0800401 if (ret < 0) {
402 printf("drmModePageFlip failed ret=%d\n", ret);
403 return nullptr;
404 }
Jeremy Compostella955da1e2018-06-07 10:51:33 -0700405
406 while (ongoing_flip) {
407 struct pollfd fds = {
408 .fd = drm_fd,
409 .events = POLLIN
410 };
411
412 ret = poll(&fds, 1, -1);
413 if (ret == -1 || !(fds.revents & POLLIN)) {
414 printf("poll() failed on drm fd\n");
415 break;
416 }
417
418 drmEventContext evctx = {
419 .version = DRM_EVENT_CONTEXT_VERSION,
420 .page_flip_handler = page_flip_complete
421 };
422
423 ret = drmHandleEvent(drm_fd, &evctx);
424 if (ret != 0) {
425 printf("drmHandleEvent failed ret=%d\n", ret);
426 break;
427 }
428 }
429
Tao Bao76be34c2017-02-07 13:30:19 -0800430 current_buffer = 1 - current_buffer;
Tao Bao557fa1f2017-02-07 12:51:00 -0800431 return GRSurfaceDrms[current_buffer];
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700432}
433
Tao Bao557fa1f2017-02-07 12:51:00 -0800434MinuiBackendDrm::~MinuiBackendDrm() {
435 DrmDisableCrtc(drm_fd, main_monitor_crtc);
436 DrmDestroySurface(GRSurfaceDrms[0]);
437 DrmDestroySurface(GRSurfaceDrms[1]);
Tao Bao76be34c2017-02-07 13:30:19 -0800438 drmModeFreeCrtc(main_monitor_crtc);
439 drmModeFreeConnector(main_monitor_connector);
440 close(drm_fd);
441 drm_fd = -1;
Stéphane Marchesin1a92c442015-06-29 20:05:48 -0700442}