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 /common.c | |
parent | 31d162224b29d65715b70b307818c383be7b4f3c (diff) | |
download | kmscube-26326be53e30da9c101075fda081d38ea9ec758d.tar.gz |
surfaceless support
Diffstat (limited to 'common.c')
-rw-r--r-- | common.c | 154 |
1 files changed, 148 insertions, 6 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; } |