opengl moment #1
@ -23,6 +23,14 @@ add_subdirectory(third-party/physfs)
|
||||
add_subdirectory(third-party/libxm)
|
||||
|
||||
|
||||
if(UNIX)
|
||||
set(SYSTEM_SOURCE_FILES
|
||||
src/system/linux/elf.c
|
||||
)
|
||||
else()
|
||||
set(SYSTEM_SOURCE_FILES)
|
||||
endif()
|
||||
|
||||
set(SOURCE_FILES
|
||||
third-party/physfs/extras/physfsrwops.c
|
||||
third-party/stb/stb_vorbis.c
|
||||
@ -49,6 +57,8 @@ set(SOURCE_FILES
|
||||
src/game/scenes/scene.c src/game/scenes/scene.h
|
||||
src/game/scenes/title.c src/game/scenes/title.h
|
||||
src/game/scenes/ingame.c src/game/scenes/ingame.h
|
||||
|
||||
${SYSTEM_SOURCE_FILES}
|
||||
)
|
||||
|
||||
# target
|
||||
@ -90,19 +100,24 @@ else()
|
||||
# these SHOULDN'T break anything...
|
||||
-fno-math-errno
|
||||
-ffp-contract=fast
|
||||
-fno-signed-zeros
|
||||
-fno-trapping-math
|
||||
-freciprocal-math)
|
||||
-fno-signed-zeros)
|
||||
set(BUILD_FLAGS_RELEASE
|
||||
-O3
|
||||
-flto
|
||||
-Wl,-gc-sections
|
||||
-fdata-sections
|
||||
-ffunction-sections)
|
||||
-ffunction-sections
|
||||
-funroll-loops
|
||||
-fomit-frame-pointer
|
||||
-fallow-store-data-races)
|
||||
set(BUILD_FLAGS_DEBUG
|
||||
-O0
|
||||
-g3
|
||||
-gdwarf
|
||||
-fno-omit-frame-pointer
|
||||
-fstack-protector-all
|
||||
-fsanitize=undefined
|
||||
-fsanitize-trap=undefined)
|
||||
-fsanitize=address)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
${WARNING_FLAGS}
|
||||
${BUILD_FLAGS}
|
||||
|
@ -244,7 +244,7 @@ static void audio_sample_and_mixin_channel(const struct audio_channel *channel,
|
||||
static uint8_t buffer[16384];
|
||||
const int int16_buffer_frames = sizeof (buffer) / sizeof (int16_t);
|
||||
const int float_buffer_frames = sizeof (buffer) / sizeof (float);
|
||||
const int stream_frames = len / sizeof (int16_t);
|
||||
const int stream_frames = len / (int)(sizeof (int16_t));
|
||||
|
||||
switch (channel->file_type) {
|
||||
case audio_file_type_ogg: {
|
||||
|
@ -65,6 +65,7 @@ static void ingame_end(struct state *state) {
|
||||
struct scene_ingame *scn = (struct scene_ingame *)state->scene;
|
||||
player_destroy(scn->player);
|
||||
world_destroy(scn->world);
|
||||
free(state->scene);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,7 @@ static void title_end(struct state *state) {
|
||||
struct scene_title *scn = (struct scene_title *)state->scene;
|
||||
player_destroy(scn->player);
|
||||
world_destroy(scn->world);
|
||||
free(state->scene);
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,7 +95,6 @@ union uncolored_space_triangle {
|
||||
/* batch of primitives with overlapping properties */
|
||||
struct mesh_batch {
|
||||
GLuint buffer; /* server side storage */
|
||||
size_t buffer_len; /* element count */
|
||||
uint8_t *primitives;
|
||||
};
|
||||
|
||||
|
68
src/system/linux/elf.c
Normal file
68
src/system/linux/elf.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include "elf.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <elf.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool infer_elf_section_bounds(const char *const restrict name,
|
||||
const char **restrict vm_start,
|
||||
const char **restrict vm_end)
|
||||
{
|
||||
bool result = false;
|
||||
char buf[PATH_MAX];
|
||||
ssize_t l = readlink("/proc/self/exe", buf, PATH_MAX);
|
||||
if (l == -1)
|
||||
goto ERR_CANT_READLINK;
|
||||
buf[l] = 0; /* readlink() doesn't write a terminator */
|
||||
|
||||
int elf = open(buf, O_RDONLY);
|
||||
if (elf == -1)
|
||||
goto ERR_CANT_OPEN_SELF;
|
||||
|
||||
/* elf header */
|
||||
Elf64_Ehdr ehdr;
|
||||
read(elf, &ehdr, sizeof ehdr);
|
||||
if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
|
||||
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
|
||||
ehdr.e_ident[EI_MAG3] != ELFMAG3)
|
||||
goto ERR_NOT_ELF;
|
||||
|
||||
/* section header string table */
|
||||
Elf64_Shdr shstrdr;
|
||||
lseek(elf, ehdr.e_shoff + ehdr.e_shstrndx * sizeof (Elf64_Shdr), SEEK_SET);
|
||||
read(elf, &shstrdr, sizeof shstrdr);
|
||||
char *sh = malloc(shstrdr.sh_size);
|
||||
lseek(elf, shstrdr.sh_offset, SEEK_SET);
|
||||
read(elf, sh, shstrdr.sh_size);
|
||||
|
||||
/* walk sections searching for needed name */
|
||||
lseek(elf, ehdr.e_shoff, SEEK_SET);
|
||||
for (size_t s = 0; s < ehdr.e_shnum; ++s) {
|
||||
Elf64_Shdr shdr;
|
||||
read(elf, &shdr, sizeof shdr);
|
||||
|
||||
if (strcmp(&sh[shdr.sh_name], name) == 0) {
|
||||
result = true;
|
||||
*vm_start = getauxval(AT_ENTRY) - ehdr.e_entry + (char *)shdr.sh_addr;
|
||||
*vm_end = getauxval(AT_ENTRY) - ehdr.e_entry + (char *)shdr.sh_addr + shdr.sh_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(sh);
|
||||
|
||||
ERR_NOT_ELF:
|
||||
close(elf);
|
||||
|
||||
ERR_CANT_OPEN_SELF:
|
||||
ERR_CANT_READLINK:
|
||||
return result;
|
||||
}
|
10
src/system/linux/elf.h
Normal file
10
src/system/linux/elf.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef ELF_H
|
||||
#define ELF_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool infer_elf_section_bounds(const char *restrict name,
|
||||
const char **restrict vm_start,
|
||||
const char **restrict vm_end);
|
||||
|
||||
#endif
|
@ -295,8 +295,9 @@ void textures_dump_atlases(struct texture_cache *cache) {
|
||||
|
||||
static t_texture_key textures_load(struct texture_cache *cache, const char *path) {
|
||||
/* no need to do anything if it was loaded already */
|
||||
if (shgeti(cache->hash, path) >= 0)
|
||||
return (t_texture_key){0};
|
||||
const ptrdiff_t i = shgeti(cache->hash, path);
|
||||
if (i >= 0)
|
||||
return (t_texture_key){ (uint16_t)i };
|
||||
|
||||
SDL_Surface *surface = image_to_surface(path);
|
||||
struct texture new_texture = {0};
|
||||
@ -308,12 +309,12 @@ static t_texture_key textures_load(struct texture_cache *cache, const char *path
|
||||
upload_texture_from_surface(new_texture.loner_texture, surface);
|
||||
new_texture.srcrect = (t_rect) { .w = surface->w, .h = surface->h };
|
||||
shput(cache->hash, path, new_texture);
|
||||
return (t_texture_key){ shgeti(cache->hash, path) };
|
||||
return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) };
|
||||
} else {
|
||||
new_texture.atlas_index = cache->atlas_index;
|
||||
shput(cache->hash, path, new_texture);
|
||||
cache->is_dirty = true;
|
||||
return (t_texture_key){ shgeti(cache->hash, path) };
|
||||
return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) };
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,35 +364,44 @@ void textures_update_atlas(struct texture_cache *cache) {
|
||||
}
|
||||
|
||||
/* EXPERIMANTAL: LIKELY TO BE REMOVED! */
|
||||
/* todo: If it's proven to be useful: add runtime checking for .rodata > .data */
|
||||
#ifdef __unix__ /* use rodata elf section for fast lookups of repeating textures */
|
||||
#ifdef __linux__ /* use rodata elf section for fast lookups of repeating textures */
|
||||
|
||||
extern const char start_rodata_address[];
|
||||
extern const char stop_rodata_heuristic[];
|
||||
#include "system/linux/elf.h"
|
||||
|
||||
asm(".set start_rodata_address, .rodata");
|
||||
asm(".set stop_rodata_heuristic, .data"); /* there's nothing in default linker script to know the size of .rodata */
|
||||
static const char *rodata_start;
|
||||
static const char *rodata_stop;
|
||||
|
||||
/* TODO: it might be better to contruct a new table that hashes pointers, not strings, to texture keys */
|
||||
/* this way every used texture will benefit, no matter the order of commission */
|
||||
t_texture_key textures_get_key(struct texture_cache *cache, const char *path) {
|
||||
static const char *last_path = NULL;
|
||||
static t_texture_key last_texture;
|
||||
static struct ptr_to_texture {
|
||||
const void *key;
|
||||
t_texture_key value;
|
||||
} *ptr_to_texture;
|
||||
|
||||
/* fast path */
|
||||
if (rodata_stop == NULL)
|
||||
if (!infer_elf_section_bounds(".rodata", &rodata_start, &rodata_stop))
|
||||
CRY("Section inference", ".rodata section lookup failed");
|
||||
|
||||
/* the fastest path */
|
||||
if (path == last_path)
|
||||
return last_texture;
|
||||
else {
|
||||
/* moderately fast path, by pointer hashing */
|
||||
const ptrdiff_t texture = hmgeti(ptr_to_texture, path);
|
||||
if (texture != -1) {
|
||||
if (path >= rodata_start && path < rodata_stop)
|
||||
last_path = path;
|
||||
last_texture = ptr_to_texture[texture].value;
|
||||
return last_texture;
|
||||
}
|
||||
}
|
||||
|
||||
/* hash tables are assumed to be stable, so we just return indices */
|
||||
ptrdiff_t texture = shgeti(cache->hash, path);
|
||||
/* try loading */
|
||||
last_texture = textures_load(cache, path);
|
||||
hmput(ptr_to_texture, path, last_texture);
|
||||
|
||||
/* load it if it isn't */
|
||||
if (texture == -1) {
|
||||
last_texture = textures_load(cache, path);
|
||||
} else
|
||||
last_texture = (t_texture_key){ (uint16_t)texture };
|
||||
|
||||
if (path >= start_rodata_address && path < stop_rodata_heuristic)
|
||||
if (path >= rodata_start && path < rodata_stop)
|
||||
last_path = path;
|
||||
|
||||
return last_texture;
|
||||
@ -400,7 +410,7 @@ t_texture_key textures_get_key(struct texture_cache *cache, const char *path) {
|
||||
#else
|
||||
t_texture_key textures_get_key(struct texture_cache *cache, const char *path) {
|
||||
/* hash tables are assumed to be stable, so we just return indices */
|
||||
ptrdiff_t texture = shgeti(cache->hash, path);
|
||||
const ptrdiff_t texture = shgeti(cache->hash, path);
|
||||
|
||||
/* load it if it isn't */
|
||||
if (texture == -1) {
|
||||
|
6
third-party/stb/stb_ds.h
vendored
6
third-party/stb/stb_ds.h
vendored
@ -1121,7 +1121,7 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed)
|
||||
unsigned char *d = (unsigned char *) p;
|
||||
|
||||
if (len == 4) {
|
||||
unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
|
||||
uint32_t hash = (uint32_t)d[0] | ((uint32_t)d[1] << 8) | ((uint32_t)d[2] << 16) | ((uint32_t)d[3] << 24);
|
||||
#if 0
|
||||
// HASH32-A Bob Jenkin's hash function w/o large constants
|
||||
hash ^= seed;
|
||||
@ -1177,8 +1177,8 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed)
|
||||
|
||||
return (((size_t) hash << 16 << 16) | hash) ^ seed;
|
||||
} else if (len == 8 && sizeof(size_t) == 8) {
|
||||
size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
|
||||
hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4
|
||||
size_t hash = (size_t)d[0] | ((size_t)d[1] << 8) | ((size_t)d[2] << 16) | ((size_t)d[3] << 24);
|
||||
hash |= ((size_t)d[4] | ((size_t)d[5] << 8) | ((size_t)d[6] << 16) | ((size_t)d[7] << 24)) << 16 << 16;
|
||||
hash ^= seed;
|
||||
hash = (~hash) + (hash << 21);
|
||||
hash ^= STBDS_ROTATE_RIGHT(hash,24);
|
||||
|
Loading…
Reference in New Issue
Block a user