gpu evictor thread
This commit is contained in:
parent
130b90bf7a
commit
af4391300c
304
src/gp_dx12.c
304
src/gp_dx12.c
@ -57,6 +57,21 @@
|
|||||||
#define DX12_NUM_RTV_DESCRIPTORS (1024 * 1)
|
#define DX12_NUM_RTV_DESCRIPTORS (1024 * 1)
|
||||||
#define DX12_COMMAND_BUFFER_MIN_SIZE (1024 * 64)
|
#define DX12_COMMAND_BUFFER_MIN_SIZE (1024 * 64)
|
||||||
|
|
||||||
|
#define DX12_MULTI_QUEUE 1
|
||||||
|
#if DX12_MULTI_QUEUE
|
||||||
|
# define DX12_QUEUE_DIRECT 0
|
||||||
|
# define DX12_QUEUE_COMPUTE 1
|
||||||
|
# define DX12_QUEUE_COPY_CRITICAL 2
|
||||||
|
# define DX12_QUEUE_COPY_BACKGROUND 3
|
||||||
|
# define DX12_NUM_QUEUES 4
|
||||||
|
#else
|
||||||
|
# define DX12_QUEUE_DIRECT 0
|
||||||
|
# define DX12_QUEUE_COMPUTE 0
|
||||||
|
# define DX12_QUEUE_COPY_CRITICAL 0
|
||||||
|
# define DX12_QUEUE_COPY_BACKGROUND 0
|
||||||
|
# define DX12_NUM_QUEUES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#if RTC
|
#if RTC
|
||||||
# define DX12_DEBUG 1
|
# define DX12_DEBUG 1
|
||||||
# define DX12_SHADER_DEBUG 1
|
# define DX12_SHADER_DEBUG 1
|
||||||
@ -200,8 +215,8 @@ struct descriptor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct dx12_resource {
|
struct dx12_resource {
|
||||||
ID3D12Resource *resource;
|
|
||||||
enum D3D12_RESOURCE_STATES state;
|
enum D3D12_RESOURCE_STATES state;
|
||||||
|
ID3D12Resource *resource;
|
||||||
struct descriptor *cbv_descriptor;
|
struct descriptor *cbv_descriptor;
|
||||||
struct descriptor *srv_descriptor;
|
struct descriptor *srv_descriptor;
|
||||||
struct descriptor *uav_descriptor;
|
struct descriptor *uav_descriptor;
|
||||||
@ -242,6 +257,17 @@ struct cpu_descriptor_heap {
|
|||||||
struct D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
struct D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum fenced_release_kind {
|
||||||
|
FENCED_RELEASE_KIND_NONE,
|
||||||
|
FENCED_RELEASE_KIND_RESOURCE,
|
||||||
|
FENCED_RELEASE_KIND_PIPELINE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fenced_release_data {
|
||||||
|
enum fenced_release_kind kind;
|
||||||
|
void *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
enum handle_kind {
|
enum handle_kind {
|
||||||
DX12_HANDLE_KIND_NONE,
|
DX12_HANDLE_KIND_NONE,
|
||||||
DX12_HANDLE_KIND_RESOURCE,
|
DX12_HANDLE_KIND_RESOURCE,
|
||||||
@ -293,6 +319,11 @@ GLOBAL struct {
|
|||||||
struct dict *top_successful_pipelines; /* Latest pipelines that successfully compiled */
|
struct dict *top_successful_pipelines; /* Latest pipelines that successfully compiled */
|
||||||
struct pipeline_scope *first_free_pipeline_scope;
|
struct pipeline_scope *first_free_pipeline_scope;
|
||||||
|
|
||||||
|
/* Fenced release queue */
|
||||||
|
struct sys_mutex *fenced_releases_mutex;
|
||||||
|
struct arena *fenced_releases_arena;
|
||||||
|
u64 fenced_release_targets[DX12_NUM_QUEUES];
|
||||||
|
|
||||||
/* Factory */
|
/* Factory */
|
||||||
IDXGIFactory6 *factory;
|
IDXGIFactory6 *factory;
|
||||||
|
|
||||||
@ -311,16 +342,17 @@ GLOBAL struct {
|
|||||||
struct cpu_descriptor_heap *rtv_heap;
|
struct cpu_descriptor_heap *rtv_heap;
|
||||||
|
|
||||||
/* Command queues */
|
/* Command queues */
|
||||||
/* TODO: Add optional mode to route everything to direct queue */
|
|
||||||
struct sys_mutex *global_command_list_record_mutex;
|
struct sys_mutex *global_command_list_record_mutex;
|
||||||
struct sys_mutex *global_command_list_submit_mutex;
|
struct sys_mutex *global_submit_mutex;
|
||||||
struct command_queue *cq_direct;
|
struct command_queue *command_queues[DX12_NUM_QUEUES];
|
||||||
struct command_queue *cq_compute;
|
|
||||||
struct command_queue *cq_copy_critical;
|
|
||||||
struct command_queue *cq_copy_background;
|
|
||||||
|
|
||||||
/* Swapchain */
|
/* Swapchain */
|
||||||
struct swapchain swapchain;
|
struct swapchain swapchain;
|
||||||
|
|
||||||
|
/* Evictor thread */
|
||||||
|
struct atomic_i32 evictor_thread_shutdown;
|
||||||
|
HANDLE evictor_thread_wake_event;
|
||||||
|
struct sys_thread *evictor_thread;
|
||||||
} G = ZI, DEBUG_ALIAS(G, G_gp_dx12);
|
} G = ZI, DEBUG_ALIAS(G, G_gp_dx12);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -334,7 +366,8 @@ INTERNAL void dx12_init_pipelines(void);
|
|||||||
INTERNAL struct cpu_descriptor_heap *cpu_descriptor_heap_alloc(enum D3D12_DESCRIPTOR_HEAP_TYPE type);
|
INTERNAL struct cpu_descriptor_heap *cpu_descriptor_heap_alloc(enum D3D12_DESCRIPTOR_HEAP_TYPE type);
|
||||||
INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE type, enum D3D12_COMMAND_QUEUE_PRIORITY priority, struct string dbg_name);
|
INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE type, enum D3D12_COMMAND_QUEUE_PRIORITY priority, struct string dbg_name);
|
||||||
INTERNAL void command_queue_release(struct command_queue *cq);
|
INTERNAL void command_queue_release(struct command_queue *cq);
|
||||||
INTERNAL void dx12_resource_release(struct dx12_resource *resource);
|
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(evictor_thread_entry_point, arg);
|
||||||
|
INTERNAL void fenced_release(void *data, enum fenced_release_kind kind);
|
||||||
|
|
||||||
#if RESOURCE_RELOADING
|
#if RESOURCE_RELOADING
|
||||||
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name);
|
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name);
|
||||||
@ -368,6 +401,10 @@ struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr)
|
|||||||
G.top_pipelines = dict_init(G.pipelines_arena, 1024);
|
G.top_pipelines = dict_init(G.pipelines_arena, 1024);
|
||||||
G.top_successful_pipelines = dict_init(G.pipelines_arena, 1024);
|
G.top_successful_pipelines = dict_init(G.pipelines_arena, 1024);
|
||||||
|
|
||||||
|
/* Initialize fenced releases queue */
|
||||||
|
G.fenced_releases_mutex = sys_mutex_alloc();
|
||||||
|
G.fenced_releases_arena = arena_alloc(GIGABYTE(64));
|
||||||
|
|
||||||
/* Initialize dx12 */
|
/* Initialize dx12 */
|
||||||
dx12_init_device();
|
dx12_init_device();
|
||||||
dx12_init_objects();
|
dx12_init_objects();
|
||||||
@ -379,6 +416,10 @@ struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr)
|
|||||||
#endif
|
#endif
|
||||||
app_register_exit_callback(gp_shutdown);
|
app_register_exit_callback(gp_shutdown);
|
||||||
|
|
||||||
|
/* Start evictor thread */
|
||||||
|
G.evictor_thread_wake_event = CreateEvent(NULL, false, false, NULL);
|
||||||
|
G.evictor_thread = sys_thread_alloc(evictor_thread_entry_point, NULL, LIT("[P2] GPU evictor thread"));
|
||||||
|
|
||||||
struct gp_startup_receipt res = ZI;
|
struct gp_startup_receipt res = ZI;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -386,25 +427,27 @@ struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr)
|
|||||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gp_shutdown)
|
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gp_shutdown)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
#if DX12_DEBUG
|
#if 0
|
||||||
/* Release objects to make live object reporting less noisy */
|
/* Release objects to make live object reporting less noisy */
|
||||||
//IDXGISwapChain3_Release(G.swapchain);
|
//IDXGISwapChain3_Release(G.swapchain);
|
||||||
command_queue_release(G.cq_copy_background);
|
for (u32 i = 0; i < ARRAY_COUNT(G.command_queues); ++i) {
|
||||||
command_queue_release(G.cq_copy_critical);
|
struct command_queue *cq = G.command_queues[i];
|
||||||
command_queue_release(G.cq_compute);
|
cmomand_queue_release(cq);
|
||||||
command_queue_release(G.cq_direct);
|
}
|
||||||
ID3D12Device_Release(G.device);
|
ID3D12Device_Release(G.device);
|
||||||
#else
|
#else
|
||||||
(UNUSED)command_queue_release;
|
(UNUSED)command_queue_release;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
atomic_i32_eval_exchange(&G.evictor_thread_shutdown, 1);
|
||||||
|
SetEvent(G.evictor_thread_wake_event);
|
||||||
|
sys_thread_wait_release(G.evictor_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Handle
|
* Handle
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void dx12_resource_release(struct dx12_resource *t);
|
|
||||||
|
|
||||||
INTERNAL struct gp_handle handle_alloc(enum handle_kind kind, void *data)
|
INTERNAL struct gp_handle handle_alloc(enum handle_kind kind, void *data)
|
||||||
{
|
{
|
||||||
u64 old_gen = 0;
|
u64 old_gen = 0;
|
||||||
@ -502,7 +545,7 @@ void gp_release(struct gp_handle handle)
|
|||||||
|
|
||||||
case DX12_HANDLE_KIND_RESOURCE:
|
case DX12_HANDLE_KIND_RESOURCE:
|
||||||
{
|
{
|
||||||
dx12_resource_release(data);
|
fenced_release(data, FENCED_RELEASE_KIND_RESOURCE);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -684,11 +727,18 @@ INTERNAL void dx12_init_objects(void)
|
|||||||
|
|
||||||
/* Create command queues */
|
/* Create command queues */
|
||||||
G.global_command_list_record_mutex = sys_mutex_alloc();
|
G.global_command_list_record_mutex = sys_mutex_alloc();
|
||||||
G.global_command_list_submit_mutex = sys_mutex_alloc();
|
G.global_submit_mutex = sys_mutex_alloc();
|
||||||
G.cq_direct = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Direct queue"));
|
for (u32 i = 0; i < DX12_NUM_QUEUES; ++i) {
|
||||||
G.cq_compute = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Compute queue"));
|
if (i == DX12_QUEUE_DIRECT) {
|
||||||
G.cq_copy_critical = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COPY, D3D12_COMMAND_QUEUE_PRIORITY_HIGH, LIT("High priority copy queue"));
|
G.command_queues[i] = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Direct queue"));
|
||||||
G.cq_copy_background = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COPY, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Background copy queue"));
|
} else if (i == DX12_QUEUE_COMPUTE) {
|
||||||
|
G.command_queues[i] = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Compute queue"));
|
||||||
|
} else if (i == DX12_QUEUE_COPY_CRITICAL) {
|
||||||
|
G.command_queues[i] = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COPY, D3D12_COMMAND_QUEUE_PRIORITY_HIGH, LIT("High priority copy queue"));
|
||||||
|
} else if (i == DX12_QUEUE_COPY_BACKGROUND) {
|
||||||
|
G.command_queues[i] = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COPY, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Background copy queue"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -696,7 +746,6 @@ INTERNAL void dx12_init_objects(void)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void pipeline_alloc_from_desc(u64 num_pipelines, struct pipeline_desc *descs, struct pipeline **pipelines_out);
|
INTERNAL void pipeline_alloc_from_desc(u64 num_pipelines, struct pipeline_desc *descs, struct pipeline **pipelines_out);
|
||||||
INTERNAL void pipeline_release(struct pipeline *pipeline);
|
|
||||||
INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines);
|
INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines);
|
||||||
|
|
||||||
INTERNAL void dx12_init_pipelines(void)
|
INTERNAL void dx12_init_pipelines(void)
|
||||||
@ -1205,17 +1254,13 @@ INTERNAL void pipeline_alloc_from_desc(u64 num_pipelines, struct pipeline_desc *
|
|||||||
work_wait(work);
|
work_wait(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void pipeline_release(struct pipeline *pipeline)
|
INTERNAL void pipeline_release_now(struct pipeline *pipeline)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
/* FIXME: Delayed release based on queue fence */
|
|
||||||
(UNUSED)pipeline;
|
|
||||||
#if 0
|
|
||||||
if (pipeline->pso) {
|
if (pipeline->pso) {
|
||||||
ID3D12PipelineState_Release(pipeline->pso);
|
ID3D12PipelineState_Release(pipeline->pso);
|
||||||
}
|
}
|
||||||
arena_release(pipeline->arena);
|
arena_release(pipeline->arena);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1255,7 +1300,7 @@ INTERNAL void pipeline_scope_end(struct pipeline_scope *scope)
|
|||||||
for (struct dict_entry *entry = scope->refs->first; entry; entry = entry->next) {
|
for (struct dict_entry *entry = scope->refs->first; entry; entry = entry->next) {
|
||||||
struct pipeline *pipeline = (struct pipeline *)entry->value;
|
struct pipeline *pipeline = (struct pipeline *)entry->value;
|
||||||
if (--pipeline->refcount <= 0) {
|
if (--pipeline->refcount <= 0) {
|
||||||
pipeline_release(pipeline);
|
fenced_release(pipeline, FENCED_RELEASE_KIND_PIPELINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope->next_free = G.first_free_pipeline_scope;
|
scope->next_free = G.first_free_pipeline_scope;
|
||||||
@ -1304,7 +1349,7 @@ INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines)
|
|||||||
{
|
{
|
||||||
struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_pipelines, hash);
|
struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_pipelines, hash);
|
||||||
if (old_pipeline && --old_pipeline->refcount <= 0) {
|
if (old_pipeline && --old_pipeline->refcount <= 0) {
|
||||||
pipeline_release(old_pipeline);
|
fenced_release(old_pipeline, FENCED_RELEASE_KIND_PIPELINE);
|
||||||
}
|
}
|
||||||
dict_set(G.pipelines_arena, G.top_pipelines, hash, (u64)pipeline);
|
dict_set(G.pipelines_arena, G.top_pipelines, hash, (u64)pipeline);
|
||||||
++pipeline->refcount;
|
++pipeline->refcount;
|
||||||
@ -1313,7 +1358,7 @@ INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines)
|
|||||||
if (pipeline->success) {
|
if (pipeline->success) {
|
||||||
struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_successful_pipelines, hash);
|
struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_successful_pipelines, hash);
|
||||||
if (old_pipeline && --old_pipeline->refcount <= 0) {
|
if (old_pipeline && --old_pipeline->refcount <= 0) {
|
||||||
pipeline_release(old_pipeline);
|
fenced_release(old_pipeline, FENCED_RELEASE_KIND_PIPELINE);
|
||||||
}
|
}
|
||||||
dict_set(G.pipelines_arena, G.top_successful_pipelines, hash, (u64)pipeline);
|
dict_set(G.pipelines_arena, G.top_successful_pipelines, hash, (u64)pipeline);
|
||||||
++pipeline->refcount;
|
++pipeline->refcount;
|
||||||
@ -1614,6 +1659,38 @@ i32 gp_push_cmd(struct gp_flow *gp_flow, struct gp_cmd_desc *cmd_desc)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Fenced release
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
INTERNAL void fenced_release(void *data, enum fenced_release_kind kind)
|
||||||
|
{
|
||||||
|
struct fenced_release_data fr = ZI;
|
||||||
|
fr.kind = kind;
|
||||||
|
fr.ptr = data;
|
||||||
|
|
||||||
|
u64 fr_targets[ARRAY_COUNT(G.fenced_release_targets)] = ZI;
|
||||||
|
|
||||||
|
/* Read fence values */
|
||||||
|
for (u32 i = 0; i < ARRAY_COUNT(G.command_queues); ++i) {
|
||||||
|
struct command_queue *cq = G.command_queues[i];
|
||||||
|
struct sys_lock lock = sys_mutex_lock_s(cq->submit_fence_mutex);
|
||||||
|
fr_targets[i] = cq->submit_fence_target;
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push data to release queue */
|
||||||
|
{
|
||||||
|
struct sys_lock lock = sys_mutex_lock_e(G.fenced_releases_mutex);
|
||||||
|
*arena_push(G.fenced_releases_arena, struct fenced_release_data) = fr;
|
||||||
|
MEMCPY(G.fenced_release_targets, fr_targets, sizeof(fr_targets));
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wake evictor */
|
||||||
|
SetEvent(G.evictor_thread_wake_event);
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Resource
|
* Resource
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -1681,11 +1758,33 @@ INTERNAL struct dx12_resource *dx12_resource_alloc(D3D12_HEAP_PROPERTIES heap_pr
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void dx12_resource_release(struct dx12_resource *t)
|
INTERNAL void dx12_resource_release_now(struct dx12_resource *t)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
/* TODO */
|
|
||||||
(UNUSED)t;
|
/* Release descriptors */
|
||||||
|
/* TODO: Batch lock heaps */
|
||||||
|
if (t->cbv_descriptor) {
|
||||||
|
descriptor_release(t->cbv_descriptor);
|
||||||
|
}
|
||||||
|
if (t->srv_descriptor) {
|
||||||
|
descriptor_release(t->srv_descriptor);
|
||||||
|
}
|
||||||
|
if (t->uav_descriptor) {
|
||||||
|
descriptor_release(t->uav_descriptor);
|
||||||
|
}
|
||||||
|
if (t->rtv_descriptor) {
|
||||||
|
descriptor_release(t->rtv_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release resource */
|
||||||
|
ID3D12Resource_Release(t->resource);
|
||||||
|
|
||||||
|
/* Add to free list */
|
||||||
|
struct sys_lock lock = sys_mutex_lock_e(G.resources_mutex);
|
||||||
|
t->next_free = G.first_free_resource;
|
||||||
|
G.first_free_resource = t;
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL enum D3D12_RESOURCE_STATES dx12_resource_barrier(ID3D12GraphicsCommandList *cl, struct dx12_resource *resource, enum D3D12_RESOURCE_STATES state)
|
INTERNAL enum D3D12_RESOURCE_STATES dx12_resource_barrier(ID3D12GraphicsCommandList *cl, struct dx12_resource *resource, enum D3D12_RESOURCE_STATES state)
|
||||||
@ -1755,7 +1854,7 @@ INTERNAL void command_queue_release(struct command_queue *cq)
|
|||||||
__prof;
|
__prof;
|
||||||
/* TODO */
|
/* TODO */
|
||||||
(UNUSED)cq;
|
(UNUSED)cq;
|
||||||
//ID3D12CommandQueue_Release(G.cq_copy_background->cq);
|
//ID3D12CommandQueue_Release(cq->cq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1875,7 +1974,7 @@ INTERNAL u64 command_list_close(struct command_list *cl)
|
|||||||
u64 submit_fence_target = 0;
|
u64 submit_fence_target = 0;
|
||||||
{
|
{
|
||||||
__profscope(Execute);
|
__profscope(Execute);
|
||||||
struct sys_lock global_lock = sys_mutex_lock_s(G.global_command_list_submit_mutex);
|
struct sys_lock submit_lock = sys_mutex_lock_s(G.global_submit_mutex);
|
||||||
struct sys_lock fence_lock = sys_mutex_lock_e(cq->submit_fence_mutex);
|
struct sys_lock fence_lock = sys_mutex_lock_e(cq->submit_fence_mutex);
|
||||||
{
|
{
|
||||||
submit_fence_target = ++cq->submit_fence_target;
|
submit_fence_target = ++cq->submit_fence_target;
|
||||||
@ -1883,7 +1982,7 @@ INTERNAL u64 command_list_close(struct command_list *cl)
|
|||||||
ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target);
|
ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target);
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&fence_lock);
|
sys_mutex_unlock(&fence_lock);
|
||||||
sys_mutex_unlock(&global_lock);
|
sys_mutex_unlock(&submit_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add descriptor heaps to submitted list */
|
/* Add descriptor heaps to submitted list */
|
||||||
@ -2333,7 +2432,7 @@ struct gp_handle gp_texture_alloc(enum gp_texture_format format, u32 flags, stru
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Copy from upload heap to texture */
|
/* Copy from upload heap to texture */
|
||||||
struct command_queue *cq = G.cq_copy_background;
|
struct command_queue *cq = G.command_queues[DX12_QUEUE_COPY_BACKGROUND];
|
||||||
struct command_list *cl = command_list_open(cq->cl_pool);
|
struct command_list *cl = command_list_open(cq->cl_pool);
|
||||||
{
|
{
|
||||||
__profscope_dx12(cl->cq->prof, cl->cl, Upload texture, RGB32_F(0.2, 0.5, 0.2));
|
__profscope_dx12(cl->cq->prof, cl->cl, Upload texture, RGB32_F(0.2, 0.5, 0.2));
|
||||||
@ -2359,7 +2458,7 @@ struct gp_handle gp_texture_alloc(enum gp_texture_format format, u32 flags, stru
|
|||||||
/* TODO: Return async waitable to caller */
|
/* TODO: Return async waitable to caller */
|
||||||
{
|
{
|
||||||
__profscope(Wait for upload);
|
__profscope(Wait for upload);
|
||||||
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
HANDLE event = CreateEvent(NULL, false, false, NULL);
|
||||||
ID3D12Fence_SetEventOnCompletion(cq->submit_fence, fence_target, event);
|
ID3D12Fence_SetEventOnCompletion(cq->submit_fence, fence_target, event);
|
||||||
WaitForSingleObject(event, INFINITE);
|
WaitForSingleObject(event, INFINITE);
|
||||||
CloseHandle(event);
|
CloseHandle(event);
|
||||||
@ -2401,7 +2500,8 @@ void gp_dispatch(struct gp_dispatch_params params)
|
|||||||
struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
|
struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
|
||||||
struct pipeline *material_pipeline = pipeline_from_name(pipeline_scope, LIT("material"));
|
struct pipeline *material_pipeline = pipeline_from_name(pipeline_scope, LIT("material"));
|
||||||
struct pipeline *shape_pipeline = pipeline_from_name(pipeline_scope, LIT("shape"));
|
struct pipeline *shape_pipeline = pipeline_from_name(pipeline_scope, LIT("shape"));
|
||||||
struct command_list *cl = command_list_open(G.cq_direct->cl_pool);
|
struct command_queue *cq = G.command_queues[DX12_QUEUE_DIRECT];
|
||||||
|
struct command_list *cl = command_list_open(cq->cl_pool);
|
||||||
{
|
{
|
||||||
__profscope_dx12(cl->cq->prof, cl->cl, Dispatch, RGB32_F(0.5, 0.2, 0.2));
|
__profscope_dx12(cl->cq->prof, cl->cl, Dispatch, RGB32_F(0.5, 0.2, 0.2));
|
||||||
struct dx12_resource *target = handle_get_data(params.draw_target, DX12_HANDLE_KIND_RESOURCE);
|
struct dx12_resource *target = handle_get_data(params.draw_target, DX12_HANDLE_KIND_RESOURCE);
|
||||||
@ -2616,21 +2716,21 @@ INTERNAL struct swapchain_buffer *update_swapchain(struct swapchain *swapchain,
|
|||||||
b32 should_rebuild = !v2i32_eq(swapchain->resolution, resolution);
|
b32 should_rebuild = !v2i32_eq(swapchain->resolution, resolution);
|
||||||
if (should_rebuild) {
|
if (should_rebuild) {
|
||||||
HRESULT hr = 0;
|
HRESULT hr = 0;
|
||||||
struct command_queue *cq = G.cq_direct;
|
struct command_queue *cq = G.command_queues[DX12_QUEUE_DIRECT];
|
||||||
HWND hwnd = (HWND)sys_window_get_internal_handle(window);
|
HWND hwnd = (HWND)sys_window_get_internal_handle(window);
|
||||||
if (swapchain->swapchain) {
|
if (swapchain->swapchain) {
|
||||||
ASSERT(hwnd == swapchain->hwnd);
|
ASSERT(hwnd == swapchain->hwnd);
|
||||||
|
|
||||||
/* Lock direct queue submissions (in case any write to backbuffer) */
|
/* Lock direct queue submissions (in case any write to backbuffer) */
|
||||||
/* TODO: Less overkill approach - Only flush present_blit since we know it's the only operation targeting backbuffer */
|
/* TODO: Less overkill approach - Only flush present_blit since we know it's the only operation targeting backbuffer */
|
||||||
//struct sys_lock lock = sys_mutex_lock_e(cq->submit_fence_mutex);
|
struct sys_lock lock = sys_mutex_lock_e(cq->submit_fence_mutex);
|
||||||
DEBUGBREAKABLE;
|
//DEBUGBREAKABLE;
|
||||||
struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_record_mutex);
|
//struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_record_mutex);
|
||||||
{
|
{
|
||||||
/* Flush direct queue */
|
/* Flush direct queue */
|
||||||
//ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target);
|
//ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target);
|
||||||
{
|
{
|
||||||
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
HANDLE event = CreateEvent(NULL, false, false, NULL);
|
||||||
ID3D12Fence_SetEventOnCompletion(cq->submit_fence, cq->submit_fence_target, event);
|
ID3D12Fence_SetEventOnCompletion(cq->submit_fence, cq->submit_fence_target, event);
|
||||||
WaitForSingleObject(event, INFINITE);
|
WaitForSingleObject(event, INFINITE);
|
||||||
CloseHandle(event);
|
CloseHandle(event);
|
||||||
@ -2720,7 +2820,8 @@ INTERNAL void present_blit(struct swapchain_buffer *dst, struct dx12_resource *s
|
|||||||
struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
|
struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
|
||||||
struct pipeline *blit_pipeline = pipeline_from_name(pipeline_scope, LIT("blit"));
|
struct pipeline *blit_pipeline = pipeline_from_name(pipeline_scope, LIT("blit"));
|
||||||
if (blit_pipeline->success) {
|
if (blit_pipeline->success) {
|
||||||
struct command_list *cl = command_list_open(G.cq_direct->cl_pool);
|
struct command_queue *cq = G.command_queues[DX12_QUEUE_DIRECT];
|
||||||
|
struct command_list *cl = command_list_open(cq->cl_pool);
|
||||||
{
|
{
|
||||||
__profscope_dx12(cl->cq->prof, cl->cl, Blit, RGB32_F(0.5, 0.2, 0.2));
|
__profscope_dx12(cl->cq->prof, cl->cl, Blit, RGB32_F(0.5, 0.2, 0.2));
|
||||||
struct swapchain *swapchain = dst->swapchain;
|
struct swapchain *swapchain = dst->swapchain;
|
||||||
@ -2838,18 +2939,18 @@ void gp_present(struct sys_window *window, struct v2i32 backresolution, struct g
|
|||||||
__profscope(Mark queue frames);
|
__profscope(Mark queue frames);
|
||||||
/* Lock because frame marks shouldn't occur while command lists are recording */
|
/* Lock because frame marks shouldn't occur while command lists are recording */
|
||||||
struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_record_mutex);
|
struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_record_mutex);
|
||||||
__prof_dx12_new_frame(G.cq_direct->prof);
|
for (u32 i = 0; i < ARRAY_COUNT(G.command_queues); ++i) {
|
||||||
__prof_dx12_new_frame(G.cq_compute->prof);
|
struct command_queue *cq = G.command_queues[i];
|
||||||
__prof_dx12_new_frame(G.cq_copy_critical->prof);
|
__prof_dx12_new_frame(cq->prof);
|
||||||
__prof_dx12_new_frame(G.cq_copy_background->prof);
|
}
|
||||||
sys_mutex_unlock(&lock);
|
sys_mutex_unlock(&lock);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
__profscope(Collect queues);
|
__profscope(Collect queues);
|
||||||
__prof_dx12_collect(G.cq_direct->prof);
|
for (u32 i = 0; i < ARRAY_COUNT(G.command_queues); ++i) {
|
||||||
__prof_dx12_collect(G.cq_compute->prof);
|
struct command_queue *cq = G.command_queues[i];
|
||||||
__prof_dx12_collect(G.cq_copy_critical->prof);
|
__prof_dx12_collect(cq->prof);
|
||||||
__prof_dx12_collect(G.cq_copy_background->prof);
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2860,7 +2961,104 @@ void gp_present(struct sys_window *window, struct v2i32 backresolution, struct g
|
|||||||
(UNUSED)vsync;
|
(UNUSED)vsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Evictor thread
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(evictor_thread_entry_point, arg)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
(UNUSED)arg;
|
||||||
|
struct arena_temp scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
HANDLE event = CreateEvent(NULL, false, false, NULL);
|
||||||
|
HANDLE events[2] = ZI;
|
||||||
|
events[0] = G.evictor_thread_wake_event;
|
||||||
|
events[1] = event;
|
||||||
|
|
||||||
|
u64 completed_targets[DX12_NUM_QUEUES] = ZI;
|
||||||
|
|
||||||
|
b32 shutdown = atomic_i32_eval(&G.evictor_thread_shutdown);
|
||||||
|
while (!shutdown) {
|
||||||
|
struct arena_temp temp = arena_temp_begin(scratch.arena);
|
||||||
|
{
|
||||||
|
__profscope(Run);
|
||||||
|
|
||||||
|
u64 targets[ARRAY_COUNT(completed_targets)] = ZI;
|
||||||
|
|
||||||
|
/* Copy queued data */
|
||||||
|
u32 num_fenced_releases = 0;
|
||||||
|
struct fenced_release_data *fenced_releases = NULL;
|
||||||
|
{
|
||||||
|
__profscope(Copy queued releases);
|
||||||
|
struct sys_lock lock = sys_mutex_lock_e(G.fenced_releases_mutex);
|
||||||
|
num_fenced_releases = G.fenced_releases_arena->pos / sizeof(struct fenced_release_data);
|
||||||
|
fenced_releases = arena_push_array_no_zero(temp.arena, struct fenced_release_data, num_fenced_releases);
|
||||||
|
MEMCPY(fenced_releases, arena_base(G.fenced_releases_arena), G.fenced_releases_arena->pos);
|
||||||
|
arena_reset(G.fenced_releases_arena);
|
||||||
|
MEMCPY(targets, G.fenced_release_targets, sizeof(targets));
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until fences reach target */
|
||||||
|
{
|
||||||
|
__profscope(Check fences);
|
||||||
|
for (u32 i = 0; i < ARRAY_COUNT(targets) && !shutdown; ++i) {
|
||||||
|
while (completed_targets[i] < targets[i] && !shutdown) {
|
||||||
|
struct command_queue *cq = G.command_queues[i];
|
||||||
|
completed_targets[i] = ID3D12Fence_GetCompletedValue(cq->submit_fence);
|
||||||
|
if (completed_targets[i] < targets[i]) {
|
||||||
|
ID3D12Fence_SetEventOnCompletion(cq->submit_fence, targets[i], event);
|
||||||
|
{
|
||||||
|
__profscope(Wait on fence);
|
||||||
|
WaitForMultipleObjects(2, events, false, INFINITE);
|
||||||
|
shutdown = atomic_i32_eval(&G.evictor_thread_shutdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process releases */
|
||||||
|
if (!shutdown) {
|
||||||
|
__profscope(Release);
|
||||||
|
for (u32 i = 0; i < num_fenced_releases; ++i) {
|
||||||
|
struct fenced_release_data *fr = &fenced_releases[i];
|
||||||
|
switch (fr->kind) {
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/* Unknown handle type */
|
||||||
|
ASSERT(false);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FENCED_RELEASE_KIND_RESOURCE:
|
||||||
|
{
|
||||||
|
struct dx12_resource *resource = (struct dx12_resource *)fr->ptr;
|
||||||
|
dx12_resource_release_now(resource);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case FENCED_RELEASE_KIND_PIPELINE:
|
||||||
|
{
|
||||||
|
struct pipeline *pipeline = (struct pipeline *)fr->ptr;
|
||||||
|
pipeline_release_now(pipeline);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arena_temp_end(temp);
|
||||||
|
{
|
||||||
|
__profscope(Sleep);
|
||||||
|
WaitForSingleObject(G.evictor_thread_wake_event, INFINITE);
|
||||||
|
shutdown = atomic_i32_eval(&G.evictor_thread_shutdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release event */
|
||||||
|
CloseHandle(event);
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user