diff --git a/example/rotation.c b/example/rotation.c index 361cfb8c7..656196e06 100644 --- a/example/rotation.c +++ b/example/rotation.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ struct state { struct wl_list config; struct gl { - GLuint prog; + struct wlr_shader *shader; GLuint vao; GLuint vbo; GLuint ebo; @@ -65,53 +66,14 @@ struct output_config { struct wl_list link; }; -static GLuint create_shader(GLenum type, const GLchar *src, GLint len) { - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &src, &len); - glCompileShader(shader); - - GLint success; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - - if (success == GL_FALSE) { - GLint loglen; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &loglen); - - GLchar msg[loglen]; - glGetShaderInfoLog(shader, loglen, &loglen, msg); - - fprintf(stderr, "Failed to create shader: %s\n", msg); - exit(1); - } - - return shader; -} - static void init_gl(struct gl *gl) { - GLuint vert = create_shader(GL_VERTEX_SHADER, vert_src, strlen(vert_src)); - GLuint frag = create_shader(GL_FRAGMENT_SHADER, frag_src, strlen(frag_src)); - - gl->prog = glCreateProgram(); - glAttachShader(gl->prog, vert); - glAttachShader(gl->prog, frag); - glLinkProgram(gl->prog); - - GLint success; - glGetProgramiv(gl->prog, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) { - GLint len; - glGetProgramiv(gl->prog, GL_INFO_LOG_LENGTH, &len); - - GLchar msg[len]; - glGetProgramInfoLog(gl->prog, len, &len, msg); - - fprintf(stderr, "Failed to link program: %s\n", msg); + gl->shader = wlr_shader_init(vert_src); + if (!gl->shader) { + exit(1); + } + if (!wlr_shader_add_format(gl->shader, WL_SHM_FORMAT_RGB332, frag_src)) { exit(1); } - - glDeleteProgram(vert); - glDeleteProgram(frag); GLfloat verticies[] = { 1, 1, 1, 1, // bottom right @@ -147,7 +109,7 @@ static void init_gl(struct gl *gl) { } static void cleanup_gl(struct gl *gl) { - glDeleteProgram(gl->prog); + wlr_shader_destroy(gl->shader); glDeleteVertexArrays(1, &gl->vao); glDeleteBuffers(1, &gl->vbo); glDeleteTextures(1, &gl->tex); @@ -166,7 +128,7 @@ static void output_frame(struct wl_listener *listener, void *data) { glViewport(0, 0, width, height); wlr_output_effective_resolution(output, &width, &height); - glUseProgram(s->gl.prog); + wlr_shader_use(s->gl.shader, WL_SHM_FORMAT_RGB332); glBindVertexArray(s->gl.vao); glBindBuffer(GL_ARRAY_BUFFER, s->gl.vbo); diff --git a/include/render.h b/include/render.h new file mode 100644 index 000000000..fd1ea0249 --- /dev/null +++ b/include/render.h @@ -0,0 +1,28 @@ +#ifndef _WLR_RENDER_INTERNAL_H +#define _WLR_RENDER_INTERNAL_H +#include +#include +#include +#include +#include + +struct wlr_texture { + GLuint tex_id; + uint32_t format; + int width, height; +}; + +struct wlr_shader { + bool valid; + uint32_t format; + GLuint vert; + GLuint program; + struct wl_list link; +}; + +struct wlr_renderer { + struct wlr_shader *shader; + // TODO: EGL stuff +}; + +#endif diff --git a/include/wlr/render.h b/include/wlr/render.h new file mode 100644 index 000000000..d3abfcc3e --- /dev/null +++ b/include/wlr/render.h @@ -0,0 +1,29 @@ +#ifndef _WLR_RENDER_H +#define _WLR_RENDER_H +#include +#include + +struct wlr_surface; +struct wlr_surface *wlr_surface_create(); +void wlr_surface_attach_pixels(struct wlr_surface *tex, uint32_t format, + int width, int height, const unsigned char *pixels); +void wlr_surface_attach_shm(struct wlr_surface *tex, uint32_t format, + struct wl_shm_buffer *shm); +// TODO: EGL +void wlr_surface_destroy(struct wlr_surface *tex); + +struct wlr_shader; +struct wlr_shader *wlr_shader_init(const char *vertex); +bool wlr_shader_add_format(struct wlr_shader *shader, uint32_t format, + const char *frag); +bool wlr_shader_use(struct wlr_shader *shader, uint32_t format); +void wlr_shader_destroy(struct wlr_shader *shader); + +struct wlr_renderer; +struct wlr_renderer *wlr_renderer_init(); +void wlr_renderer_set_shader(struct wlr_renderer *renderer, + struct wlr_shader *shader); +bool wlr_render_quad(struct wlr_renderer *renderer, struct wlr_surface *tex, + float x, float y, float width, float height); + +#endif diff --git a/render/CMakeLists.txt b/render/CMakeLists.txt index 16d9e8d24..597077ed7 100644 --- a/render/CMakeLists.txt +++ b/render/CMakeLists.txt @@ -1,3 +1,4 @@ add_library(wlr-render STATIC matrix.c + shader.c ) diff --git a/render/shader.c b/render/shader.c new file mode 100644 index 000000000..d7c106143 --- /dev/null +++ b/render/shader.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "render.h" + +static bool create_shader(GLenum type, const GLchar *src, GLint len, GLuint *shader) { + *shader = glCreateShader(type); + glShaderSource(*shader, 1, &src, &len); + glCompileShader(*shader); + + GLint success; + glGetShaderiv(*shader, GL_COMPILE_STATUS, &success); + + if (success == GL_FALSE) { + GLint loglen; + glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &loglen); + + GLchar msg[loglen]; + glGetShaderInfoLog(*shader, loglen, &loglen, msg); + return false; + } + return true; +} + +struct wlr_shader *wlr_shader_init(const char *vertex) { + struct wlr_shader *shader = calloc(sizeof(struct wlr_shader), 1); + if (!create_shader(GL_VERTEX_SHADER, vertex, strlen(vertex), &shader->vert)) { + wlr_shader_destroy(shader); + return NULL; + } + return shader; +} + +bool wlr_shader_add_format(struct wlr_shader *shader, uint32_t format, + const char *frag) { + assert(shader); + struct wlr_shader *_shader = shader; + if (_shader->valid) { + shader = calloc(sizeof(struct wlr_shader), 1); + shader->vert = _shader->vert; + } + shader->format = format; + GLuint _frag; + if (!create_shader(GL_FRAGMENT_SHADER, frag, strlen(frag), &_frag)) { + goto error; + } + shader->program = glCreateProgram(); + glAttachShader(shader->program, shader->vert); + glAttachShader(shader->program, _frag); + glLinkProgram(shader->program); + glDeleteProgram(_frag); + if (!_shader->valid) { + _shader->valid = true; + } else { + wl_list_insert(&_shader->link, &shader->link); + } + return true; +error: + if (_shader->valid) { + wlr_shader_destroy(shader); + } + return false; +} + +bool wlr_shader_use(struct wlr_shader *shader, uint32_t format) { + struct wlr_shader *s = shader; + if (s->format == format) { + glUseProgram(s->program); + return true; + } + if (shader->link.next) { + wl_list_for_each(s, &shader->link, link) { + if (s->format == format) { + glUseProgram(s->program); + return true; + } + } + } + return false; +} + +void wlr_shader_destroy(struct wlr_shader *shader) { + if (!shader) { + return; + } + glDeleteProgram(shader->vert); + glDeleteProgram(shader->program); + if (shader->link.next) { + struct wlr_shader *next = wl_container_of(shader->link.next, + next, link); + wlr_shader_destroy(next); + } + free(shader); +}