summaryrefslogtreecommitdiff
path: root/common.c
diff options
context:
space:
mode:
authorRob Clark <robdclark@chromium.org>2020-09-02 09:16:25 -0700
committerRob Clark <robdclark@chromium.org>2020-09-02 09:50:08 -0700
commit26326be53e30da9c101075fda081d38ea9ec758d (patch)
treef6f41f70df5ea5ebadc18e4856a2960ae08b341b /common.c
parent31d162224b29d65715b70b307818c383be7b4f3c (diff)
downloadkmscube-26326be53e30da9c101075fda081d38ea9ec758d.tar.gz
surfaceless support
Diffstat (limited to 'common.c')
-rw-r--r--common.c154
1 files changed, 148 insertions, 6 deletions
diff --git a/common.c b/common.c
index 9ee97b6..8ad0ad5 100644
--- a/common.c
+++ b/common.c
@@ -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;
}