summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Halase <jordan@halase.me>2019-10-30 16:54:54 -0500
committerJordan Halase <jordan@halase.me>2019-10-30 16:54:54 -0500
commit8700e9a9bcab89de998d9e9b43372bc574c86cc0 (patch)
tree8b7022389b7ac507683c1610f1730ab705c6a479
parentd73a1c763f36e1560efc2536f8219784a32a617d (diff)
Refactor
-rw-r--r--CMakeLists.txt2
-rw-r--r--main.c117
2 files changed, 79 insertions, 40 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3192c6a..e63816d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.2)
project(vkpugltest LANGUAGES C)
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
+
set(pugldir "../../pugl")
set(PUGL_INCLUDE "${pugldir}")
set(PUGL_LIBDIR "${pugldir}/build")
diff --git a/main.c b/main.c
index fb81e89..e0d2451 100644
--- a/main.c
+++ b/main.c
@@ -83,8 +83,10 @@ struct VulkanAPI {
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
};
+/** Vulkan application that uses Pugl for windows and events */
struct RenderVulkan {
struct VulkanAPI *api;
+ PuglWorld *world;
char *errMsg;
VkInstance instance;
VkDebugReportCallbackEXT debugCallback;
@@ -121,12 +123,12 @@ const char *rvkGetErrMsg(struct RenderVulkan *vk)
#if defined(_WIN32)
#define VULKAN_SONAME_LATEST "vulkan-1.dll"
-void *appDlopen(const char *soname)
+static inline void *appDlopen(const char *soname)
{
return LoadLibraryA(soname);
}
-char *appDlerror()
+static inline char *appDlerror()
{
// TODO: Print a more informative string. Error codes are annoying.
DWORD errCode = GetLastError();
@@ -135,34 +137,39 @@ char *appDlerror()
return errStr;
}
-void *appDlsym(void *handle, const char *symbol)
+static inline void *appDlsym(void *handle, const char *symbol)
{
const uintptr_t ulAddr = (uintptr_t)GetProcAddress(handle, symbol);
return (void*)ulAddr;
}
-int appDlclose(void *handle)
+static inline int appDlclose(void *handle)
{
return FreeLibrary(handle);
}
-void getRequiredInstanceExtensions(PuglWorld *world,
- unsigned *pExtensionCount,
+PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
+ uint32_t *pExtensionCount,
const char **const ppExtensionNames)
{
- (void)world;
+ if (!world) {
+ if (pExtensionCount) *pExtensionCount = 0;
+ if (ppExtensionNames) *ppExtensionNames = NULL;
+ return PUGL_FAILURE;
+ }
static const char *const required[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
};
- static const unsigned num = sizeof(required) / sizeof(required[0]);
+ static const uint32_t num = sizeof(required) / sizeof(required[0]);
if (ppExtensionNames) {
- for (int i = 0; i < num; ++i) {
+ for (uint32_t i = 0; i < num; ++i) {
ppExtensionNames[i] = required[i];
}
} else {
*pExtensionCount = num;
}
+ return PUGL_SUCCESS;
}
VkResult createVulkanSurface(PuglView *view,
@@ -184,36 +191,31 @@ VkResult createVulkanSurface(PuglView *view,
#else
#define VULKAN_SONAME_LATEST "libvulkan.so.1"
#include <dlfcn.h>
-// XXX: puglDlopen()
-void *appDlopen(const char *soname)
+// XXX: puglDlopen() and friends
+static inline void *appDlopen(const char *soname)
{
return dlopen(soname, RTLD_NOW);
}
-char *appDlerror()
+static inline char *appDlerror()
{
return dlerror();
}
-void *appDlsym(void *handle, const char *symbol)
+static inline void *appDlsym(void *handle, const char *symbol)
{
return dlsym(handle, symbol);
}
-int appDlclose(void *handle)
+static inline int appDlclose(void *handle)
{
return dlclose(handle);
}
/* XXX: puglGetRequiredInstanceExtensions()
- * This will return the platform-specific names of the instance level
- * extensions required to display images to the screen.
- * Vulkan is off-screen by default and can be used without presenting
- * at all, so off-screen applications will not need to call this
- * function. In other words:
- *
- * "Get the names of the required instance extensions if you want to
- * display your images to the screen."
+ * "Get the platform-specific names of the required instance-level
+ * extensions if you want to display your images to the screen."
+ * Reminder that Vulkan is off-screen by default.
*
* TODO: Linux actually has three possible surfaces: Xlib, XCB, and Wayland.
* This should be figured out at runtime (without using #ifdefs).
@@ -222,27 +224,38 @@ int appDlclose(void *handle)
* variable should be left in the function signature for forward
* compatibility.
*/
-void getRequiredInstanceExtensions(PuglWorld *world,
- unsigned *pExtensionCount,
+PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
+ uint32_t *pExtensionCount,
const char **const ppExtensionNames)
{
- (void)world;
+ if (!world) {
+ if (pExtensionCount) *pExtensionCount = 0;
+ if (ppExtensionNames) *ppExtensionNames = NULL;
+ return PUGL_FAILURE;
+ }
+ // TODO: if (world->system == X11) { ... } else if (world->system == Wayland) { ... } else ...
static const char *const required[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME
};
- static const unsigned num = sizeof(required) / sizeof(required[0]);
+ static const uint32_t num = sizeof(required) / sizeof(required[0]);
if (ppExtensionNames) {
- for (int i = 0; i < num; ++i) {
+ for (uint32_t i = 0; i < num; ++i) {
ppExtensionNames[i] = required[i];
}
} else {
*pExtensionCount = num;
}
+ return PUGL_SUCCESS;
}
/* XXX: puglCreateVulkanSurface()
- * No need to wrap VkFreeSurfaceKHR()
+ *
+ * Creating a surface is platform-specific and should be handled by Pugl
+ * with this function exposed publicly.
+ *
+ * No need to wrap vkFreeSurfaceKHR(). Creating a surface is platform
+ * specific, but freeing it is not.
*/
VkResult createVulkanSurface(PuglView *view,
VkInstance instance,
@@ -312,13 +325,13 @@ static VkResult createInstance(struct RenderVulkan *vk,
/* MoltenVK for macOS currently only supports Vulkan 1.0 */
appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
- unsigned i, j, nRequired;
- getRequiredInstanceExtensions(NULL, &nRequired, NULL);
+ uint32_t i, j, nRequired;
+ getRequiredInstanceExtensions(vk->world, &nRequired, NULL);
const uint32_t nExtensions = nRequired + nAdditional;
const char **const extensions = malloc(sizeof(const char*) * nExtensions);
- getRequiredInstanceExtensions(NULL, NULL, extensions);
+ getRequiredInstanceExtensions(vk->world, NULL, extensions);
for (i = nRequired, j = 0; i < nExtensions; ++i, ++j) {
extensions[i] = additionalExtensions[j];
}
@@ -375,11 +388,24 @@ void rvkDestroy(struct RenderVulkan *vk)
/** Create a self-contained Vulkan instance and set up a debug reporter
*
+ * XXX
+ *
+ * At the moment `world` is not used for anything, but if/when Pugl supports
+ * dynamically choosing a backend (X11, XCB, Wayland), it is anticipated that
+ * `world` will contain information regarding which is in use, which will then
+ * be used by `createVulkanSurface`.
+ *
+ * If creating a surface is handled by Pugl (`puglCreateVulkanSurface`), then
+ * `PuglWorld` can remain completely opaque to the application.
+ *
+ * `world` is NOT internally managed by the application. It MUST be destroyed
+ * separately.
+ *
* If errors occurred, the struct will be returned in an unusable state,
* and MUST be checked via `rvkGetErrMsg`. It MUST then be destroyed via
* `rvkDestroy`.
* */
-struct RenderVulkan *rvkCreate()
+struct RenderVulkan *rvkCreate(PuglWorld *world)
{
static const char *const instanceLayers[] = {
"VK_LAYER_LUNARG_standard_validation"
@@ -391,6 +417,11 @@ struct RenderVulkan *rvkCreate()
const uint32_t nInstanceExtensions = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]);
struct RenderVulkan *vk = calloc(1, sizeof(*vk));
+ if (!world) {
+ rvkSetErrMsg(vk, "No PuglWorld provided");
+ return vk;
+ }
+ vk->world = world;
vk->api = calloc(1, sizeof(*vk->api));
vk->api->handle = loadVulkanLibrary(NULL);
@@ -570,14 +601,12 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)
*
* Because this application will load all resources before any rendering begins,
* and the amount of resources are small enough to be loaded almost instantly,
- * it will not make use of a separate TRANSFER queue family. This application
- * will also not attempt to find the "most powerful" device on the system, and
- * will choose the first suitable device it finds.
+ * it will not make use of a separate TRANSFER queue family.
*
* Information for many devices is available online at
* https://vulkan.gpuinfo.org/
*/
-static int isDeviceSuitable(const struct RenderVulkan *const vk,
+static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk,
const VkPhysicalDevice physicalDevice,
uint32_t *const graphicsIndex)
{
@@ -622,6 +651,11 @@ static int isDeviceSuitable(const struct RenderVulkan *const vk,
return 1;
}
+/** Selects a physical device
+ *
+ * This application will not attempt to find the "most powerful" device on the
+ * system, and will choose the first suitable device it finds.
+ */
void rvkSelectPhysicalDevice(struct RenderVulkan *vk)
{
if (!vk->surface) {
@@ -663,7 +697,7 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk)
for (i = 0; i < nDevices; ++i) {
printf("Checking suitability for\t`%s`...\n", deviceProperties[i].deviceName);
uint32_t graphicsIndex;
- if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) {
+ if (rvkIsDeviceSuitable(vk, devices[i], &graphicsIndex)) {
printf("Using physical device:\t\t`%s`\n", deviceProperties[i].deviceName);
vk->deviceProperties = deviceProperties[i];
vk->physicalDevice = devices[i];
@@ -712,19 +746,21 @@ int main()
/* The Mesa Vulkan drivers require this to be called */
XInitThreads();
#endif
+ PuglWorld *world = puglNewWorld();
const char *errMsg = NULL;
- struct RenderVulkan *vk = rvkCreate();
+
+ /** Vulkan application that uses Pugl for windows and events */
+ struct RenderVulkan *vk = rvkCreate(world);
rvkCheckFatal(vk);
printf("Created Vulkan Instance Successfully\n");
- PuglWorld *world = puglNewWorld();
PuglView *view = puglNewView(world);
const PuglRect frame = { 0, 0, 800, 600 };
puglSetBackend(view, puglStubBackend());
PuglStatus status;
- if ((status = puglCreateWindow(view, "Pugl Vulkan Test"))) {
+ if ((status = puglCreateWindow(view, "Vulkan Application Using Pugl"))) {
fprintf(stderr, "Could not create window: %d\n", status);
rvkDestroy(vk);
puglFreeWorld(world);
@@ -746,6 +782,7 @@ int main()
puglFreeView(view);
puglFreeWorld(world);
+ /* Vulkan library MUST be unloaded AFTER call to XCloseDisplay() or it will segfault */
rvkDestroy(vk);
return 0;
}