1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (c) 2011-2017 - Daniel De Matteis
3  *
4  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
5  *  of the GNU General Public License as published by the Free Software Found-
6  *  ation, either version 3 of the License, or (at your option) any later version.
7  *
8  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10  *  PURPOSE.  See the GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License along with RetroArch.
13  *  If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 #include <compat/strl.h>
17 
18 #include <retro_miscellaneous.h>
19 
20 #include "../../verbosity.h"
21 
22 #include "drm_common.h"
23 
24 /* TODO/FIXME - globals */
25 drmEventContext g_drm_evctx;
26 struct pollfd g_drm_fds;
27 uint32_t g_connector_id               = 0;
28 int g_drm_fd                          = 0;
29 uint32_t g_crtc_id                    = 0;
30 drmModeCrtc *g_orig_crtc              = NULL;
31 drmModeConnector *g_drm_connector     = NULL;
32 drmModeModeInfo *g_drm_mode           = NULL;
33 
34 /* TODO/FIXME - static globals */
35 static drmModeRes *g_drm_resources    = NULL;
36 static drmModeEncoder *g_drm_encoder  = NULL;
37 
38 /* Restore the original CRTC. */
drm_restore_crtc(void)39 void drm_restore_crtc(void)
40 {
41    if (!g_orig_crtc)
42       return;
43 
44    drmModeSetCrtc(g_drm_fd, g_orig_crtc->crtc_id,
45          g_orig_crtc->buffer_id,
46          g_orig_crtc->x,
47          g_orig_crtc->y,
48          &g_connector_id, 1, &g_orig_crtc->mode);
49 
50    drmModeFreeCrtc(g_orig_crtc);
51    g_orig_crtc = NULL;
52 }
53 
drm_get_resources(int fd)54 bool drm_get_resources(int fd)
55 {
56    g_drm_resources = drmModeGetResources(fd);
57    if (!g_drm_resources)
58    {
59       RARCH_WARN("[DRM]: Couldn't get device resources.\n");
60       return false;
61    }
62 
63    return true;
64 }
65 
drm_get_connector(int fd,unsigned monitor_index)66 bool drm_get_connector(int fd, unsigned monitor_index)
67 {
68    unsigned i;
69    unsigned monitor_index_count = 0;
70    unsigned monitor       = MAX(monitor_index, 1);
71 
72    /* Enumerate all connectors. */
73 
74    RARCH_LOG("[DRM]: Found %d connectors.\n", g_drm_resources->count_connectors);
75 
76    for (i = 0; (int)i < g_drm_resources->count_connectors; i++)
77    {
78       drmModeConnectorPtr conn = drmModeGetConnector(
79             fd, g_drm_resources->connectors[i]);
80 
81       if (conn)
82       {
83          bool connected = conn->connection == DRM_MODE_CONNECTED;
84          RARCH_LOG("[DRM]: Connector %d connected: %s\n", i, connected ? "yes" : "no");
85          RARCH_LOG("[DRM]: Connector %d has %d modes.\n", i, conn->count_modes);
86          if (connected && conn->count_modes > 0)
87          {
88             monitor_index_count++;
89             RARCH_LOG("[DRM]: Connector %d assigned to monitor index: #%u.\n", i, monitor_index_count);
90          }
91          drmModeFreeConnector(conn);
92       }
93    }
94 
95    monitor_index_count = 0;
96 
97    for (i = 0; (int)i < g_drm_resources->count_connectors; i++)
98    {
99       g_drm_connector = drmModeGetConnector(fd,
100             g_drm_resources->connectors[i]);
101 
102       if (!g_drm_connector)
103          continue;
104       if (g_drm_connector->connection == DRM_MODE_CONNECTED
105             && g_drm_connector->count_modes > 0)
106       {
107          monitor_index_count++;
108          if (monitor_index_count == monitor)
109             break;
110       }
111 
112       drmModeFreeConnector(g_drm_connector);
113       g_drm_connector = NULL;
114    }
115 
116    if (!g_drm_connector)
117    {
118       RARCH_WARN("[DRM]: Couldn't get device connector.\n");
119       return false;
120    }
121    return true;
122 }
123 
drm_calc_refresh_rate(drmModeModeInfo * mode)124 float drm_calc_refresh_rate(drmModeModeInfo *mode)
125 {
126    float refresh_rate = (mode->clock * 1000.0f) / (mode->htotal * mode->vtotal);
127    return refresh_rate;
128 }
129 
drm_get_encoder(int fd)130 bool drm_get_encoder(int fd)
131 {
132    unsigned i;
133 
134    for (i = 0; (int)i < g_drm_resources->count_encoders; i++)
135    {
136       g_drm_encoder = drmModeGetEncoder(fd, g_drm_resources->encoders[i]);
137 
138       if (!g_drm_encoder)
139          continue;
140 
141       if (g_drm_encoder->encoder_id == g_drm_connector->encoder_id)
142          break;
143 
144       drmModeFreeEncoder(g_drm_encoder);
145       g_drm_encoder = NULL;
146    }
147 
148    if (!g_drm_encoder)
149    {
150       RARCH_WARN("[DRM]: Couldn't find DRM encoder.\n");
151       return false;
152    }
153 
154    for (i = 0; (int)i < g_drm_connector->count_modes; i++)
155    {
156       RARCH_LOG("[DRM]: Mode %d: (%s) %d x %d, %f Hz\n",
157             i,
158             g_drm_connector->modes[i].name,
159             g_drm_connector->modes[i].hdisplay,
160             g_drm_connector->modes[i].vdisplay,
161             drm_calc_refresh_rate(&g_drm_connector->modes[i]));
162    }
163 
164    return true;
165 }
166 
drm_setup(int fd)167 void drm_setup(int fd)
168 {
169    g_crtc_id        = g_drm_encoder->crtc_id;
170    g_connector_id   = g_drm_connector->connector_id;
171    g_orig_crtc      = drmModeGetCrtc(fd, g_crtc_id);
172    if (!g_orig_crtc)
173       RARCH_WARN("[DRM]: Cannot find original CRTC.\n");
174 }
175 
drm_get_refresh_rate(void * data)176 float drm_get_refresh_rate(void *data)
177 {
178    float refresh_rate = 0.0f;
179 
180    if (g_drm_mode)
181    {
182       refresh_rate = drm_calc_refresh_rate(g_drm_mode);
183    }
184 
185    return refresh_rate;
186 }
187 
drm_free(void)188 void drm_free(void)
189 {
190    if (g_drm_encoder)
191       drmModeFreeEncoder(g_drm_encoder);
192    if (g_drm_connector)
193       drmModeFreeConnector(g_drm_connector);
194    if (g_drm_resources)
195       drmModeFreeResources(g_drm_resources);
196 
197    memset(&g_drm_fds,     0, sizeof(struct pollfd));
198    memset(&g_drm_evctx,   0, sizeof(drmEventContext));
199 
200    g_drm_encoder      = NULL;
201    g_drm_connector    = NULL;
202    g_drm_resources    = NULL;
203 }
204