summaryrefslogtreecommitdiff
path: root/gfx/src/render/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/render/core.c')
-rw-r--r--gfx/src/render/core.c414
1 files changed, 414 insertions, 0 deletions
diff --git a/gfx/src/render/core.c b/gfx/src/render/core.c
new file mode 100644
index 0000000..7a6d9cc
--- /dev/null
+++ b/gfx/src/render/core.c
@@ -0,0 +1,414 @@
1#include "core_impl.h"
2
3#include "gl_util.h"
4
5// #include <log/log.h>
6
7#include <assert.h>
8
9void gfx_init_gfxcore(GfxCore* gfxcore) {
10 assert(gfxcore);
11
12 mempool_make(&gfxcore->buffers);
13 mempool_make(&gfxcore->framebuffers);
14 mempool_make(&gfxcore->geometries);
15 mempool_make(&gfxcore->renderbuffers);
16 mempool_make(&gfxcore->shaders);
17 mempool_make(&gfxcore->shader_programs);
18 mempool_make(&gfxcore->textures);
19
20 mempool_make(&gfxcore->shader_cache);
21 mempool_make(&gfxcore->program_cache);
22
23 glEnable(GL_CULL_FACE);
24 glFrontFace(GL_CCW);
25 glCullFace(GL_BACK);
26
27 glEnable(GL_DEPTH_TEST);
28
29 // Filter cubemaps across their faces to avoid seams.
30 // https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap
31 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
32}
33
34// Conveniently destroy any objects that have not been destroyed by the
35// application.
36void gfx_del_gfxcore(GfxCore* gfxcore) {
37 assert(gfxcore);
38
39 mempool_foreach(&gfxcore->buffers, buffer, { gfx_del_buffer(buffer); });
40
41 mempool_foreach(&gfxcore->framebuffers, framebuffer, {
42 gfx_del_framebuffer(framebuffer);
43 });
44
45 mempool_foreach(
46 &gfxcore->geometries, geometry, { gfx_del_geometry(geometry); });
47
48 mempool_foreach(&gfxcore->renderbuffers, renderbuffer, {
49 gfx_del_renderbuffer(renderbuffer);
50 });
51
52 mempool_foreach(
53 &gfxcore->shader_programs, prog, { gfx_del_shader_program(prog); });
54
55 mempool_foreach(&gfxcore->shaders, shader, { gfx_del_shader(shader); });
56
57 mempool_foreach(&gfxcore->textures, texture, { gfx_del_texture(texture); });
58}
59
60// -----------------------------------------------------------------------------
61// Render commands.
62// -----------------------------------------------------------------------------
63
64void gfx_start_frame(GfxCore* gfxcore) {
65 assert(gfxcore);
66
67 glViewport(0, 0, gfxcore->viewport.width, gfxcore->viewport.height);
68 glClearColor(0, 0, 0, 0);
69 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
70
71 ASSERT_GL;
72}
73
74void gfx_end_frame(GfxCore* gfxcore) {
75 assert(gfxcore);
76 ASSERT_GL;
77}
78
79void gfx_set_viewport(GfxCore* gfxcore, int width, int height) {
80 assert(gfxcore);
81 gfxcore->viewport.width = width;
82 gfxcore->viewport.height = height;
83}
84
85void gfx_get_viewport(GfxCore* gfxcore, int* width, int* height) {
86 assert(gfxcore);
87 assert(width);
88 assert(height);
89 *width = gfxcore->viewport.width;
90 *height = gfxcore->viewport.height;
91}
92
93void gfx_set_blending(GfxCore* gfxcore, bool enable) {
94 assert(gfxcore);
95 if (enable) {
96 glEnable(GL_BLEND);
97 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
98 } else {
99 glDisable(GL_BLEND);
100 }
101}
102
103void gfx_set_depth_mask(GfxCore* gfxcore, bool enable) {
104 assert(gfxcore);
105 glDepthMask(enable ? GL_TRUE : GL_FALSE);
106}
107
108void gfx_set_culling(GfxCore* gfxcore, bool enable) {
109 assert(gfxcore);
110 if (enable) {
111 glEnable(GL_CULL_FACE);
112 } else {
113 glDisable(GL_CULL_FACE);
114 }
115}
116
117void gfx_set_polygon_offset(GfxCore* gfxcore, float scale, float bias) {
118 assert(gfxcore);
119 if ((scale != 0.0f) || (bias != 0.0f)) {
120 glEnable(GL_POLYGON_OFFSET_FILL);
121 } else {
122 glDisable(GL_POLYGON_OFFSET_FILL);
123 }
124 glPolygonOffset(scale, bias);
125}
126
127void gfx_reset_polygon_offset(GfxCore* gfxcore) {
128 assert(gfxcore);
129 glPolygonOffset(0, 0);
130 glDisable(GL_POLYGON_OFFSET_FILL);
131}
132
133// -----------------------------------------------------------------------------
134// Buffers.
135// -----------------------------------------------------------------------------
136
137Buffer* gfx_make_buffer(GfxCore* gfxcore, const BufferDesc* desc) {
138 assert(gfxcore);
139 assert(desc);
140
141 Buffer* buffer = mempool_alloc(&gfxcore->buffers);
142 if (!gfx_init_buffer(buffer, desc)) {
143 mempool_free(&gfxcore->buffers, &buffer);
144 return 0;
145 }
146 return buffer;
147}
148
149void gfx_destroy_buffer(GfxCore* gfxcore, Buffer** buffer) {
150 assert(gfxcore);
151 assert(buffer);
152 if (*buffer) {
153 gfx_del_buffer(*buffer);
154 mempool_free(&gfxcore->buffers, buffer);
155 }
156}
157
158// -----------------------------------------------------------------------------
159// Geometry.
160// -----------------------------------------------------------------------------
161
162Geometry* gfx_make_geometry(GfxCore* gfxcore, const GeometryDesc* desc) {
163 assert(gfxcore);
164 assert(desc);
165
166 Geometry* geometry = mempool_alloc(&gfxcore->geometries);
167 if (!gfx_init_geometry(geometry, gfxcore, desc)) {
168 mempool_free(&gfxcore->geometries, &geometry);
169 return 0;
170 }
171 return geometry;
172}
173
174void gfx_destroy_geometry(GfxCore* gfxcore, Geometry** geometry) {
175 assert(gfxcore);
176 assert(geometry);
177
178 if (*geometry) {
179 gfx_del_geometry(*geometry);
180 mempool_free(&gfxcore->geometries, geometry);
181 }
182}
183
184// -----------------------------------------------------------------------------
185// Textures.
186// -----------------------------------------------------------------------------
187
188Texture* gfx_make_texture(GfxCore* gfxcore, const TextureDesc* desc) {
189 assert(gfxcore);
190 assert(desc);
191
192 Texture* texture = mempool_alloc(&gfxcore->textures);
193 if (!gfx_init_texture(texture, desc)) {
194 mempool_free(&gfxcore->textures, &texture);
195 return 0;
196 }
197 return texture;
198}
199
200void gfx_destroy_texture(GfxCore* gfxcore, Texture** texture) {
201 assert(gfxcore);
202 assert(texture);
203 assert(*texture);
204
205 if (*texture) {
206 gfx_del_texture(*texture);
207 mempool_free(&gfxcore->textures, texture);
208 }
209}
210
211// -----------------------------------------------------------------------------
212// Renderbuffers.
213// -----------------------------------------------------------------------------
214
215RenderBuffer* gfx_make_renderbuffer(
216 GfxCore* gfxcore, const RenderBufferDesc* desc) {
217 assert(gfxcore);
218 assert(desc);
219
220 RenderBuffer* renderbuffer = mempool_alloc(&gfxcore->renderbuffers);
221 if (!gfx_init_renderbuffer(renderbuffer, desc)) {
222 mempool_free(&gfxcore->renderbuffers, &renderbuffer);
223 }
224 return renderbuffer;
225}
226
227void gfx_destroy_renderbuffer(GfxCore* gfxcore, RenderBuffer** renderbuffer) {
228 assert(gfxcore);
229 assert(renderbuffer);
230 assert(*renderbuffer);
231
232 if (*renderbuffer) {
233 gfx_del_renderbuffer(*renderbuffer);
234 mempool_free(&gfxcore->renderbuffers, renderbuffer);
235 }
236}
237
238// -----------------------------------------------------------------------------
239// Framebuffers.
240// -----------------------------------------------------------------------------
241
242FrameBuffer* gfx_make_framebuffer(
243 GfxCore* gfxcore, const FrameBufferDesc* desc) {
244 assert(gfxcore);
245 assert(desc);
246
247 FrameBuffer* framebuffer = mempool_alloc(&gfxcore->framebuffers);
248 if (!gfx_init_framebuffer(framebuffer, desc)) {
249 mempool_free(&gfxcore->framebuffers, &framebuffer);
250 return 0;
251 }
252 return framebuffer;
253}
254
255void gfx_destroy_framebuffer(GfxCore* gfxcore, FrameBuffer** framebuffer) {
256 assert(gfxcore);
257 assert(framebuffer);
258 assert(*framebuffer);
259
260 if (*framebuffer) {
261 gfx_del_framebuffer(*framebuffer);
262 mempool_free(&gfxcore->framebuffers, framebuffer);
263 }
264}
265
266// -----------------------------------------------------------------------------
267// Shaders.
268// -----------------------------------------------------------------------------
269
270static uint64_t hash_shader_desc(const ShaderDesc* desc) {
271 assert(desc);
272 // Note that defines may affect shader permutations, so we need to hash those
273 // as well.
274 uint64_t hash = 0;
275 for (size_t i = 0; i < desc->num_defines; ++i) {
276 const ShaderCompilerDefine* define = &desc->defines[i];
277 hash = (((hash << 13) + sstring_hash(define->name)) << 7) +
278 sstring_hash(define->value);
279 }
280 return (hash << 17) + cstring_hash(desc->code);
281}
282
283static uint64_t hash_program_desc(const ShaderProgramDesc* desc) {
284 assert(desc);
285 return ((uint64_t)desc->vertex_shader->id << 32) |
286 (uint64_t)desc->fragment_shader->id;
287}
288
289static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) {
290 assert(cache);
291 mempool_foreach(cache, entry, {
292 if (entry->hash == hash) {
293 return entry->shader;
294 }
295 });
296 return 0;
297}
298
299static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) {
300 assert(cache);
301 mempool_foreach(cache, entry, {
302 if (entry->hash == hash) {
303 return entry->program;
304 }
305 });
306 return 0;
307}
308
309static ShaderCacheEntry* find_shader_cache_entry(
310 ShaderCache* cache, const Shader* shader) {
311 assert(cache);
312 assert(shader);
313 mempool_foreach(cache, entry, {
314 if (entry->shader == shader) {
315 return entry;
316 }
317 });
318 return 0;
319}
320
321static ShaderProgramCacheEntry* find_program_cache_entry(
322 ProgramCache* cache, const ShaderProgram* prog) {
323 assert(cache);
324 assert(prog);
325 mempool_foreach(cache, entry, {
326 if (entry->program == prog) {
327 return entry;
328 }
329 });
330 return 0;
331}
332
333Shader* gfx_make_shader(GfxCore* gfxcore, const ShaderDesc* desc) {
334 assert(gfxcore);
335 assert(desc);
336
337 // Check the shader cache first.
338 ShaderCache* cache = &gfxcore->shader_cache;
339 const uint64_t hash = hash_shader_desc(desc);
340 Shader* shader = find_cached_shader(cache, hash);
341 if (shader) {
342 // LOGD("Found cached shader with hash [%lx]", hash);
343 return shader;
344 }
345
346 shader = mempool_alloc(&gfxcore->shaders);
347 if (!shader) {
348 return 0;
349 }
350 if (!gfx_compile_shader(shader, desc)) {
351 mempool_free(&gfxcore->shaders, &shader);
352 return 0;
353 }
354 ShaderCacheEntry* entry = mempool_alloc(cache);
355 *entry = (ShaderCacheEntry){.hash = hash, .shader = shader};
356 // LOGD("Added shader with hash [%lx] to cache", hash);
357 return shader;
358}
359
360void gfx_destroy_shader(GfxCore* gfxcore, Shader** shader) {
361 assert(gfxcore);
362 assert(shader);
363
364 if (*shader) {
365 // Remove the shader from the cache.
366 ShaderCache* cache = &gfxcore->shader_cache;
367 ShaderCacheEntry* entry = find_shader_cache_entry(cache, *shader);
368 assert(entry); // Must be there, shaders can't go untracked.
369 mempool_free(cache, &entry);
370
371 gfx_del_shader(*shader);
372 mempool_free(&gfxcore->shaders, shader);
373 }
374}
375
376ShaderProgram* gfx_make_shader_program(
377 GfxCore* gfxcore, const ShaderProgramDesc* desc) {
378 assert(gfxcore);
379 assert(desc);
380
381 // Check the shader program cache first.
382 ProgramCache* cache = &gfxcore->program_cache;
383 const uint64_t hash = hash_program_desc(desc);
384 ShaderProgram* prog = find_cached_program(cache, hash);
385 if (prog) {
386 // LOGD("Found cached shader program with hash [%lx]", hash);
387 return prog;
388 }
389
390 prog = mempool_alloc(&gfxcore->shader_programs);
391 if (!gfx_build_shader_program(prog, desc)) {
392 mempool_free(&gfxcore->shader_programs, &prog);
393 return 0;
394 }
395 ShaderProgramCacheEntry* entry = mempool_alloc(cache);
396 *entry = (ShaderProgramCacheEntry){.hash = hash, .program = prog};
397 // LOGD("Added shader program with hash [%lx] to cache", hash);
398 return prog;
399}
400
401void gfx_destroy_shader_program(GfxCore* gfxcore, ShaderProgram** prog) {
402 assert(gfxcore);
403 assert(prog);
404 if (*prog) {
405 // Remove the shader program from the cache.
406 ProgramCache* cache = &gfxcore->program_cache;
407 ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog);
408 assert(entry); // Must be there, shaders can't go untracked.
409 mempool_free(cache, &entry);
410
411 gfx_del_shader_program(*prog);
412 mempool_free(&gfxcore->shader_programs, prog);
413 }
414}