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[])