pl-template/src/app.c

622 lines
25 KiB
C

/*
app.c
- template app
- loads only stable APIs
*/
/*
Index of this file:
// [SECTION] includes
// [SECTION] structs
// [SECTION] apis
// [SECTION] helper functions forward declarations
// [SECTION] pl_app_load
// [SECTION] pl_app_shutdown
// [SECTION] pl_app_resize
// [SECTION] pl_app_update
// [SECTION] helper functions implementations
*/
//-----------------------------------------------------------------------------
// [SECTION] includes
//-----------------------------------------------------------------------------
#include <stdlib.h> // malloc, free
#include <string.h> // memset
#include "pl.h"
#include "pl_memory.h"
#define PL_MATH_INCLUDE_FUNCTIONS
#include "pl_math.h"
// extensions
#include "pl_log_ext.h"
#include "pl_window_ext.h"
#include "pl_shader_ext.h"
#include "pl_draw_ext.h"
#include "pl_ui_ext.h"
#include "pl_graphics_ext.h"
#include "pl_draw_backend_ext.h"
#include "pl_profile_ext.h"
#include "pl_stats_ext.h"
#include "pl_job_ext.h"
#include "pl_string_intern_ext.h"
#include "pl_network_ext.h"
#include "pl_threads_ext.h"
#include "pl_atomics_ext.h"
#include "pl_library_ext.h"
#include "pl_file_ext.h"
#include "pl_rect_pack_ext.h"
#include "pl_gpu_allocators_ext.h"
#include "pl_image_ext.h"
#include "pl_virtual_memory_ext.h"
#include "pl_console_ext.h"
#include "pl_screen_log_ext.h"
#include "pl_debug_ext.h" // not technically stable
// example extensions
#include "pl_example_ext.h"
//-----------------------------------------------------------------------------
// [SECTION] structs
//-----------------------------------------------------------------------------
typedef struct _plAppData
{
// window
plWindow* ptWindow;
// drawing stuff
plDrawList2D* ptDrawlist;
plDrawLayer2D* ptFGLayer;
plDrawLayer2D* ptBGLayer;
plFont* ptDefaultFont;
// ui options
bool bShowUiDebug;
bool bShowUiStyle;
bool* pbShowDeviceMemoryAnalyzer;
bool* pbShowMemoryAllocations;
bool* pbShowProfiling;
bool* pbShowStats;
bool* pbShowLogging;
// graphics & sync objects
plDevice* ptDevice;
plSurface* ptSurface;
plSwapchain* ptSwapchain;
plTimelineSemaphore* aptSemaphores[PL_MAX_FRAMES_IN_FLIGHT];
uint64_t aulNextTimelineValue[PL_MAX_FRAMES_IN_FLIGHT];
plCommandPool* atCmdPools[PL_MAX_FRAMES_IN_FLIGHT];
plRenderPassHandle tMainRenderPass;
plRenderPassLayoutHandle tMainRenderPassLayout;
} plAppData;
//-----------------------------------------------------------------------------
// [SECTION] apis
//-----------------------------------------------------------------------------
const plMemoryI* gptMemory = NULL;
const plIOI* gptIO = NULL;
const plWindowI* gptWindows = NULL;
const plGraphicsI* gptGfx = NULL;
const plDrawI* gptDraw = NULL;
const plUiI* gptUi = NULL;
const plShaderI* gptShader = NULL;
const plDrawBackendI* gptDrawBackend = NULL;
const plProfileI* gptProfile = NULL;
const plExampleI* gptExample = NULL;
const plStatsI* gptStats = NULL;
const plDebugApiI* gptDebug = NULL;
const plImageI* gptImage = NULL;
const plGPUAllocatorsI* gptGpuAllocators = NULL;
const plJobI* gptJob = NULL;
const plThreadsI* gptThreads = NULL;
const plAtomicsI* gptAtomics = NULL;
const plRectPackI* gptRect = NULL;
const plFileI* gptFile = NULL;
const plNetworkI* gptNetwork = NULL;
const plStringInternI* gptString = NULL;
const plLibraryI* gptLibrary = NULL;
const plLogI* gptLog = NULL;
const plVirtualMemoryI* gptVirtualMemory = NULL;
const plConsoleI* gptConsole = NULL;
const plScreenLogI* gptScreenLog = NULL;
// helpers
#define PL_ALLOC(x) gptMemory->tracked_realloc(NULL, (x), __FILE__, __LINE__)
#define PL_REALLOC(x, y) gptMemory->tracked_realloc((x), (y), __FILE__, __LINE__)
#define PL_FREE(x) gptMemory->tracked_realloc((x), 0, __FILE__, __LINE__)
#define PL_DS_ALLOC(x) gptMemory->tracked_realloc(NULL, (x), __FILE__, __LINE__)
#define PL_DS_ALLOC_INDIRECT(x, FILE, LINE) gptMemory->tracked_realloc(NULL, (x), FILE, LINE)
#define PL_DS_FREE(x) gptMemory->tracked_realloc((x), 0, __FILE__, __LINE__)
#include "pl_ds.h"
//-----------------------------------------------------------------------------
// [SECTION] helper functions forward declarations
//-----------------------------------------------------------------------------
void pl__setup_graphics_extensions (plAppData*);
void pl__resize_graphics_extensions(plAppData*);
void pl__resize_graphics_extensions(plAppData*);
//-----------------------------------------------------------------------------
// [SECTION] pl_app_load
//-----------------------------------------------------------------------------
PL_EXPORT void*
pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
{
// NOTE: on first load, "ptAppData" will be NULL but on reloads
// it will be the value returned from this function
// retrieve the data registry API, this is the API used for sharing data
// between extensions & the runtime
const plDataRegistryI* ptDataRegistry = pl_get_api_latest(ptApiRegistry, plDataRegistryI);
// if "ptAppData" is a valid pointer, then this function is being called
// during a hot reload.
if(ptAppData)
{
// re-retrieve the apis since we are now in
// a different dll/so
gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI);
gptIO = pl_get_api_latest(ptApiRegistry, plIOI);
gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI);
gptGfx = pl_get_api_latest(ptApiRegistry, plGraphicsI);
gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI);
gptShader = pl_get_api_latest(ptApiRegistry, plShaderI);
gptDrawBackend = pl_get_api_latest(ptApiRegistry, plDrawBackendI);
gptUi = pl_get_api_latest(ptApiRegistry, plUiI);
gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI);
gptStats = pl_get_api_latest(ptApiRegistry, plStatsI);
gptExample = pl_get_api_latest(ptApiRegistry, plExampleI);
gptDebug = pl_get_api_latest(ptApiRegistry, plDebugApiI);
gptImage = pl_get_api_latest(ptApiRegistry, plImageI);
gptGpuAllocators = pl_get_api_latest(ptApiRegistry, plGPUAllocatorsI);
gptJob = pl_get_api_latest(ptApiRegistry, plJobI);
gptThreads = pl_get_api_latest(ptApiRegistry, plThreadsI);
gptAtomics = pl_get_api_latest(ptApiRegistry, plAtomicsI);
gptRect = pl_get_api_latest(ptApiRegistry, plRectPackI);
gptFile = pl_get_api_latest(ptApiRegistry, plFileI);
gptNetwork = pl_get_api_latest(ptApiRegistry, plNetworkI);
gptString = pl_get_api_latest(ptApiRegistry, plStringInternI);
gptLibrary = pl_get_api_latest(ptApiRegistry, plLibraryI);
gptLog = pl_get_api_latest(ptApiRegistry, plLogI);
gptVirtualMemory = pl_get_api_latest(ptApiRegistry, plVirtualMemoryI);
gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI);
gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
return ptAppData;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~apis & extensions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// retrieve extension registry
const plExtensionRegistryI* ptExtensionRegistry = pl_get_api_latest(ptApiRegistry, plExtensionRegistryI);
// load extensions
ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, false);
ptExtensionRegistry->load("pl_example_ext", NULL, NULL, true);
// load apis
gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI);
gptIO = pl_get_api_latest(ptApiRegistry, plIOI);
gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI);
gptGfx = pl_get_api_latest(ptApiRegistry, plGraphicsI);
gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI);
gptShader = pl_get_api_latest(ptApiRegistry, plShaderI);
gptDrawBackend = pl_get_api_latest(ptApiRegistry, plDrawBackendI);
gptUi = pl_get_api_latest(ptApiRegistry, plUiI);
gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI);
gptStats = pl_get_api_latest(ptApiRegistry, plStatsI);
gptExample = pl_get_api_latest(ptApiRegistry, plExampleI);
gptDebug = pl_get_api_latest(ptApiRegistry, plDebugApiI);
gptImage = pl_get_api_latest(ptApiRegistry, plImageI);
gptGpuAllocators = pl_get_api_latest(ptApiRegistry, plGPUAllocatorsI);
gptJob = pl_get_api_latest(ptApiRegistry, plJobI);
gptThreads = pl_get_api_latest(ptApiRegistry, plThreadsI);
gptAtomics = pl_get_api_latest(ptApiRegistry, plAtomicsI);
gptRect = pl_get_api_latest(ptApiRegistry, plRectPackI);
gptFile = pl_get_api_latest(ptApiRegistry, plFileI);
gptNetwork = pl_get_api_latest(ptApiRegistry, plNetworkI);
gptString = pl_get_api_latest(ptApiRegistry, plStringInternI);
gptLibrary = pl_get_api_latest(ptApiRegistry, plLibraryI);
gptLog = pl_get_api_latest(ptApiRegistry, plLogI);
gptVirtualMemory = pl_get_api_latest(ptApiRegistry, plVirtualMemoryI);
gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI);
gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
// this path is taken only during first load, so we
// allocate app memory here
ptAppData = PL_ALLOC(sizeof(plAppData));
memset(ptAppData, 0, sizeof(plAppData));
// add console variables
gptConsole->initialize((plConsoleSettings){.tFlags = PL_CONSOLE_FLAGS_POPUP});
// use window API to create a window
plWindowDesc tWindowDesc = {
.pcTitle = "App Template",
.iXPos = 200,
.iYPos = 200,
.uWidth = 500,
.uHeight = 500,
};
gptWindows->create_window(tWindowDesc, &ptAppData->ptWindow);
// initialize APIs that require it
gptDebug->initialize();
// retrieve some console variables
ptAppData->pbShowLogging = (bool*)gptConsole->get_variable("d.LogTool", NULL, NULL);
ptAppData->pbShowStats = (bool*)gptConsole->get_variable("d.StatTool", NULL, NULL);
ptAppData->pbShowProfiling = (bool*)gptConsole->get_variable("d.ProfileTool", NULL, NULL);
ptAppData->pbShowMemoryAllocations = (bool*)gptConsole->get_variable("d.MemoryAllocationTool", NULL, NULL);
ptAppData->pbShowDeviceMemoryAnalyzer = (bool*)gptConsole->get_variable("d.DeviceMemoryAnalyzerTool", NULL, NULL);
// setup graphics extension
pl__setup_graphics_extensions(ptAppData);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~setup draw extensions~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// initialize
gptDraw->initialize(NULL);
gptDrawBackend->initialize(ptAppData->ptDevice);
// create font atlas
plFontAtlas* ptAtlas = gptDraw->create_font_atlas();
gptDraw->set_font_atlas(ptAtlas);
ptAppData->ptDefaultFont = gptDraw->add_default_font(ptAtlas);
// build font atlas
plCommandPool* ptCmdPool = ptAppData->atCmdPools[gptGfx->get_current_frame_index()];
plCommandBuffer* ptCmdBuffer = gptGfx->request_command_buffer(ptCmdPool);
gptDrawBackend->build_font_atlas(ptCmdBuffer, ptAtlas);
gptGfx->return_command_buffer(ptCmdBuffer);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~message extension~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gptScreenLog->initialize((plScreenLogSettings){.ptFont = ptAppData->ptDefaultFont});
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ui extension~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gptUi->initialize();
gptUi->set_default_font(ptAppData->ptDefaultFont);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~app stuff~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create drawlist and some layers to draw to
ptAppData->ptDrawlist = gptDraw->request_2d_drawlist();
ptAppData->ptFGLayer = gptDraw->request_2d_layer(ptAppData->ptDrawlist);
ptAppData->ptBGLayer = gptDraw->request_2d_layer(ptAppData->ptDrawlist);
// demonstrate example extension
gptExample->print_to_console("From example extension!");
// return app memory
return ptAppData;
}
//-----------------------------------------------------------------------------
// [SECTION] pl_app_shutdown
//-----------------------------------------------------------------------------
PL_EXPORT void
pl_app_shutdown(plAppData* ptAppData)
{
// ensure GPU is finished before cleanup
gptGfx->flush_device(ptAppData->ptDevice);
for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++)
{
gptGfx->cleanup_command_pool(ptAppData->atCmdPools[i]);
gptGfx->cleanup_semaphore(ptAppData->aptSemaphores[i]);
}
gptDrawBackend->cleanup_font_atlas(NULL);
gptUi->cleanup();
gptDrawBackend->cleanup();
gptGfx->cleanup_swapchain(ptAppData->ptSwapchain);
gptGfx->cleanup_surface(ptAppData->ptSurface);
gptGfx->cleanup_device(ptAppData->ptDevice);
gptGfx->cleanup();
gptWindows->destroy_window(ptAppData->ptWindow);
PL_FREE(ptAppData);
}
//-----------------------------------------------------------------------------
// [SECTION] pl_app_resize
//-----------------------------------------------------------------------------
PL_EXPORT void
pl_app_resize(plAppData* ptAppData)
{
pl__resize_graphics_extensions(ptAppData);
}
//-----------------------------------------------------------------------------
// [SECTION] pl_app_update
//-----------------------------------------------------------------------------
PL_EXPORT void
pl_app_update(plAppData* ptAppData)
{
gptProfile->begin_frame();
pl_begin_cpu_sample(gptProfile, 0, __FUNCTION__);
// for convience
plIO* ptIO = gptIO->get_io();
// new frame stuff
gptIO->new_frame();
gptDrawBackend->new_frame();
gptUi->new_frame();
gptStats->new_frame();
gptGfx->begin_frame(ptAppData->ptDevice);
plCommandPool* ptCmdPool = ptAppData->atCmdPools[gptGfx->get_current_frame_index()];
gptGfx->reset_command_pool(ptCmdPool, 0);
// update statistics
static double* pdFrameTimeCounter = NULL;
if(!pdFrameTimeCounter)
pdFrameTimeCounter = gptStats->get_counter("frametime (ms)");
*pdFrameTimeCounter = (double)ptIO->fDeltaTime * 1000.0;
// acquire swapchain image
if(!gptGfx->acquire_swapchain_image(ptAppData->ptSwapchain))
{
pl_app_resize(ptAppData);
pl_end_cpu_sample(gptProfile, 0);
gptProfile->end_frame();
return;
}
// just some drawing
gptDraw->add_circle(ptAppData->ptFGLayer, (plVec2){100.0f, 100.0f}, 50.0f, 12, (plDrawLineOptions){.fThickness = 2.0f, .uColor = PL_COLOR_32_RGBA(1.0f, 0.0f, 1.0f, 1.0f)});
if(gptIO->is_key_pressed(PL_KEY_F1, false))
gptConsole->open();
gptConsole->update();
if(gptUi->begin_window("Pilot Light", NULL, false))
{
const float pfRatios[] = {1.0f};
gptUi->layout_row(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, 0.0f, 1, pfRatios);
if(gptUi->begin_collapsing_header("Information", 0))
{
gptUi->text("Pilot Light %s", PILOT_LIGHT_VERSION_STRING);
gptUi->end_collapsing_header();
}
if(gptUi->begin_collapsing_header("Tools", 0))
{
gptUi->checkbox("Device Memory Analyzer", ptAppData->pbShowDeviceMemoryAnalyzer);
gptUi->checkbox("Memory Allocations", ptAppData->pbShowMemoryAllocations);
gptUi->checkbox("Profiling", ptAppData->pbShowProfiling);
gptUi->checkbox("Statistics", ptAppData->pbShowStats);
gptUi->checkbox("Logging", ptAppData->pbShowLogging);
gptUi->end_collapsing_header();
}
if(gptUi->begin_collapsing_header("User Interface", 0))
{
gptUi->checkbox("UI Debug", &ptAppData->bShowUiDebug);
gptUi->checkbox("UI Style", &ptAppData->bShowUiStyle);
gptUi->end_collapsing_header();
}
gptUi->end_window();
}
if(ptAppData->bShowUiStyle)
gptUi->show_style_editor_window(&ptAppData->bShowUiStyle);
if(ptAppData->bShowUiDebug)
gptUi->show_debug_window(&ptAppData->bShowUiDebug);
gptDebug->update();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~graphics work~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const uint32_t uCurrentFrameIndex = gptGfx->get_current_frame_index();
plCommandBuffer* ptCommandBuffer = gptGfx->request_command_buffer(ptCmdPool);
const plBeginCommandInfo tBeginInfo = {
.uWaitSemaphoreCount = 1,
.atWaitSempahores = {ptAppData->aptSemaphores[uCurrentFrameIndex]},
.auWaitSemaphoreValues = {ptAppData->aulNextTimelineValue[uCurrentFrameIndex]},
};
gptGfx->begin_command_recording(ptCommandBuffer, &tBeginInfo);
// begin main renderpass (directly to swapchain)
plRenderEncoder* ptEncoder = gptGfx->begin_render_pass(ptCommandBuffer, ptAppData->tMainRenderPass, NULL);
// submit our layers & drawlist
gptDraw->submit_2d_layer(ptAppData->ptBGLayer);
gptDraw->submit_2d_layer(ptAppData->ptFGLayer);
gptDrawBackend->submit_2d_drawlist(ptAppData->ptDrawlist, ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
// submits UI layers
gptUi->end_frame();
// submit UI drawlists
gptDrawBackend->submit_2d_drawlist(gptUi->get_draw_list(), ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
gptDrawBackend->submit_2d_drawlist(gptUi->get_debug_draw_list(), ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
// end render pass
gptGfx->end_render_pass(ptEncoder);
// end recording
gptGfx->end_command_recording(ptCommandBuffer);
//~~~~~~~~~~~~~~~~~~~~~~~~~~submit work to GPU & present~~~~~~~~~~~~~~~~~~~~~~~
const plSubmitInfo tSubmitInfo = {
.uSignalSemaphoreCount = 1,
.atSignalSempahores = {ptAppData->aptSemaphores[uCurrentFrameIndex]},
.auSignalSemaphoreValues = {++ptAppData->aulNextTimelineValue[uCurrentFrameIndex]},
};
if(!gptGfx->present(ptCommandBuffer, &tSubmitInfo, &ptAppData->ptSwapchain, 1))
pl_app_resize(ptAppData);
gptGfx->return_command_buffer(ptCommandBuffer);
pl_end_cpu_sample(gptProfile, 0);
gptProfile->end_frame();
}
//-----------------------------------------------------------------------------
// [SECTION] helper functions implementations
//-----------------------------------------------------------------------------
void
pl__setup_graphics_extensions(plAppData* ptAppData)
{
// initialize shader extension (shader compiler)
static const plShaderOptions tDefaultShaderOptions = {
.apcIncludeDirectories = {
"../shaders/"
},
.apcDirectories = {
"../shaders/"
},
.tFlags = PL_SHADER_FLAGS_AUTO_OUTPUT
};
gptShader->initialize(&tDefaultShaderOptions);
// initialize graphics system
const plGraphicsInit tGraphicsInit = {
.tFlags = PL_GRAPHICS_INIT_FLAGS_VALIDATION_ENABLED | PL_GRAPHICS_INIT_FLAGS_SWAPCHAIN_ENABLED
};
gptGfx->initialize(&tGraphicsInit);
ptAppData->ptSurface = gptGfx->create_surface(ptAppData->ptWindow);
// find suitable device
uint32_t uDeviceCount = 16;
plDeviceInfo atDeviceInfos[16] = {0};
gptGfx->enumerate_devices(atDeviceInfos, &uDeviceCount);
// we will prefer discrete, then integrated
int iBestDvcIdx = 0;
int iDiscreteGPUIdx = -1;
int iIntegratedGPUIdx = -1;
for(uint32_t i = 0; i < uDeviceCount; i++)
{
if(atDeviceInfos[i].tType == PL_DEVICE_TYPE_DISCRETE)
iDiscreteGPUIdx = i;
else if(atDeviceInfos[i].tType == PL_DEVICE_TYPE_INTEGRATED)
iIntegratedGPUIdx = i;
}
if(iDiscreteGPUIdx > -1)
iBestDvcIdx = iDiscreteGPUIdx;
else if(iIntegratedGPUIdx > -1)
iBestDvcIdx = iIntegratedGPUIdx;
// create device
const plDeviceInit tDeviceInit = {
.uDeviceIdx = iBestDvcIdx,
.ptSurface = ptAppData->ptSurface
};
ptAppData->ptDevice = gptGfx->create_device(&tDeviceInit);
// create command pools
for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++)
ptAppData->atCmdPools[i] = gptGfx->create_command_pool(ptAppData->ptDevice, NULL);
// create swapchain
plSwapchainInit tSwapInit = {
.tSampleCount = PL_SAMPLE_COUNT_1
};
ptAppData->ptSwapchain = gptGfx->create_swapchain(ptAppData->ptDevice, ptAppData->ptSurface, &tSwapInit);
uint32_t uImageCount = 0;
plTextureHandle* atSwapchainImages = gptGfx->get_swapchain_images(ptAppData->ptSwapchain, &uImageCount);
// create main render pass layout
const plRenderPassLayoutDesc tMainRenderPassLayoutDesc = {
.atRenderTargets = {
{ .tFormat = gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tFormat }, // swapchain
},
.atSubpasses = {
{
.uRenderTargetCount = 1,
.auRenderTargets = {0}
}
},
.atSubpassDependencies = {
{
.uSourceSubpass = UINT32_MAX,
.uDestinationSubpass = 0,
.tSourceStageMask = PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS | PL_PIPELINE_STAGE_COMPUTE_SHADER,
.tDestinationStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS,
.tSourceAccessMask = PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
.tDestinationAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
},
{
.uSourceSubpass = 0,
.uDestinationSubpass = UINT32_MAX,
.tSourceStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS,
.tDestinationStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS | PL_PIPELINE_STAGE_COMPUTE_SHADER,
.tSourceAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
.tDestinationAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
},
}
};
ptAppData->tMainRenderPassLayout = gptGfx->create_render_pass_layout(ptAppData->ptDevice, &tMainRenderPassLayoutDesc);
// create main render pass
const plRenderPassDesc tMainRenderPassDesc = {
.tLayout = ptAppData->tMainRenderPassLayout,
.atColorTargets = {
{
.tLoadOp = PL_LOAD_OP_CLEAR,
.tStoreOp = PL_STORE_OP_STORE,
.tCurrentUsage = PL_TEXTURE_USAGE_UNSPECIFIED,
.tNextUsage = PL_TEXTURE_USAGE_PRESENT,
.tClearColor = {0.0f, 0.0f, 0.0f, 1.0f}
}
},
.tDimensions = {(float)gptGfx->get_swapchain_info(ptAppData->ptSwapchain).uWidth, (float)gptGfx->get_swapchain_info(ptAppData->ptSwapchain).uHeight},
.ptSwapchain = ptAppData->ptSwapchain
};
plRenderPassAttachments atMainAttachmentSets[16] = {0};
for(uint32_t i = 0; i < uImageCount; i++)
{
atMainAttachmentSets[i].atViewAttachments[0] = atSwapchainImages[i];
}
ptAppData->tMainRenderPass = gptGfx->create_render_pass(ptAppData->ptDevice, &tMainRenderPassDesc, atMainAttachmentSets);
// create timeline semaphores to syncronize GPU work submission
for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++)
ptAppData->aptSemaphores[i] = gptGfx->create_semaphore(ptAppData->ptDevice, false);
}
void
pl__resize_graphics_extensions(plAppData* ptAppData)
{
plIO* ptIO = gptIO->get_io();
plSwapchainInit tDesc = {
.bVSync = true,
.uWidth = (uint32_t)ptIO->tMainViewportSize.x,
.uHeight = (uint32_t)ptIO->tMainViewportSize.y,
.tSampleCount = gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount,
};
gptGfx->recreate_swapchain(ptAppData->ptSwapchain, &tDesc);
uint32_t uImageCount = 0;
plTextureHandle* atSwapchainImages = gptGfx->get_swapchain_images(ptAppData->ptSwapchain, &uImageCount);
plRenderPassAttachments atMainAttachmentSets[16] = {0};
for(uint32_t i = 0; i < uImageCount; i++)
{
atMainAttachmentSets[i].atViewAttachments[0] = atSwapchainImages[i];
}
gptGfx->update_render_pass_attachments(ptAppData->ptDevice, ptAppData->tMainRenderPass, gptIO->get_io()->tMainViewportSize, atMainAttachmentSets);
}