Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ build-*
.DS_Store
clion_compile.sh
.python-version
**/__pycache__
**/__pycache__
src/.cache/*
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebI
add_definitions(-DSKITY_RELEASE)
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DSKITY_DEBUG)
endif()

if (${SKITY_OPTIMIZE_O3})
message("build with o3")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
Expand Down
4 changes: 3 additions & 1 deletion cmake/ThirdPartyDep.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ endif()
# Vulkan deps
if(${SKITY_VK_BACKEND})
target_include_directories(skity PRIVATE third_party/Vulkan-Headers/include)
target_include_directories(skity PRIVATE third_party/VulkanMemoryAllocator/include)
endif()

# OpenGL header file
Expand All @@ -34,12 +35,13 @@ if(${SKITY_VK_BACKEND})
# set vulkan headers
if (NOT ANDROID)
# android can use system vulkan headers from NDK
set(VULKAN_HEADERS_INSTALL_DIR "third_party/Vulkan-Headers" CACHE PATH "Vulkan-Headers")
set(VULKAN_HEADERS_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/Vulkan-Headers" CACHE PATH "Vulkan-Headers")
endif()

target_compile_definitions(skity PRIVATE VK_NO_PROTOTYPES=1)
add_subdirectory(third_party/volk)
target_link_libraries(skity PRIVATE volk::volk)

endif()

# json parser
Expand Down
17 changes: 17 additions & 0 deletions example/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,27 @@ if (${SKITY_MTL_BACKEND})

endif()

if (${SKITY_VK_BACKEND})
target_compile_definitions(skity_example_common PUBLIC -DSKITY_EXAMPLE_VK_BACKEND=1)

target_sources(skity_example_common PRIVATE
${CMAKE_CURRENT_LIST_DIR}/vk/window_vk.cc
${CMAKE_CURRENT_LIST_DIR}/vk/window_vk.hpp
)

target_link_libraries(skity_example_common PRIVATE volk)
endif()

add_library(skity::example_common ALIAS skity_example_common)

target_include_directories(skity_example_common PUBLIC ${CMAKE_SOURCE_DIR}/example)
target_include_directories(skity_example_common PUBLIC ${CMAKE_SOURCE_DIR}/third_party/glad/include)
target_include_directories(skity_example_common PRIVATE ${CMAKE_SOURCE_DIR})
target_include_directories(skity_example_common PRIVATE ${CMAKE_SOURCE_DIR}/module/wgx/include)
target_include_directories(skity_example_common PRIVATE ${CMAKE_SOURCE_DIR}/third_party/glm)
target_include_directories(skity_example_common PRIVATE ${CMAKE_SOURCE_DIR}/third_party/volk)
target_include_directories(skity_example_common PRIVATE ${CMAKE_SOURCE_DIR}/third_party/Vulkan-Headers/include)
target_include_directories(skity_example_common PRIVATE ${CMAKE_SOURCE_DIR}/third_party/VulkanMemoryAllocator/include)

target_link_libraries(skity_example_common PUBLIC glfw skity::skity)
target_link_libraries(skity_example_common PUBLIC skity::codec)
Expand Down
196 changes: 196 additions & 0 deletions example/common/vk/window_vk.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright 2021 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.

#include "common/vk/window_vk.hpp"

#include <volk.h> // Include volk first to define Vulkan types

#include <iostream>
#define GLFW_INCLUDE_NONE // Don't include any API headers
#include <GLFW/glfw3.h>

// Forward declare GLFW Vulkan function
extern "C" {
VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface);
}
#include <skity/gpu/gpu_context_vk.hpp>
#include <skity/gpu/gpu_render_target.hpp>

#include "src/gpu/vk/gpu_context_impl_vk.hpp"
#include "src/gpu/vk/gpu_device_vk.hpp"
#include "src/render/hw/hw_canvas.hpp"

namespace skity {
namespace example {

WindowVK::WindowVK(int width, int height, std::string title)
: Window(width, height, std::move(title)) {}

bool WindowVK::OnInit() {
// Set GLFW hints for Vulkan
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
return true;
}

GLFWwindow* WindowVK::CreateWindowHandler() {
return glfwCreateWindow(GetWidth(), GetHeight(), GetTitle().c_str(), nullptr,
nullptr);
}

std::unique_ptr<skity::GPUContext> WindowVK::CreateGPUContext() {
// Check if Vulkan is available
if (!skity::IsVulkanAvailable()) {
std::cerr << "[ERROR]Vulkan is not available on this system." << std::endl;
return nullptr;
}

// Get available devices
uint32_t device_count = 0;
const char** devices = skity::VkGetAvailableDevices(&device_count);
std::cout << "Found " << device_count << " Vulkan devices:" << std::endl;
if (devices) {
for (uint32_t i = 0; i < device_count; i++) {
std::cout << " Device " << i << ": " << devices[i] << std::endl;
}
}

// Configure Vulkan context with validation layers enabled
skity::VkDevicePreferences prefs;
prefs.enable_validation = true; // Enable validation layers for debugging
prefs.preferred_device_type = 2; // Prefer discrete GPU

// Create Vulkan context with preferences
auto context = skity::VkContextCreate(prefs);
if (!context) {
std::cerr << "[ERROR] Failed to create Vulkan context with validation."
<< std::endl;
return nullptr;
}

// Validate the context backend type
auto backend_type = context->GetBackendType();
std::cout << "Context backend type: " << static_cast<int>(backend_type)
<< std::endl;
return context;
}

void WindowVK::OnShow() {
// Validate GPU context
auto* gpu_context = GetGPUContext();
if (!gpu_context) {
std::cerr << "[ERROR] No GPU context available for surface creation"
<< std::endl;
return;
}

// Cast to Vulkan-specific implementations
auto* vk_context_impl = static_cast<GPUContextImplVk*>(gpu_context);
auto* vk_device = static_cast<GPUDeviceVk*>(vk_context_impl->GetGPUDevice());

// Try to create VkSurfaceKHR from GLFW window using the new API
uint64_t instance_handle = VkGetInstance(gpu_context);

if (instance_handle == 0) {
std::cerr << "[ERROR] Failed to get VkInstance from context" << std::endl;
exit(0);
return;
}

VkInstance instance = reinterpret_cast<VkInstance>(instance_handle);
if (instance == VK_NULL_HANDLE) {
std::cerr << "[ERROR] VkInstance is VK_NULL_HANDLE" << std::endl;
}

// Initialize volk if not already done
VkResult volk_result = volkInitialize();
if (volk_result != VK_SUCCESS) {
std::cerr << "[ERROR] Failed to initialize volk: " << volk_result
<< std::endl;
exit(0);
return;
}

volkLoadInstance(instance); // Load instance-specific functions

// Check what extensions GLFW requires
uint32_t glfw_extension_count = 0;
const char** glfw_extensions =
glfwGetRequiredInstanceExtensions(&glfw_extension_count);
std::cout << "GLFW requires " << glfw_extension_count
<< " extensions:" << std::endl;
for (uint32_t i = 0; i < glfw_extension_count; i++) {
std::cout << " - " << glfw_extensions[i] << std::endl;
}

std::cout << "Creating window surface..." << std::endl;
VkResult result = glfwCreateWindowSurface(instance, GetNativeWindow(),
nullptr, &vk_surface_);
if (result != VK_SUCCESS) {
std::cerr << "[ERROR] Failed to create window surface: " << result
<< std::endl;
exit(0);
return;
}

GPUSurfaceDescriptorVk vk_desc{};
vk_desc.backend = GPUBackendType::kVulkan;
vk_desc.width = GetWidth();
vk_desc.height = GetHeight();
vk_desc.sample_count = 1;
vk_desc.content_scale = 1.0f;
vk_desc.surface_type = VkSurfaceType::kSwapchain;
vk_desc.native_surface = reinterpret_cast<void*>(vk_surface_);

window_surface_ = gpu_context->CreateSurface(&vk_desc);
if (!window_surface_) {
std::cerr << "[ERROR] Failed to create GPUSurface with swapchain"
<< std::endl;
exit(0);
return;
}
}

skity::Canvas* WindowVK::AquireCanvas() {
if (window_surface_) {
auto* canvas = window_surface_->LockCanvas(false);
return canvas;
}
std::cerr << "[ERROR] No render surface available." << std::endl;
return nullptr;
}

void WindowVK::OnPresent() {
if (window_surface_) {
window_surface_->Flush();
return;
}
std::cerr << "[ERROR] No render surface available for present" << std::endl;
}

void WindowVK::OnTerminate() {
// Clean up resources
window_surface_.reset();

// Destroy VkSurfaceKHR if created
if (vk_surface_ != VK_NULL_HANDLE) {
auto* gpu_context = GetGPUContext();
if (gpu_context) {
uint64_t instance_handle = VkGetInstance(gpu_context);
if (instance_handle != 0) {
VkInstance instance = reinterpret_cast<VkInstance>(instance_handle);
volkLoadInstance(instance); // Ensure volk functions are loaded
vkDestroySurfaceKHR(instance, vk_surface_, nullptr);
}
}
vk_surface_ = VK_NULL_HANDLE;
}

std::cout << "Vulkan window terminated." << std::endl;
}

} // namespace example
} // namespace skity
43 changes: 43 additions & 0 deletions example/common/vk/window_vk.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2021 The Lynx Authors. All rights reserved.
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.

#ifndef SKITY_EXAMPLE_COMMON_VK_WINDOW_VK_HPP
#define SKITY_EXAMPLE_COMMON_VK_WINDOW_VK_HPP

#include <volk.h>

#include <memory>

#include "common/window.hpp"

namespace skity {
class VkInterface;

namespace example {

class WindowVK : public Window {
public:
WindowVK(int width, int height, std::string title);
~WindowVK() override = default;

Backend GetBackend() const override { return Backend::kVulkan; }

protected:
bool OnInit() override;
GLFWwindow* CreateWindowHandler() override;
std::unique_ptr<skity::GPUContext> CreateGPUContext() override;
void OnShow() override;
skity::Canvas* AquireCanvas() override;
void OnPresent() override;
void OnTerminate() override;

private:
VkSurfaceKHR vk_surface_ = VK_NULL_HANDLE;
std::unique_ptr<skity::GPUSurface> window_surface_;
};

} // namespace example
} // namespace skity

#endif // SKITY_EXAMPLE_COMMON_VK_WINDOW_VK_HPP
10 changes: 10 additions & 0 deletions example/common/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "common/sw/window_sw.hpp"
#endif

#ifdef SKITY_EXAMPLE_VK_BACKEND
#include "common/vk/window_vk.hpp"
#endif

namespace skity {
namespace example {

Expand All @@ -44,6 +48,12 @@ std::unique_ptr<Window> Window::CreateWindow(Backend backend, uint32_t width,
window = std::make_unique<WindowSW>(width, height, std::move(title));
#else
std::cerr << "Software backend is not supported." << std::endl;
#endif
} else if (backend == Backend::kVulkan) {
#ifdef SKITY_EXAMPLE_VK_BACKEND
window = std::make_unique<WindowVK>(width, height, std::move(title));
#else
std::cerr << "Vulkan backend is not supported." << std::endl;
#endif
}

Expand Down
12 changes: 12 additions & 0 deletions hab/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,16 @@ deps = {
"ignore_in_git": True,
"commit": "ee86beb30e4973f5feffe3ce63bfa4fbadf72f38",
},
"third_party/SPIRV-Cross": {
"type": "git",
"url": "https://github.com/KhronosGroup/SPIRV-Cross.git",
"ignore_in_git": True,
"commit": "ebe2aa0cd80f5eb5cd8a605da604cacf72205f3b",
},
"third_party/glslang": {
"type": "git",
"url": "https://github.com/KhronosGroup/glslang.git",
"ignore_in_git": True,
"commit": "d1517d64cfca91f573af1bf7341dc3a5113349c0",
},
}
Loading