bubel-ecs/demos/source/game_core/job_updater.d
Dawid Masiukiewicz 024356df9b Common update:
-added multiple new function to allocate template and add entity
-updated README.md (complete initial version)
-empty components now don't take memory
-fixedd small bug with TestRunner
-added many new tests (HashMap, Vector, EntityMeta, ...)
-added default hashing function to HashMap
-fixed critical bug with adding entities
-fixed small bug with adding entity with remplacement components
-added asserts into code to better bug detection
-small performance improvement for events
-added ComponentRef structure which contain data pointer and componentID
-remove EntityID from Event structure
-now events are handled before removing entiteis
-fixed GDC compilation
-fixed rendering of rotated sprites
-added weapons as separate entities to space ship and others
-added Tower enemy to SpaceInvaders demo
-added Boss to SpaceInvaders demo (boss has four tower attached to it)
-Boss towers shoot multiple bullets upon death
-fixed critical bug with demos switching
-fixed critical bug related to adding/removing entities form inside onAdd/onRemove entity callback
-added animation support
-added particles sypport and particles for firing and explostions, and more
-multithreaded rendering now has same rendering order as singlethreaded
-application automaticallu detect host CPU threads count
-added upgrades to SPaceInvaders demo
-fixed texture memory freeing
-improved documentation
-improved multithreaded performance
-improve shader code
-fixed registration issue
-some additional performance improvements
-added depth and colors to rendering parameters
-jobs now has names corresponding to their systems
-change execute() -> willExecute()
-added EntityMeta structure to speedup getting fetching components form entity
-improved multithreading rendering
-added possibility tio change number of threads runtime
-added bullets collision detection in SpaceInvaders demo
-some CI changes
-added VBO batch rendering (current default, no render mode switch yet)
-fixed camera positioning calculation
-fixed buffer issue with WebGL
-added viewport scalling (at least 300 pixels height). Pixels are scalled if screen is bigger.
-center demos gameplay area
-added fullpage html template for Emscripten build
-added many new sprites to atlas
-fixed critical bug with CPU usage in multithreaded mode
-snake render tile coresponding to body part
-snake is destroyed after collision and emit some particles
-added some functionality to vectors
-fixed documentation issue in Manager.d
-more minor code changes and cleanup
2020-05-28 16:48:42 +00:00

250 lines
No EOL
5.7 KiB
D

module game_core.job_updater;
import bubel.ecs.std;
import bubel.ecs.vector;
import bubel.ecs.atomic;
import ecs_utils.utils;
//import core.time;
import bubel.ecs.manager;
import mmutils.thread_pool;
version(LDC)
{
import ldc.attributes;
}
else
{
struct optStrategy {
string strategy;
}
}
//import supre.core.call_graph_generator;
struct ECSJobUpdater
{
this(uint threads)
{
onCreate(threads);
}
~this()
{
pool.waitThreads();
//pool.unregistExternalThread(thread_data);
if(jobs)Mallocator.dispose(jobs);
version(WebAssembly)pthread_key_delete(tls_key);
}
version(WebAssembly)
{
__gshared pthread_key_t tls_key;
}
else static uint thread_id = 0;
ThreadPool pool;
ThreadData* thread_data;
int job_id = 0;
int no_dep_count = 0;
//static uint thread_id = 0;
struct Group
{
~this() nothrow
{
}
JobsGroup group;
JobData[1024] jobs;
JobCaller[1024] callers;
uint count = 0;
string name;
void dependantOn(Group* dependency)
{
group.dependantOn(&dependency.group);
}
void start()
{
group.thPool.addGroupAsynchronous(&group);
}
void build(ThreadPool* pool)
{
group.thPool = pool;
group.jobs = jobs[0..count];
}
void clear()
{
group = JobsGroup("name",null);
count = 0;
}
void add(JobCaller caller)
{
callers[count] = caller;
jobs[count] = JobData(&callers[count].callJob,name);
count++;
}
}
Group[] jobs;
Vector!(Group*) call_jobs;
Group last_job;
JobData[1] groupEndJobs;
//TrackData[32] trackers;
void onCreate(uint threads_count)
{
version(WebAssembly)pthread_key_create(&tls_key, null);
pool.initialize();
thread_data = pool.registerExternalThread();
pool.setThreadsNum(threads_count);
jobs = Mallocator.makeArray!Group(256);
}
uint getThreadID() @nogc nothrow
{
version(WebAssembly)return cast(int)pthread_getspecific(tls_key);
else return thread_id;
}
void begin()
{
job_id = 0;
call_jobs.clear();
foreach(ref job;jobs)
{
job.clear();
}
last_job.clear();
}
void clearTracker()
{
//foreach(ref tracker;trackers)tracker.clear();
}
@optStrategy("none")
void nop()
{
int i;
i++;
}
//@optStrategy("none")
void call()
{
if(last_job.group.getDependenciesWaitCount() == 0)return;
if(call_jobs.length == 0)return;
//JobData[1] groupEndJobs;
groupEndJobs[0] = JobData(&releaseMainThread, "Stop Threads", null, null);
last_job.group.jobs = groupEndJobs;
last_job.group.thPool = &pool;
last_job.group.executeOnThreadNum = 0;
foreach(job;call_jobs)
{
job.start();
}
/*while(atomicLoad(ret) == 1)//!cas(&ret,0,1))
{
nop();
version(WebAssembly)//emscripten_main_thread_process_queued_calls();
}//*/
thread_data.threadStartFunc();
}
void releaseMainThread(ThreadData* th_data, JobData* data)
{
//atomicStore(ret,0);
pool.releaseExternalThreads();
}
static struct JobCaller
{
EntityManager.Job* job;
ECSJobUpdater* updater;
uint id;
void callJob(ThreadData* th_data, JobData* data)
{
//uint job_id = updater.getThreadID();
//updater.trackers[job_id].begin(id);
version(WebAssembly)
{
//updater.thread_id = th_data.threadId;
pthread_setspecific(tls_key, cast(void*)th_data.threadId);
if(th_data.threadId == 0)
{
emscripten_main_thread_process_queued_calls();
job.execute();
emscripten_main_thread_process_queued_calls();
}
else job.execute();
}
else
{
updater.thread_id = th_data.threadId;
job.execute();
}
//atomicOp!"-="(updater.jobs_count,1);
//updater.trackers[job_id].end();
}
}
void dispatch(EntityManager.JobGroup group)
{
if(group.jobs.length == 0)
{
return;
}
jobs[group.id].name = cast(string)group.caller.system.name;
foreach(ref job;group.jobs)
{
uint index = 0;
if(job.callers.length)index = job.callers[0].system_id;
JobCaller caller;
caller.updater = &this;
caller.job = &job;
caller.id = index;
jobs[group.id].add(caller);
}
jobs[group.id].build(&pool);
uint deps = cast(uint)group.dependencies.length;
foreach(dep;group.dependencies)
{
if(jobs[dep.id].count && dep.caller.system.willExecute && dep.caller.system.enabled)jobs[group.id].dependantOn(&jobs[dep.id]);
else deps--;
}
if(deps == 0)
{
call_jobs.add(&jobs[group.id]);
}
last_job.dependantOn(&jobs[group.id]);
}
}