/
test-drm-itself.c
361 lines (295 loc) · 9.37 KB
/
test-drm-itself.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#include <sys/ioctl.h>
// fprintf
#include <stdio.h>
// close
#include <unistd.h>
#include <stdint.h>
// struct drm_mode_create_dumb
#include <libdrm/drm.h>
// drmModeGetResources -- Does not depend on X11
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <errno.h>
#include <sys/mman.h>
// strerror
#include <string.h>
// rand
#include <stdlib.h>
#include "common-drm-functions.h"
#include <libdrm/amdgpu.h>
#include <libdrm/amdgpu_drm.h>
// -- STRUCTURES
struct myy_drm_internal_structures {
drmModeRes * __restrict drm_resources;
drmModeConnector * __restrict valid_connector;
drmModeModeInfo * __restrict chosen_resolution;
drmModeEncoder * __restrict screen_encoder;
};
struct myy_drm_frame_buffer {
uint8_t * buffer;
uint32_t id;
struct drm_mode_create_dumb metadata;
drmModeFB * __restrict underlying_object;
struct myy_drm_internal_structures related_structures;
};
// -- FUNCTIONS
drmModeModeInfo * choose_preferred_resolution_on_connector
(drmModeConnector * __restrict const connector)
{
drmModeModeInfo * best_resolution = NULL;
for (int_fast32_t m = 0; m < connector->count_modes; m++) {
drmModeModeInfo * __restrict tested_resolution =
&connector->modes[m];
if (tested_resolution->type & DRM_MODE_TYPE_PREFERRED) {
best_resolution = tested_resolution;
break;
}
}
return best_resolution;
}
int drm_init_display
(int const drm_fd,
struct myy_drm_frame_buffer * __restrict const myy_fb)
{
/* DRM is based on the fact that you can connect multiple screens,
* on multiple different connectors, which have, of course, multiple
* encoders that transform applications framebuffer represented in
* XRGB8888 into something the selected screen comprehend, before
* sending it this framebuffer for display.
*
* The default selection system is simple :
* - We try to find the first connected screen and choose its
* preferred resolution.
*/
drmModeRes * __restrict drm_resources;
drmModeConnector * __restrict valid_connector = NULL;
drmModeModeInfo * __restrict chosen_resolution = NULL;
drmModeEncoder * __restrict screen_encoder = NULL;
int ret = 0;
/* Let's see what we can use through this drm node */
drm_resources = drmModeGetResources(drm_fd);
for (int_fast32_t c = 0; c < drm_resources->count_connectors; c++) {
valid_connector =
drmModeGetConnector(drm_fd, drm_resources->connectors[c]);
if (valid_connector->connection == DRM_MODE_CONNECTED)
break;
drmModeFreeConnector(valid_connector);
valid_connector = NULL;
}
if (!valid_connector) {
/* Then there was no connectors,
* or no connector were connected */
LOG("No connectors or no connected connectors found...\n");
ret = -ENOLINK;
goto no_valid_connector;
}
chosen_resolution =
choose_preferred_resolution_on_connector(valid_connector);
if (!chosen_resolution) {
LOG(
"No preferred resolution on the selected connector %u ?\n",
valid_connector->connector_id
);
ret = -ENAVAIL;
goto no_valid_resolution;
}
screen_encoder =
drmModeGetEncoder(drm_fd, valid_connector->encoder_id);
if (!screen_encoder) {
LOG(
"Could not retrieve the encoder for mode %s on connector %u.\n",
chosen_resolution->name,
valid_connector->connector_id
);
ret = -ENOLINK;
goto could_not_retrieve_encoder;
}
print_drmModeResources(drm_resources);
print_drmModeModeInfo(chosen_resolution);
myy_fb->related_structures.drm_resources = drm_resources;
myy_fb->related_structures.valid_connector = valid_connector;
myy_fb->related_structures.chosen_resolution = chosen_resolution;
myy_fb->related_structures.screen_encoder = screen_encoder;
myy_fb->metadata.width = chosen_resolution->hdisplay;
myy_fb->metadata.height = chosen_resolution->vdisplay;
return ret;
could_not_retrieve_encoder:
drmModeFreeModeInfo(chosen_resolution);
no_valid_resolution:
drmModeFreeConnector(valid_connector);
no_valid_connector:
return ret;
}
void drm_deinit_display()
{
}
int make_dumb_buffer_mapable
(int drm_fd,
struct drm_mode_create_dumb * __restrict const dumb_buffer)
{
struct drm_mode_map_dumb map_request = {
.handle = dumb_buffer->handle,
.pad = 0,
.offset = 0
};
return ioctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_request);
/*mmapped_address = mmap(
0, dumb_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED,
drm_fd, map_request.offset);
dumb_buffer_mapping_request_denied:
return mmapped_address;*/
}
uint32_t drm_crtc_get_current
(struct myy_drm_frame_buffer * __restrict const myy_fb)
{
return myy_fb->related_structures.screen_encoder->crtc_id;
}
int main() {
char const * __restrict const drm_hardware_dev_node_path =
"/dev/dri/card0";
const uint32_t fb_depth = 24;
struct myy_drm_frame_buffer myy_drm_fb = {0};
int const drm_fd = drm_open_node(drm_hardware_dev_node_path);
int prime_fd = -1;
int ret = 0;
uint32_t current_crtc_id = 0;
drmModeCrtc * crtc_to_restore = NULL;
if (drm_fd < 0) {
/* %m is actually a GLIBC specific format for strerror(errno) */
LOG(
"Could not open %s with Read-Write rights : %m\n",
drm_hardware_dev_node_path
);
goto could_not_open_drm_fd;
}
if (!drm_node_support_dumb_buffers(drm_fd)) {
LOG(
"Looks like %s do not support Dumb Buffers...\n",
drm_hardware_dev_node_path
);
goto dumb_buffers_not_supported;
}
if (drm_init_display(drm_fd, &myy_drm_fb)) {
LOG("Something went wrong when initialiasing the display\n");
goto could_not_init_display;
}
myy_drm_fb.metadata.bpp = 32;
ret = allocate_drm_dumb_buffer(drm_fd, &myy_drm_fb.metadata);
if (ret < 0) {
LOG(
"Could not allocate a %ux%u@%ubpp frame buffer... %m\n",
myy_drm_fb.metadata.width,
myy_drm_fb.metadata.height,
myy_drm_fb.metadata.bpp
);
goto could_not_allocate_drm_dumb_buffer;
}
ret = drmModeAddFB(
drm_fd,
myy_drm_fb.metadata.width, myy_drm_fb.metadata.height,
fb_depth, myy_drm_fb.metadata.bpp, myy_drm_fb.metadata.pitch,
myy_drm_fb.metadata.handle, &myy_drm_fb.id
);
if (ret) {
LOG(
"Could not add a framebuffer using drmModeAddFB : %s\n",
strerror(ret)
);
goto could_not_add_frame_buffer;
}
current_crtc_id = drm_crtc_get_current(&myy_drm_fb);
if (!current_crtc_id) {
LOG("The retrieved encoder has no CRTC attached... ?\n");
goto could_not_retrieve_current_crtc;
}
crtc_to_restore = drmModeGetCrtc(drm_fd, current_crtc_id);
if (!crtc_to_restore) {
LOG("Could not retrieve the current CRTC with a valid ID !\n");
goto could_not_retrieve_current_crtc;
}
print_crtc(crtc_to_restore);
ret = drmModeSetCrtc(
drm_fd, current_crtc_id, myy_drm_fb.id, 0, 0,
&myy_drm_fb.related_structures.valid_connector->connector_id,
1, myy_drm_fb.related_structures.chosen_resolution);
/*if (make_dumb_buffer_mapable(drm_fd, &myy_drm_fb.metadata) < 0) {
LOG("Could not make dumb buffer MMAPable\n");
goto could_not_export_dumb_buffer;
}*/
prime_fd = drm_convert_buffer_handle_to_prime_fd(
drm_fd, myy_drm_fb.metadata.handle);
if (prime_fd < 0) {
LOG("Unable to convert the GEM handle to a DRM Handle : %m\n");
goto could_not_export_dumb_buffer;
}
LOG("Got a Prime buffer FD : %d ! Yay !\n", prime_fd);
myy_drm_fb.buffer = mmap(
0, myy_drm_fb.metadata.size,
PROT_READ | PROT_WRITE, MAP_SHARED,
prime_fd, 0);
if (!myy_drm_fb.buffer || myy_drm_fb.buffer == MAP_FAILED) {
LOG("Could not map buffer exported through PRIME : %m\n");
goto could_not_map_buffer;
}
/* Map the buffer and write in it */
LOG(
"Buffer address : %p\n"
"Buffer ID : %u\n"
"Buffer width : %u\n"
"Buffer height : %u\n"
"Buffer bpp : %u\n"
"Buffer size : %llu\n"
"Buffer stride : %u\n",
myy_drm_fb.buffer,
myy_drm_fb.id,
myy_drm_fb.metadata.width,
myy_drm_fb.metadata.height,
myy_drm_fb.metadata.bpp,
myy_drm_fb.metadata.size,
myy_drm_fb.metadata.pitch);
uint32_t const bytes_per_pixel = 4;
uint_fast64_t
pixel = 0,
size = myy_drm_fb.metadata.size;
memset(myy_drm_fb.buffer, 0, size);
uint32_t const red = (0xff<<16);
uint32_t const green = (0xff<<8);
uint32_t const blue = (0xff);
uint32_t const colors[] = {red, green, blue};
/* Pitch is the stride in bytes.
We currently use 4 bytes per pixel */
uint32_t const stride_pixel = myy_drm_fb.metadata.pitch / bytes_per_pixel;
uint32_t const width_pixel = myy_drm_fb.metadata.width;
uint32_t const diff_between_width_and_stride = stride_pixel - width_pixel;
uint_fast64_t const size_in_pixels = myy_drm_fb.metadata.height * stride_pixel;
while (getc(stdin) != 'q' && pixel < size_in_pixels) {
uint32_t current_color = colors[rand()%3];
for (uint_fast32_t s = 0; s < width_pixel; s++)
((uint32_t *) myy_drm_fb.buffer)[pixel++] = current_color;
pixel += diff_between_width_and_stride;
LOG("pixel : %lu, size : %lu\n", pixel, size_in_pixels);
}
/*for (uint_fast64_t pixel = 0, size = myy_drm_fb.metadata.size;
pixel < size; pixel++) {
myy_drm_fb.buffer[pixel] = rand();
}
getc(stdin);*/
munmap(myy_drm_fb.buffer, myy_drm_fb.metadata.size);
could_not_map_buffer:
could_not_export_dumb_buffer:
free_drm_dumb_buffer(drm_fd, myy_drm_fb.metadata.handle);
drmModeSetCrtc(
drm_fd, crtc_to_restore->crtc_id,
crtc_to_restore->buffer_id, 0, 0,
&myy_drm_fb.related_structures.valid_connector->connector_id,
1, &crtc_to_restore->mode);
could_not_retrieve_current_crtc:
could_not_add_frame_buffer:
drmModeRmFB(drm_fd, myy_drm_fb.id);
could_not_allocate_drm_dumb_buffer:
dumb_buffers_not_supported:
could_not_init_display:
close(drm_fd);
could_not_open_drm_fd:
return 0;
}