|
|
|
@ -16,25 +16,6 @@ typedef struct ClientContextStruct {
|
|
|
|
|
UIContext ui;
|
|
|
|
|
} ClientContext;
|
|
|
|
|
|
|
|
|
|
void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui, uint32_t frame) {
|
|
|
|
|
UIPushConstant push = {
|
|
|
|
|
.time = 0.0,
|
|
|
|
|
.layer = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, ui->string_pipeline.pipeline);
|
|
|
|
|
for(uint32_t i = 0; i < ui->max_containers; i++) {
|
|
|
|
|
if(ui->containers[i].id != 0x00000000) {
|
|
|
|
|
for(uint32_t j = 0; j < ui->containers[i].layer_count; j++) {
|
|
|
|
|
push.layer = ui->containers[i].layers[j].address[frame];
|
|
|
|
|
command_copy_buffer(command_buffer, ui->containers[i].layers[j].layer[frame], ui->containers[i].layers[j].layer[frame], offsetof(GPULayer, num_drawables), offsetof(GPULayer, draw) + offsetof(DrawCommand, instance_count), sizeof(uint32_t));
|
|
|
|
|
vkCmdPushConstants(command_buffer, ui->string_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 16, &push);
|
|
|
|
|
vkCmdDispatchIndirect(command_buffer, ui->containers[i].layers[j].layer[frame], offsetof(GPULayer, dispatch_strings));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkResult test_ui(RenderContext* gpu, UIContext* ui) {
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
@ -173,39 +154,6 @@ VkResult test_ui(RenderContext* gpu, UIContext* ui) {
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Threads:
|
|
|
|
|
// 1. render
|
|
|
|
|
// - Submits the draw buffer to the GPU as soon as it can
|
|
|
|
|
// 2. network
|
|
|
|
|
// - Handles packets to/from the network to/from the main thread
|
|
|
|
|
// 3. main
|
|
|
|
|
// - updates the data in the GPU that's being drawn from
|
|
|
|
|
// - updates the data in the GPU from network requests
|
|
|
|
|
//
|
|
|
|
|
// Data:
|
|
|
|
|
// Render thread reads Render and UI context
|
|
|
|
|
// Main thread reads and writes UI context
|
|
|
|
|
|
|
|
|
|
void* render_thread(void* data) {
|
|
|
|
|
ClientContext* context = (ClientContext*)data;
|
|
|
|
|
|
|
|
|
|
double last_frame_time = glfwGetTime();
|
|
|
|
|
while(glfwWindowShouldClose(context->window) == 0) {
|
|
|
|
|
double frame_time = glfwGetTime();
|
|
|
|
|
double delta_time = frame_time - last_frame_time;
|
|
|
|
|
(void)delta_time;
|
|
|
|
|
|
|
|
|
|
VkResult result = draw_frame(&context->render, &context->ui, frame_time);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result));
|
|
|
|
|
glfwDestroyWindow(context->window);
|
|
|
|
|
}
|
|
|
|
|
last_frame_time = frame_time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* network_thread(void* data) {
|
|
|
|
|
ClientContext* context = (ClientContext*)data;
|
|
|
|
|
(void)context;
|
|
|
|
@ -213,46 +161,82 @@ void* network_thread(void* data) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main_thread(void* data) {
|
|
|
|
|
ClientContext* context = (ClientContext*)data;
|
|
|
|
|
int main_thread(ClientContext* context) {
|
|
|
|
|
GPUString fps_string = {
|
|
|
|
|
.pos = {0, 32},
|
|
|
|
|
.size = 32,
|
|
|
|
|
.color = {1.0, 1.0, 1.0, 1.0},
|
|
|
|
|
.offset = 0,
|
|
|
|
|
.length = 4,
|
|
|
|
|
.font = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LayerInput fps_layer = {
|
|
|
|
|
.num_strings = 1,
|
|
|
|
|
.strings = &fps_string,
|
|
|
|
|
.max_codes = 10,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ContainerInput fps_container = {
|
|
|
|
|
.id = 1,
|
|
|
|
|
.size = {200, 200},
|
|
|
|
|
.layer_count = 1,
|
|
|
|
|
.layers = &fps_layer,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int x = 0;
|
|
|
|
|
create_container(&fps_container, &context->render, &context->ui);
|
|
|
|
|
|
|
|
|
|
double last_draw = -1;
|
|
|
|
|
double draw_interval = 1;
|
|
|
|
|
double frame_count = 0;
|
|
|
|
|
while(glfwWindowShouldClose(context->window) == 0) {
|
|
|
|
|
glfwPollEvents();
|
|
|
|
|
if(x == 0 && glfwGetTime() > 0.0) {
|
|
|
|
|
x = 1;
|
|
|
|
|
test_ui(&context->render, &context->ui);
|
|
|
|
|
double frame_time = glfwGetTime();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if(frame_time - last_draw > draw_interval) {
|
|
|
|
|
context->render.frame[context->render.current_frame].transfer_count = 2;
|
|
|
|
|
|
|
|
|
|
TransferInfo* transfer_infos = context->render.frame[context->render.current_frame].transfer_infos;
|
|
|
|
|
transfer_infos[0].size = 10*sizeof(uint32_t);
|
|
|
|
|
transfer_infos[0].dst_offset = 0;
|
|
|
|
|
transfer_infos[0].buffers[0] = context->ui.containers[0].layers[0].codes[0];
|
|
|
|
|
transfer_infos[0].buffers[1] = context->ui.containers[0].layers[0].codes[1];
|
|
|
|
|
|
|
|
|
|
transfer_infos[1].size = sizeof(GPUString);
|
|
|
|
|
transfer_infos[1].dst_offset = 0;
|
|
|
|
|
transfer_infos[1].buffers[0] = context->ui.containers[0].layers[0].strings[0];
|
|
|
|
|
transfer_infos[1].buffers[1] = context->ui.containers[0].layers[0].strings[1];
|
|
|
|
|
|
|
|
|
|
void* mapped = context->render.frame[context->render.current_frame].transfer_mapped;
|
|
|
|
|
uint32_t* mapped_codes = (uint32_t*)mapped;
|
|
|
|
|
GPUString* mapped_string = (GPUString*)(mapped + 10*sizeof(uint32_t));
|
|
|
|
|
char str[11];
|
|
|
|
|
snprintf(str, 11, "%3.2f", frame_count/(frame_time-last_draw));
|
|
|
|
|
map_string(str, mapped_codes, 0, 0, &context->ui);
|
|
|
|
|
mapped_string->size = 32;
|
|
|
|
|
mapped_string->pos[0] = 0;
|
|
|
|
|
mapped_string->pos[1] = 32;
|
|
|
|
|
mapped_string->color[0] = 1.0;
|
|
|
|
|
mapped_string->color[1] = 1.0;
|
|
|
|
|
mapped_string->color[2] = 1.0;
|
|
|
|
|
mapped_string->color[3] = 1.0;
|
|
|
|
|
mapped_string->font = 0;
|
|
|
|
|
mapped_string->offset = 0;
|
|
|
|
|
mapped_string->length = strlen(str);
|
|
|
|
|
|
|
|
|
|
last_draw = frame_time;
|
|
|
|
|
frame_count = 0;
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(context->render.device, context->render.transfer_pool);
|
|
|
|
|
record_ui_compute(command_buffer, &context->ui, i);
|
|
|
|
|
vkEndCommandBuffer(command_buffer);
|
|
|
|
|
FrameSync id = increment_transfer(&context->render.frame[i].id);
|
|
|
|
|
VkSemaphore wait_semaphores[] = {context->render.frame[i].transfer, context->render.frame[i].frame};
|
|
|
|
|
uint64_t wait_values[] = {id.transfer, id.frame};
|
|
|
|
|
uint64_t signal_values[] = {id.transfer+1};
|
|
|
|
|
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT};
|
|
|
|
|
VkTimelineSemaphoreSubmitInfo timeline_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
|
|
|
|
|
.pSignalSemaphoreValues = signal_values,
|
|
|
|
|
.signalSemaphoreValueCount = 1,
|
|
|
|
|
.pWaitSemaphoreValues = wait_values,
|
|
|
|
|
.waitSemaphoreValueCount = 2,
|
|
|
|
|
};
|
|
|
|
|
VkSubmitInfo submit_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
|
.pCommandBuffers = &command_buffer,
|
|
|
|
|
.signalSemaphoreCount = 1,
|
|
|
|
|
.pSignalSemaphores = &context->render.frame[i].transfer,
|
|
|
|
|
.waitSemaphoreCount = 2,
|
|
|
|
|
.pWaitSemaphores = wait_semaphores,
|
|
|
|
|
.pWaitDstStageMask = wait_stages,
|
|
|
|
|
.pNext = &timeline_info,
|
|
|
|
|
};
|
|
|
|
|
vkQueueSubmit(context->render.transfer_queue.handle, 1, &submit_info, VK_NULL_HANDLE);
|
|
|
|
|
VkResult result = draw_frame(&context->render, &context->ui, frame_time);
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result));
|
|
|
|
|
glfwDestroyWindow(context->window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
frame_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -327,15 +311,8 @@ int main() {
|
|
|
|
|
// TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary
|
|
|
|
|
VK_RESULT(create_ui_context(10, 10, 10, &context.render, &context.ui));
|
|
|
|
|
|
|
|
|
|
// Start threads
|
|
|
|
|
pthread_t render_thread_handle;
|
|
|
|
|
pthread_t network_thread_handle;
|
|
|
|
|
|
|
|
|
|
error = pthread_create(&render_thread_handle, NULL, &render_thread, &context);
|
|
|
|
|
if(error != 0) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error = pthread_create(&network_thread_handle, NULL, &network_thread, &context);
|
|
|
|
|
if(error != 0) {
|
|
|
|
|
return error;
|
|
|
|
@ -346,11 +323,6 @@ int main() {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error = pthread_join(render_thread_handle, NULL);
|
|
|
|
|
if(error != 0) {
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error = pthread_join(network_thread_handle, NULL);
|
|
|
|
|
if(error != 0) {
|
|
|
|
|
return error;
|
|
|
|
|