summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Halase <jordan@halase.me>2019-10-28 21:46:49 -0500
committerJordan Halase <jordan@halase.me>2019-10-28 21:46:49 -0500
commit4293fa94b6a4f1b97c292390b89827fcaf861d9f (patch)
tree854444e52987382bc6a43f22d4a38b5ad95a8ed3
parent76a9df154c7f2316c3e32bb9c231af721ed0de02 (diff)
Add Pugl and overhaul
-rw-r--r--main.c176
1 files changed, 139 insertions, 37 deletions
diff --git a/main.c b/main.c
index 0d479b8..30d2933 100644
--- a/main.c
+++ b/main.c
@@ -43,8 +43,12 @@ PERFORMANCE OF THIS SOFTWARE.
#else
#include <X11/Xlib.h>
#include <vulkan/vulkan_xlib.h>
+#include "pugl/detail/x11.h"
#endif
+#include "pugl/pugl.h"
+#include "pugl/pugl_stub_backend.h"
+
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
@@ -68,6 +72,7 @@ struct VulkanAPI {
PFN_vkDestroyInstance vkDestroyInstance;
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
+ PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
@@ -86,18 +91,18 @@ struct RenderVulkan {
VkDevice device;
};
-#define ERRMSG_LEN 4096
+#define RVK_ERRMSG_LEN 4096
-void setErrMsg(struct RenderVulkan *vk, const char *fmt, ...)
+void rvkSetErrMsg(struct RenderVulkan *vk, const char *fmt, ...)
{
- vk->errMsg = realloc(vk->errMsg, ERRMSG_LEN);
+ vk->errMsg = realloc(vk->errMsg, RVK_ERRMSG_LEN);
va_list args;
va_start(args, fmt);
- stbsp_vsnprintf(vk->errMsg, ERRMSG_LEN, fmt, args);
+ stbsp_vsnprintf(vk->errMsg, RVK_ERRMSG_LEN, fmt, args);
va_end(args);
}
-void clearErrMsg(struct RenderVulkan *vk)
+void rvkClearErrMsg(struct RenderVulkan *vk)
{
if (vk->errMsg) {
free(vk->errMsg);
@@ -105,7 +110,7 @@ void clearErrMsg(struct RenderVulkan *vk)
}
}
-const char *getErrMsg(struct RenderVulkan *vk)
+const char *rvkGetErrMsg(struct RenderVulkan *vk)
{
return vk->errMsg;
}
@@ -154,6 +159,23 @@ void getRequiredInstanceExtensions(void *windowCtx,
*nRequired = num;
}
}
+
+VkResult createVulkanSurface(PuglView *view,
+ VkInstance instance,
+ PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc,
+ const VkAllocationCallbacks *pAllocator,
+ VkSurfaceKHR *pSurface)
+{
+ PuglWorld *world = ((struct PuglViewImpl*)view)->world;
+ VkWin32SurfaceCreateInfoKHR createInfo = { 0 };
+ createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ createInfo.hinstance = GetModuleHandle(0); // FIXME
+ createInfo.hwnd = puglGetNativeWindow(view);
+ PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
+ uintptr_t *const ulCreateWin32SurfaceKHR = (uintptr_t*)&vkCreateWin32SurfaceKHR;
+ *ulCreateWin32SurfaceKHR = (uintptr_t)getInstanceProcAddrFunc(instance, "vkCreateWin32SurfaceKHR");
+ return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
+}
#else
#define VULKAN_SONAME_LATEST "libvulkan.so.1"
#include <dlfcn.h>
@@ -177,7 +199,8 @@ int appDlclose(void *handle)
return dlclose(handle);
}
-/* TODO: Linux actually has three possible surfaces: Xlib, XCB, and Wayland.
+/* XXX: puglGetRequiredInstanceExtensions()
+ * TODO: Linux actually has three possible surfaces: Xlib, XCB, and Wayland.
* This should be figured out at runtime (without using #ifdefs).
* In which case, `windowCtx` will be used to determine which to use.
* As of now, Pugl (and LV2!) only supports Xlib.
@@ -200,6 +223,26 @@ void getRequiredInstanceExtensions(void *windowCtx,
*nRequired = num;
}
}
+
+/* XXX: puglCreateVulkanSurface()
+ * No need to wrap VkFreeSurfaceKHR()
+ */
+VkResult createVulkanSurface(PuglView *view,
+ VkInstance instance,
+ PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc,
+ const VkAllocationCallbacks *pAllocator,
+ VkSurfaceKHR *pSurface)
+{
+ PuglWorld *world = ((struct PuglViewImpl*)view)->world;
+ VkXlibSurfaceCreateInfoKHR createInfo = { 0 };
+ createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ createInfo.dpy = ((struct PuglWorldImpl*)world)->impl->display;
+ createInfo.window = puglGetNativeWindow(view);
+ PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
+ uintptr_t *const ulCreateXlibSurfaceKHR = (uintptr_t*)&vkCreateXlibSurfaceKHR;
+ *ulCreateXlibSurfaceKHR = (uintptr_t)getInstanceProcAddrFunc(instance, "vkCreateXlibSurfaceKHR");
+ return vkCreateXlibSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
+}
#endif
void *loadVulkanLibrary(const char *prefix)
@@ -239,7 +282,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
return VK_FALSE;
}
-VkResult createInstance(struct RenderVulkan *vk,
+static VkResult createInstance(struct RenderVulkan *vk,
const uint32_t nLayers, const char *const *const layers,
const uint32_t nAdditional, const char *const *const additionalExtensions)
{
@@ -281,23 +324,24 @@ VkResult createInstance(struct RenderVulkan *vk,
VkResult result = VK_SUCCESS;
if ((result = vk->api->vkCreateInstance(&createInfo, ALLOC_VK, &vk->instance))) {
- setErrMsg(vk, "Could not create Vulkan Instance: %d\n", result);
+ rvkSetErrMsg(vk, "Could not create Vulkan Instance: %d\n", result);
}
free(extensions);
return result;
}
/** Must not be called until all derivative objects are destroyed first */
-void destroyInstance(struct RenderVulkan *vk)
+static void destroyInstance(struct RenderVulkan *vk)
{
vk->api->vkDestroyInstance(vk->instance, ALLOC_VK);
vk->instance = VK_NULL_HANDLE;
}
/** This must work no matter the current state of `vk` */
-void renderVulkanDestroy(struct RenderVulkan *vk)
+void rvkDestroy(struct RenderVulkan *vk)
{
if (vk) {
+ if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK);
if (vk->debugCallback) {
/* `vk->debugCallback` implies `vk->api` and instance functions loaded */
vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK);
@@ -315,10 +359,10 @@ void renderVulkanDestroy(struct RenderVulkan *vk)
/** Create a self-contained Vulkan instance and set up a debug reporter
*
* If errors occurred, the struct will be returned in an unusable state,
- * and MUST be checked via `getErrMsg`. It MUST then be destroyed via
- * `renderVulkanDestroy`.
+ * and MUST be checked via `rvkGetErrMsg`. It MUST then be destroyed via
+ * `rvkDestroy`.
* */
-struct RenderVulkan *renderVulkanCreate()
+struct RenderVulkan *rvkCreate()
{
static const char *const instanceLayers[] = {
"VK_LAYER_LUNARG_standard_validation"
@@ -334,20 +378,20 @@ struct RenderVulkan *renderVulkanCreate()
vk->api->handle = loadVulkanLibrary(NULL);
if (!vk->api->handle) {
- setErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror());
+ rvkSetErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror());
return vk;
}
loadVulkanGetInstanceProcAddrFunc(vk->api->handle, &vk->api->vkGetInstanceProcAddr);
if (!vk->api->vkGetInstanceProcAddr) {
- setErrMsg(vk, "Error loading `vkGetInstanceProcAddr`:\n%s", appDlerror());
+ rvkSetErrMsg(vk, "Error loading `vkGetInstanceProcAddr`:\n%s", appDlerror());
return vk;
}
uintptr_t *const ulCreateInstance = (uintptr_t*)&vk->api->vkCreateInstance;
*ulCreateInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(NULL, "vkCreateInstance");
if (!vk->api->vkCreateInstance) {
- setErrMsg(vk, "Error loading `vkCreateInstance`");
+ rvkSetErrMsg(vk, "Error loading `vkCreateInstance`");
return vk;
}
@@ -364,7 +408,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *const ulDestroyInstance = (uintptr_t*)&vk->api->vkDestroyInstance;
*ulDestroyInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroyInstance);
if (!vk->api->vkDestroyInstance) {
- setErrMsg(vk, strErrLd, strDestroyInstance);
+ rvkSetErrMsg(vk, strErrLd, strDestroyInstance);
return vk;
}
@@ -377,7 +421,15 @@ struct RenderVulkan *renderVulkanCreate()
/* But not if we are unable to destroy a created debug reporter */
if (vk->api->vkCreateDebugReportCallbackEXT && !vk->api->vkDestroyDebugReportCallbackEXT) {
- setErrMsg(vk, "No debug reporter destroy function loaded for corresponding create function\n");
+ rvkSetErrMsg(vk, "No debug reporter destroy function loaded for corresponding create function\n");
+ return vk;
+ }
+
+ static const char *const strDestroySurfaceKHR = "vkDestroySurfaceKHR";
+ uintptr_t *ulDestroySurfaceKHR = (uintptr_t*)&vk->api->vkDestroySurfaceKHR;
+ *ulDestroySurfaceKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroySurfaceKHR);
+ if (!vk->api->vkDestroySurfaceKHR) {
+ rvkSetErrMsg(vk, strErrLd, strDestroySurfaceKHR);
return vk;
}
@@ -385,7 +437,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *ulEnumeratePhysicalDevices = (uintptr_t*)&vk->api->vkEnumeratePhysicalDevices;
*ulEnumeratePhysicalDevices = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumeratePhysicalDevices);
if (!vk->api->vkEnumeratePhysicalDevices) {
- setErrMsg(vk, strErrLd, strEnumeratePhysicalDevices);
+ rvkSetErrMsg(vk, strErrLd, strEnumeratePhysicalDevices);
return vk;
}
@@ -393,7 +445,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *ulGetPhysicalDeviceProperties = (uintptr_t*)&vk->api->vkGetPhysicalDeviceProperties;
*ulGetPhysicalDeviceProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceProperties);
if (!vk->api->vkGetPhysicalDeviceProperties) {
- setErrMsg(vk, strErrLd, strGetPhysicalDeviceProperties);
+ rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceProperties);
return vk;
}
@@ -401,7 +453,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *ulGetPhysicalDeviceQueueFamilyProperties = (uintptr_t*)&vk->api->vkGetPhysicalDeviceQueueFamilyProperties;
*ulGetPhysicalDeviceQueueFamilyProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceQueueFamilyProperties);
if (!vk->api->vkGetPhysicalDeviceQueueFamilyProperties) {
- setErrMsg(vk, strErrLd, strGetPhysicalDeviceQueueFamilyProperties);
+ rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceQueueFamilyProperties);
return vk;
}
@@ -409,7 +461,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *ulGetPhysicalDeviceSurfaceSupportKHR = (uintptr_t*)&vk->api->vkGetPhysicalDeviceSurfaceSupportKHR;
*ulGetPhysicalDeviceSurfaceSupportKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceSurfaceSupportKHR);
if (!vk->api->vkGetPhysicalDeviceSurfaceSupportKHR) {
- setErrMsg(vk, strErrLd, strGetPhysicalDeviceSurfaceSupportKHR);
+ rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceSurfaceSupportKHR);
return vk;
}
@@ -417,7 +469,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *ulGetPhysicalDeviceMemoryProperties = (uintptr_t*)&vk->api->vkGetPhysicalDeviceMemoryProperties;
*ulGetPhysicalDeviceMemoryProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceMemoryProperties);
if (!vk->api->vkGetPhysicalDeviceMemoryProperties) {
- setErrMsg(vk, strErrLd, strGetPhysicalDeviceMemoryProperties);
+ rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceMemoryProperties);
return vk;
}
@@ -425,7 +477,7 @@ struct RenderVulkan *renderVulkanCreate()
uintptr_t *ulEnumerateDeviceExtensionProperties = (uintptr_t*)&vk->api->vkEnumerateDeviceExtensionProperties;
*ulEnumerateDeviceExtensionProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumerateDeviceExtensionProperties);
if (!vk->api->vkEnumerateDeviceExtensionProperties) {
- setErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties);
+ rvkSetErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties);
return vk;
}
@@ -436,7 +488,7 @@ struct RenderVulkan *renderVulkanCreate()
debugInfo.pfnCallback = debugCallback;
if ((result = vk->api->vkCreateDebugReportCallbackEXT(vk->instance,
&debugInfo, ALLOC_VK, &vk->debugCallback))) {
- setErrMsg(vk, "Could not create debug reporter: %d", result);
+ rvkSetErrMsg(vk, "Could not create debug reporter: %d", result);
return vk;
}
}
@@ -444,6 +496,14 @@ struct RenderVulkan *renderVulkanCreate()
return vk;
}
+static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)
+{
+ VkResult result;
+ if ((result = createVulkanSurface(view, vk->instance, vk->api->vkGetInstanceProcAddr, ALLOC_VK, &vk->surface))) {
+ rvkSetErrMsg(vk, "Could not create window surface: %d\n", result);
+ }
+}
+
int isDeviceSuitable(struct RenderVulkan *vk, VkPhysicalDevice pd)
{
uint32_t nQueueFamilies;
@@ -472,10 +532,10 @@ int isDeviceSuitable(struct RenderVulkan *vk, VkPhysicalDevice pd)
return 1;
}
-void selectPhysicalDevice(struct RenderVulkan *vk)
+void rvkSelectPhysicalDevice(struct RenderVulkan *vk)
{
if (!vk->surface) {
- setErrMsg(vk, "Cannot select a physical device without a surface");
+ rvkSetErrMsg(vk, "Cannot select a physical device without a surface");
return;
}
static const char *const strErrEnum = "Could not enumerate physical devices: %s";
@@ -484,20 +544,20 @@ void selectPhysicalDevice(struct RenderVulkan *vk)
VkResult result;
if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) {
if (result != VK_INCOMPLETE) {
- setErrMsg(vk, strErrEnum, result);
+ rvkSetErrMsg(vk, strErrEnum, result);
return;
} else {
fprintf(stderr, "%s\n", strWarnEnum);
}
}
if (!nDevices) {
- setErrMsg(vk, "No physical devices found");
+ rvkSetErrMsg(vk, "No physical devices found");
return;
}
VkPhysicalDevice *devices = malloc(nDevices * sizeof(*devices));
if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) {
if (result != VK_INCOMPLETE) {
- setErrMsg(vk, strErrEnum, result);
+ rvkSetErrMsg(vk, strErrEnum, result);
goto done;
} else {
fprintf(stderr, "%s\n", strWarnEnum);
@@ -521,7 +581,7 @@ void selectPhysicalDevice(struct RenderVulkan *vk)
printf("Device `%s` not suitable\n", deviceProperties.deviceName);
}
if (i >= nDevices) {
- setErrMsg(vk, "No suitable devices found");
+ rvkSetErrMsg(vk, "No suitable devices found");
}
done:
free(devices);
@@ -530,25 +590,67 @@ done:
void rvkCheckFatal(struct RenderVulkan *vk)
{
const char *errMsg = NULL;
- if ((errMsg = getErrMsg(vk))) {
+ if ((errMsg = rvkGetErrMsg(vk))) {
fprintf(stderr, "%s\n", errMsg);
- renderVulkanDestroy(vk);
+ rvkDestroy(vk);
exit(1);
}
}
+int running = 1;
+
+PuglStatus onEvent(PuglView *view, const PuglEvent *e)
+{
+ switch (e->type) {
+ case PUGL_CLOSE:
+ running = 0;
+ break;
+ default:
+ break;
+ }
+ return PUGL_SUCCESS;
+}
+
int main()
{
+#if defined(__linux__)
+ XInitThreads();
+#endif
const char *errMsg = NULL;
- struct RenderVulkan *vk = renderVulkanCreate();
+ struct RenderVulkan *vk = rvkCreate();
rvkCheckFatal(vk);
printf("Created Vulkan Instance Successfully\n");
- selectPhysicalDevice(vk);
+ 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"))) {
+ fprintf(stderr, "Could not create window: %d\n", status);
+ rvkDestroy(vk);
+ puglFreeWorld(world);
+ exit(1);
+ }
+ puglSetEventFunc(view, onEvent);
+
+ rvkCreateSurface(vk, view);
rvkCheckFatal(vk);
- renderVulkanDestroy(vk);
+ rvkSelectPhysicalDevice(vk);
+ rvkCheckFatal(vk);
+
+ puglShowWindow(view);
+ while (running) {
+ puglPollEvents(world, -1);
+ puglDispatchEvents(world);
+ }
+
+ puglFreeView(view);
+ puglFreeWorld(world);
+ rvkDestroy(vk);
return 0;
}