summaryrefslogtreecommitdiff
path: root/gfx/src/asset/asset_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/asset/asset_cache.c')
-rw-r--r--gfx/src/asset/asset_cache.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/gfx/src/asset/asset_cache.c b/gfx/src/asset/asset_cache.c
new file mode 100644
index 0000000..0c6a8dc
--- /dev/null
+++ b/gfx/src/asset/asset_cache.c
@@ -0,0 +1,183 @@
1#include "asset_cache.h"
2
3#include <gfx/asset.h>
4#include <gfx/gfx.h>
5#include <gfx/util/scene.h>
6#include <gfx/util/texture.h>
7
8#include <cstring.h>
9#include <log/log.h>
10
11#include <assert.h>
12#include <stddef.h>
13
14static Hash calc_scene_hash(const LoadSceneCmd* cmd) {
15 assert(cmd);
16 switch (cmd->origin) {
17 case AssetFromFile:
18 return cstring_hash(mstring_cstr(&cmd->filepath));
19 case AssetFromMemory:
20 return (Hash)cmd->data;
21 }
22 assert(false);
23 return 0;
24}
25
26static Hash calc_texture_hash(const LoadTextureCmd* cmd) {
27 assert(cmd);
28 switch (cmd->origin) {
29 case AssetFromFile:
30 switch (cmd->type) {
31 case LoadTexture:
32 return cstring_hash(mstring_cstr(&cmd->data.texture.filepath));
33 case LoadCubemap:
34 return cstring_hash(
35 mstring_cstr(&cmd->data.cubemap.filepaths.filepath_pos_x)) ^
36 cstring_hash(
37 mstring_cstr(&cmd->data.cubemap.filepaths.filepath_neg_x)) ^
38 cstring_hash(
39 mstring_cstr(&cmd->data.cubemap.filepaths.filepath_pos_y)) ^
40 cstring_hash(
41 mstring_cstr(&cmd->data.cubemap.filepaths.filepath_neg_y)) ^
42 cstring_hash(
43 mstring_cstr(&cmd->data.cubemap.filepaths.filepath_pos_z)) ^
44 cstring_hash(
45 mstring_cstr(&cmd->data.cubemap.filepaths.filepath_neg_z));
46 }
47 break;
48 case AssetFromMemory:
49 switch (cmd->type) {
50 case LoadTexture:
51 return (Hash)cmd->data.texture.data;
52 case LoadCubemap:
53 return (Hash)cmd->data.cubemap.buffers.data_pos_x ^
54 (Hash)cmd->data.cubemap.buffers.data_neg_x ^
55 (Hash)cmd->data.cubemap.buffers.data_pos_y ^
56 (Hash)cmd->data.cubemap.buffers.data_neg_y ^
57 (Hash)cmd->data.cubemap.buffers.data_pos_z ^
58 (Hash)cmd->data.cubemap.buffers.data_neg_z;
59 }
60 break;
61 }
62 assert(false);
63 return 0;
64}
65
66static Asset* lookup_cache(AssetCache* cache, Hash hash) {
67 assert(cache);
68 mempool_foreach(&cache->assets, asset, {
69 if (asset->hash == hash) {
70 return asset;
71 }
72 });
73 return 0;
74}
75
76// TODO: questionable function. Make mempool_alloc() fail when out of memory.
77static void insert_into_cache(AssetCache* cache, const Asset* asset) {
78 assert(cache);
79 assert(asset);
80 Asset* poolAsset = mempool_alloc(&cache->assets);
81 assert(asset);
82 *poolAsset = *asset;
83}
84
85static void log_scene_cache_hit(const LoadSceneCmd* cmd, Hash hash) {
86 assert(cmd);
87 switch (cmd->origin) {
88 case AssetFromFile:
89 LOGI(
90 "Found asset [%s] in cache with hash [%lu]",
91 mstring_cstr(&cmd->filepath), hash);
92 break;
93 case AssetFromMemory:
94 LOGI("Found asset [%p] in cache with hash [%lu]", cmd->data, hash);
95 break;
96 }
97}
98
99static void log_scene_loaded(const LoadSceneCmd* cmd) {
100 assert(cmd);
101 switch (cmd->origin) {
102 case AssetFromFile:
103 LOGI("Loaded asset from file: [%s]", mstring_cstr(&cmd->filepath));
104 break;
105 case AssetFromMemory:
106 LOGI("Loaded asset from memory: [%p]", cmd->data);
107 break;
108 }
109}
110
111void gfx_init_asset_cache(AssetCache* cache) {
112 assert(cache);
113 mempool_make(&cache->assets);
114
115 // Allocate a dummy asset at index 0 to guarantee that no assets allocated by
116 // the caller map to index 0.
117 const Asset* dummy = mempool_alloc(&cache->assets);
118 assert(mempool_get_block_index(&cache->assets, dummy) == 0);
119}
120
121void gfx_destroy_asset_cache(AssetCache* cache) {
122 assert(cache);
123 mempool_del(&cache->assets);
124}
125
126SceneNode* gfx_load_scene(
127 Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) {
128 assert(gfx);
129
130 AssetCache* cache = gfx_get_asset_cache(gfx);
131
132 // First search for the asset in the cache.
133 // TODO: Animated models are currently mutated in place, so sharing them is
134 // not really valid.
135 const uint64_t hash = calc_scene_hash(cmd);
136 Asset* asset = lookup_cache(cache, hash);
137 if (asset) {
138 log_scene_cache_hit(cmd, hash);
139 return (SceneNode*)asset;
140 }
141
142 // Asset not found in the cache.
143 // Load it, insert it into the cache, and return it.
144 SceneNode* node = gfx_scene_load(gfx, root_node, cmd);
145 if (node) {
146 insert_into_cache(
147 cache, &(Asset){
148 .type = SceneAsset,
149 .hash = hash,
150 .data = node,
151 });
152 log_scene_loaded(cmd);
153 }
154 return node;
155}
156
157Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) {
158 assert(gfx);
159 assert(cmd);
160
161 AssetCache* cache = gfx_get_asset_cache(gfx);
162
163 // First search for the asset in the cache.
164 const uint64_t hash = calc_texture_hash(cmd);
165 Asset* asset = lookup_cache(cache, hash);
166 if (asset) {
167 return (Texture*)asset;
168 }
169
170 // Asset not found in the cache.
171 // Load it, insert it into the cache, and return it.
172 RenderBackend* render_backend = gfx_get_render_backend(gfx);
173 Texture* texture = gfx_texture_load(render_backend, cmd);
174 if (texture) {
175 insert_into_cache(
176 cache, &(Asset){
177 .type = TextureAsset,
178 .hash = hash,
179 .data = texture,
180 });
181 }
182 return texture;
183}