Codebase list kmscube / 26326be
surfaceless support Rob Clark 3 years ago
6 changed file(s) with 206 addition(s) and 21 deletion(s). Raw diff Collapse all Expand all
2121 * DEALINGS IN THE SOFTWARE.
2222 */
2323
24 #include <assert.h>
2425 #include <errno.h>
2526 #include <fcntl.h>
2627 #include <stdbool.h>
2829 #include <stdlib.h>
2930 #include <string.h>
3031 #include <time.h>
32 #include <unistd.h>
3133
3234 #include "common.h"
3335
3941 uint32_t format,
4042 const uint64_t *modifiers,
4143 const unsigned int count);
44 WEAK struct gbm_bo *
45 gbm_bo_create_with_modifiers(struct gbm_device *gbm,
46 uint32_t width, uint32_t height,
47 uint32_t format,
48 const uint64_t *modifiers,
49 const unsigned int count);
50
51 static struct gbm_bo * init_bo(uint64_t modifier)
52 {
53 struct gbm_bo *bo = NULL;
54
55 if (gbm_bo_create_with_modifiers) {
56 bo = gbm_bo_create_with_modifiers(gbm.dev,
57 gbm.width, gbm.height,
58 gbm.format,
59 &modifier, 1);
60 }
61
62 if (!bo) {
63 if (modifier != DRM_FORMAT_MOD_LINEAR) {
64 fprintf(stderr, "Modifiers requested but support isn't available\n");
65 return NULL;
66 }
67
68 bo = gbm_bo_create(gbm.dev,
69 gbm.width, gbm.height,
70 gbm.format,
71 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
72 }
73
74 if (!bo) {
75 printf("failed to create gbm bo\n");
76 return NULL;
77 }
78
79 return bo;
80 }
81
82 static struct gbm * init_surfaceless(uint64_t modifier)
83 {
84 for (unsigned i = 0; i < ARRAY_SIZE(gbm.bos); i++) {
85 gbm.bos[i] = init_bo(modifier);
86 if (!gbm.bos[i])
87 return NULL;
88 }
89 return &gbm;
90 }
4291
4392 static struct gbm * init_surface(uint64_t modifier)
4493 {
70119 return &gbm;
71120 }
72121
73 const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t modifier)
122 const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format,
123 uint64_t modifier, bool surfaceless)
74124 {
75125 gbm.dev = gbm_create_device(drm_fd);
76126 gbm.format = format;
78128
79129 gbm.width = w;
80130 gbm.height = h;
131
132 if (surfaceless)
133 return init_surfaceless(modifier);
81134
82135 return init_surface(modifier);
83136 }
164217 free(configs);
165218 if (config_index == -1)
166219 return false;
220
221 return true;
222 }
223
224 static bool
225 create_framebuffer(const struct egl *egl, struct gbm_bo *bo,
226 struct framebuffer *fb) {
227 assert(egl->eglCreateImageKHR);
228 assert(bo);
229 assert(fb);
230
231 // 1. Create EGLImage.
232 int fd = gbm_bo_get_fd(bo);
233 if (fd < 0) {
234 printf("failed to get fd for bo: %d\n", fd);
235 return false;
236 }
237
238 EGLint khr_image_attrs[17] = {
239 EGL_WIDTH, gbm_bo_get_width(bo),
240 EGL_HEIGHT, gbm_bo_get_height(bo),
241 EGL_LINUX_DRM_FOURCC_EXT, (int)gbm_bo_get_format(bo),
242 EGL_DMA_BUF_PLANE0_FD_EXT, fd,
243 EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
244 EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride(bo),
245 EGL_NONE, EGL_NONE, /* modifier lo */
246 EGL_NONE, EGL_NONE, /* modifier hi */
247 EGL_NONE,
248 };
249
250 if (egl->modifiers_supported) {
251 const uint64_t modifier = gbm_bo_get_modifier(bo);
252 if (modifier != DRM_FORMAT_MOD_LINEAR) {
253 size_t attrs_index = 12;
254 khr_image_attrs[attrs_index++] =
255 EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
256 khr_image_attrs[attrs_index++] = modifier & 0xfffffffful;
257 khr_image_attrs[attrs_index++] =
258 EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
259 khr_image_attrs[attrs_index++] = modifier >> 32;
260 }
261 }
262
263 fb->image = egl->eglCreateImageKHR(egl->display, EGL_NO_CONTEXT,
264 EGL_LINUX_DMA_BUF_EXT, NULL /* no client buffer */,
265 khr_image_attrs);
266
267 if (fb->image == EGL_NO_IMAGE_KHR) {
268 printf("failed to make image from buffer object\n");
269 return false;
270 }
271
272 // EGLImage takes the fd ownership.
273 close(fd);
274
275 // 2. Create GL texture and framebuffer.
276 glGenTextures(1, &fb->tex);
277 glBindTexture(GL_TEXTURE_2D, fb->tex);
278 egl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, fb->image);
279 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
280 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
281 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
282 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
283 glBindTexture(GL_TEXTURE_2D, 0);
284
285 glGenFramebuffers(1, &fb->fb);
286 glBindFramebuffer(GL_FRAMEBUFFER, fb->fb);
287 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
288 fb->tex, 0);
289
290 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
291 printf("failed framebuffer check for created target buffer\n");
292 glDeleteFramebuffers(1, &fb->fb);
293 glDeleteTextures(1, &fb->tex);
294 return false;
295 }
167296
168297 return true;
169298 }
259388 return -1;
260389 }
261390
262 egl->surface = eglCreateWindowSurface(egl->display, egl->config,
263 (EGLNativeWindowType)gbm->surface, NULL);
264 if (egl->surface == EGL_NO_SURFACE) {
265 printf("failed to create egl surface\n");
266 return -1;
391 if (!gbm->surface) {
392 egl->surface = EGL_NO_SURFACE;
393 } else {
394 egl->surface = eglCreateWindowSurface(egl->display, egl->config,
395 (EGLNativeWindowType)gbm->surface, NULL);
396 if (egl->surface == EGL_NO_SURFACE) {
397 printf("failed to create egl surface\n");
398 return -1;
399 }
267400 }
268401
269402 /* connect the context to the surface */
292425 get_proc_gl(GL_AMD_performance_monitor, glEndPerfMonitorAMD);
293426 get_proc_gl(GL_AMD_performance_monitor, glGetPerfMonitorCounterDataAMD);
294427
428 if (!gbm->surface) {
429 for (unsigned i = 0; i < ARRAY_SIZE(gbm->bos); i++) {
430 if (!create_framebuffer(egl, gbm->bos[i], &egl->fbs[i])) {
431 printf("failed to create framebuffer\n");
432 return -1;
433 }
434 }
435 }
436
295437 return 0;
296438 }
297439
9595 #define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
9696 #endif
9797
98 #define NUM_BUFFERS 2
99
98100 struct gbm {
99101 struct gbm_device *dev;
100102 struct gbm_surface *surface;
103 struct gbm_bo *bos[NUM_BUFFERS]; /* for the surfaceless case */
101104 uint32_t format;
102105 int width, height;
103106 };
104107
105 const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t modifier);
106
108 const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t modifier, bool surfaceless);
109
110 struct framebuffer {
111 EGLImageKHR image;
112 GLuint tex;
113 GLuint fb;
114 };
107115
108116 struct egl {
109117 EGLDisplay display;
110118 EGLConfig config;
111119 EGLContext context;
112120 EGLSurface surface;
121 struct framebuffer fbs[NUM_BUFFERS]; /* for the surfaceless case */
113122
114123 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
115124 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
195195 start_time = report_time = get_time_ns();
196196
197197 while (i < drm.count) {
198 unsigned frame = i;
198199 struct gbm_bo *next_bo;
199200 EGLSyncKHR gpu_fence = NULL; /* out-fence from gpu, in-fence to kms */
200201 EGLSyncKHR kms_fence = NULL; /* in-fence to gpu, out-fence from kms */
221222 start_time = report_time = get_time_ns();
222223 }
223224
225 if (!gbm->surface) {
226 glBindFramebuffer(GL_FRAMEBUFFER, egl->fbs[frame % NUM_BUFFERS].fb);
227 }
228
224229 egl->draw(i++);
225230
226231 /* insert fence to be singled in cmdstream.. this fence will be
229234 gpu_fence = create_fence(egl, EGL_NO_NATIVE_FENCE_FD_ANDROID);
230235 assert(gpu_fence);
231236
232 eglSwapBuffers(egl->display, egl->surface);
237 if (gbm->surface) {
238 eglSwapBuffers(egl->display, egl->surface);
239 }
233240
234241 /* after swapbuffers, gpu_fence should be flushed, so safe
235242 * to get fd:
238245 egl->eglDestroySyncKHR(egl->display, gpu_fence);
239246 assert(drm.kms_in_fence_fd != -1);
240247
241 next_bo = gbm_surface_lock_front_buffer(gbm->surface);
248 if (gbm->surface) {
249 next_bo = gbm_surface_lock_front_buffer(gbm->surface);
250 } else {
251 next_bo = gbm->bos[frame % NUM_BUFFERS];
252 }
242253 if (!next_bo) {
243254 printf("Failed to lock frontbuffer\n");
244255 return -1;
299310 }
300311
301312 /* release last buffer to render on again: */
302 if (bo)
313 if (bo && gbm->surface)
303314 gbm_surface_release_buffer(gbm->surface, bo);
304315 bo = next_bo;
305316
5353 int64_t start_time, report_time, cur_time;
5454 int ret;
5555
56 eglSwapBuffers(egl->display, egl->surface);
57 bo = gbm_surface_lock_front_buffer(gbm->surface);
56 if (gbm->surface) {
57 eglSwapBuffers(egl->display, egl->surface);
58 bo = gbm_surface_lock_front_buffer(gbm->surface);
59 } else {
60 bo = gbm->bos[0];
61 }
5862 fb = drm_fb_get_from_bo(bo);
5963 if (!fb) {
6064 fprintf(stderr, "Failed to get a new framebuffer BO\n");
7276 start_time = report_time = get_time_ns();
7377
7478 while (i < drm.count) {
79 unsigned frame = i;
7580 struct gbm_bo *next_bo;
7681 int waiting_for_flip = 1;
7782
8287 start_time = report_time = get_time_ns();
8388 }
8489
90 if (!gbm->surface) {
91 glBindFramebuffer(GL_FRAMEBUFFER, egl->fbs[frame % NUM_BUFFERS].fb);
92 }
93
8594 egl->draw(i++);
8695
87 eglSwapBuffers(egl->display, egl->surface);
88 next_bo = gbm_surface_lock_front_buffer(gbm->surface);
96 if (gbm->surface) {
97 eglSwapBuffers(egl->display, egl->surface);
98 next_bo = gbm_surface_lock_front_buffer(gbm->surface);
99 } else {
100 glFinish();
101 next_bo = gbm->bos[frame % NUM_BUFFERS];
102 }
89103 fb = drm_fb_get_from_bo(next_bo);
90104 if (!fb) {
91105 fprintf(stderr, "Failed to get a new framebuffer BO\n");
134148 }
135149
136150 /* release last buffer to render on again: */
137 gbm_surface_release_buffer(gbm->surface, bo);
151 if (gbm->surface) {
152 gbm_surface_release_buffer(gbm->surface, bo);
153 }
138154 bo = next_bo;
139155 }
140156
4040 static const struct gbm *gbm;
4141 static const struct drm *drm;
4242
43 static const char *shortopts = "Ac:D:f:M:m:p:S:s:V:v:";
43 static const char *shortopts = "Ac:D:f:M:m:p:S:s:V:v:x";
4444
4545 static const struct option longopts[] = {
4646 {"atomic", no_argument, 0, 'A'},
5353 {"samples", required_argument, 0, 's'},
5454 {"video", required_argument, 0, 'V'},
5555 {"vmode", required_argument, 0, 'v'},
56 {"surfaceless", no_argument, 0, 'x'},
5657 {0, 0, 0, 0}
5758 };
5859
5960 static void usage(const char *name)
6061 {
61 printf("Usage: %s [-ADfMmSsVv]\n"
62 printf("Usage: %s [-ADfMmSsVvx]\n"
6263 "\n"
6364 "options:\n"
6465 " -A, --atomic use atomic modesetting and fencing\n"
7879 " -s, --samples=N use MSAA\n"
7980 " -V, --video=FILE video textured cube (comma separated list)\n"
8081 " -v, --vmode=VMODE specify the video mode in the format\n"
81 " <mode>[-<vrefresh>]\n",
82 " <mode>[-<vrefresh>]\n"
83 " -x, --surfaceless use surfaceless mode, instead of gbm surface\n"
84 ,
8285 name);
8386 }
8487
99102 unsigned int len;
100103 unsigned int vrefresh = 0;
101104 unsigned int count = ~0;
105 bool surfaceless = false;
102106
103107 #ifdef HAVE_GST
104108 gst_init(&argc, &argv);
176180 strncpy(mode_str, optarg, len);
177181 mode_str[len] = '\0';
178182 break;
183 case 'x':
184 surfaceless = true;
185 break;
179186 default:
180187 usage(argv[0]);
181188 return -1;
192199 }
193200
194201 gbm = init_gbm(drm->fd, drm->mode->hdisplay, drm->mode->vdisplay,
195 format, modifier);
202 format, modifier, surfaceless);
196203 if (!gbm) {
197204 printf("failed to initialize GBM\n");
198205 return -1;
956956 }
957957
958958 gbm = init_gbm(drm->fd, drm->mode->hdisplay, drm->mode->vdisplay,
959 DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR);
959 DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, false);
960960 if (!gbm) {
961961 printf("failed to initialize GBM\n");
962962 return -1;