From bcdddec36c08531adc487aa448a7fb15e8702155 Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Thu, 13 Apr 2017 23:37:10 -0400 Subject: [PATCH] added framebuffer objects to render_backend added rb_sync / rb_wait rename vertex2d / surface2d to vertex2 / surface2 --- src/ui/microprofile.cc | 78 ++++++++--------- src/ui/nuklear.c | 21 +++-- src/ui/nuklear.h | 2 +- src/video/gl_backend.c | 167 ++++++++++++++++++++++++++++++------- src/video/render_backend.h | 29 +++++-- 5 files changed, 208 insertions(+), 89 deletions(-) diff --git a/src/ui/microprofile.cc b/src/ui/microprofile.cc index 02bde01e..ef86af7c 100644 --- a/src/ui/microprofile.cc +++ b/src/ui/microprofile.cc @@ -29,9 +29,9 @@ struct microprofile { struct render_backend *rb; struct window_listener listener; texture_handle_t font_texture; - struct surface2d surfs[MAX_2D_SURFACES]; + struct surface2 surfs[MAX_2D_SURFACES]; int num_surfs; - struct vertex2d verts[MAX_2D_VERTICES]; + struct vertex2 verts[MAX_2D_VERTICES]; int num_verts; }; @@ -65,16 +65,15 @@ static void mp_mousemove(void *data, int x, int y) { MicroProfileMousePosition(x, y, 0); } -static struct vertex2d *mp_alloc_verts(struct microprofile *mp, - const struct surface2d &desc, - int count) { +static struct vertex2 *mp_alloc_verts(struct microprofile *mp, + const struct surface2 &desc, int count) { CHECK(mp->num_verts + count <= MAX_2D_VERTICES); uint32_t first_vert = mp->num_verts; mp->num_verts += count; /* try to batch with the last surface if possible */ if (mp->num_surfs) { - struct surface2d &last_surf = mp->surfs[mp->num_surfs - 1]; + struct surface2 &last_surf = mp->surfs[mp->num_surfs - 1]; if (last_surf.prim_type == desc.prim_type && last_surf.texture == desc.texture && @@ -87,7 +86,7 @@ static struct vertex2d *mp_alloc_verts(struct microprofile *mp, /* else, allocate a new surface */ CHECK(mp->num_surfs < MAX_2D_SURFACES); - struct surface2d &next_surf = mp->surfs[mp->num_surfs]; + struct surface2 &next_surf = mp->surfs[mp->num_surfs]; next_surf.prim_type = desc.prim_type; next_surf.texture = desc.texture; next_surf.src_blend = desc.src_blend; @@ -106,15 +105,16 @@ static void mp_draw_text(struct microprofile *mp, int x, int y, uint32_t color, float fy2 = fy + (MICROPROFILE_TEXT_HEIGHT + 1); int text_len = static_cast(strlen(text)); - struct vertex2d *vertex = mp_alloc_verts(mp, {PRIM_TRIANGLES, - mp->font_texture, - BLEND_SRC_ALPHA, - BLEND_ONE_MINUS_SRC_ALPHA, - false, - {0.0f, 0.0f, 0.0f, 0.0f}, - 0, - 0}, - 6 * text_len); + struct vertex2 *vertex = mp_alloc_verts(mp, {PRIM_TRIANGLES, + 0, + mp->font_texture, + BLEND_SRC_ALPHA, + BLEND_ONE_MINUS_SRC_ALPHA, + false, + {0.0f, 0.0f, 0.0f, 0.0f}, + 0, + 0}, + 6 * text_len); for (int i = 0; i < text_len; i++) { float fx2 = fx + MICROPROFILE_TEXT_WIDTH; @@ -154,15 +154,16 @@ static void mp_draw_text(struct microprofile *mp, int x, int y, uint32_t color, static void mp_draw_box(struct microprofile *mp, int x0, int y0, int x1, int y1, uint32_t color, enum box_type type) { - struct vertex2d *vertex = mp_alloc_verts(mp, {PRIM_TRIANGLES, - 0, - BLEND_SRC_ALPHA, - BLEND_ONE_MINUS_SRC_ALPHA, - false, - {0.0f, 0.0f, 0.0f, 0.0f}, - 0, - 0}, - 6); + struct vertex2 *vertex = mp_alloc_verts(mp, {PRIM_TRIANGLES, + 0, + 0, + BLEND_SRC_ALPHA, + BLEND_ONE_MINUS_SRC_ALPHA, + false, + {0.0f, 0.0f, 0.0f, 0.0f}, + 0, + 0}, + 6); if (type == BOX_FLAT) { Q0(vertex, xy[0], (float)x0); @@ -213,15 +214,16 @@ static void mp_draw_line(struct microprofile *mp, float *verts, int num_verts, uint32_t color) { CHECK(num_verts); - struct vertex2d *vertex = mp_alloc_verts(mp, {PRIM_LINES, - 0, - BLEND_SRC_ALPHA, - BLEND_ONE_MINUS_SRC_ALPHA, - false, - {0.0f, 0.0f, 0.0f, 0.0f}, - 0, - 0}, - 2 * (num_verts - 1)); + struct vertex2 *vertex = mp_alloc_verts(mp, {PRIM_LINES, + 0, + 0, + BLEND_SRC_ALPHA, + BLEND_ONE_MINUS_SRC_ALPHA, + false, + {0.0f, 0.0f, 0.0f, 0.0f}, + 0, + 0}, + 2 * (num_verts - 1)); for (int i = 0; i < num_verts - 1; ++i) { vertex[0].xy[0] = verts[i * 2]; @@ -242,14 +244,14 @@ void mp_end_frame(struct microprofile *mp) { /* render the surfaces */ rb_begin_ortho(mp->rb); - rb_begin_surfaces2d(mp->rb, mp->verts, mp->num_verts, nullptr, 0); + rb_begin_surfaces2(mp->rb, mp->verts, mp->num_verts, nullptr, 0); for (int i = 0; i < mp->num_surfs; i++) { - struct surface2d *surf = &mp->surfs[i]; - rb_draw_surface2d(mp->rb, surf); + struct surface2 *surf = &mp->surfs[i]; + rb_draw_surface2(mp->rb, surf); } - rb_end_surfaces2d(mp->rb); + rb_end_surfaces2(mp->rb); rb_end_ortho(mp->rb); /* reset surfaces */ diff --git a/src/ui/nuklear.c b/src/ui/nuklear.c index 8010e01d..93522ae2 100644 --- a/src/ui/nuklear.c +++ b/src/ui/nuklear.c @@ -53,10 +53,9 @@ static void nk_mousemove(void *data, int x, int y) { void nk_end_frame(struct nuklear *nk) { /* convert draw list into vertex / element buffers */ static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct vertex2d, xy)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct vertex2d, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, - NK_OFFSETOF(struct vertex2d, color)}, + {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct vertex2, xy)}, + {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct vertex2, uv)}, + {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct vertex2, color)}, {NK_VERTEX_LAYOUT_END}}; struct nk_buffer vbuf, ebuf; @@ -65,8 +64,8 @@ void nk_end_frame(struct nuklear *nk) { struct nk_convert_config config = {0}; config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct vertex2d); - config.vertex_alignment = NK_ALIGNOF(struct vertex2d); + config.vertex_size = sizeof(struct vertex2); + config.vertex_alignment = NK_ALIGNOF(struct vertex2); config.null = nk->null; config.global_alpha = 1.0f; config.shape_AA = NK_ANTI_ALIASING_OFF; @@ -76,14 +75,14 @@ void nk_end_frame(struct nuklear *nk) { /* bind buffers */ rb_begin_ortho(nk->rb); - rb_begin_surfaces2d(nk->rb, nk->vertices, nk->ctx.draw_list.vertex_count, - nk->elements, nk->ctx.draw_list.element_count); + rb_begin_surfaces2(nk->rb, nk->vertices, nk->ctx.draw_list.vertex_count, + nk->elements, nk->ctx.draw_list.element_count); /* pass each draw command off to the render backend */ const struct nk_draw_command *cmd = NULL; int offset = 0; - struct surface2d surf = {0}; + struct surface2 surf = {0}; surf.prim_type = PRIM_TRIANGLES; surf.src_blend = BLEND_SRC_ALPHA; surf.dst_blend = BLEND_ONE_MINUS_SRC_ALPHA; @@ -103,13 +102,13 @@ void nk_end_frame(struct nuklear *nk) { surf.first_vert = offset; surf.num_verts = cmd->elem_count; - rb_draw_surface2d(nk->rb, &surf); + rb_draw_surface2(nk->rb, &surf); offset += cmd->elem_count; } nk_clear(&nk->ctx); - rb_end_surfaces2d(nk->rb); + rb_end_surfaces2(nk->rb); rb_end_ortho(nk->rb); /* reset mouse wheel state as it won't be reset through any event */ diff --git a/src/ui/nuklear.h b/src/ui/nuklear.h index 02e8565b..f0e74e27 100644 --- a/src/ui/nuklear.h +++ b/src/ui/nuklear.h @@ -30,7 +30,7 @@ struct nuklear { texture_handle_t font_texture; /* render buffers */ - struct vertex2d vertices[NK_MAX_VERTICES]; + struct vertex2 vertices[NK_MAX_VERTICES]; uint16_t elements[NK_MAX_ELEMENTS]; /* input state */ diff --git a/src/video/gl_backend.c b/src/video/gl_backend.c index 3e867b26..18613e7e 100644 --- a/src/video/gl_backend.c +++ b/src/video/gl_backend.c @@ -8,6 +8,7 @@ #include "ui/window.h" #include "video/render_backend.h" +#define MAX_FRAMEBUFFERS 8 #define MAX_TEXTURES 8192 enum texture_map { @@ -39,7 +40,6 @@ enum shader_attr { ATTR_OFFSET_COLOR = 0x20, ATTR_PT_ALPHA_TEST = 0x40, ATTR_COUNT = 0x80 - }; struct shader_program { @@ -50,6 +50,16 @@ struct shader_program { uint64_t uniform_token; }; +struct framebuffer { + GLuint fbo; + GLuint color_component; + GLuint depth_component; +}; + +struct texture { + GLuint texture; +}; + struct render_backend { struct window *window; @@ -57,8 +67,9 @@ struct render_backend { int debug_wireframe; /* resources */ - GLuint textures[MAX_TEXTURES]; - GLuint white_tex; + struct framebuffer framebuffers[MAX_FRAMEBUFFERS]; + struct texture textures[MAX_TEXTURES]; + struct texture white; struct shader_program ta_programs[ATTR_COUNT]; struct shader_program ui_program; @@ -355,13 +366,16 @@ static void rb_destroy_textures(struct render_backend *rb) { return; } - glDeleteTextures(1, &rb->white_tex); + glDeleteTextures(1, &rb->white.texture); for (int i = 1; i < MAX_TEXTURES; i++) { - if (!rb->textures[i]) { + struct texture *tex = &rb->textures[i]; + + if (!tex->texture) { continue; } - glDeleteTextures(1, &rb->textures[i]); + + glDeleteTextures(1, &tex->texture); } } @@ -369,8 +383,8 @@ static void rb_create_textures(struct render_backend *rb) { uint8_t pixels[64 * 64 * 4]; memset(pixels, 0xff, sizeof(pixels)); - glGenTextures(1, &rb->white_tex); - glBindTexture(GL_TEXTURE_2D, rb->white_tex); + glGenTextures(1, &rb->white.texture); + glBindTexture(GL_TEXTURE_2D, rb->white.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_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, @@ -470,19 +484,19 @@ static void rb_create_vertex_buffers(struct render_backend *rb) { /* xy */ glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex2d), - (void *)offsetof(struct vertex2d, xy)); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex2), + (void *)offsetof(struct vertex2, xy)); /* texcoord */ glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex2d), - (void *)offsetof(struct vertex2d, uv)); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex2), + (void *)offsetof(struct vertex2, uv)); /* color */ glEnableVertexAttribArray(2); glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, - sizeof(struct vertex2d), - (void *)offsetof(struct vertex2d, color)); + sizeof(struct vertex2), + (void *)offsetof(struct vertex2, color)); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -578,7 +592,8 @@ void rb_draw_surface(struct render_backend *rb, const struct surface *surf) { } if (surf->texture) { - rb_bind_texture(rb, MAP_DIFFUSE, rb->textures[surf->texture]); + struct texture *tex = &rb->textures[surf->texture]; + rb_bind_texture(rb, MAP_DIFFUSE, tex->texture); } glDrawArrays(GL_TRIANGLE_STRIP, surf->first_vert, surf->num_verts); @@ -601,10 +616,9 @@ void rb_begin_surfaces(struct render_backend *rb, const float *projection, } } -void rb_end_surfaces2d(struct render_backend *rb) {} +void rb_end_surfaces2(struct render_backend *rb) {} -void rb_draw_surface2d(struct render_backend *rb, - const struct surface2d *surf) { +void rb_draw_surface2(struct render_backend *rb, const struct surface2 *surf) { if (surf->scissor) { rb_set_scissor_test(rb, 1); rb_set_scissor_clip(rb, (int)surf->scissor_rect[0], @@ -615,8 +629,16 @@ void rb_draw_surface2d(struct render_backend *rb, } rb_set_blend_func(rb, surf->src_blend, surf->dst_blend); - rb_bind_texture(rb, MAP_DIFFUSE, - surf->texture ? rb->textures[surf->texture] : rb->white_tex); + + if (surf->framebuffer) { + struct framebuffer *fb = &rb->framebuffers[surf->framebuffer]; + rb_bind_texture(rb, MAP_DIFFUSE, fb->color_component); + } else if (surf->texture) { + struct texture *tex = &rb->textures[surf->texture]; + rb_bind_texture(rb, MAP_DIFFUSE, tex->texture); + } else { + rb_bind_texture(rb, MAP_DIFFUSE, rb->white.texture); + } if (rb->ui_use_ibo) { glDrawElements(prim_types[surf->prim_type], surf->num_verts, @@ -628,11 +650,10 @@ void rb_draw_surface2d(struct render_backend *rb, } } -void rb_begin_surfaces2d(struct render_backend *rb, - const struct vertex2d *verts, int num_verts, - uint16_t *indices, int num_indices) { +void rb_begin_surfaces2(struct render_backend *rb, const struct vertex2 *verts, + int num_verts, uint16_t *indices, int num_indices) { glBindBuffer(GL_ARRAY_BUFFER, rb->ui_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(struct vertex2d) * num_verts, verts, + glBufferData(GL_ARRAY_BUFFER, sizeof(struct vertex2) * num_verts, verts, GL_DYNAMIC_DRAW); if (indices) { @@ -690,15 +711,29 @@ void rb_begin_frame(struct render_backend *rb) { rb_set_depth_mask(rb, 1); glViewport(0, 0, rb->window->width, rb->window->height); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +void rb_wait(sync_handle_t on) { + GLsync sync = on; + CHECK(glIsSync(sync)); + + GLenum res = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, UINT64_MAX); + CHECK(res == GL_ALREADY_SIGNALED || res == GL_CONDITION_SATISFIED); + glDeleteSync(sync); +} + +sync_handle_t rb_sync(struct render_backend *rb) { + GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + return sync; +} + void rb_destroy_texture(struct render_backend *rb, texture_handle_t handle) { - GLuint *gltex = &rb->textures[handle]; - glDeleteTextures(1, gltex); - *gltex = 0; + struct texture *tex = &rb->textures[handle]; + glDeleteTextures(1, &tex->texture); + tex->texture = 0; } texture_handle_t rb_create_texture(struct render_backend *rb, @@ -710,7 +745,8 @@ texture_handle_t rb_create_texture(struct render_backend *rb, /* find next open texture handle */ texture_handle_t handle; for (handle = 1; handle < MAX_TEXTURES; handle++) { - if (!rb->textures[handle]) { + struct texture *tex = &rb->textures[handle]; + if (!tex->texture) { break; } } @@ -744,9 +780,9 @@ texture_handle_t rb_create_texture(struct render_backend *rb, break; } - GLuint *gltex = &rb->textures[handle]; - glGenTextures(1, gltex); - glBindTexture(GL_TEXTURE_2D, *gltex); + struct texture *tex = &rb->textures[handle]; + glGenTextures(1, &tex->texture); + glBindTexture(GL_TEXTURE_2D, tex->texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_funcs[mipmaps * NUM_FILTER_MODES + filter]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_funcs[filter]); @@ -764,6 +800,73 @@ texture_handle_t rb_create_texture(struct render_backend *rb, return handle; } +void rb_destroy_framebuffer(struct render_backend *rb, + framebuffer_handle_t handle) { + struct framebuffer *fb = &rb->framebuffers[handle]; + + glDeleteTextures(1, &fb->color_component); + fb->color_component = 0; + + glDeleteRenderbuffers(1, &fb->depth_component); + fb->depth_component = 0; + + glDeleteFramebuffers(1, &fb->fbo); + fb->fbo = 0; +} + +void rb_bind_framebuffer(struct render_backend *rb, + framebuffer_handle_t handle) { + struct framebuffer *fb = &rb->framebuffers[handle]; + + glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo); +} + +framebuffer_handle_t rb_create_framebuffer(struct render_backend *rb) { + /* find next open framebuffer handle */ + framebuffer_handle_t handle; + for (handle = 1; handle < MAX_FRAMEBUFFERS; handle++) { + struct framebuffer *fb = &rb->framebuffers[handle]; + if (!fb->fbo) { + break; + } + } + CHECK_LT(handle, MAX_FRAMEBUFFERS); + + struct framebuffer *fb = &rb->framebuffers[handle]; + + /* create color component */ + glGenTextures(1, &fb->color_component); + glBindTexture(GL_TEXTURE_2D, fb->color_component); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rb->window->width, rb->window->height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); + + /* create depth component */ + glGenRenderbuffers(1, &fb->depth_component); + glBindRenderbuffer(GL_RENDERBUFFER, fb->depth_component); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, rb->window->width, + rb->window->height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + /* create fbo */ + glGenFramebuffers(1, &fb->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + fb->color_component, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, fb->depth_component); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + CHECK_EQ(status, GL_FRAMEBUFFER_COMPLETE); + + /* switch back to default framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return handle; +} + void rb_destroy(struct render_backend *rb) { rb_destroy_vertex_buffers(rb); rb_destroy_shaders(rb); diff --git a/src/video/render_backend.h b/src/video/render_backend.h index 018f3be3..b4bf080b 100644 --- a/src/video/render_backend.h +++ b/src/video/render_backend.h @@ -5,7 +5,9 @@ struct window; +typedef int framebuffer_handle_t; typedef int texture_handle_t; +typedef void *sync_handle_t; enum pxl_format { PXL_INVALID, @@ -103,19 +105,24 @@ struct surface { int num_verts; }; -struct vertex2d { +struct vertex2 { float xy[2]; float uv[2]; uint32_t color; }; -struct surface2d { +struct surface2 { enum prim_type prim_type; + + framebuffer_handle_t framebuffer; texture_handle_t texture; + enum blend_func src_blend; enum blend_func dst_blend; + int scissor; float scissor_rect[4]; + int first_vert; int num_verts; }; @@ -125,6 +132,12 @@ struct render_backend; struct render_backend *rb_create(struct window *window); void rb_destroy(struct render_backend *rb); +framebuffer_handle_t rb_create_framebuffer(struct render_backend *rb); +void rb_bind_framebuffer(struct render_backend *rb, + framebuffer_handle_t handle); +void rb_destroy_framebuffer(struct render_backend *rb, + framebuffer_handle_t handle); + texture_handle_t rb_create_texture(struct render_backend *rb, enum pxl_format format, enum filter_mode filter, @@ -133,6 +146,9 @@ texture_handle_t rb_create_texture(struct render_backend *rb, const uint8_t *buffer); void rb_destroy_texture(struct render_backend *rb, texture_handle_t handle); +sync_handle_t rb_sync(struct render_backend *rb); +void rb_wait(sync_handle_t on); + void rb_begin_frame(struct render_backend *rb); void rb_end_frame(struct render_backend *rb); @@ -144,10 +160,9 @@ void rb_begin_surfaces(struct render_backend *rb, const float *projection, void rb_draw_surface(struct render_backend *rb, const struct surface *surf); void rb_end_surfaces(struct render_backend *rb); -void rb_begin_surfaces2d(struct render_backend *rb, - const struct vertex2d *verts, int num_verts, - uint16_t *indices, int num_indices); -void rb_draw_surface2d(struct render_backend *rb, const struct surface2d *surf); -void rb_end_surfaces2d(struct render_backend *rb); +void rb_begin_surfaces2(struct render_backend *rb, const struct vertex2 *verts, + int num_verts, uint16_t *indices, int num_indices); +void rb_draw_surface2(struct render_backend *rb, const struct surface2 *surf); +void rb_end_surfaces2(struct render_backend *rb); #endif