diff options
author | Rob Clark <robdclark@chromium.org> | 2020-09-02 09:16:25 -0700 |
---|---|---|
committer | Rob Clark <robdclark@chromium.org> | 2020-09-02 09:50:08 -0700 |
commit | 26326be53e30da9c101075fda081d38ea9ec758d (patch) | |
tree | f6f41f70df5ea5ebadc18e4856a2960ae08b341b | |
parent | 31d162224b29d65715b70b307818c383be7b4f3c (diff) |
surfaceless support
-rw-r--r-- | common.c | 154 | ||||
-rw-r--r-- | common.h | 11 | ||||
-rw-r--r-- | drm-atomic.c | 17 | ||||
-rw-r--r-- | drm-legacy.c | 26 | ||||
-rw-r--r-- | kmscube.c | 15 | ||||
-rw-r--r-- | texturator.c | 2 |
6 files changed, 205 insertions, 20 deletions
@@ -22,6 +22,7 @@ * DEALINGS IN THE SOFTWARE. */ +#include <assert.h> #include <errno.h> #include <fcntl.h> #include <stdbool.h> @@ -29,6 +30,7 @@ #include <stdlib.h> #include <string.h> #include <time.h> +#include <unistd.h> #include "common.h" @@ -40,6 +42,53 @@ gbm_surface_create_with_modifiers(struct gbm_device *gbm, uint32_t format, const uint64_t *modifiers, const unsigned int count); +WEAK struct gbm_bo * +gbm_bo_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + const unsigned int count); + +static struct gbm_bo * init_bo(uint64_t modifier) +{ + struct gbm_bo *bo = NULL; + + if (gbm_bo_create_with_modifiers) { + bo = gbm_bo_create_with_modifiers(gbm.dev, + gbm.width, gbm.height, + gbm.format, + &modifier, 1); + } + + if (!bo) { + if (modifier != DRM_FORMAT_MOD_LINEAR) { + fprintf(stderr, "Modifiers requested but support isn't available\n"); + return NULL; + } + + bo = gbm_bo_create(gbm.dev, + gbm.width, gbm.height, + gbm.format, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + } + + if (!bo) { + printf("failed to create gbm bo\n"); + return NULL; + } + + return bo; +} + +static struct gbm * init_surfaceless(uint64_t modifier) +{ + for (unsigned i = 0; i < ARRAY_SIZE(gbm.bos); i++) { + gbm.bos[i] = init_bo(modifier); + if (!gbm.bos[i]) + return NULL; + } + return &gbm; +} static struct gbm * init_surface(uint64_t modifier) { @@ -71,7 +120,8 @@ static struct gbm * init_surface(uint64_t modifier) return &gbm; } -const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t modifier) +const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, + uint64_t modifier, bool surfaceless) { gbm.dev = gbm_create_device(drm_fd); gbm.format = format; @@ -80,6 +130,9 @@ const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t gbm.width = w; gbm.height = h; + if (surfaceless) + return init_surfaceless(modifier); + return init_surface(modifier); } @@ -169,6 +222,82 @@ out: return true; } +static bool +create_framebuffer(const struct egl *egl, struct gbm_bo *bo, + struct framebuffer *fb) { + assert(egl->eglCreateImageKHR); + assert(bo); + assert(fb); + + // 1. Create EGLImage. + int fd = gbm_bo_get_fd(bo); + if (fd < 0) { + printf("failed to get fd for bo: %d\n", fd); + return false; + } + + EGLint khr_image_attrs[17] = { + EGL_WIDTH, gbm_bo_get_width(bo), + EGL_HEIGHT, gbm_bo_get_height(bo), + EGL_LINUX_DRM_FOURCC_EXT, (int)gbm_bo_get_format(bo), + EGL_DMA_BUF_PLANE0_FD_EXT, fd, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, + EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride(bo), + EGL_NONE, EGL_NONE, /* modifier lo */ + EGL_NONE, EGL_NONE, /* modifier hi */ + EGL_NONE, + }; + + if (egl->modifiers_supported) { + const uint64_t modifier = gbm_bo_get_modifier(bo); + if (modifier != DRM_FORMAT_MOD_LINEAR) { + size_t attrs_index = 12; + khr_image_attrs[attrs_index++] = + EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + khr_image_attrs[attrs_index++] = modifier & 0xfffffffful; + khr_image_attrs[attrs_index++] = + EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + khr_image_attrs[attrs_index++] = modifier >> 32; + } + } + + fb->image = egl->eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL /* no client buffer */, + khr_image_attrs); + + if (fb->image == EGL_NO_IMAGE_KHR) { + printf("failed to make image from buffer object\n"); + return false; + } + + // EGLImage takes the fd ownership. + close(fd); + + // 2. Create GL texture and framebuffer. + glGenTextures(1, &fb->tex); + glBindTexture(GL_TEXTURE_2D, fb->tex); + egl->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, fb->image); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &fb->fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb->fb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + fb->tex, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + printf("failed framebuffer check for created target buffer\n"); + glDeleteFramebuffers(1, &fb->fb); + glDeleteTextures(1, &fb->tex); + return false; + } + + return true; +} + int init_egl(struct egl *egl, const struct gbm *gbm, int samples) { EGLint major, minor; @@ -260,11 +389,15 @@ int init_egl(struct egl *egl, const struct gbm *gbm, int samples) return -1; } - egl->surface = eglCreateWindowSurface(egl->display, egl->config, - (EGLNativeWindowType)gbm->surface, NULL); - if (egl->surface == EGL_NO_SURFACE) { - printf("failed to create egl surface\n"); - return -1; + if (!gbm->surface) { + egl->surface = EGL_NO_SURFACE; + } else { + egl->surface = eglCreateWindowSurface(egl->display, egl->config, + (EGLNativeWindowType)gbm->surface, NULL); + if (egl->surface == EGL_NO_SURFACE) { + printf("failed to create egl surface\n"); + return -1; + } } /* connect the context to the surface */ @@ -293,6 +426,15 @@ int init_egl(struct egl *egl, const struct gbm *gbm, int samples) get_proc_gl(GL_AMD_performance_monitor, glEndPerfMonitorAMD); get_proc_gl(GL_AMD_performance_monitor, glGetPerfMonitorCounterDataAMD); + if (!gbm->surface) { + for (unsigned i = 0; i < ARRAY_SIZE(gbm->bos); i++) { + if (!create_framebuffer(egl, gbm->bos[i], &egl->fbs[i])) { + printf("failed to create framebuffer\n"); + return -1; + } + } + } + return 0; } @@ -96,21 +96,30 @@ EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, #define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A #endif +#define NUM_BUFFERS 2 + struct gbm { struct gbm_device *dev; struct gbm_surface *surface; + struct gbm_bo *bos[NUM_BUFFERS]; /* for the surfaceless case */ uint32_t format; int width, height; }; -const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t modifier); +const struct gbm * init_gbm(int drm_fd, int w, int h, uint32_t format, uint64_t modifier, bool surfaceless); +struct framebuffer { + EGLImageKHR image; + GLuint tex; + GLuint fb; +}; struct egl { EGLDisplay display; EGLConfig config; EGLContext context; EGLSurface surface; + struct framebuffer fbs[NUM_BUFFERS]; /* for the surfaceless case */ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; diff --git a/drm-atomic.c b/drm-atomic.c index 1fc7586..16c4d08 100644 --- a/drm-atomic.c +++ b/drm-atomic.c @@ -196,6 +196,7 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl) start_time = report_time = get_time_ns(); while (i < drm.count) { + unsigned frame = i; struct gbm_bo *next_bo; EGLSyncKHR gpu_fence = NULL; /* out-fence from gpu, in-fence to kms */ EGLSyncKHR kms_fence = NULL; /* in-fence to gpu, out-fence from kms */ @@ -222,6 +223,10 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl) start_time = report_time = get_time_ns(); } + if (!gbm->surface) { + glBindFramebuffer(GL_FRAMEBUFFER, egl->fbs[frame % NUM_BUFFERS].fb); + } + egl->draw(i++); /* insert fence to be singled in cmdstream.. this fence will be @@ -230,7 +235,9 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl) gpu_fence = create_fence(egl, EGL_NO_NATIVE_FENCE_FD_ANDROID); assert(gpu_fence); - eglSwapBuffers(egl->display, egl->surface); + if (gbm->surface) { + eglSwapBuffers(egl->display, egl->surface); + } /* after swapbuffers, gpu_fence should be flushed, so safe * to get fd: @@ -239,7 +246,11 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl) egl->eglDestroySyncKHR(egl->display, gpu_fence); assert(drm.kms_in_fence_fd != -1); - next_bo = gbm_surface_lock_front_buffer(gbm->surface); + if (gbm->surface) { + next_bo = gbm_surface_lock_front_buffer(gbm->surface); + } else { + next_bo = gbm->bos[frame % NUM_BUFFERS]; + } if (!next_bo) { printf("Failed to lock frontbuffer\n"); return -1; @@ -300,7 +311,7 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl) } /* release last buffer to render on again: */ - if (bo) + if (bo && gbm->surface) gbm_surface_release_buffer(gbm->surface, bo); bo = next_bo; diff --git a/drm-legacy.c b/drm-legacy.c index 6c35904..8f773e8 100644 --- a/drm-legacy.c +++ b/drm-legacy.c @@ -54,8 +54,12 @@ static int legacy_run(const struct gbm *gbm, const struct egl *egl) int64_t start_time, report_time, cur_time; int ret; - eglSwapBuffers(egl->display, egl->surface); - bo = gbm_surface_lock_front_buffer(gbm->surface); + if (gbm->surface) { + eglSwapBuffers(egl->display, egl->surface); + bo = gbm_surface_lock_front_buffer(gbm->surface); + } else { + bo = gbm->bos[0]; + } fb = drm_fb_get_from_bo(bo); if (!fb) { fprintf(stderr, "Failed to get a new framebuffer BO\n"); @@ -73,6 +77,7 @@ static int legacy_run(const struct gbm *gbm, const struct egl *egl) start_time = report_time = get_time_ns(); while (i < drm.count) { + unsigned frame = i; struct gbm_bo *next_bo; int waiting_for_flip = 1; @@ -83,10 +88,19 @@ static int legacy_run(const struct gbm *gbm, const struct egl *egl) start_time = report_time = get_time_ns(); } + if (!gbm->surface) { + glBindFramebuffer(GL_FRAMEBUFFER, egl->fbs[frame % NUM_BUFFERS].fb); + } + egl->draw(i++); - eglSwapBuffers(egl->display, egl->surface); - next_bo = gbm_surface_lock_front_buffer(gbm->surface); + if (gbm->surface) { + eglSwapBuffers(egl->display, egl->surface); + next_bo = gbm_surface_lock_front_buffer(gbm->surface); + } else { + glFinish(); + next_bo = gbm->bos[frame % NUM_BUFFERS]; + } fb = drm_fb_get_from_bo(next_bo); if (!fb) { fprintf(stderr, "Failed to get a new framebuffer BO\n"); @@ -135,7 +149,9 @@ static int legacy_run(const struct gbm *gbm, const struct egl *egl) } /* release last buffer to render on again: */ - gbm_surface_release_buffer(gbm->surface, bo); + if (gbm->surface) { + gbm_surface_release_buffer(gbm->surface, bo); + } bo = next_bo; } @@ -41,7 +41,7 @@ static const struct egl *egl; static const struct gbm *gbm; static const struct drm *drm; -static const char *shortopts = "Ac:D:f:M:m:p:S:s:V:v:"; +static const char *shortopts = "Ac:D:f:M:m:p:S:s:V:v:x"; static const struct option longopts[] = { {"atomic", no_argument, 0, 'A'}, @@ -54,12 +54,13 @@ static const struct option longopts[] = { {"samples", required_argument, 0, 's'}, {"video", required_argument, 0, 'V'}, {"vmode", required_argument, 0, 'v'}, + {"surfaceless", no_argument, 0, 'x'}, {0, 0, 0, 0} }; static void usage(const char *name) { - printf("Usage: %s [-ADfMmSsVv]\n" + printf("Usage: %s [-ADfMmSsVvx]\n" "\n" "options:\n" " -A, --atomic use atomic modesetting and fencing\n" @@ -79,7 +80,9 @@ static void usage(const char *name) " -s, --samples=N use MSAA\n" " -V, --video=FILE video textured cube (comma separated list)\n" " -v, --vmode=VMODE specify the video mode in the format\n" - " <mode>[-<vrefresh>]\n", + " <mode>[-<vrefresh>]\n" + " -x, --surfaceless use surfaceless mode, instead of gbm surface\n" + , name); } @@ -100,6 +103,7 @@ int main(int argc, char *argv[]) unsigned int len; unsigned int vrefresh = 0; unsigned int count = ~0; + bool surfaceless = false; #ifdef HAVE_GST gst_init(&argc, &argv); @@ -177,6 +181,9 @@ int main(int argc, char *argv[]) strncpy(mode_str, optarg, len); mode_str[len] = '\0'; break; + case 'x': + surfaceless = true; + break; default: usage(argv[0]); return -1; @@ -193,7 +200,7 @@ int main(int argc, char *argv[]) } gbm = init_gbm(drm->fd, drm->mode->hdisplay, drm->mode->vdisplay, - format, modifier); + format, modifier, surfaceless); if (!gbm) { printf("failed to initialize GBM\n"); return -1; diff --git a/texturator.c b/texturator.c index 8695a63..d9335d7 100644 --- a/texturator.c +++ b/texturator.c @@ -957,7 +957,7 @@ int main(int argc, char *argv[]) } gbm = init_gbm(drm->fd, drm->mode->hdisplay, drm->mode->vdisplay, - DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR); + DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_LINEAR, false); if (!gbm) { printf("failed to initialize GBM\n"); return -1; |