Skip to content

Instantly share code, notes, and snippets.

@fredldotme
Created April 1, 2023 18:39
Show Gist options
  • Save fredldotme/066d8c7b42c5d6e825c0c3cd9740fff4 to your computer and use it in GitHub Desktop.
Save fredldotme/066d8c7b42c5d6e825c0c3cd9740fff4 to your computer and use it in GitHub Desktop.
color correction WIP
static GLint
xwl_eglstream_compile_glsl_prog(GLenum type, const char *source)
{
GLint ok;
GLint prog;
prog = glCreateShader(type);
glShaderSource(prog, 1, (const GLchar **) &source, NULL);
glCompileShader(prog);
glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
if (info) {
glGetShaderInfoLog(prog, size, NULL, info);
ErrorF("Failed to compile %s: %s\n",
type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
ErrorF("Program source:\n%s", source);
free(info);
}
else
ErrorF("Failed to get shader compilation info.\n");
FatalError("GLSL compile failure\n");
}
return prog;
}
static GLuint
xwl_eglstream_build_glsl_prog(GLuint vs, GLuint fs)
{
GLint ok;
GLuint prog;
prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
glGetProgramInfoLog(prog, size, NULL, info);
ErrorF("Failed to link: %s\n", info);
FatalError("GLSL link failure\n");
}
return prog;
}
static inline void
xwl_eglstream_init_shaders(struct glamor_egl_screen_private *xwl_screen)
{
GLint fs, vs, attrib;
const char *blit_vs_src =
"#version 100\n"
"attribute highp vec2 vertexCoord;\n"
"attribute highp vec2 textureCoord;\n"
"varying highp vec2 uv;\n"
"\n"
"void main() {\n"
" uv = textureCoord.xy;\n"
" gl_Position = vec4(vertexCoord, 0, 1);\n"
"}\n";
const char *blit_fs_src =
"#version 100\n"
"\n"
"uniform sampler2D tex;\n"
"uniform bool is_rgba;\n"
"varying highp vec2 uv;\n"
"void main() {\n"
" if (is_rgba)\n"
" gl_FragColor = texture2D(tex, uv);\n"
" else\n"
" gl_FragColor = vec4(texture2D(tex, uv).rgb, 1.0);\n"
"}";
static const GLfloat vertex_buffer_data[] = {
-1,-1, 0,
-1, 1, 0,
1,-1, 0,
-1, 1, 0,
1,-1, 0,
1, 1, 0
};
static const GLfloat texture_buffer_data[] = {
0, 0,
0, 1,
1, 0,
0, 1,
1, 0,
1, 1
};
vs = xwl_eglstream_compile_glsl_prog(GL_VERTEX_SHADER, blit_vs_src);
fs = xwl_eglstream_compile_glsl_prog(GL_FRAGMENT_SHADER, blit_fs_src);
xwl_screen->blit_prog = xwl_eglstream_build_glsl_prog(vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
/* Create the blitter's vao */
glGenVertexArrays(1, &xwl_screen->blit_vao);
glBindVertexArray(xwl_screen->blit_vao);
/* Set the data for both position and texcoord in the vbo */
glGenBuffers(2, xwl_screen->blit_vbos);
/* Vertex buffer data */
glBindBuffer(GL_ARRAY_BUFFER, xwl_screen->blit_vbos[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer_data), vertex_buffer_data, GL_STATIC_DRAW);
attrib = glGetAttribLocation(xwl_screen->blit_prog, "vertexCoord");
glVertexAttribPointer(attrib, 3, GL_FLOAT, GL_TRUE, 0, 0);
glEnableVertexAttribArray(attrib);
/* Texture buffer data */
glBindBuffer(GL_ARRAY_BUFFER, xwl_screen->blit_vbos[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texture_buffer_data), texture_buffer_data, GL_STATIC_DRAW);
attrib = glGetAttribLocation(xwl_screen->blit_prog, "textureCoord");
glVertexAttribPointer(attrib, 2, GL_FLOAT, GL_TRUE, 0, 0);
glEnableVertexAttribArray(attrib);
/* Save the location of uniforms we'll set later */
xwl_screen->blit_is_rgba_pos =
glGetUniformLocation(xwl_screen->blit_prog, "is_rgba");
xwl_screen->texture_pos =
glGetUniformLocation(xwl_screen->blit_prog, "tex");
}
static PixmapPtr
xwl_glamor_hybris_create_pixmap_for_native_buffer(ScreenPtr screen, EGLClientBuffer buf, int width, int height,
int depth, int format, int stride)
{
PixmapPtr pixmap;
struct xwl_pixmap *xwl_pixmap;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
GLuint tmp_fbo = 0, tmp_texture = 0;
GLint prev_fbo = 0;
GLenum draw_buffers[1] = {GL_COLOR_ATTACHMENT0};
int status;
/* TODO: make use of this */
const EGLint attrs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE
};
xwl_pixmap = malloc(sizeof *xwl_pixmap);
if (xwl_pixmap == NULL)
return NULL;
pixmap = glamor_create_pixmap(screen,
width,
height,
depth,
GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
if (!pixmap) {
free(xwl_pixmap);
return NULL;
}
xwl_glamor_egl_make_current(xwl_screen);
xwl_pixmap->buf = buf;
xwl_pixmap->buffer = NULL;
xwl_pixmap->stride = stride;
xwl_pixmap->format = format;
xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_HYBRIS,
xwl_pixmap->buf, NULL);
if (xwl_pixmap->image == EGL_NO_IMAGE_KHR)
goto error;
/* Save current GL state */
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
/* Set up receiving texture and temporaries */
glGenTextures(1, &xwl_pixmap->texture);
glGenTextures(1, &tmp_texture);
glGenFramebuffers(1, &tmp_fbo);
/* Use the xwl_pixmap's texture as the receiving end of the render pipeline */
glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture);
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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
/* Bind receiving texture as the FBO's color attachment */
glBindFramebuffer(GL_FRAMEBUFFER, tmp_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, xwl_pixmap->texture, 0);
glDrawBuffers(1, draw_buffers);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
ErrorF("hybris: Framebuffer incomplete 0x%X, not color-converting native buffer\n", status);
goto error;
}
/* Take the opportunity to set up the shader and temporary texture */
glUseProgram(glamor_egl->blit_prog);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tmp_texture);
glBindVertexArray(glamor_egl->blit_vao);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUniform1i(glamor_egl->texture_pos, 0);
glUniform1i(glamor_egl->blit_is_rgba_pos, depth >= 32);
/* Dump the EGLImage onto texture */
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
if ((status = eglGetError()) != EGL_SUCCESS) {
ErrorF("hybris: Failed to dump EGLImage onto texture, 0x%X\n", status);
goto error;
}
/* And draw */
glDrawArrays(GL_TRIANGLES, 0, 6);
glViewport(0, 0, width, height);
/* Rendering complete, reset state */
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glUseProgram(0);
glDeleteFramebuffers(1, &tmp_fbo);
glDeleteTextures(1, &tmp_texture);
glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture);
/* `set_pixmap_texture()` may fail silently if the FBO creation failed,
* so we check again the texture to be sure it worked.
*/
if (!glamor_get_pixmap_texture(pixmap)) {
ErrorF("hybris: Setting pixmap texture failed\n");
goto error;
}
glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_ONLY);
xwl_pixmap_set_private(pixmap, xwl_pixmap);
return pixmap;
error:
glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
if (tmp_fbo != 0)
glDeleteFramebuffers(1, &tmp_fbo);
if (tmp_texture != 0)
glDeleteTextures(1, &tmp_texture);
if (xwl_pixmap->image != EGL_NO_IMAGE_KHR)
eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
if (pixmap)
glamor_destroy_pixmap(pixmap);
free(xwl_pixmap);
return NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment