DECLARE_TEST(time, builtin) { tick_t tick, newtick, tps; deltatime_t dt; tps = time_ticks_per_second(); EXPECT_GT(tps, 0); tick = time_current(); thread_sleep(30); newtick = time_current(); EXPECT_TICKNE(tick, 0); EXPECT_TICKGT(newtick, tick); EXPECT_TICKGT(time_diff(tick, newtick), 0); EXPECT_GT_MSGFORMAT(time_diff(tick, newtick), (tps / 100LL), "time elapsed not more than 10ms: %" PRId64 " (%" PRId64 ")", time_diff(tick, newtick), (tps / 100)); //more than 10 ms EXPECT_LT_MSGFORMAT(time_diff(tick, newtick), (tps / 20LL), "time elapsed not less than 50ms: %" PRId64 " (%" PRId64 ")", time_diff(tick, newtick), (tps / 33)); //less than 30 ms EXPECT_REALGT(time_elapsed(tick), 0); EXPECT_REALGT(time_elapsed(tick), 0.01f); //more than 10 ms EXPECT_TICKGT(time_elapsed_ticks(tick), 0); EXPECT_TICKGT(time_elapsed_ticks(tick), (tps / 100)); //more than 10 ms EXPECT_TICKLT(time_elapsed_ticks(tick), (tps / 20)); //less than 50 ms dt = time_ticks_to_seconds(newtick - tick); EXPECT_REALGT(dt, 0); EXPECT_GT_MSGFORMAT(dt, 0.01f, "time elapsed in seconds not more than 10ms: %.5f", dt); //more than 10 ms EXPECT_LT_MSGFORMAT(dt, 0.05f, "time elapsed in seconds not less than 30ms: %.5f", dt); //less than 30 ms tick = time_startup(); EXPECT_TICKGT(tick, 0); EXPECT_TICKLT(tick, newtick); EXPECT_TICKEQ(tick, time_startup()); tick = time_system(); thread_sleep(100); newtick = time_system(); EXPECT_TICKGT(tick, 0); EXPECT_TICKGT(newtick, 0); EXPECT_TICKGT(newtick, tick); EXPECT_GT_MSGFORMAT(newtick - tick, 50, "Elapsed system time less than 50ms, expected 100ms, got %" PRId64 "ms", newtick - tick); EXPECT_LT_MSGFORMAT(newtick - tick, 200, "Elapsed system time more than 200ms, expected 100ms, got %" PRId64 "ms", newtick - tick); return 0; }
static void _random_seed_buffer( unsigned int* buffer ) { int i; uint64_t base = time_system(); for( i = 0; i < RANDOM_STATE_SIZE; ++i ) buffer[i] ^= ( base + time_current() + ( i * RANDOM_HIGH_LIMIT * RANDOM_LOW_LIMIT ) ) & 0xFFFFFFFFULL; }
DECLARE_TEST( time, builtin ) { tick_t tick, newtick, tps; deltatime_t dt; tps = time_ticks_per_second(); EXPECT_GT( tps, 0 ); tick = time_current(); thread_sleep( 20 ); newtick = time_current(); EXPECT_NE( tick, 0 ); EXPECT_GT( newtick, tick ); EXPECT_GT( time_diff( tick, newtick ), 0 ); EXPECT_GT_MSGFORMAT( time_diff( tick, newtick ), ( tps / 100LL ), "time elapsed not more than 10ms: %lld (%lld)", time_diff( tick, newtick ), ( tps / 100LL ) ); //more than 10 ms EXPECT_LT_MSGFORMAT( time_diff( tick, newtick ), ( tps / 30LL ), "time elapsed not less than 30ms: %lld (%lld)", time_diff( tick, newtick ), ( tps / 33LL ) ); //less than 30 ms EXPECT_GT( time_elapsed( tick ), 0 ); EXPECT_GT( time_elapsed( tick ), 0.01f ); //more than 10 ms EXPECT_GT( time_elapsed_ticks( tick ), 0 ); EXPECT_GT( time_elapsed_ticks( tick ), ( tps / 100 ) ); //more than 10 ms dt = time_ticks_to_seconds( newtick - tick ); EXPECT_GT( dt, 0 ); EXPECT_GT_MSGFORMAT( dt, 0.01f, "time elapsed in seconds not more than 10ms: %.5f", dt ); //more than 10 ms EXPECT_LT_MSGFORMAT( dt, 0.03f, "time elapsed in seconds not less than 30ms: %.5f", dt ); //less than 30 ms tick = time_startup(); EXPECT_GT( tick, 0 ); EXPECT_LT( tick, newtick ); EXPECT_EQ( tick, time_startup() ); tick = time_system(); EXPECT_GT( tick, 0 ); thread_sleep( 100 ); newtick = time_system(); EXPECT_GT( newtick, 0 ); EXPECT_GT( newtick, tick ); EXPECT_GT( newtick - tick, 50 ); //more than 50 ms EXPECT_LT( newtick - tick, 200 ); //less than 200 ms return 0; }
DECLARE_TEST( fs, util ) { tick_t systime = time_system(); tick_t lastmod = 0; char* testpath = path_merge( environment_temporary_directory(), string_from_int_static( random64(), 0, 0 ) ); if( !fs_is_directory( environment_temporary_directory() ) ) fs_make_directory( environment_temporary_directory() ); if( fs_is_directory( testpath ) ) fs_remove_directory( testpath ); fs_remove_file( testpath ); EXPECT_EQ( fs_last_modified( testpath ), 0 ); thread_sleep( 1000 ); //For fs time granularity, make sure at least one second passed since systime stream_deallocate( fs_open_file( testpath, STREAM_OUT ) ); EXPECT_TRUE( fs_is_file( testpath ) ); EXPECT_GE( fs_last_modified( testpath ), systime ); fs_remove_file( testpath ); EXPECT_FALSE( fs_is_file( testpath ) ); EXPECT_EQ( fs_last_modified( testpath ), 0 ); stream_deallocate( fs_open_file( testpath, STREAM_OUT ) ); EXPECT_TRUE( fs_is_file( testpath ) ); EXPECT_GE( fs_last_modified( testpath ), systime ); lastmod = fs_last_modified( testpath ); thread_sleep( 5000 ); EXPECT_EQ( fs_last_modified( testpath ), lastmod ); fs_touch( testpath ); EXPECT_GT( fs_last_modified( testpath ), lastmod ); fs_remove_file( testpath ); string_deallocate( testpath ); return 0; }
static int lua_import_output(const uuid_t uuid, const luaimport_dump_t* dump) { resource_source_t source; hash_t checksum; tick_t timestamp; uint64_t platform; string_const_t type = string_const(STRING_CONST("lua")); int ret = 0; resource_source_initialize(&source); resource_source_read(&source, uuid); timestamp = time_system(); platform = 0; checksum = hash(dump->bytecode, dump->bytecode_size); if (resource_source_write_blob(uuid, timestamp, HASH_SOURCE, platform, checksum, dump->bytecode, dump->bytecode_size)) { resource_source_set_blob(&source, timestamp, HASH_SOURCE, platform, checksum, dump->bytecode_size); } else { ret = -1; goto finalize; } resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, STRING_ARGS(type)); if (!resource_source_write(&source, uuid, false)) { ret = -1; goto finalize; } finalize: resource_source_finalize(&source); return ret; }
uuid_t uuid_generate_time( void ) { uuid_time_t time_uuid; uuid_convert_t convert; int64_t current_time; int32_t current_counter; tick_t current_tick; int in = 0; uint32_t clock_seq = 0; uint64_t host_id = 0; //Allows creation of 10000 unique timestamps per millisecond current_time = time_system(); current_counter = atomic_incr32( &_uuid_last_counter ) % 10000; current_tick = ( (tick_t)current_time * 10000ULL ) + current_counter + 0x01B21DD213814000ULL; //Convert to 100ns since UUID UTC base time, October 15 1582, and add counter //We have no state so clock sequence is random clock_seq = random32(); time_uuid.time_low = (uint32_t)( current_tick & 0xFFFFFFFFULL ); time_uuid.time_mid = (uint16_t)( ( current_tick >> 32ULL ) & 0xFFFFULL ); time_uuid.time_hi_and_version = (uint16_t)( current_tick >> 48ULL ); time_uuid.clock_seq_low = ( clock_seq & 0xFF ); time_uuid.clock_seq_hi_and_reserved = ( ( clock_seq & 0x3F00 ) >> 8 ); //If hardware node ID is null, use random and set identifier (multicast) bit host_id = system_hostid(); if( host_id ) { for( in = 0; in < 6; ++in ) time_uuid.node[5-in] = (uint8_t)( ( host_id >> ( 8ULL * in ) ) & 0xFF ); } else { for( in = 0; in < 6; ++in )
static int render_import_glsl_shader(stream_t* stream, const uuid_t uuid, const char* type, size_t type_length) { resource_source_t source; void* blob = 0; size_t size; size_t read; size_t begin; size_t next; hash_t checksum; tick_t timestamp; uint64_t platform; size_t maxtokens; size_t parameter; string_const_t* token = 0; string_const_t valstr; char buffer[128]; int ret = 0; resource_platform_t platformdecl = { -1, -1, RENDERAPIGROUP_OPENGL, -1, -1, -1}; resource_source_initialize(&source); resource_source_read(&source, uuid); read = 0; size = stream_size(stream); blob = memory_allocate(HASH_RESOURCE, size, 0, MEMORY_PERSISTENT); size = stream_read(stream, blob, size); platform = resource_platform(platformdecl); timestamp = time_system(); checksum = hash(blob, size); if (resource_source_write_blob(uuid, timestamp, HASH_SOURCE, platform, checksum, blob, size)) { resource_source_set_blob(&source, timestamp, HASH_SOURCE, platform, checksum, size); } else { ret = -1; goto finalize; } //Parse source and set parameters maxtokens = 256; token = memory_allocate(HASH_RESOURCE, sizeof(string_const_t) * maxtokens, 0, MEMORY_PERSISTENT); begin = 0; parameter = 0; do { string_const_t tokens[64], line; size_t itok, ntokens; next = string_find_first_of(blob, size, STRING_CONST("\n\r"), begin); line = string_substr(blob, size, begin, next - begin); ntokens = string_explode(STRING_ARGS(line), STRING_CONST(GLSL_TOKEN_DELIM), tokens, maxtokens, false); for (itok = 0; itok < ntokens; ++itok) { if ((string_equal(STRING_ARGS(tokens[itok]), STRING_CONST("attribute")) || string_equal(STRING_ARGS(tokens[itok]), STRING_CONST("uniform"))) && (itok + 2 < ntokens)) { char typebuf[16], dimbuf[16]; string_const_t typestr = tokens[itok + 1]; string_const_t namestr = tokens[itok + 2]; string_const_t dimstr; int parameter_type = glsl_type_to_parameter_type(typestr); if (parameter_type < 0) continue; int parameter_dim = glsl_dim_from_token(typestr); if (parameter_dim == 1) parameter_dim = glsl_dim_from_token(namestr); namestr = glsl_name_from_token(namestr); typestr = string_to_const(string_from_uint(typebuf, sizeof(typebuf), (unsigned int)parameter_type, false, 0, 0)); dimstr = string_to_const(string_from_uint(dimbuf, sizeof(dimbuf), (unsigned int)parameter_dim, false, 0, 0)); log_debugf(HASH_RESOURCE, STRING_CONST("parameter: %.*s type %.*s dim %.*s"), STRING_FORMAT(namestr), STRING_FORMAT(typestr), STRING_FORMAT(dimstr)); string_t param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_type_%" PRIsize), parameter); resource_source_set(&source, timestamp, hash(STRING_ARGS(param)), platform, STRING_ARGS(typestr)); param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_name_%" PRIsize), parameter); resource_source_set(&source, timestamp, hash(STRING_ARGS(param)), platform, STRING_ARGS(namestr)); param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_dim_%" PRIsize), parameter); resource_source_set(&source, timestamp, hash(STRING_ARGS(param)), platform, STRING_ARGS(dimstr)); ++parameter; } } begin = string_find_first_not_of(blob, size, STRING_CONST(STRING_WHITESPACE), next); } while (next != STRING_NPOS); valstr = string_from_uint_static(parameter, false, 0, 0); resource_source_set(&source, timestamp, HASH_PARAMETER_COUNT, platform, STRING_ARGS(valstr)); resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, type, type_length); if (!resource_source_write(&source, uuid, false)) { string_const_t uuidstr = string_from_uuid_static(uuid); log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported GLSL shader: %.*s"), STRING_FORMAT(uuidstr)); ret = -1; goto finalize; } else { string_const_t uuidstr = string_from_uuid_static(uuid); log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported GLSL shader: %.*s"), STRING_FORMAT(uuidstr)); } finalize: memory_deallocate(blob); memory_deallocate(token); resource_source_finalize(&source); return ret; }
static int render_import_program(stream_t* stream, const uuid_t uuid) { char buffer[1024]; char pathbuf[BUILD_MAX_PATHLEN]; resource_source_t source; resource_platform_t platformdecl = {-1, -1, -1, -1, -1, -1}; uint64_t platform; tick_t timestamp; int ret = 0; resource_source_initialize(&source); resource_source_read(&source, uuid); platform = resource_platform(platformdecl); timestamp = time_system(); while (!stream_eos(stream)) { string_const_t type, ref; string_const_t fullpath; string_const_t uuidstr; uuid_t shaderuuid; hash_t typehash; string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n'); string_split(STRING_ARGS(line), STRING_CONST(" \t"), &type, &ref, false); type = string_strip(STRING_ARGS(type), STRING_CONST(STRING_WHITESPACE)); ref = string_strip(STRING_ARGS(ref), STRING_CONST(STRING_WHITESPACE)); if (!type.length || !ref.length) continue; typehash = hash(STRING_ARGS(type)); if ((typehash != HASH_VERTEXSHADER) && (typehash != HASH_PIXELSHADER)) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Ignore invalid line: %.*s"), STRING_FORMAT(line)); continue; } shaderuuid = string_to_uuid(STRING_ARGS(ref)); if (uuid_is_null(shaderuuid)) { if (path_is_absolute(STRING_ARGS(ref))) { fullpath = ref; } else { string_t full; string_const_t path = stream_path(stream); path = path_directory_name(STRING_ARGS(path)); full = path_concat(pathbuf, sizeof(pathbuf), STRING_ARGS(path), STRING_ARGS(ref)); full = path_absolute(STRING_ARGS(full), sizeof(pathbuf)); fullpath = string_const(STRING_ARGS(full)); } resource_signature_t sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { if (!resource_import(STRING_ARGS(fullpath), uuid_null())) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Unable to import linked shader: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Import linked shader gave no UUID: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } } shaderuuid = sig.uuid; } if (!uuid_is_null(shaderuuid)) { uuidstr = string_from_uuid_static(shaderuuid); resource_source_set(&source, timestamp, typehash, platform, STRING_ARGS(uuidstr)); } } resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, STRING_CONST("program")); if (!resource_source_write(&source, uuid, false)) { string_const_t uuidstr = string_from_uuid_static(uuid); log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported program: %.*s"), STRING_FORMAT(uuidstr)); ret = -1; goto finalize; } else { string_const_t uuidstr = string_from_uuid_static(uuid); log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported program: %.*s"), STRING_FORMAT(uuidstr)); } finalize: resource_source_finalize(&source); return ret; }
static int render_import_shader(stream_t* stream, const uuid_t uuid) { char buffer[1024]; char pathbuf[BUILD_MAX_PATHLEN]; resource_source_t source; resource_platform_t platformdecl = {-1, -1, -1, -1, -1, -1}; uint64_t platform; tick_t timestamp; int ret = 0; resource_source_initialize(&source); resource_source_read(&source, uuid); platform = resource_platform(platformdecl); timestamp = time_system(); while (!stream_eos(stream)) { uuid_t shaderuuid; string_const_t target, ref, fullpath; string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n'); string_split(STRING_ARGS(line), STRING_CONST(" \t"), &target, &ref, false); ref = string_strip(STRING_ARGS(ref), STRING_CONST(STRING_WHITESPACE)); shaderuuid = string_to_uuid(STRING_ARGS(ref)); if (uuid_is_null(shaderuuid)) { if (path_is_absolute(STRING_ARGS(ref))) { fullpath = ref; } else { string_t full; string_const_t path = stream_path(stream); path = path_directory_name(STRING_ARGS(path)); full = path_concat(pathbuf, sizeof(pathbuf), STRING_ARGS(path), STRING_ARGS(ref)); full = path_absolute(STRING_ARGS(full), sizeof(pathbuf)); fullpath = string_const(STRING_ARGS(full)); } resource_signature_t sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { if (!resource_import(STRING_ARGS(fullpath), uuid_null())) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Unable to import linked shader: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } sig = resource_import_lookup(STRING_ARGS(fullpath)); if (uuid_is_null(sig.uuid)) { log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Import linked shader gave no UUID: %.*s"), STRING_FORMAT(fullpath)); ret = -1; goto finalize; } } shaderuuid = sig.uuid; } if (!uuid_is_null(shaderuuid)) { resource_platform_t targetplatformdecl = render_import_parse_target(STRING_ARGS(target), platformdecl); uint64_t targetplatform = resource_platform(targetplatformdecl); if (resource_autoimport_need_update(shaderuuid, targetplatform)) resource_autoimport(shaderuuid); const string_const_t uuidstr = string_from_uuid_static(shaderuuid); resource_source_set(&source, timestamp, HASH_SHADER, targetplatform, STRING_ARGS(uuidstr)); resource_source_set_dependencies(uuid, targetplatform, &shaderuuid, 1); } } resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, STRING_CONST("shader")); if (!resource_source_write(&source, uuid, false)) { string_const_t uuidstr = string_from_uuid_static(uuid); log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported shader: %.*s"), STRING_FORMAT(uuidstr)); ret = -1; goto finalize; } else { string_const_t uuidstr = string_from_uuid_static(uuid); log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported shader: %.*s"), STRING_FORMAT(uuidstr)); } finalize: resource_source_finalize(&source); return 0; }