summaryrefslogtreecommitdiff
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
parent31d162224b29d65715b70b307818c383be7b4f3c (diff)
surfaceless support
-rw-r--r--common.c154
-rw-r--r--common.h11
-rw-r--r--drm-atomic.c17
-rw-r--r--drm-legacy.c26
-rw-r--r--kmscube.c15
-rw-r--r--texturator.c2
6 files changed, 205 insertions, 20 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;
}
diff --git a/common.h b/common.h
index 149fae9..7c41fee 100644
--- a/common.h
+++ b/common.h
@@ -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;
}
diff --git a/kmscube.c b/kmscube.c
index 28f2dcd..7f2ac26 100644
--- a/kmscube.c
+++ b/kmscube.c
@@ -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;