diff options
| -rw-r--r-- | gfx/src/render/render_backend.c | 115 | ||||
| -rw-r--r-- | gfx/src/render/render_backend_impl.h | 21 |
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 | ||
| 10 | void gfx_init_render_backend(RenderBackend* render_backend) { | 10 | void 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 | ||
| 266 | static 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 | |||
| 279 | static 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 | |||
| 285 | static 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 | |||
| 295 | static 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 | |||
| 305 | static 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 | |||
| 317 | static 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 | |||
| 262 | Shader* gfx_make_shader(RenderBackend* render_backend, const ShaderDesc* desc) { | 329 | Shader* 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. | ||
| 21 | typedef struct ShaderCacheEntry { | ||
| 22 | uint64_t hash; | ||
| 23 | Shader* shader; | ||
| 24 | } ShaderCacheEntry; | ||
| 25 | |||
| 26 | typedef struct ShaderProgramCacheEntry { | ||
| 27 | uint64_t hash; | ||
| 28 | ShaderProgram* program; | ||
| 29 | } ShaderProgramCacheEntry; | ||
| 30 | |||
| 16 | DEF_MEMPOOL(buffer_pool, Buffer, GFX_MAX_NUM_BUFFERS) | 31 | DEF_MEMPOOL(buffer_pool, Buffer, GFX_MAX_NUM_BUFFERS) |
| 17 | DEF_MEMPOOL(framebuffer_pool, FrameBuffer, GFX_MAX_NUM_FRAMEBUFFERS) | 32 | DEF_MEMPOOL(framebuffer_pool, FrameBuffer, GFX_MAX_NUM_FRAMEBUFFERS) |
| 18 | DEF_MEMPOOL(geometry_pool, Geometry, GFX_MAX_NUM_GEOMETRIES) | 33 | DEF_MEMPOOL(geometry_pool, Geometry, GFX_MAX_NUM_GEOMETRIES) |
| @@ -21,6 +36,9 @@ DEF_MEMPOOL(shader_pool, Shader, GFX_MAX_NUM_SHADERS) | |||
| 21 | DEF_MEMPOOL(shader_program_pool, ShaderProgram, GFX_MAX_NUM_SHADER_PROGRAMS) | 36 | DEF_MEMPOOL(shader_program_pool, ShaderProgram, GFX_MAX_NUM_SHADER_PROGRAMS) |
| 22 | DEF_MEMPOOL(texture_pool, Texture, GFX_MAX_NUM_TEXTURES) | 37 | DEF_MEMPOOL(texture_pool, Texture, GFX_MAX_NUM_TEXTURES) |
| 23 | 38 | ||
| 39 | DEF_MEMPOOL(ShaderCache, ShaderCacheEntry, GFX_MAX_NUM_SHADERS) | ||
| 40 | DEF_MEMPOOL(ProgramCache, ShaderProgramCacheEntry, GFX_MAX_NUM_SHADER_PROGRAMS) | ||
| 41 | |||
| 24 | typedef struct { | 42 | typedef 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. |
