#include #include #include #include #include "render.h" #include #include void create_mask(struct render *render); static int drm_ioctl(int fd, unsigned long request, void *arg) { ioctl_t io; io.handle = fd; io.io_code = request; io.input = arg; io.inp_size = 64; io.output = NULL; io.out_size = 0; return call_service(&io); } static EGLImageKHR px_create_image(EGLDisplay display, EGLContext context, int width, int height, int stride, int name) { EGLImageKHR image; EGLint attribs[] = { EGL_WIDTH, 0, EGL_HEIGHT, 0, EGL_DRM_BUFFER_STRIDE_MESA, 0, EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA | EGL_DRM_BUFFER_USE_SCANOUT_MESA, EGL_NONE }; attribs[1] = width; attribs[3] = height; attribs[5] = stride/4; printf("%s w:%d :%d pitch:%d handle %d\n", __FUNCTION__, width, height, stride, name); image = eglCreateImageKHR(display, context, EGL_DRM_BUFFER_MESA, (void *) (uintptr_t)name, attribs); return image; } static GLint create_shader(GLenum type, const char *source) { GLint ok; GLint shader; shader = glCreateShader(type); if(shader == 0) goto err; glShaderSource(shader, 1, (const GLchar **) &source, NULL); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); if (!ok) { GLchar *info; GLint size; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); info = malloc(size); glGetShaderInfoLog(shader, size, NULL, info); printf("Failed to compile %s: %s\n", type == GL_FRAGMENT_SHADER ? "FS" : "VS",info); printf("Program source:\n%s", source); printf("GLSL compile failure\n"); free(info); glDeleteShader(shader); shader = 0; } err: return shader; } struct render* create_render(EGLDisplay dpy, EGLSurface surface, int dx, int dy) { const char *vs_src = "attribute vec4 v_position;\n" "attribute vec4 v_texcoord0;\n" "varying vec2 source_texture;\n" "void main()\n" "{\n" " gl_Position = v_position;\n" " source_texture = v_texcoord0.xy;\n" "}\n"; const char *fs_src = "varying vec2 source_texture;\n" "uniform sampler2D sampler_src;\n" "uniform sampler2D sampler_mask;\n" "void main()\n" "{\n" " float ca = texture2D(sampler_mask, source_texture).r;\n" " gl_FragColor = vec4(texture2D(sampler_src, source_texture).rgb, ca);\n" "}\n"; EGLint config_attribs[14]; EGLConfig config; EGLint num_configs; EGLContext context; struct drm_i915_fb_info fb; GLint vs_shader, fs_shader; GLenum status; GLint ret; int fd; struct render *render; fd = get_service("DISPLAY"); memset(&fb, 0, sizeof(fb)); ret = drm_ioctl(fd, SRV_FBINFO, &fb); if( ret != 0 ) { printf("failed to get framebuffer info\n"); goto err; }; render = (struct render*)malloc(sizeof(struct render)); if(render == NULL) goto err; render->fd = fd; render->dpy = dpy; render->dx = dx; render->dy = dy; if(!eglQuerySurface(dpy, surface, EGL_WIDTH, &render->width)) goto err1; if(!eglQuerySurface(dpy, surface, EGL_HEIGHT, &render->height)) goto err1; render->scr_width = fb.width; render->scr_height = fb.height; render->front = eglGetBufferImage(dpy, surface, EGL_DRM_BUFFER_FRONT); if(render->front == EGL_NO_IMAGE_KHR) goto err1; render->back = eglGetBufferImage(dpy, surface, EGL_DRM_BUFFER_BACK); if( render->back == EGL_NO_IMAGE_KHR) goto err2; context = eglGetCurrentContext(); config_attribs[0] = EGL_RED_SIZE; config_attribs[1] = 1; config_attribs[2] = EGL_GREEN_SIZE; config_attribs[3] = 1; config_attribs[4] = EGL_BLUE_SIZE; config_attribs[5] = 1; config_attribs[6] = EGL_DEPTH_SIZE; config_attribs[7] = 1; config_attribs[8] = EGL_SURFACE_TYPE; config_attribs[9] = EGL_WINDOW_BIT; config_attribs[10] = EGL_RENDERABLE_TYPE; config_attribs[11] = EGL_OPENGL_BIT; config_attribs[12] = EGL_NONE; if (!eglChooseConfig(dpy,config_attribs, &config, 1, &num_configs) || !num_configs) { printf("failed to choose a config"); goto err3; } render->context = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL); if (!context) { printf("failed to create context"); goto err3; }; if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, render->context)) { printf("failed to make window current"); goto err4; }; glGenTextures(2, render->tx_buffers); if(glGetError() != GL_NO_ERROR) goto err5; glBindTexture(GL_TEXTURE_2D, render->tx_buffers[EGL_DRM_BUFFER_FRONT]); if(glGetError() != GL_NO_ERROR) goto err6; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,render->front); if(glGetError() != GL_NO_ERROR) goto err6; glBindTexture(GL_TEXTURE_2D, render->tx_buffers[EGL_DRM_BUFFER_BACK]); if(glGetError() != GL_NO_ERROR) goto err6; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,render->back); if(glGetError() != GL_NO_ERROR) goto err6; glBindTexture(GL_TEXTURE_2D, 0); render->back_buffer = EGL_DRM_BUFFER_FRONT; render->screen = px_create_image(dpy,context,fb.width,fb.height, fb.pitch,fb.name); if(render->screen == EGL_NO_IMAGE_KHR) goto err6; glGenTextures(1, &render->tx_screen); if(glGetError() != GL_NO_ERROR) goto err6; glBindTexture(GL_TEXTURE_2D, render->tx_screen); if(glGetError() != GL_NO_ERROR) goto err7; glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,render->screen); if(glGetError() != GL_NO_ERROR) goto err7; glBindTexture(GL_TEXTURE_2D, 0); create_mask(render); glGenFramebuffers(1, &render->framebuffer); if(glGetError() != GL_NO_ERROR) goto err8; glBindFramebuffer(GL_FRAMEBUFFER, render->framebuffer); if(glGetError() != GL_NO_ERROR) goto err9; glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render->tx_screen,0); status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { const char *str; switch (status) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str = "incomplete attachment"; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str = "incomplete/missing attachment"; break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str = "incomplete draw buffer"; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str = "incomplete read buffer"; break; case GL_FRAMEBUFFER_UNSUPPORTED: str = "unsupported"; break; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str = "incomplete multiple"; break; default: str = "unknown error"; break; } printf("destination is framebuffer incomplete: %s [%#x]\n", str, status); goto err9; } glViewport(0, 0, render->scr_width, render->scr_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); render->blit_prog = glCreateProgram(); if(render->blit_prog == 0) goto err9; vs_shader = create_shader(GL_VERTEX_SHADER,vs_src); if(vs_shader == 0) goto err10; fs_shader = create_shader(GL_FRAGMENT_SHADER, fs_src); if(fs_shader == 0) goto err11; glAttachShader(render->blit_prog, vs_shader); glAttachShader(render->blit_prog, fs_shader); glBindAttribLocation(render->blit_prog, 0, "v_position"); glBindAttribLocation(render->blit_prog, 1, "v_texcoord0"); glLinkProgram(render->blit_prog); glGetProgramiv(render->blit_prog, GL_LINK_STATUS, &ret); if (!ret) { GLchar *info; GLint size; glGetProgramiv(render->blit_prog, GL_INFO_LOG_LENGTH, &size); info = malloc(size); glGetProgramInfoLog(render->blit_prog, size, NULL, info); printf("Failed to link: %s\n", info); printf("GLSL link failure\n"); free(info); goto err12; } render->sampler = glGetUniformLocation(render->blit_prog,"sampler_src"); render->sm_mask = glGetUniformLocation(render->blit_prog,"sampler_mask"); glUseProgram(render->blit_prog); glUniform1i(render->sampler, 0); glUniform1i(render->sm_mask, 1); glVertexAttribPointer(0, 2, GL_FLOAT,GL_FALSE, 2 * sizeof(float),render->vertices); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float),render->tc_src); glEnableVertexAttribArray(1); render->tc_src[0] = 0.0; render->tc_src[1] = 0.0; render->tc_src[1*2] = 1.0; render->tc_src[1*2+1]= 0.0; render->tc_src[2*2] = 1.0; render->tc_src[2*2+1]= 1.0; render->tc_src[3*2] = 0.0; render->tc_src[3*2+1]= 1.0; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, render->tx_mask); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); eglMakeCurrent(dpy, surface, surface, context); return render; err12: glDeleteShader(fs_shader); err11: glDeleteShader(vs_shader); err10: glDeleteProgram(render->blit_prog); err9: glDeleteFramebuffers(1, &render->framebuffer); err8: eglDestroyImageKHR(dpy, render->screen); err7: glDeleteTextures(1, &render->tx_screen); err6: glDeleteTextures(2, render->tx_buffers); err5: eglMakeCurrent(dpy, surface, surface, context); err4: eglDestroyContext(dpy, render->context); err3: eglDestroyImageKHR(dpy, render->back); err2: eglDestroyImageKHR(dpy, render->front); err1: free(render); err: return NULL; }; void create_mask(struct render *render) { struct drm_i915_gem_create create; struct drm_gem_close close; struct drm_gem_flink flink; struct drm_i915_gem_mmap mmap_arg; EGLint handle, stride; int winw, winh, pitch; void *data; int ret; GLuint mask_handle, mask_name; EGLImageKHR mask_image; glGenTextures(1, &render->tx_mask); if(glGetError() != GL_NO_ERROR) return; glBindTexture(GL_TEXTURE_2D, render->tx_mask); if(glGetError() != GL_NO_ERROR) goto err1; pitch = (render->width+15) & ~15; create.size = pitch *render->height; create.handle = 0; ret = drm_ioctl(render->fd, DRM_IOCTL_I915_GEM_CREATE, &create); if(ret != 0) goto err1; mask_handle = create.handle; flink.handle = create.handle; ret = drm_ioctl(render->fd, DRM_IOCTL_GEM_FLINK, &flink); if (ret != 0) goto err2; mask_name = flink.name; printf("create mask bo handle %d name %d\n", create.handle, flink.name); EGLint attribs[] = { EGL_WIDTH, 0, EGL_HEIGHT, 0, EGL_DRM_BUFFER_STRIDE_MESA, 0, EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_R8_MESA, EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA, EGL_NONE }; attribs[1] = pitch; attribs[3] = render->height; attribs[5] = pitch; mask_image = eglCreateImageKHR(render->dpy, render->context, EGL_DRM_BUFFER_MESA, (void *) (uintptr_t)mask_name, attribs); printf("create mask image %p\n", mask_image); if(mask_image == NULL) goto err2 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mask_image); if(glGetError() != GL_NO_ERROR) goto err3; glBindTexture(GL_TEXTURE_2D, 0); mmap_arg.handle = mask_handle; mmap_arg.offset = 0; mmap_arg.size = pitch * render->height; if (drm_ioctl(render->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg)) { printf("%s: failed to mmap image %p handle=%d, %d bytes, into CPU domain\n", __FUNCTION__, mask_image, mask_handle, pitch * render->height); goto err3; } render->mask_handle = mask_handle; render->mask_name = mask_name; render->mask_buffer = (void *)(uintptr_t)mmap_arg.addr_ptr; render->mask_image = mask_image; return; err3: eglDestroyImageKHR(render->dpy, mask_image); err2: close.handle = mask_handle; (void)drm_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close); glBindTexture(GL_TEXTURE_2D, 0); err1: glDeleteTextures(1, &render->tx_mask); };