diff --git a/bwtest/bwtest.c b/bwtest/bwtest.c
index e7bf4d59b810..3c39c1bf0beb 100644
--- a/bwtest/bwtest.c
+++ b/bwtest/bwtest.c
@@ -3,6 +3,15 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/time.h>
+#include <drm.h>
+#include <drm_fourcc.h>
+#include <gbm.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2ext.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
 
 #define W 1024
 #define H 768
@@ -102,13 +111,19 @@ void hexdump_pixels(unsigned char *pix, int width, int height, int max_pixels) {
   if (max_pixels % 8 != 0) printf("\n");
 }
 
+static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = NULL;
+static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = NULL;
+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL;
+
 int main(){
-  EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  int drm_fd = open("/dev/dri/renderD128", O_RDWR);
+  struct gbm_device *gbm_dev = gbm_create_device(drm_fd);
+
+  EGLDisplay dpy =  eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, gbm_dev, NULL);
   EGLBoolean ok = eglInitialize(dpy, NULL, NULL);
   if (!ok) bad("eglInitialize");
 
   EGLint cfgAttr[] = {
-    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
     EGL_RED_SIZE,8, EGL_GREEN_SIZE,8, EGL_BLUE_SIZE,8,
     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
     EGL_NONE
@@ -117,15 +132,33 @@ int main(){
   EGLint nc;
   if (!eglChooseConfig(dpy,cfgAttr,&cfg,1,&nc) || nc==0) bad("eglChooseConfig");
 
-  EGLint pbufAttr[] = { EGL_WIDTH,W, EGL_HEIGHT,H, EGL_NONE };
-  EGLSurface surf = eglCreatePbufferSurface(dpy,cfg,pbufAttr);
-  if (surf == EGL_NO_SURFACE) bad("eglCreatePbufferSurface");
-
   EGLint ctxAttr[] = { EGL_CONTEXT_CLIENT_VERSION,2, EGL_NONE };
   EGLContext ctx = eglCreateContext(dpy,cfg,EGL_NO_CONTEXT,ctxAttr);
   if (ctx == EGL_NO_CONTEXT) bad("eglCreateContext");
 
-  if (!eglMakeCurrent(dpy, surf, surf, ctx)) bad("eglMakeCurrent");
+  eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
+  eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
+  glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
+
+  struct gbm_bo *bo = gbm_bo_create(gbm_dev, WO, HO, GBM_FORMAT_ARGB8888, GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
+  int stride = gbm_bo_get_stride(bo);
+
+  int dma_buf_fd = gbm_bo_get_fd(bo);
+  void *mapped_ptr = mmap(NULL, WO * HO * 4, PROT_READ, MAP_SHARED, dma_buf_fd, 0);
+
+  EGLint img_attrs[] = {
+      EGL_WIDTH, (EGLint)WO,
+      EGL_HEIGHT, (EGLint)HO,
+      EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
+      EGL_DMA_BUF_PLANE0_FD_EXT, dma_buf_fd,
+      EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
+      EGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)stride,
+      EGL_NONE
+  };
+  EGLImageKHR egl_image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, img_attrs);
+  close(dma_buf_fd);
+
+  if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) bad("eglMakeCurrent");
 
   GLuint vs=glCreateShader(GL_VERTEX_SHADER);
   glShaderSource(vs,1,&vsrc,NULL);
@@ -182,7 +215,7 @@ int main(){
   glBindTexture(GL_TEXTURE_2D, fboTex);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WO, HO, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
 
   GLuint fbo;
   glGenFramebuffers(1, &fbo);
@@ -203,14 +236,18 @@ int main(){
   printf("Render loop\n");
   double t0=now();
 
+  // Create Bayer texture
+  GLuint tex;
+  glGenTextures(1, &tex);
+  glBindTexture(GL_TEXTURE_2D, tex);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, W, H, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bayer);
+
   for(int i=0;i<loops;i++){
-    // Create Bayer texture
-    GLuint tex;
-    glGenTextures(1, &tex);
-    glBindTexture(GL_TEXTURE_2D, tex);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, W, H, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bayer);
+    // TODO: Import dmabuf from V4L here
+    // V4L export example: https://docs.kernel.org/userspace-api/media/v4l/vidioc-expbuf.html#vidioc-expbuf
+    // GLES import: see eglCreateImageKHR and glEGLImageTargetTexture2DOES above, and use GL_TEXTURE_EXTERNAL_OES in glBindTexture
 
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, tex);
@@ -234,15 +271,13 @@ int main(){
 
     printf("Running readback test...\n");
   
-    glReadPixels(0,0,WO,HO,GL_RGBA,GL_UNSIGNED_BYTE,pix);
+    //memcpy(pix, mapped_ptr, WO*HO*4);
     check("read");
-
-    glDeleteTextures(1, &tex);
   }
   double dt = now()-t0;
   double mb = (double)WO*HO*4*loops/1e6;
   printf("Readback: %.1f MB in %.2fs = %.1f MB/s\n", mb, dt, mb/dt);
-  hexdump_pixels(pix, WO, HO, 64);
+  hexdump_pixels(mapped_ptr, WO, HO, 64);
 
   // Cleanup
   free(bayer);
@@ -253,7 +288,6 @@ int main(){
   glDeleteShader(vs);
   glDeleteShader(fs);
 
-  eglDestroySurface(dpy, surf);
   eglDestroyContext(dpy, ctx);
   eglTerminate(dpy);
 
