initial vulkan only
This commit is contained in:
parent
998f922764
commit
79be18d11f
@ -56,7 +56,7 @@ From within a local directory, enter the following commands in your terminal:
|
|||||||
# clone & build pilot light
|
# clone & build pilot light
|
||||||
git clone https://github.com/PilotLightTech/pilotlight
|
git clone https://github.com/PilotLightTech/pilotlight
|
||||||
cd pilotlight/src
|
cd pilotlight/src
|
||||||
chmod +x build_linux.sh
|
chmod +x build.sh -c moltenvk
|
||||||
./build_linux.sh
|
./build_linux.sh
|
||||||
|
|
||||||
# clone & build example
|
# clone & build example
|
||||||
|
BIN
data/test.hdr
Normal file
BIN
data/test.hdr
Normal file
Binary file not shown.
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
pl_example_ext.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Index of this file:
|
|
||||||
// [SECTION] includes
|
|
||||||
// [SECTION] public api implementation
|
|
||||||
// [SECTION] extension loading
|
|
||||||
*/
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] includes
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "pl.h"
|
|
||||||
#include "pl_example_ext.h"
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] public api implementation
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static void
|
|
||||||
pl__example_print_to_console(const char* pcText)
|
|
||||||
{
|
|
||||||
printf("%s\n", pcText);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] extension loading
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
PL_EXPORT void
|
|
||||||
pl_load_ext(plApiRegistryI* ptApiRegistry, bool bReload)
|
|
||||||
{
|
|
||||||
const plExampleI tApi = {
|
|
||||||
.print_to_console = pl__example_print_to_console
|
|
||||||
};
|
|
||||||
pl_set_api(ptApiRegistry, plExampleI, &tApi);
|
|
||||||
}
|
|
||||||
|
|
||||||
PL_EXPORT void
|
|
||||||
pl_unload_ext(plApiRegistryI* ptApiRegistry, bool bReload)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(bReload)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const plExampleI* ptApi = pl_get_api_latest(ptApiRegistry, plExampleI);
|
|
||||||
ptApiRegistry->remove_api(ptApi);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
pl_example_ext.h
|
|
||||||
- example extension
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Index of this file:
|
|
||||||
// [SECTION] header mess
|
|
||||||
// [SECTION] apis
|
|
||||||
// [SECTION] public api
|
|
||||||
*/
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] header mess
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef PL_EXAMPLE_EXT_H
|
|
||||||
#define PL_EXAMPLE_EXT_H
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] apis
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#define plExampleI_version {1, 0, 0}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] public api
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
typedef struct _plExampleI
|
|
||||||
{
|
|
||||||
void (*print_to_console)(const char* text);
|
|
||||||
} plExampleI;
|
|
||||||
|
|
||||||
#endif // PL_EXAMPLE_EXT_H
|
|
@ -57,9 +57,6 @@ with pl.project("game"):
|
|||||||
pl.add_profile(compiler_filter=["msvc"],
|
pl.add_profile(compiler_filter=["msvc"],
|
||||||
configuration_filter=["debug"],
|
configuration_filter=["debug"],
|
||||||
compiler_flags=["-Od", "-MDd", "-Zi"])
|
compiler_flags=["-Od", "-MDd", "-Zi"])
|
||||||
pl.add_profile(compiler_filter=["msvc"],
|
|
||||||
configuration_filter=["release"],
|
|
||||||
compiler_flags=["-O2", "-MD"])
|
|
||||||
|
|
||||||
|
|
||||||
# linux or gcc only
|
# linux or gcc only
|
||||||
@ -84,54 +81,6 @@ with pl.project("game"):
|
|||||||
|
|
||||||
# configs
|
# configs
|
||||||
pl.add_profile(configuration_filter=["debug"], definitions=["_DEBUG", "PL_CONFIG_DEBUG"])
|
pl.add_profile(configuration_filter=["debug"], definitions=["_DEBUG", "PL_CONFIG_DEBUG"])
|
||||||
pl.add_profile(configuration_filter=["release"], definitions=["NDEBUG", "PL_CONFIG_RELEASE"])
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
# [SECTION] extensions
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
with pl.target("pl_example_ext", pl.TargetType.DYNAMIC_LIBRARY, True):
|
|
||||||
|
|
||||||
pl.add_source_files("../extensions/pl_example_ext.c")
|
|
||||||
pl.set_output_binary("pl_example_ext")
|
|
||||||
|
|
||||||
# default config
|
|
||||||
with pl.configuration("debug"):
|
|
||||||
|
|
||||||
# win32
|
|
||||||
with pl.platform("Windows"):
|
|
||||||
|
|
||||||
with pl.compiler("msvc"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# linux
|
|
||||||
with pl.platform("Linux"):
|
|
||||||
with pl.compiler("gcc"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# macos
|
|
||||||
with pl.platform("Darwin"):
|
|
||||||
with pl.compiler("clang"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# release
|
|
||||||
with pl.configuration("release"):
|
|
||||||
|
|
||||||
# win32
|
|
||||||
with pl.platform("Windows"):
|
|
||||||
|
|
||||||
with pl.compiler("msvc"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# linux
|
|
||||||
with pl.platform("Linux"):
|
|
||||||
with pl.compiler("gcc"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# macos
|
|
||||||
with pl.platform("Darwin"):
|
|
||||||
with pl.compiler("clang"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# [SECTION] app
|
# [SECTION] app
|
||||||
@ -148,35 +97,21 @@ with pl.project("game"):
|
|||||||
# win32
|
# win32
|
||||||
with pl.platform("Windows"):
|
with pl.platform("Windows"):
|
||||||
with pl.compiler("msvc"):
|
with pl.compiler("msvc"):
|
||||||
pass
|
pl.add_static_link_libraries("vulkan-1")
|
||||||
|
pl.add_include_directories("%VULKAN_SDK%\\Include")
|
||||||
|
pl.add_link_directories('%VULKAN_SDK%\\Lib')
|
||||||
|
|
||||||
# linux
|
# linux
|
||||||
with pl.platform("Linux"):
|
with pl.platform("Linux"):
|
||||||
with pl.compiler("gcc"):
|
with pl.compiler("gcc"):
|
||||||
pass
|
pl.add_dynamic_link_libraries("vulkan")
|
||||||
|
pl.add_include_directories('$VULKAN_SDK/include', '/usr/include/vulkan')
|
||||||
|
pl.add_link_directories('$VULKAN_SDK/lib')
|
||||||
|
|
||||||
# mac os
|
# mac os
|
||||||
with pl.platform("Darwin"):
|
with pl.platform("Darwin"):
|
||||||
with pl.compiler("clang"):
|
with pl.compiler("clang"):
|
||||||
pass
|
pl.add_dynamic_link_libraries("vulkan")
|
||||||
|
|
||||||
# release
|
|
||||||
with pl.configuration("release"):
|
|
||||||
|
|
||||||
# win32
|
|
||||||
with pl.platform("Windows"):
|
|
||||||
with pl.compiler("msvc"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# linux
|
|
||||||
with pl.platform("Linux"):
|
|
||||||
with pl.compiler("gcc"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# mac os
|
|
||||||
with pl.platform("Darwin"):
|
|
||||||
with pl.compiler("clang"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# [SECTION] generate scripts
|
# [SECTION] generate scripts
|
||||||
|
@ -28,7 +28,8 @@ includes = [
|
|||||||
"${workspaceFolder}/../pilotlight/libs",
|
"${workspaceFolder}/../pilotlight/libs",
|
||||||
"${workspaceFolder}/../pilotlight/extensions",
|
"${workspaceFolder}/../pilotlight/extensions",
|
||||||
"${workspaceFolder}/../pilotlight/dependencies/stb",
|
"${workspaceFolder}/../pilotlight/dependencies/stb",
|
||||||
"${workspaceFolder}/../pilotlight/dependencies/cgltf"
|
"${workspaceFolder}/../pilotlight/dependencies/cgltf",
|
||||||
|
"${env:VK_SDK_PATH}/Include"
|
||||||
]
|
]
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
30
shaders/shader.comp
Normal file
30
shaders/shader.comp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) buffer Pos {
|
||||||
|
float values[ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// PRACTICE (how to get 6144 to the shader without hard coding?)
|
||||||
|
const uint row_stride = 6144 * 4;
|
||||||
|
|
||||||
|
uint pixel_x = gl_GlobalInvocationID.x;
|
||||||
|
uint pixel_y = gl_GlobalInvocationID.y;
|
||||||
|
|
||||||
|
// const int iXCoord = int(gl_WorkGroupID.x * 8 + gl_LocalInvocationID.x);
|
||||||
|
|
||||||
|
// original colors
|
||||||
|
float fOriginalRed = values[ pixel_x * 4 + pixel_y * row_stride];
|
||||||
|
float fOriginalGreen = values[ pixel_x * 4 + pixel_y * row_stride + 1];
|
||||||
|
float fOriginalBlue = values[ pixel_x * 4 + pixel_y * row_stride + 2];
|
||||||
|
float fOriginalAlpha = values[ pixel_x * 4 + pixel_y * row_stride + 3];
|
||||||
|
|
||||||
|
// swap red & green channels (and unnormalize)
|
||||||
|
values[pixel_x * 4 + pixel_y * row_stride] = clamp(fOriginalRed * 255, 0, 255);
|
||||||
|
values[pixel_x * 4 + pixel_y * row_stride + 1] = clamp(fOriginalGreen * 255, 0, 255);
|
||||||
|
values[pixel_x * 4 + pixel_y * row_stride + 2] = clamp(fOriginalBlue * 255, 0, 255);
|
||||||
|
values[pixel_x * 4 + pixel_y * row_stride + 3] = clamp(255, 0, 255);
|
||||||
|
}
|
565
src/app.c
565
src/app.c
@ -1,15 +1,3 @@
|
|||||||
/*
|
|
||||||
example_basic_2.c
|
|
||||||
- demonstrates loading APIs
|
|
||||||
- demonstrates loading extensions
|
|
||||||
- demonstrates hot reloading
|
|
||||||
- demonstrates starter extension
|
|
||||||
- demonstrates basic drawing extension (2D)
|
|
||||||
- demonstrates basic screen log extension
|
|
||||||
- demonstrates basic console extension
|
|
||||||
- demonstrates basic UI extension
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Index of this file:
|
Index of this file:
|
||||||
// [SECTION] quick notes
|
// [SECTION] quick notes
|
||||||
@ -22,45 +10,6 @@ Index of this file:
|
|||||||
// [SECTION] pl_app_update
|
// [SECTION] pl_app_update
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] quick notes
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/*
|
|
||||||
This example is the first to introduce extensions. Extensions are just
|
|
||||||
shared libraries that export a "load" and "unload" function. The default
|
|
||||||
being:
|
|
||||||
|
|
||||||
* void pl_load_ext (plApiRegistryI*, bool reload)
|
|
||||||
* void pl_unload_ext(plApiRegistryI*, bool reload)
|
|
||||||
|
|
||||||
Later examples will explain more about the details of creating an extension
|
|
||||||
but the important thing to understand now is that an extension just provides
|
|
||||||
an implementation of an API. The "load" function allows an extension to
|
|
||||||
request APIs it depends on and to register any API it provides. The unload
|
|
||||||
function just allows an extension the opportunity to unregister and perform
|
|
||||||
any required cleanup.
|
|
||||||
|
|
||||||
This example is also the first to introduce the "starter" extension. This
|
|
||||||
extension acts a bit as a helper extension to remove some common boilerplate
|
|
||||||
but is also just useful in general for most applications only needing to use
|
|
||||||
UI, plotting, drawing, etc. Or even to just experiment with the lower level
|
|
||||||
graphics extension in an isolated manner. Later examples will gradually peel
|
|
||||||
away at this extension and others. For this example, we will just demonstrate
|
|
||||||
some of the smaller helpful extensions. These include:
|
|
||||||
|
|
||||||
* log
|
|
||||||
* profile
|
|
||||||
* stat
|
|
||||||
* console
|
|
||||||
* screen log
|
|
||||||
* ui
|
|
||||||
|
|
||||||
This will be very light introductions with later examples going into more
|
|
||||||
detail. Feel free to open the header file for the extension for more
|
|
||||||
information and functionality.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] includes
|
// [SECTION] includes
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -73,17 +22,17 @@ Index of this file:
|
|||||||
#include "pl_math.h"
|
#include "pl_math.h"
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
#include "pl_draw_ext.h"
|
#define PL_GRAPHICS_EXPOSE_VULKAN
|
||||||
|
#include "pl_graphics_ext.h"
|
||||||
|
#include "pl_shader_ext.h"
|
||||||
#include "pl_starter_ext.h"
|
#include "pl_starter_ext.h"
|
||||||
#include "pl_ui_ext.h"
|
#include "pl_image_ext.h"
|
||||||
|
#include "pl_vfs_ext.h"
|
||||||
#include "pl_screen_log_ext.h"
|
#include "pl_screen_log_ext.h"
|
||||||
#include "pl_profile_ext.h"
|
|
||||||
#include "pl_log_ext.h"
|
|
||||||
#include "pl_stats_ext.h"
|
|
||||||
#include "pl_console_ext.h"
|
|
||||||
|
|
||||||
// out extension
|
#include "vulkan/vulkan.h"
|
||||||
#include "pl_example_ext.h"
|
|
||||||
|
#define VULKAN_CHECK(x) assert(x == VK_SUCCESS)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] structs
|
// [SECTION] structs
|
||||||
@ -93,12 +42,12 @@ typedef struct _plAppData
|
|||||||
{
|
{
|
||||||
// window
|
// window
|
||||||
plWindow* ptWindow;
|
plWindow* ptWindow;
|
||||||
|
plSurface* ptSurface;
|
||||||
|
plDevice* ptDevice;
|
||||||
|
|
||||||
// log channel
|
// shaders
|
||||||
uint64_t uExampleLogChannel;
|
plShaderHandle tShader;
|
||||||
|
|
||||||
// console variable
|
|
||||||
bool bShowHelpWindow;
|
|
||||||
} plAppData;
|
} plAppData;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -107,20 +56,12 @@ typedef struct _plAppData
|
|||||||
|
|
||||||
const plIOI* gptIO = NULL;
|
const plIOI* gptIO = NULL;
|
||||||
const plWindowI* gptWindows = NULL;
|
const plWindowI* gptWindows = NULL;
|
||||||
const plDrawI* gptDraw = NULL;
|
const plGraphicsI* gptGfx = NULL;
|
||||||
|
const plShaderI* gptShader = NULL;
|
||||||
const plStarterI* gptStarter = NULL;
|
const plStarterI* gptStarter = NULL;
|
||||||
const plUiI* gptUI = NULL;
|
const plImageI* gptImage = NULL;
|
||||||
|
const plVfsI* gptVfs = NULL;
|
||||||
const plScreenLogI* gptScreenLog = NULL;
|
const plScreenLogI* gptScreenLog = NULL;
|
||||||
const plProfileI* gptProfile = NULL;
|
|
||||||
const plStatsI* gptStats = NULL;
|
|
||||||
const plMemoryI* gptMemory = NULL;
|
|
||||||
const plLogI* gptLog = NULL;
|
|
||||||
const plConsoleI* gptConsole = NULL;
|
|
||||||
const plExampleI* gptExample = NULL;
|
|
||||||
|
|
||||||
#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__)
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] pl_app_load
|
// [SECTION] pl_app_load
|
||||||
@ -129,76 +70,35 @@ const plExampleI* gptExample = NULL;
|
|||||||
PL_EXPORT void*
|
PL_EXPORT void*
|
||||||
pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
|
pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
|
||||||
{
|
{
|
||||||
// NOTE: on first load, "pAppData" will be NULL but on reloads
|
|
||||||
// it will be the value returned from this function
|
|
||||||
|
|
||||||
// if "ptAppData" is a valid pointer, then this function is being called
|
// this path is taken only during first load, so we
|
||||||
// during a hot reload.
|
// allocate app memory here
|
||||||
if(ptAppData)
|
ptAppData = malloc(sizeof(plAppData));
|
||||||
{
|
memset(ptAppData, 0, sizeof(plAppData));
|
||||||
|
|
||||||
// re-retrieve the apis since we are now in
|
|
||||||
// a different dll/so
|
|
||||||
gptIO = pl_get_api_latest(ptApiRegistry, plIOI);
|
|
||||||
gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI);
|
|
||||||
gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI);
|
|
||||||
gptStarter = pl_get_api_latest(ptApiRegistry, plStarterI);
|
|
||||||
gptUI = pl_get_api_latest(ptApiRegistry, plUiI);
|
|
||||||
gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
|
|
||||||
gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI);
|
|
||||||
gptStats = pl_get_api_latest(ptApiRegistry, plStatsI);
|
|
||||||
gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI);
|
|
||||||
gptLog = pl_get_api_latest(ptApiRegistry, plLogI);
|
|
||||||
gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI);
|
|
||||||
gptExample = pl_get_api_latest(ptApiRegistry, plExampleI);
|
|
||||||
|
|
||||||
return ptAppData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve extension registry
|
// retrieve extension registry
|
||||||
const plExtensionRegistryI* ptExtensionRegistry = pl_get_api_latest(ptApiRegistry, plExtensionRegistryI);
|
const plExtensionRegistryI* ptExtensionRegistry = pl_get_api_latest(ptApiRegistry, plExtensionRegistryI);
|
||||||
|
|
||||||
// load extensions
|
// load extensions
|
||||||
// * first argument is the shared library name WITHOUT the extension
|
|
||||||
// * second & third argument is the load/unload functions names (use NULL for the default of "pl_load_ext" &
|
|
||||||
// "pl_unload_ext")
|
|
||||||
// * fourth argument indicates if the extension is reloadable (should we check for changes and reload if changed)
|
|
||||||
ptExtensionRegistry->add_path("../../pl-template/out");
|
ptExtensionRegistry->add_path("../../pl-template/out");
|
||||||
ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, false);
|
ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, true);
|
||||||
ptExtensionRegistry->load("pl_platform_ext", NULL, NULL, false); // provides the file API used by the drawing ext
|
ptExtensionRegistry->load("pl_platform_ext", NULL, NULL, false);
|
||||||
ptExtensionRegistry->load("pl_example_ext", NULL, NULL, true);
|
|
||||||
|
|
||||||
// load required apis
|
// load required apis
|
||||||
gptIO = pl_get_api_latest(ptApiRegistry, plIOI);
|
gptIO = pl_get_api_latest(ptApiRegistry, plIOI);
|
||||||
gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI);
|
gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI);
|
||||||
|
|
||||||
// load required apis (these are provided though extensions)
|
// load required apis (these are provided though extensions)
|
||||||
gptDraw = pl_get_api_latest(ptApiRegistry, plDrawI);
|
gptGfx = pl_get_api_latest(ptApiRegistry, plGraphicsI);
|
||||||
|
gptShader = pl_get_api_latest(ptApiRegistry, plShaderI);
|
||||||
gptStarter = pl_get_api_latest(ptApiRegistry, plStarterI);
|
gptStarter = pl_get_api_latest(ptApiRegistry, plStarterI);
|
||||||
gptUI = pl_get_api_latest(ptApiRegistry, plUiI);
|
gptImage = pl_get_api_latest(ptApiRegistry, plImageI);
|
||||||
|
gptVfs = pl_get_api_latest(ptApiRegistry, plVfsI);
|
||||||
gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
|
gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
|
||||||
gptProfile = pl_get_api_latest(ptApiRegistry, plProfileI);
|
|
||||||
gptStats = pl_get_api_latest(ptApiRegistry, plStatsI);
|
|
||||||
gptMemory = pl_get_api_latest(ptApiRegistry, plMemoryI);
|
|
||||||
gptLog = pl_get_api_latest(ptApiRegistry, plLogI);
|
|
||||||
gptConsole = pl_get_api_latest(ptApiRegistry, plConsoleI);
|
|
||||||
|
|
||||||
// out extension
|
|
||||||
gptExample = pl_get_api_latest(ptApiRegistry, plExampleI);
|
|
||||||
|
|
||||||
gptExample->print_to_console("Hello from example extension");
|
|
||||||
|
|
||||||
// this path is taken only during first load, so we
|
|
||||||
// allocate app memory here
|
|
||||||
ptAppData = PL_ALLOC(sizeof(plAppData));
|
|
||||||
memset(ptAppData, 0, sizeof(plAppData));
|
|
||||||
|
|
||||||
// default values
|
|
||||||
ptAppData->bShowHelpWindow = true;
|
|
||||||
|
|
||||||
// use window API to create a window
|
// use window API to create a window
|
||||||
plWindowDesc tWindowDesc = {
|
plWindowDesc tWindowDesc = {
|
||||||
.pcTitle = "Template App",
|
.pcTitle = "Vulkan Example",
|
||||||
.iXPos = 200,
|
.iXPos = 200,
|
||||||
.iYPos = 200,
|
.iYPos = 200,
|
||||||
.uWidth = 600,
|
.uWidth = 600,
|
||||||
@ -207,21 +107,27 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
|
|||||||
gptWindows->create(tWindowDesc, &ptAppData->ptWindow);
|
gptWindows->create(tWindowDesc, &ptAppData->ptWindow);
|
||||||
gptWindows->show(ptAppData->ptWindow);
|
gptWindows->show(ptAppData->ptWindow);
|
||||||
|
|
||||||
// initialize the starter API (handles alot of boilerplate)
|
plGraphicsInit tGraphicsDesc = {
|
||||||
plStarterInit tStarterInit = {
|
.tFlags = PL_GRAPHICS_INIT_FLAGS_SWAPCHAIN_ENABLED | PL_GRAPHICS_INIT_FLAGS_VALIDATION_ENABLED
|
||||||
.tFlags = PL_STARTER_FLAGS_ALL_EXTENSIONS,
|
|
||||||
.ptWindow = ptAppData->ptWindow
|
|
||||||
};
|
};
|
||||||
gptStarter->initialize(tStarterInit);
|
gptGfx->initialize(&tGraphicsDesc);
|
||||||
gptStarter->finalize();
|
|
||||||
|
|
||||||
// add a log channel
|
ptAppData->ptSurface = gptGfx->create_surface(ptAppData->ptWindow);
|
||||||
ptAppData->uExampleLogChannel = gptLog->add_channel("Example 2", (plLogExtChannelInit){.tType = PL_LOG_CHANNEL_TYPE_BUFFER});
|
|
||||||
|
|
||||||
// add a console variable
|
ptAppData->ptDevice = gptStarter->create_device(ptAppData->ptSurface);
|
||||||
gptConsole->add_toggle_variable("a.HelpWindow", &ptAppData->bShowHelpWindow, "toggle help window", PL_CONSOLE_VARIABLE_FLAGS_NONE);
|
|
||||||
|
|
||||||
// return app memory
|
// initialize shader extension (we are doing this ourselves so we can add additional shader directories)
|
||||||
|
static const plShaderOptions tDefaultShaderOptions = {
|
||||||
|
.apcIncludeDirectories = {
|
||||||
|
"../../pl-template/shaders/"
|
||||||
|
},
|
||||||
|
.apcDirectories = {
|
||||||
|
"../shaders/",
|
||||||
|
"../../pl-template/shaders/"
|
||||||
|
},
|
||||||
|
.tFlags = PL_SHADER_FLAGS_AUTO_OUTPUT | PL_SHADER_FLAGS_ALWAYS_COMPILE
|
||||||
|
};
|
||||||
|
gptShader->initialize(&tDefaultShaderOptions);
|
||||||
return ptAppData;
|
return ptAppData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,9 +138,14 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
|
|||||||
PL_EXPORT void
|
PL_EXPORT void
|
||||||
pl_app_shutdown(plAppData* ptAppData)
|
pl_app_shutdown(plAppData* ptAppData)
|
||||||
{
|
{
|
||||||
gptStarter->cleanup();
|
gptGfx->flush_device(ptAppData->ptDevice);
|
||||||
|
gptShader->cleanup();
|
||||||
gptWindows->destroy(ptAppData->ptWindow);
|
gptWindows->destroy(ptAppData->ptWindow);
|
||||||
PL_FREE(ptAppData);
|
gptScreenLog->cleanup();
|
||||||
|
gptGfx->cleanup_surface(ptAppData->ptSurface);
|
||||||
|
gptGfx->cleanup_device(ptAppData->ptDevice);
|
||||||
|
gptGfx->cleanup();
|
||||||
|
free(ptAppData);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -244,7 +155,7 @@ pl_app_shutdown(plAppData* ptAppData)
|
|||||||
PL_EXPORT void
|
PL_EXPORT void
|
||||||
pl_app_resize(plAppData* ptAppData)
|
pl_app_resize(plAppData* ptAppData)
|
||||||
{
|
{
|
||||||
gptStarter->resize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -254,88 +165,322 @@ pl_app_resize(plAppData* ptAppData)
|
|||||||
PL_EXPORT void
|
PL_EXPORT void
|
||||||
pl_app_update(plAppData* ptAppData)
|
pl_app_update(plAppData* ptAppData)
|
||||||
{
|
{
|
||||||
// this needs to be the first call when using the starter
|
gptIO->new_frame(); // must be called once at the beginning of a frame
|
||||||
// extension. You must return if it returns false (usually a swapchain recreation).
|
|
||||||
if(!gptStarter->begin_frame())
|
|
||||||
return;
|
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stats API~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
plIO* ptIO = gptIO->get_io();
|
||||||
|
ptIO->bRunning = false;
|
||||||
|
|
||||||
// rather than have to lookup the counter every frame, its best to "store" it
|
// core (basically every vulkan application will have these)
|
||||||
// like this. To update it, just deference it and set the value.
|
|
||||||
static double* pdExample2Counter = NULL;
|
|
||||||
if(!pdExample2Counter)
|
|
||||||
pdExample2Counter = gptStats->get_counter("example 2 counter");
|
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~drawing & profile API~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// global resources (for simplicity, we are treating these as global resources)
|
||||||
|
VkDescriptorPool gtDescriptorPool; // pool of descriptors
|
||||||
|
VkCommandPool gtComputeCommandPool; // pool of command buffers
|
||||||
|
VkFence gtComputeWorkFence; // fence to signal compute work is done (not needed for this example but required by API)
|
||||||
|
|
||||||
gptProfile->begin_sample(0, "example drawing");
|
// example specific resources
|
||||||
|
VkBuffer gtStorageBuffer; // storage buffer (reading & writing for this example)
|
||||||
|
VkDeviceMemory gtStorageBufferMemory; // storage buffer actual device memory
|
||||||
|
VkDescriptorSet gtDescriptorSet; // descriptor set which will contain a descriptor to the storage buffer
|
||||||
|
float* gpfMemoryMap; // persistant mapping to the storage buffer
|
||||||
|
|
||||||
plDrawLayer2D* ptFGLayer = gptStarter->get_foreground_layer();
|
// example specific compute pipeline stuff
|
||||||
gptDraw->add_line(ptFGLayer,
|
VkDescriptorSetLayout gtDescriptorSetLayout; // describes the compute shader descriptor set layout (single set in this example)
|
||||||
(plVec2){0.0f, 0.0f},
|
VkPipelineLayout gtPipelineLayout; // describes the compute shader pipeline layout (descriptor set layout + other stuff in general)
|
||||||
(plVec2){500.0f, 500.0f}, (plDrawLineOptions){ .fThickness = 1.0f, .uColor = PL_COLOR_32_MAGENTA});
|
VkPipeline gtPipeline; // complete pipeline state object for compute shader (this really is the "shader")
|
||||||
|
VkShaderModule gtShaderModule; // SPIR-V code
|
||||||
|
|
||||||
plDrawLayer2D* ptBGLayer = gptStarter->get_background_layer();
|
VkDevice gtLogicalDevice = gptGfx->get_vulkan_device(ptAppData->ptDevice);
|
||||||
gptDraw->add_triangle_filled(ptBGLayer,
|
|
||||||
(plVec2){50.0f, 100.0f},
|
|
||||||
(plVec2){200.0f},
|
|
||||||
(plVec2){100.0f, 200.0f}, (plDrawSolidOptions){.uColor = PL_COLOR_32_RGBA(0.0f, 0.5f, 1.0f, 0.5f)});
|
|
||||||
|
|
||||||
gptProfile->end_sample(0);
|
plShaderModule tShader = gptShader->load_glsl("shader.comp", "main", NULL, NULL);
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~UI & Screen Log API~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//-----------------------------------------------------------------------------
|
||||||
|
// load an image
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// creating a window
|
size_t szImageFileSize = gptVfs->get_file_size_str("../../pl-template/data/test.hdr");
|
||||||
if(ptAppData->bShowHelpWindow)
|
unsigned char* pucBuffer = malloc(szImageFileSize);
|
||||||
|
plVfsFileHandle tEnvMapHandle = gptVfs->open_file("../../pl-template/data/test.hdr", PL_VFS_FILE_MODE_READ);
|
||||||
|
gptVfs->read_file(tEnvMapHandle, pucBuffer, &szImageFileSize);
|
||||||
|
gptVfs->close_file(tEnvMapHandle);
|
||||||
|
|
||||||
|
int iImageWidth = 0;
|
||||||
|
int iImageHeight = 0;
|
||||||
|
int iImageChannels = 0;
|
||||||
|
float* pfRawImageBytes = gptImage->load_hdr(pucBuffer, (int)szImageFileSize, &iImageWidth, &iImageHeight, &iImageChannels, 4);
|
||||||
|
assert(pfRawImageBytes);
|
||||||
|
free(pucBuffer);
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// create storage buffer
|
||||||
|
// - we are using a storage buffer for this example to read & write from
|
||||||
|
// - we are also storing it in host visible memory for simplicity
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// create storage buffer
|
||||||
|
VkBufferCreateInfo tBufferInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
|
.size = iImageWidth * iImageHeight * 4 * sizeof(float),
|
||||||
|
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||||
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreateBuffer(gtLogicalDevice, &tBufferInfo, NULL, >StorageBuffer));
|
||||||
|
|
||||||
|
// get buffer memory requirements
|
||||||
|
VkMemoryRequirements tMemRequirements = {0};
|
||||||
|
vkGetBufferMemoryRequirements(gtLogicalDevice, gtStorageBuffer, &tMemRequirements);
|
||||||
|
|
||||||
|
// allocate actual device memory
|
||||||
|
VkMemoryAllocateInfo tStorageAllocInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
.allocationSize = tMemRequirements.size,
|
||||||
|
};
|
||||||
|
|
||||||
|
// find suitable memory type
|
||||||
|
VkPhysicalDeviceMemoryProperties gtMemProps = gptGfx->get_vulkan_memory_properties(ptAppData->ptDevice);
|
||||||
|
for (uint32_t i = 0; i < gtMemProps.memoryTypeCount; i++)
|
||||||
{
|
{
|
||||||
if(gptUI->begin_window("Help", NULL, PL_UI_WINDOW_FLAGS_AUTO_SIZE | PL_UI_WINDOW_FLAGS_NO_COLLAPSE))
|
if ((tMemRequirements.memoryTypeBits & (1 << i)) && (gtMemProps.memoryTypes[i].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
|
||||||
{
|
{
|
||||||
gptUI->layout_static(0.0f, 500.0f, 1);
|
tStorageAllocInfo.memoryTypeIndex = i;
|
||||||
gptUI->text("Press F1 to bring up console.");
|
break;
|
||||||
gptUI->text("Look for t.StatsTool (we added a stat)");
|
|
||||||
gptUI->text("Look for t.LogTool (we added a log channel)");
|
|
||||||
gptUI->text("Look for t.ProfileTool");
|
|
||||||
gptUI->text("Look for t.MemoryAllocationTool and look for example 2!");
|
|
||||||
gptUI->text("Look for a.HelpWindow (console variable we added)");
|
|
||||||
gptUI->end_window();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VULKAN_CHECK(vkAllocateMemory(gtLogicalDevice, &tStorageAllocInfo, NULL, >StorageBufferMemory));
|
||||||
|
|
||||||
// creating another window
|
// bind memory to resource
|
||||||
if(gptUI->begin_window("Pilot Light", NULL, PL_UI_WINDOW_FLAGS_NONE))
|
VULKAN_CHECK(vkBindBufferMemory(gtLogicalDevice, gtStorageBuffer, gtStorageBufferMemory, 0));
|
||||||
{
|
|
||||||
gptUI->text("Pilot Light %s", PILOT_LIGHT_VERSION_STRING);
|
|
||||||
|
|
||||||
if(gptUI->button("Log"))
|
//-----------------------------------------------------------------------------
|
||||||
{
|
// map to the memory persistantly
|
||||||
gptLog->trace(ptAppData->uExampleLogChannel, "Log");
|
// - this is really just to make the example simpler
|
||||||
gptLog->debug(ptAppData->uExampleLogChannel, "Log");
|
// - more generally, you would need to transfer the data & syncronize access
|
||||||
gptLog->info(ptAppData->uExampleLogChannel, "Log");
|
//-----------------------------------------------------------------------------
|
||||||
gptLog->warn(ptAppData->uExampleLogChannel, "Log");
|
|
||||||
gptLog->error(ptAppData->uExampleLogChannel, "Log");
|
VULKAN_CHECK(vkMapMemory(gtLogicalDevice, gtStorageBufferMemory, 0, iImageWidth * iImageHeight * 4 * sizeof(float), 0, (void**)&gpfMemoryMap));
|
||||||
gptLog->fatal(ptAppData->uExampleLogChannel, "Log");
|
memcpy(gpfMemoryMap, pfRawImageBytes, iImageWidth * iImageHeight * 4 * sizeof(float));
|
||||||
}
|
gptImage->free(pfRawImageBytes);
|
||||||
|
|
||||||
static int iCounter = 0;
|
//-----------------------------------------------------------------------------
|
||||||
gptUI->slider_int("Stat Counter Example", &iCounter, -10, 10, 0);
|
// create descriptor pool, layout, & set
|
||||||
*pdExample2Counter = iCounter; // setting our stat variable
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
gptUI->layout_row_begin(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, 0.0f, 2); // got to pl_ui_ext.h to see layout systems
|
// create descriptor pool
|
||||||
|
VkDescriptorPoolSize tPoolSize = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 100 };
|
||||||
gptUI->layout_row_push(0.3f);
|
const VkDescriptorPoolCreateInfo tDescriptorPoolInfo = {
|
||||||
if(gptUI->button("Log To Screen"))
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
gptScreenLog->add_message(5.0, "Cool Message!");
|
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||||
|
.maxSets = 100,
|
||||||
gptUI->layout_row_push(0.3f);
|
.poolSizeCount = 1,
|
||||||
if(gptUI->button("Big Log To Screen"))
|
.pPoolSizes = &tPoolSize,
|
||||||
gptScreenLog->add_message_ex(0, 5, PL_COLOR_32_GREEN, 3.0f, "%s", "Bigger & Greener!");
|
};
|
||||||
|
VULKAN_CHECK(vkCreateDescriptorPool(gtLogicalDevice, &tDescriptorPoolInfo, NULL, >DescriptorPool));
|
||||||
gptUI->layout_row_end();
|
|
||||||
|
// create descriptor set layout
|
||||||
gptUI->end_window();
|
const VkDescriptorSetLayoutBinding tBindings = {
|
||||||
}
|
.binding = 0u,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
// must be the last function called when using the starter extension
|
.descriptorCount = 1,
|
||||||
gptStarter->end_frame();
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
|
||||||
|
};
|
||||||
|
|
||||||
|
const VkDescriptorSetLayoutCreateInfo tLayoutInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.bindingCount = 1,
|
||||||
|
.pBindings = &tBindings
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreateDescriptorSetLayout(gtLogicalDevice, &tLayoutInfo, NULL, >DescriptorSetLayout));
|
||||||
|
|
||||||
|
// allocate descriptor set from descriptor pool
|
||||||
|
const VkDescriptorSetAllocateInfo tAllocInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
|
.descriptorPool = gtDescriptorPool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = >DescriptorSetLayout
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkAllocateDescriptorSets(gtLogicalDevice, &tAllocInfo, >DescriptorSet));
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// write data to descriptors
|
||||||
|
// - you have already created the storage buffer, created the descriptor set,
|
||||||
|
// but you haven't "connected" them, which is what you are doing here
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// descriptor info
|
||||||
|
VkDescriptorBufferInfo tBufferDescriptorInfo = {
|
||||||
|
.buffer = gtStorageBuffer,
|
||||||
|
.range = VK_WHOLE_SIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
VkWriteDescriptorSet tDescriptorWrites = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.dstBinding = 0u,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.dstSet = gtDescriptorSet,
|
||||||
|
.pBufferInfo = &tBufferDescriptorInfo
|
||||||
|
};
|
||||||
|
vkUpdateDescriptorSets(gtLogicalDevice, 1, &tDescriptorWrites, 0, NULL);
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// create shader & pipeline & pipeline layout
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// create pipeline layout (resource bindings)
|
||||||
|
VkPipelineLayoutCreateInfo tPipelineLayoutInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.setLayoutCount = 1,
|
||||||
|
.pSetLayouts = >DescriptorSetLayout
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreatePipelineLayout(gtLogicalDevice, &tPipelineLayoutInfo, NULL, >PipelineLayout));
|
||||||
|
|
||||||
|
VkShaderModuleCreateInfo tShaderCreateInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||||
|
.codeSize = tShader.szCodeSize,
|
||||||
|
.pCode = (const uint32_t*)(tShader.puCode)
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreateShaderModule(gtLogicalDevice, &tShaderCreateInfo, NULL, >ShaderModule));
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo tShaderStage = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
|
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.module = gtShaderModule,
|
||||||
|
.pName = "main"
|
||||||
|
};
|
||||||
|
|
||||||
|
// create compute pipeline (FYI, this is when actual shader compilation is performed by the driver)
|
||||||
|
VkComputePipelineCreateInfo tPipelineCreateInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
||||||
|
.layout = gtPipelineLayout,
|
||||||
|
.stage = tShaderStage
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreateComputePipelines(gtLogicalDevice, VK_NULL_HANDLE, 1, &tPipelineCreateInfo, NULL, >Pipeline));
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// WORK
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// create command pool
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// create command pool from compute queue
|
||||||
|
const VkCommandPoolCreateInfo tCommandPoolInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||||
|
.queueFamilyIndex = gptGfx->get_vulkan_queue_family(ptAppData->ptDevice),
|
||||||
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreateCommandPool(gtLogicalDevice, &tCommandPoolInfo, NULL, >ComputeCommandPool));
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo tCommandAllocInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||||
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||||
|
.commandPool = gtComputeCommandPool,
|
||||||
|
.commandBufferCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// allocate a command buffer from the command pool
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VkCommandBuffer tCommandBuffer = {0};
|
||||||
|
vkAllocateCommandBuffers(gtLogicalDevice, &tCommandAllocInfo, &tCommandBuffer);
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// begin recording work into the command buffer
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo tCommandBufferBeginInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||||
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkBeginCommandBuffer(tCommandBuffer, &tCommandBufferBeginInfo));
|
||||||
|
|
||||||
|
// bind compute pipeline
|
||||||
|
vkCmdBindPipeline(tCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, gtPipeline);
|
||||||
|
|
||||||
|
// bind resources (remember this is done in sets)
|
||||||
|
vkCmdBindDescriptorSets(tCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, gtPipelineLayout, 0, 1, >DescriptorSet, 0, 0);
|
||||||
|
|
||||||
|
// dispatch work
|
||||||
|
// vkCmdDispatch(tCommandBuffer, iImageWidth, iImageHeight, 1);
|
||||||
|
vkCmdDispatch(tCommandBuffer, iImageWidth, iImageHeight, 1);
|
||||||
|
|
||||||
|
// finish recording
|
||||||
|
VULKAN_CHECK(vkEndCommandBuffer(tCommandBuffer));
|
||||||
|
|
||||||
|
// submit command buffer to compute queue
|
||||||
|
const VkPipelineStageFlags tWaitStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
const VkSubmitInfo tComputeSubmitInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||||
|
.pWaitDstStageMask = &tWaitStageMask,
|
||||||
|
.commandBufferCount = 1,
|
||||||
|
.pCommandBuffers = &tCommandBuffer
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// create syncronization primitives
|
||||||
|
// - not really needed for this example but is required when submitting work
|
||||||
|
// I believe.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// fence for compute command buffer sync
|
||||||
|
const VkFenceCreateInfo tFenceCreateInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||||
|
.flags = VK_FENCE_CREATE_SIGNALED_BIT
|
||||||
|
};
|
||||||
|
VULKAN_CHECK(vkCreateFence(gtLogicalDevice, &tFenceCreateInfo, NULL, >ComputeWorkFence));
|
||||||
|
|
||||||
|
vkResetFences(gtLogicalDevice, 1, >ComputeWorkFence);
|
||||||
|
VULKAN_CHECK(vkQueueSubmit(gptGfx->get_vulkan_queue(ptAppData->ptDevice), 1, &tComputeSubmitInfo, gtComputeWorkFence));
|
||||||
|
|
||||||
|
// wait for fence to be signaled
|
||||||
|
VULKAN_CHECK(vkWaitForFences(gtLogicalDevice, 1, >ComputeWorkFence, VK_TRUE, UINT64_MAX));
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// RESULTS
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// can only output non-normalized unfortunately
|
||||||
|
unsigned char* pucResults = malloc(iImageHeight * iImageWidth * 4);
|
||||||
|
for(uint32_t i = 0; i < (uint32_t)(iImageHeight * iImageWidth * 4); i++)
|
||||||
|
pucResults[i] = (unsigned char)gpfMemoryMap[i];
|
||||||
|
|
||||||
|
plImageWriteInfo tWriteInfo = {
|
||||||
|
.iWidth = iImageWidth,
|
||||||
|
.iHeight = iImageHeight,
|
||||||
|
.iComponents = 4,
|
||||||
|
.iByteStride = iImageWidth * 4
|
||||||
|
};
|
||||||
|
gptImage->write("../../pl-template/out/test_image_results.png", pucResults, &tWriteInfo);
|
||||||
|
|
||||||
|
free(pucResults);
|
||||||
|
|
||||||
|
// unmap memory & cleanup storage buffer
|
||||||
|
vkUnmapMemory(gtLogicalDevice, gtStorageBufferMemory);
|
||||||
|
vkDestroyBuffer(gtLogicalDevice, gtStorageBuffer, NULL);
|
||||||
|
vkFreeMemory(gtLogicalDevice, gtStorageBufferMemory, NULL);
|
||||||
|
|
||||||
|
// cleanup pipeline & shader
|
||||||
|
vkDestroyShaderModule(gtLogicalDevice, gtShaderModule, NULL);
|
||||||
|
vkDestroyPipelineLayout(gtLogicalDevice, gtPipelineLayout, NULL);
|
||||||
|
vkDestroyPipeline(gtLogicalDevice, gtPipeline, NULL);
|
||||||
|
|
||||||
|
// cleanup some global resources
|
||||||
|
vkDestroyCommandPool(gtLogicalDevice, gtComputeCommandPool, NULL);
|
||||||
|
vkDestroyDescriptorSetLayout(gtLogicalDevice, gtDescriptorSetLayout, NULL);
|
||||||
|
vkDestroyDescriptorPool(gtLogicalDevice, gtDescriptorPool, NULL);
|
||||||
|
vkDestroyFence(gtLogicalDevice, gtComputeWorkFence, NULL);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user