diff --git a/BUILD.md b/BUILD.md
index 411895db..c99b7c74 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -20,6 +20,7 @@ Use the provided CMakeLists.txt with [CMake](https://cmake.org) to generate a bu
##### [Window system integration](https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#wsi)
- **XCB**: Default WSI (if no cmake option is specified)
- **Wayland**: Use cmake option ```USE_WAYLAND_WSI``` (```-DUSE_WAYLAND_WSI=ON```)
+- **DirectFB**: Use cmake option ```USE_DIRECTFB_WSI``` (```-DUSE_DIRECTFB_WSI=ON```)
- **DirectToDisplay**: Use cmake option ```USE_D2D_WSI``` (```-DUSE_D2D_WSI=ON```)
##
[Android](android/)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd2814b2..15913934 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,7 @@ include_directories(external/ktx/other_include)
include_directories(base)
OPTION(USE_D2D_WSI "Build the project using Direct to Display swapchain" OFF)
+OPTION(USE_DIRECTFB_WSI "Build the project using DirectFB swapchain" OFF)
OPTION(USE_WAYLAND_WSI "Build the project using Wayland swapchain" OFF)
set(RESOURCE_INSTALL_DIR "" CACHE PATH "Path to install resources to (leave empty for running uninstalled)")
@@ -51,6 +52,10 @@ ELSEIF(LINUX)
IF(USE_D2D_WSI)
MESSAGE("Using direct to display extension...")
add_definitions(-D_DIRECT2DISPLAY)
+ ELSEIF(USE_DIRECTFB_WSI)
+ find_package(DirectFB REQUIRED)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_DIRECTFB_EXT")
+ include_directories(${DIRECTFB_INCLUDE_DIR})
ELSEIF(USE_WAYLAND_WSI)
find_program(PKG_CONFIG pkg-config)
if (NOT PKG_CONFIG)
@@ -130,7 +135,7 @@ IF(WIN32)
ELSEIF(APPLE)
link_libraries(${Vulkan_LIBRARY} "-framework AppKit" "-framework QuartzCore")
ELSE(WIN32)
- link_libraries(${XCB_LIBRARIES} ${Vulkan_LIBRARY} ${Vulkan_LIBRARY} ${WAYLAND_CLIENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+ link_libraries(${XCB_LIBRARIES} ${Vulkan_LIBRARY} ${Vulkan_LIBRARY} ${DIRECTFB_LIBRARIES} ${WAYLAND_CLIENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(WIN32)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/")
diff --git a/base/VulkanSwapChain.cpp b/base/VulkanSwapChain.cpp
index 8af7b3c3..64bb0d49 100644
--- a/base/VulkanSwapChain.cpp
+++ b/base/VulkanSwapChain.cpp
@@ -15,6 +15,8 @@
void VulkanSwapChain::initSurface(void* platformHandle, void* platformWindow)
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
void VulkanSwapChain::initSurface(ANativeWindow* window)
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+void VulkanSwapChain::initSurface(IDirectFB* dfb, IDirectFBSurface* window)
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
void VulkanSwapChain::initSurface(wl_display *display, wl_surface *window)
#elif defined(VK_USE_PLATFORM_XCB_KHR)
@@ -55,6 +57,12 @@ void VulkanSwapChain::initSurface(uint32_t width, uint32_t height)
err = vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, NULL, &surface);
#elif defined(_DIRECT2DISPLAY)
createDirect2DisplaySurface(width, height);
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ VkDirectFBSurfaceCreateInfoEXT surfaceCreateInfo = {};
+ surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT;
+ surfaceCreateInfo.dfb = dfb;
+ surfaceCreateInfo.surface = window;
+ err = vkCreateDirectFBSurfaceEXT(instance, &surfaceCreateInfo, nullptr, &surface);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
diff --git a/base/VulkanSwapChain.h b/base/VulkanSwapChain.h
index bd2622ad..67b72a52 100644
--- a/base/VulkanSwapChain.h
+++ b/base/VulkanSwapChain.h
@@ -58,6 +58,8 @@ public:
void initSurface(void* platformHandle, void* platformWindow);
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
void initSurface(ANativeWindow* window);
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ void initSurface(IDirectFB* dfb, IDirectFBSurface* window);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
void initSurface(wl_display* display, wl_surface* window);
#elif defined(VK_USE_PLATFORM_XCB_KHR)
diff --git a/base/keycodes.hpp b/base/keycodes.hpp
index 7120070a..d9d7f654 100644
--- a/base/keycodes.hpp
+++ b/base/keycodes.hpp
@@ -89,6 +89,27 @@
#define KEY_O 0x1F
#define KEY_T 0x11
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+#define KEY_ESCAPE DIKS_ESCAPE
+#define KEY_F1 DIKS_F1
+#define KEY_F2 DIKS_F2
+#define KEY_F3 DIKS_F3
+#define KEY_F4 DIKS_F4
+#define KEY_W DIKS_SMALL_W
+#define KEY_A DIKS_SMALL_A
+#define KEY_S DIKS_SMALL_S
+#define KEY_D DIKS_SMALL_D
+#define KEY_P DIKS_SMALL_P
+#define KEY_SPACE DIKS_SPACE
+#define KEY_KPADD DIKS_PLUS_SIGN
+#define KEY_KPSUB DIKS_MINUS_SIGN
+#define KEY_B DIKS_SMALL_B
+#define KEY_F DIKS_SMALL_F
+#define KEY_L DIKS_SMALL_L
+#define KEY_N DIKS_SMALL_N
+#define KEY_O DIKS_SMALL_O
+#define KEY_T DIKS_SMALL_T
+
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
#include
diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp
index 9e4a2b5b..68029abf 100644
--- a/base/vulkanexamplebase.cpp
+++ b/base/vulkanexamplebase.cpp
@@ -41,6 +41,8 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation)
instanceExtensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
#elif defined(_DIRECT2DISPLAY)
instanceExtensions.push_back(VK_KHR_DISPLAY_EXTENSION_NAME);
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ instanceExtensions.push_back(VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
instanceExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#elif defined(VK_USE_PLATFORM_XCB_KHR)
@@ -437,6 +439,48 @@ void VulkanExampleBase::renderLoop()
}
updateOverlay();
}
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ while (!quit)
+ {
+ auto tStart = std::chrono::high_resolution_clock::now();
+ if (viewUpdated)
+ {
+ viewUpdated = false;
+ viewChanged();
+ }
+ DFBWindowEvent event;
+ while (!event_buffer->GetEvent(event_buffer, DFB_EVENT(&event)))
+ {
+ handleEvent(&event);
+ }
+ render();
+ frameCounter++;
+ auto tEnd = std::chrono::high_resolution_clock::now();
+ auto tDiff = std::chrono::duration(tEnd - tStart).count();
+ frameTimer = tDiff / 1000.0f;
+ camera.update(frameTimer);
+ if (camera.moving())
+ {
+ viewUpdated = true;
+ }
+ // Convert to clamped timer value
+ if (!paused)
+ {
+ timer += timerSpeed * frameTimer;
+ if (timer > 1.0)
+ {
+ timer -= 1.0f;
+ }
+ }
+ float fpsTimer = std::chrono::duration(tEnd - lastTimestamp).count();
+ if (fpsTimer > 1000.0f)
+ {
+ lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
+ frameCounter = 0;
+ lastTimestamp = tEnd;
+ }
+ updateOverlay();
+ }
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
while (!quit)
{
@@ -806,6 +850,17 @@ VulkanExampleBase::~VulkanExampleBase()
#if defined(_DIRECT2DISPLAY)
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ if (event_buffer)
+ event_buffer->Release(event_buffer);
+ if (surface)
+ surface->Release(surface);
+ if (window)
+ window->Release(window);
+ if (layer)
+ layer->Release(layer);
+ if (dfb)
+ dfb->Release(dfb);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
xdg_toplevel_destroy(xdg_toplevel);
xdg_surface_destroy(xdg_surface);
@@ -1684,6 +1739,200 @@ void VulkanExampleBase::windowDidResize()
resizing = false;
}
#elif defined(_DIRECT2DISPLAY)
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+IDirectFBSurface *VulkanExampleBase::setupWindow()
+{
+ DFBResult ret;
+ int posx = 0, posy = 0;
+
+ ret = DirectFBInit(NULL, NULL);
+ if (ret)
+ {
+ std::cout << "Could not initialize DirectFB!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ ret = DirectFBCreate(&dfb);
+ if (ret)
+ {
+ std::cout << "Could not create main interface of DirectFB!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ ret = dfb->GetDisplayLayer(dfb, DLID_PRIMARY, &layer);
+ if (ret)
+ {
+ std::cout << "Could not get DirectFB display layer interface!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ DFBDisplayLayerConfig layer_config;
+ ret = layer->GetConfiguration(layer, &layer_config);
+ if (ret)
+ {
+ std::cout << "Could not get DirectFB display layer configuration!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ if (settings.fullscreen)
+ {
+ width = layer_config.width;
+ height = layer_config.height;
+ }
+ else
+ {
+ if (layer_config.width > width)
+ posx = (layer_config.width - width) / 2;
+ if (layer_config.height > height)
+ posy = (layer_config.height - height) / 2;
+ }
+
+ DFBWindowDescription desc;
+ desc.flags = (DFBWindowDescriptionFlags)(DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_POSX | DWDESC_POSY);
+ desc.width = width;
+ desc.height = height;
+ desc.posx = posx;
+ desc.posy = posy;
+ ret = layer->CreateWindow(layer, &desc, &window);
+ if (ret)
+ {
+ std::cout << "Could not create DirectFB window interface!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ ret = window->GetSurface(window, &surface);
+ if (ret)
+ {
+ std::cout << "Could not get DirectFB surface interface!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ ret = window->CreateEventBuffer(window, &event_buffer);
+ if (ret)
+ {
+ std::cout << "Could not create DirectFB event buffer interface!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ ret = window->SetOpacity(window, 0xFF);
+ if (ret)
+ {
+ std::cout << "Could not set DirectFB window opacity!\n";
+ fflush(stdout);
+ exit(1);
+ }
+
+ return surface;
+}
+
+void VulkanExampleBase::handleEvent(const DFBWindowEvent *event)
+{
+ switch (event->type)
+ {
+ case DWET_CLOSE:
+ quit = true;
+ break;
+ case DWET_MOTION:
+ handleMouseMove(event->x, event->y);
+ break;
+ case DWET_BUTTONDOWN:
+ switch (event->button)
+ {
+ case DIBI_LEFT:
+ mouseButtons.left = true;
+ break;
+ case DIBI_MIDDLE:
+ mouseButtons.middle = true;
+ break;
+ case DIBI_RIGHT:
+ mouseButtons.right = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ case DWET_BUTTONUP:
+ switch (event->button)
+ {
+ case DIBI_LEFT:
+ mouseButtons.left = false;
+ break;
+ case DIBI_MIDDLE:
+ mouseButtons.middle = false;
+ break;
+ case DIBI_RIGHT:
+ mouseButtons.right = false;
+ break;
+ default:
+ break;
+ }
+ break;
+ case DWET_KEYDOWN:
+ switch (event->key_symbol)
+ {
+ case KEY_W:
+ camera.keys.up = true;
+ break;
+ case KEY_S:
+ camera.keys.down = true;
+ break;
+ case KEY_A:
+ camera.keys.left = true;
+ break;
+ case KEY_D:
+ camera.keys.right = true;
+ break;
+ case KEY_P:
+ paused = !paused;
+ break;
+ case KEY_F1:
+ if (settings.overlay) {
+ settings.overlay = !settings.overlay;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case DWET_KEYUP:
+ switch (event->key_symbol)
+ {
+ case KEY_W:
+ camera.keys.up = false;
+ break;
+ case KEY_S:
+ camera.keys.down = false;
+ break;
+ case KEY_A:
+ camera.keys.left = false;
+ break;
+ case KEY_D:
+ camera.keys.right = false;
+ break;
+ case KEY_ESCAPE:
+ quit = true;
+ break;
+ default:
+ break;
+ }
+ keyPressed(event->key_symbol);
+ break;
+ case DWET_SIZE:
+ destWidth = event->w;
+ destHeight = event->h;
+ windowResize();
+ break;
+ default:
+ break;
+ }
+}
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
/*static*/void VulkanExampleBase::registryGlobalCb(void *data,
wl_registry *registry, uint32_t name, const char *interface,
@@ -2494,6 +2743,8 @@ void VulkanExampleBase::initSwapchain()
swapChain.initSurface(view);
#elif defined(_DIRECT2DISPLAY)
swapChain.initSurface(width, height);
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ swapChain.initSurface(dfb, surface);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
swapChain.initSurface(display, surface);
#elif defined(VK_USE_PLATFORM_XCB_KHR)
diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h
index 0dacf59f..79acdf42 100644
--- a/base/vulkanexamplebase.h
+++ b/base/vulkanexamplebase.h
@@ -20,6 +20,8 @@
#include
#include
#include "VulkanAndroid.h"
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+#include
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
#include
#include "xdg-shell-client-protocol.h"
@@ -230,6 +232,13 @@ public:
int64_t lastTapTime = 0;
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
void* view;
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ bool quit = false;
+ IDirectFB *dfb = nullptr;
+ IDirectFBDisplayLayer *layer = nullptr;
+ IDirectFBWindow *window = nullptr;
+ IDirectFBSurface *surface = nullptr;
+ IDirectFBEventBuffer *event_buffer = nullptr;
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_display *display = nullptr;
wl_registry *registry = nullptr;
@@ -273,6 +282,9 @@ public:
void mouseDragged(float x, float y);
void windowWillResize(float x, float y);
void windowDidResize();
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+ IDirectFBSurface *setupWindow();
+ void handleEvent(const DFBWindowEvent *event);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
struct xdg_surface *setupWindow();
void initWaylandConnection();
@@ -425,6 +437,27 @@ int main(const int argc, const char *argv[]) \
delete(vulkanExample); \
return 0; \
}
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+#define VULKAN_EXAMPLE_MAIN() \
+VulkanExample *vulkanExample; \
+static void handleEvent(const DFBWindowEvent *event) \
+{ \
+ if (vulkanExample != NULL) \
+ { \
+ vulkanExample->handleEvent(event); \
+ } \
+} \
+int main(const int argc, const char *argv[]) \
+{ \
+ for (size_t i = 0; i < argc; i++) { VulkanExample::args.push_back(argv[i]); }; \
+ vulkanExample = new VulkanExample(); \
+ vulkanExample->initVulkan(); \
+ vulkanExample->setupWindow(); \
+ vulkanExample->prepare(); \
+ vulkanExample->renderLoop(); \
+ delete(vulkanExample); \
+ return 0; \
+}
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
#define VULKAN_EXAMPLE_MAIN() \
VulkanExample *vulkanExample; \
diff --git a/cmake/FindDirectFB.cmake b/cmake/FindDirectFB.cmake
new file mode 100644
index 00000000..2c98b2ac
--- /dev/null
+++ b/cmake/FindDirectFB.cmake
@@ -0,0 +1,28 @@
+# Try to find DirectFB
+#
+# This will define:
+#
+# DIRECTFB_FOUND - True if DirectFB is found
+# DIRECTFB_LIBRARIES - Link these to use DirectFB
+# DIRECTFB_INCLUDE_DIR - Include directory for DirectFB
+# DIRECTFB_DEFINITIONS - Compiler flags for using DirectFB
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+IF (NOT WIN32)
+ FIND_PACKAGE(PkgConfig)
+ PKG_CHECK_MODULES(PKG_DIRECTFB QUIET directfb)
+
+ SET(DIRECTFB_DEFINITIONS ${PKG_DIRECTFB_CFLAGS})
+
+ FIND_PATH(DIRECTFB_INCLUDE_DIR NAMES directfb.h HINTS ${PKG_DIRECTFB_INCLUDE_DIRS})
+
+ FIND_LIBRARY(DIRECTFB_LIBRARIES NAMES directfb HINTS ${PKG_DIRECTFB_LIBRARY_DIRS})
+
+ include(FindPackageHandleStandardArgs)
+
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(DIRECTFB DEFAULT_MSG DIRECTFB_LIBRARIES DIRECTFB_INCLUDE_DIR)
+
+ MARK_AS_ADVANCED(DIRECTFB_INCLUDE_DIR DIRECTFB_LIBRARIES)
+ENDIF ()
diff --git a/examples/triangle/triangle.cpp b/examples/triangle/triangle.cpp
index 3c7f5041..f54487b0 100644
--- a/examples/triangle/triangle.cpp
+++ b/examples/triangle/triangle.cpp
@@ -1151,6 +1151,26 @@ int main(const int argc, const char *argv[])
delete(vulkanExample);
return 0;
}
+#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
+VulkanExample *vulkanExample;
+static void handleEvent(const DFBWindowEvent *event)
+{
+ if (vulkanExample != NULL)
+ {
+ vulkanExample->handleEvent(event);
+ }
+}
+int main(const int argc, const char *argv[])
+{
+ for (size_t i = 0; i < argc; i++) { VulkanExample::args.push_back(argv[i]); };
+ vulkanExample = new VulkanExample();
+ vulkanExample->initVulkan();
+ vulkanExample->setupWindow();
+ vulkanExample->prepare();
+ vulkanExample->renderLoop();
+ delete(vulkanExample);
+ return 0;
+}
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
VulkanExample *vulkanExample;
int main(const int argc, const char *argv[])