#include #include #include #include #include #include #include #include #include #include #include #include // #define APIENTRY // #define APIENTRYP APIENTRY * // #define GLAPI extern // // FIXME integrate into glad // typedef void(APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)( // GLenum target, GLeglImageOES image); // GLAPI PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glad_glEGLImageTargetTexture2DOES; // typedef void(APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)( // GLenum target, GLeglImageOES image); // GLAPI PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC // glad_glEGLImageTargetRenderbufferStorageOES; // // FIXME glad // static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; // extern void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image); int main(int argc, const char **argv) { if (argc < 2) { printf("not enough arguments\n"); return 1; } const char *card = argv[1]; const int drmfd = open(card, O_RDONLY); if (drmfd < 0) { fprintf(stderr, "card %s open failed: %s\n", card, strerror(errno)); return 1; } int err; int source_plane = 0; int source_crtc = 0; err = drmSetClientCap(drmfd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); if (err < 0) { perror("Failed to set universal planes capability: primary planes will not be usable"); } drmModePlane *plane = NULL; drmModePlaneRes *plane_res = NULL; drmModeFB2 *fb = NULL; if (source_plane > 0) { plane = drmModeGetPlane(drmfd, source_plane); if (!plane) { fprintf(stderr, "Failed to get plane %d: %s\n", source_plane, strerror(errno)); goto cleanup; } if (plane->fb_id == 0) { fprintf(stderr, "Place %d does not have an attached framebuffer\n", source_plane); } } else { plane_res = drmModeGetPlaneResources(drmfd); if (!plane_res) { perror("Failed to get plane resources"); goto cleanup; } int i; for (i = 0; i < plane_res->count_planes; i++) { plane = drmModeGetPlane(drmfd, plane_res->planes[i]); if (!plane) { fprintf(stderr, "Failed to get plane %u: %s\n", plane_res->planes[i], strerror(errno)); continue; } printf("Plane %u CRTC %u FB %u\n", plane->plane_id, plane->crtc_id, plane->fb_id); if ((source_crtc > 0 && plane->crtc_id != source_crtc) || plane->fb_id == 0) { // Either not connected to the target source CRTC // or not active. drmModeFreePlane(plane); plane = NULL; continue; } break; } if (i == plane_res->count_planes) { if (source_crtc > 0) { fprintf(stderr, "No usable planes found on CRTC %d\n", source_crtc); } else { fprintf(stderr, "No usable planes found\n"); } goto cleanup; } printf("Using plane %u to locate framebuffers\n", plane->plane_id); } uint32_t plane_id = plane->plane_id; fb = drmModeGetFB2(drmfd, plane->fb_id); if (!fb) { fprintf(stderr, "Failed to get framebuffer %u: %s\n", plane->fb_id, strerror(errno)); goto cleanup; } //printf("Template framebuffer is %u: %ux%u %ubpp %ub depth %u pitch\n", fb->fb_id, fb->width, fb->height, fb->bpp, fb->depth, fb->pitch); printf("Template framebuffer is %u: %ux%u fourcc:%u mod:%u flags:%u\n", fb->fb_id, fb->width, fb->height, fb->pixel_format, fb->modifier, fb->flags); printf("handles %u %u %u %u\n", fb->handles[0], fb->handles[1], fb->handles[2], fb->handles[3]); printf("offsets %u %u %u %u\n", fb->offsets[0], fb->offsets[1], fb->offsets[2], fb->offsets[3]); printf("pitches %u %u %u %u\n", fb->pitches[0], fb->pitches[1], fb->pitches[2], fb->pitches[3]); printf("format %s, modifier %s:%s\n", drmGetFormatName(fb->pixel_format), drmGetFormatModifierVendor(fb->modifier), drmGetFormatModifierName(fb->modifier)); if (!fb->handles[0]) { fprintf(stderr, "No handle set on framebuffer: maybe you need some additional capabilities?\n"); goto cleanup; } int fd = -1; err = drmPrimeHandleToFD(drmfd, fb->handles[0], O_RDONLY, &fd); if (err < 0 || fd < 0) { perror("Failed to get PRIME fd from framebuffer handle"); } // //size_t buflen = fb->width * fb->height * fb->bpp / 8; // size_t buflen = fb->width * fb->height * 32 / 8; // char *buf = malloc(buflen); // char *mapped = mmap(NULL, buflen, PROT_READ, MAP_SHARED, fd, 0); // if (mapped == MAP_FAILED) { // perror("mmap"); // goto cleanup; // } // memcpy(buf, mapped, buflen); //unlink("/tmp/1.raw"); //write(open("/tmp/1.raw", O_WRONLY | O_CREAT, 00644), buf, buflen); // EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); // eglInitialize(display, NULL, NULL); // EGLContext context = eglCreateContext(display, NULL, EGL_NO_CONTEXT, NULL); // eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context); EGLAttrib attrs[] = { EGL_WIDTH, fb->width, EGL_HEIGHT, fb->height, EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888, EGL_DMA_BUF_PLANE0_FD_EXT, fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, 1, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, 1 >> 32, EGL_NONE, }; EGLImage image = eglCreateImage(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "eglCreateImage\n"); } // Create an OpenGL texture and bind it to the EGL image GLuint texture; glGenTextures(1, &texture); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "glGenTextures\n"); } glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "glBindTexture\n"); } PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "glEGLImageTargetTexture2DOES\n"); } // Read the pixel data from the texture GLubyte *buf = malloc(fb->width * fb->height * 4); glReadPixels(0, 0, fb->width, fb->height, GL_RGB, GL_UNSIGNED_BYTE, buf); if (glGetError() != GL_NO_ERROR) { fprintf(stderr, "glReadPixels\n"); } // write(open("/tmp/1.raw", O_WRONLY | O_CREAT, 00644), buf, fb->width * fb->height * 4); rfbScreenInfoPtr server=rfbGetScreen(0,NULL,fb->width,fb->height,8,3,32/8); if(!server) return 1; server->frameBuffer=buf; rfbInitServer(server); rfbRunEventLoop(server,-1,FALSE); return(0); cleanup: close(drmfd); return 1; }