summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-02-10 08:32:01 -0800
committer3gg <3gg@shellblade.net>2023-02-10 08:32:01 -0800
commit8f0726b6343073f3a3677cadd217736f96e0d4dd (patch)
treebb6b9b71f0184f52281d1efc9f7f1d25c2e686c3
parenta8ba7e5e9c98890a13c0eb6868acf97f6fffaac3 (diff)
Add shader and shader program caches.
-rw-r--r--gfx/src/render/render_backend.c115
-rw-r--r--gfx/src/render/render_backend_impl.h21
2 files changed, 133 insertions, 3 deletions
diff --git a/gfx/src/render/render_backend.c b/gfx/src/render/render_backend.c
index fed906b..0fc8c85 100644
--- a/gfx/src/render/render_backend.c
+++ b/gfx/src/render/render_backend.c
@@ -3,12 +3,13 @@
3#include "gl_util.h" 3#include "gl_util.h"
4 4
5#include <GL/gl.h> 5#include <GL/gl.h>
6#include <log/log.h> 6// #include <log/log.h>
7 7
8#include <assert.h> 8#include <assert.h>
9 9
10void gfx_init_render_backend(RenderBackend* render_backend) { 10void gfx_init_render_backend(RenderBackend* render_backend) {
11 assert(render_backend); 11 assert(render_backend);
12
12 mempool_make(&render_backend->buffers); 13 mempool_make(&render_backend->buffers);
13 mempool_make(&render_backend->framebuffers); 14 mempool_make(&render_backend->framebuffers);
14 mempool_make(&render_backend->geometries); 15 mempool_make(&render_backend->geometries);
@@ -17,6 +18,9 @@ void gfx_init_render_backend(RenderBackend* render_backend) {
17 mempool_make(&render_backend->shader_programs); 18 mempool_make(&render_backend->shader_programs);
18 mempool_make(&render_backend->textures); 19 mempool_make(&render_backend->textures);
19 20
21 mempool_make(&render_backend->shader_cache);
22 mempool_make(&render_backend->program_cache);
23
20 glEnable(GL_CULL_FACE); 24 glEnable(GL_CULL_FACE);
21 glFrontFace(GL_CCW); 25 glFrontFace(GL_CCW);
22 glCullFace(GL_BACK); 26 glCullFace(GL_BACK);
@@ -259,10 +263,83 @@ void gfx_destroy_framebuffer(
259// Shaders. 263// Shaders.
260// ----------------------------------------------------------------------------- 264// -----------------------------------------------------------------------------
261 265
266static uint64_t hash_shader_desc(const ShaderDesc* desc) {
267 assert(desc);
268 // Note that defines may affect shader permutations, so we need to hash those
269 // as well.
270 uint64_t hash = 0;
271 for (size_t i = 0; i < desc->num_defines; ++i) {
272 const ShaderCompilerDefine* define = &desc->defines[i];
273 hash = (((hash << 13) + sstring_hash(define->name)) << 7) +
274 sstring_hash(define->value);
275 }
276 return (hash << 17) + cstring_hash(desc->code);
277}
278
279static uint64_t hash_program_desc(const ShaderProgramDesc* desc) {
280 assert(desc);
281 return ((uint64_t)desc->vertex_shader->id << 32) |
282 (uint64_t)desc->fragment_shader->id;
283}
284
285static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) {
286 assert(cache);
287 mempool_foreach(cache, entry, {
288 if (entry->hash == hash) {
289 return entry->shader;
290 }
291 });
292 return 0;
293}
294
295static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) {
296 assert(cache);
297 mempool_foreach(cache, entry, {
298 if (entry->hash == hash) {
299 return entry->program;
300 }
301 });
302 return 0;
303}
304
305static ShaderCacheEntry* find_shader_cache_entry(
306 ShaderCache* cache, const Shader* shader) {
307 assert(cache);
308 assert(shader);
309 mempool_foreach(cache, entry, {
310 if (entry->shader == shader) {
311 return entry;
312 }
313 });
314 return 0;
315}
316
317static ShaderProgramCacheEntry* find_program_cache_entry(
318 ProgramCache* cache, const ShaderProgram* prog) {
319 assert(cache);
320 assert(prog);
321 mempool_foreach(cache, entry, {
322 if (entry->program == prog) {
323 return entry;
324 }
325 });
326 return 0;
327}
328
262Shader* gfx_make_shader(RenderBackend* render_backend, const ShaderDesc* desc) { 329Shader* gfx_make_shader(RenderBackend* render_backend, const ShaderDesc* desc) {
263 assert(render_backend); 330 assert(render_backend);
264 assert(desc); 331 assert(desc);
265 Shader* shader = mempool_alloc(&render_backend->shaders); 332
333 // Check the shader cache first.
334 ShaderCache* cache = &render_backend->shader_cache;
335 const uint64_t hash = hash_shader_desc(desc);
336 Shader* shader = find_cached_shader(cache, hash);
337 if (shader) {
338 // LOGD("Found cached shader with hash %lx", hash);
339 return shader;
340 }
341
342 shader = mempool_alloc(&render_backend->shaders);
266 if (!shader) { 343 if (!shader) {
267 return 0; 344 return 0;
268 } 345 }
@@ -270,6 +347,10 @@ Shader* gfx_make_shader(RenderBackend* render_backend, const ShaderDesc* desc) {
270 mempool_free(&render_backend->shaders, &shader); 347 mempool_free(&render_backend->shaders, &shader);
271 return 0; 348 return 0;
272 } 349 }
350 ShaderCacheEntry* entry = mempool_alloc(cache);
351 assert(entry);
352 *entry = (ShaderCacheEntry){.hash = hash, .shader = shader};
353 // LOGD("Added shader with hash %lx to cache", hash);
273 return shader; 354 return shader;
274} 355}
275 356
@@ -277,6 +358,13 @@ void gfx_destroy_shader(RenderBackend* render_backend, Shader** shader) {
277 assert(render_backend); 358 assert(render_backend);
278 assert(shader); 359 assert(shader);
279 assert(*shader); 360 assert(*shader);
361
362 // Remove the shader from the cache.
363 ShaderCache* cache = &render_backend->shader_cache;
364 ShaderCacheEntry* entry = find_shader_cache_entry(cache, *shader);
365 assert(entry); // Must be there, shaders can't go untracked.
366 mempool_free(cache, &entry);
367
280 gfx_del_shader(*shader); 368 gfx_del_shader(*shader);
281 mempool_free(&render_backend->shaders, shader); 369 mempool_free(&render_backend->shaders, shader);
282} 370}
@@ -285,7 +373,17 @@ ShaderProgram* gfx_make_shader_program(
285 RenderBackend* render_backend, const ShaderProgramDesc* desc) { 373 RenderBackend* render_backend, const ShaderProgramDesc* desc) {
286 assert(render_backend); 374 assert(render_backend);
287 assert(desc); 375 assert(desc);
288 ShaderProgram* prog = mempool_alloc(&render_backend->shader_programs); 376
377 // Check the shader program cache first.
378 ProgramCache* cache = &render_backend->program_cache;
379 const uint64_t hash = hash_program_desc(desc);
380 ShaderProgram* prog = find_cached_program(cache, hash);
381 if (prog) {
382 // LOGD("Found cached shader program with hash %lx", hash);
383 return prog;
384 }
385
386 prog = mempool_alloc(&render_backend->shader_programs);
289 if (!prog) { 387 if (!prog) {
290 return 0; 388 return 0;
291 } 389 }
@@ -293,6 +391,10 @@ ShaderProgram* gfx_make_shader_program(
293 mempool_free(&render_backend->shader_programs, &prog); 391 mempool_free(&render_backend->shader_programs, &prog);
294 return 0; 392 return 0;
295 } 393 }
394 ShaderProgramCacheEntry* entry = mempool_alloc(cache);
395 assert(entry);
396 *entry = (ShaderProgramCacheEntry){.hash = hash, .program = prog};
397 // LOGD("Added shader program with hash %lx to cache", hash);
296 return prog; 398 return prog;
297} 399}
298 400
@@ -301,6 +403,13 @@ void gfx_destroy_shader_program(
301 assert(render_backend); 403 assert(render_backend);
302 assert(prog); 404 assert(prog);
303 assert(*prog); 405 assert(*prog);
406
407 // Remove the shader program from the cache.
408 ProgramCache* cache = &render_backend->program_cache;
409 ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog);
410 assert(entry); // Must be there, shaders can't go untracked.
411 mempool_free(cache, &entry);
412
304 gfx_del_shader_program(*prog); 413 gfx_del_shader_program(*prog);
305 mempool_free(&render_backend->shader_programs, prog); 414 mempool_free(&render_backend->shader_programs, prog);
306} 415}
diff --git a/gfx/src/render/render_backend_impl.h b/gfx/src/render/render_backend_impl.h
index 9e552c2..e149e98 100644
--- a/gfx/src/render/render_backend_impl.h
+++ b/gfx/src/render/render_backend_impl.h
@@ -13,6 +13,21 @@
13 13
14#include <mempool.h> 14#include <mempool.h>
15 15
16#include <stdint.h>
17
18// TODO: Make a generic (hash, void*) structure and define functions over it.
19// Then define a macro that defines type-safe macros given the type of the
20// entry.
21typedef struct ShaderCacheEntry {
22 uint64_t hash;
23 Shader* shader;
24} ShaderCacheEntry;
25
26typedef struct ShaderProgramCacheEntry {
27 uint64_t hash;
28 ShaderProgram* program;
29} ShaderProgramCacheEntry;
30
16DEF_MEMPOOL(buffer_pool, Buffer, GFX_MAX_NUM_BUFFERS) 31DEF_MEMPOOL(buffer_pool, Buffer, GFX_MAX_NUM_BUFFERS)
17DEF_MEMPOOL(framebuffer_pool, FrameBuffer, GFX_MAX_NUM_FRAMEBUFFERS) 32DEF_MEMPOOL(framebuffer_pool, FrameBuffer, GFX_MAX_NUM_FRAMEBUFFERS)
18DEF_MEMPOOL(geometry_pool, Geometry, GFX_MAX_NUM_GEOMETRIES) 33DEF_MEMPOOL(geometry_pool, Geometry, GFX_MAX_NUM_GEOMETRIES)
@@ -21,6 +36,9 @@ DEF_MEMPOOL(shader_pool, Shader, GFX_MAX_NUM_SHADERS)
21DEF_MEMPOOL(shader_program_pool, ShaderProgram, GFX_MAX_NUM_SHADER_PROGRAMS) 36DEF_MEMPOOL(shader_program_pool, ShaderProgram, GFX_MAX_NUM_SHADER_PROGRAMS)
22DEF_MEMPOOL(texture_pool, Texture, GFX_MAX_NUM_TEXTURES) 37DEF_MEMPOOL(texture_pool, Texture, GFX_MAX_NUM_TEXTURES)
23 38
39DEF_MEMPOOL(ShaderCache, ShaderCacheEntry, GFX_MAX_NUM_SHADERS)
40DEF_MEMPOOL(ProgramCache, ShaderProgramCacheEntry, GFX_MAX_NUM_SHADER_PROGRAMS)
41
24typedef struct { 42typedef struct {
25 int width; 43 int width;
26 int height; 44 int height;
@@ -36,6 +54,9 @@ typedef struct RenderBackend {
36 shader_pool shaders; 54 shader_pool shaders;
37 shader_program_pool shader_programs; 55 shader_program_pool shader_programs;
38 texture_pool textures; 56 texture_pool textures;
57 // Caches.
58 ShaderCache shader_cache;
59 ProgramCache program_cache;
39} RenderBackend; 60} RenderBackend;
40 61
41/// Create a new render backend. 62/// Create a new render backend.