Skip to content

Commit

Permalink
tocpp: Support Wayland
Browse files Browse the repository at this point in the history
Add C++ template strings for the Wayland platform.
  • Loading branch information
antonio-lunarg committed Nov 6, 2024
1 parent df42092 commit dfa5685
Show file tree
Hide file tree
Showing 4 changed files with 334 additions and 6 deletions.
47 changes: 47 additions & 0 deletions framework/decode/vulkan_cpp_consumer_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ void VulkanCppConsumerBase::WriteMainHeader()
case GfxToCppPlatform::PLATFORM_XCB:
fprintf(main_file_, "%s", sXcbOutputMainStart);
break;
case GfxToCppPlatform::PLATFORM_WAYLAND:
fprintf(main_file_, "%s", sWaylandOutputMainStart);
break;
}
}

Expand All @@ -116,6 +119,9 @@ void VulkanCppConsumerBase::WriteMainFooter()
case GfxToCppPlatform::PLATFORM_XCB:
fprintf(main_file_, "%s", sXcbOutputMainEnd);
break;
case GfxToCppPlatform::PLATFORM_WAYLAND:
fprintf(main_file_, "%s", sWaylandOutputMainEnd);
break;
}
}

Expand Down Expand Up @@ -155,6 +161,14 @@ bool VulkanCppConsumerBase::WriteGlobalHeaderFile()
sXcbOutputHeader,
sCommonOutputHeaderFunctions);
break;
case GfxToCppPlatform::PLATFORM_WAYLAND:
fprintf(header_file,
"%s%s%s%s",
sWaylandOutputHeadersPlatform,
sCommonHeaderOutputHeaders,
sWaylandOutputHeader,
sCommonOutputHeaderFunctions);
break;
}

PrintToFile(header_file, "extern %s;\n", GfxToCppVariable::GenerateStringVec(variable_data_));
Expand Down Expand Up @@ -191,6 +205,9 @@ void VulkanCppConsumerBase::PrintOutCMakeFile()
default:
GFXRECON_LOG_FATAL("Failed to print out CMake file: Unknown platform (%d)", platform_);
break;
case GfxToCppPlatform::PLATFORM_WAYLAND:
fprintf(cmake_file, "%s", sWaylandCMakeFile);
break;
case GfxToCppPlatform::PLATFORM_ANDROID:
// Nothing to do here
break;
Expand Down Expand Up @@ -288,6 +305,19 @@ void VulkanCppConsumerBase::PrintOutGlobalVar()
delete[] formatted_output_override_method;
break;
}
case GfxToCppPlatform::PLATFORM_WAYLAND:
{
int size = snprintf(NULL, 0, sWaylandOutputOverrideMethod, window_width_, window_height_);
char* formatted_output_override_method = new char[size + 2];
snprintf(formatted_output_override_method,
size + 2,
sWaylandOutputOverrideMethod,
window_width_,
window_height_);
fputs(formatted_output_override_method, global_file);
delete[] formatted_output_override_method;
break;
}
}

PrintToFile(global_file, "%s;\n", GfxToCppVariable::GenerateStringVec(variable_data_));
Expand Down Expand Up @@ -1721,6 +1751,23 @@ void VulkanCppConsumerBase::GenerateSurfaceCreation(GfxToCppPlatform plat
surface_create_func_call = "vkCreateXcbSurfaceKHR";
break;
}
case GfxToCppPlatform::PLATFORM_WAYLAND:
{
VkWaylandSurfaceCreateInfoKHR wayland_struct_info = {};
Decoded_VkWaylandSurfaceCreateInfoKHR decoded_wayland_info = {};

if (platform_ == platform)
{
wayland_struct_info =
*reinterpret_cast<StructPointerDecoder<Decoded_VkWaylandSurfaceCreateInfoKHR>*>(pSurfaceCreateInfo)
->GetPointer();
}
wayland_struct_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
create_info_struct_var_name = GenerateStruct_VkWaylandSurfaceCreateInfoKHR(
stream_create_info, &wayland_struct_info, &decoded_wayland_info, *this);
surface_create_func_call = "vkCreateWaylandSurfaceKHR";
break;
}
}
fprintf(file, "\n%s", stream_create_info.str().c_str());
AddKnownVariables("VkSurfaceKHR", surface_var_name, pSurface);
Expand Down
6 changes: 3 additions & 3 deletions framework/decode/vulkan_cpp_loader_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ void VulkanCppLoaderGenerator::WriteOutLoaderGenerator(const std::string& outDir
case GfxToCppPlatform::PLATFORM_XCB:
fprintf(pfn_src_file, "#define VK_USE_PLATFORM_XCB_KHR\n");
break;
case GfxToCppPlatform::PLATFORM_WAYLAND:
fprintf(pfn_src_file, "#define VK_USE_PLATFORM_WAYLAND_KHR\n");
break;
#if 0
// TODO: implement these platforms
case GfxToCppPlatform::PLATFORM_MACOS:
fprintf(pfn_src_file, "#define VK_USE_PLATFORM_METAL_EXT\n");
break;
case GfxToCppPlatform::PLATFORM_WAYLAND:
fprintf(pfn_src_file, "#define VK_USE_PLATFORM_WAYLAND_KHR\n");
break;
case GfxToCppPlatform::PLATFORM_XLIB:
fprintf(pfn_src_file, "#define VK_USE_PLATFORM_XLIB_KHR\n");
break;
Expand Down
281 changes: 281 additions & 0 deletions framework/decode/vulkan_cpp_template_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,287 @@ target_link_libraries(vulkan_app vulkan xcb)
)";
// End of Xcb template strings

// Beginning of Wayland template strings
static const char* sWaylandOutputMainStart = R"(
#include "global_var.h"
int main() {
)";

static const char* sWaylandOutputMainEnd = R"(
return 0;
}
)";

static const char* sWaylandOutputHeadersPlatform = R"(
// This file is a generated source, follow the instructions under tools/tocpp/README.md to build.
#define VK_USE_PLATFORM_WAYLAND_KHR
)";

static const char* sWaylandOutputHeader = R"(
#include <wayland-client.h>
#include <xdg-shell-client-protocol.h>
#define VK_CALL_CHECK(VK_CALL, VK_RESULT) \
LogVkError(#VK_CALL, (VK_CALL), __FILE__, __LINE__, VK_RESULT)
struct WaylandApp {
WaylandApp(uint32_t w, uint32_t h) {
width = w;
height = h;
}
~WaylandApp();
uint32_t width { 320 };
uint32_t height { 240 };
struct {
wl_display *display { nullptr };
wl_compositor *compositor { nullptr };
wl_surface *surface { nullptr };
int shm_fd {-1};
wl_shm *shm { nullptr };
wl_shm_pool *shm_pool { nullptr };
wl_buffer *buffer { nullptr };
} wl;
struct {
xdg_wm_base *wm_base { nullptr };
xdg_surface *surface { nullptr };
xdg_toplevel *toplevel { nullptr };
} xdg;
};
extern WaylandApp appdata;
extern void OverrideVkWaylandSurfaceCreateInfoKHR(VkWaylandSurfaceCreateInfoKHR* createInfo,
struct WaylandApp& appdata);
extern void UpdateWindowSize(uint32_t width,
uint32_t height,
uint32_t pre_transform,
struct WaylandApp& appdata);
extern void LogVkError(const char* function,
VkResult returnValue,
const char* file,
int line,
VkResult capturedReturnValue);
extern size_t LoadBinaryData(const char* filename,
size_t file_offset,
void* buffer,
size_t offset,
size_t data_size,
struct WaylandApp& appdata);
)";

static const char* sWaylandOutputOverrideMethod = R"(
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
WaylandApp::~WaylandApp()
{
wl_buffer_destroy(appdata.wl.buffer);
wl_shm_pool_destroy(appdata.wl.shm_pool);
wl_shm_destroy(appdata.wl.shm);
close(appdata.wl.shm_fd);
xdg_wm_base_destroy(appdata.xdg.wm_base);
xdg_toplevel_destroy(appdata.xdg.toplevel);
xdg_surface_destroy(appdata.xdg.surface);
wl_surface_destroy(appdata.wl.surface);
wl_compositor_destroy(appdata.wl.compositor);
wl_display_disconnect(appdata.wl.display);
}
static void Randname(char *buf)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = 'A'+(r&15)+(r&16)*2;
r >>= 5;
}
}
static int CreateShmFile(void)
{
int retries = 100;
do {
char name[] = "/wl_shm-XXXXXX";
Randname(name + sizeof(name) - 7);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
int AllocateShmFile(size_t size)
{
int fd = CreateShmFile();
if (fd < 0)
return -1;
int ret;
do {
ret = ftruncate(fd, size);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
return -1;
}
return fd;
}
static void
RegistryHandleGlobal(void *data, wl_registry *registry, uint32_t name, const char* interface, uint32_t version)
{
WaylandApp *app = (WaylandApp *)data;
if (strcmp(interface, wl_compositor_interface.name) == 0)
{
app->wl.compositor = (wl_compositor *)wl_registry_bind(registry, name, &wl_compositor_interface, 4);
}
if (strcmp(interface, wl_shm_interface.name) == 0)
{
app->wl.shm = (wl_shm *)wl_registry_bind(registry, name, &wl_shm_interface, 1);
}
if (strcmp(interface, xdg_wm_base_interface.name) == 0)
{
app->xdg.wm_base = (xdg_wm_base *)wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
}
}
static void RegistryHandleGlobalRemove(void *data, wl_registry *registry, uint32_t name)
{
}
static const wl_registry_listener registry_listener = {
.global = RegistryHandleGlobal,
.global_remove = RegistryHandleGlobalRemove,
};
static void XdgSurfaceConfigure(void *data, xdg_surface *xdg_surface, uint32_t serial) {}
static const xdg_surface_listener surface_listener = {
.configure = XdgSurfaceConfigure,
};
void OverrideVkWaylandSurfaceCreateInfoKHR(VkWaylandSurfaceCreateInfoKHR* createInfo, WaylandApp& appdata)
{
if (appdata.wl.display == nullptr) {
// Open the connection to the wayland server
appdata.wl.display = wl_display_connect(nullptr);
if (appdata.wl.display == nullptr)
{
printf("Cannot open display\n");
exit(1);
}
wl_registry* registry = wl_display_get_registry(appdata.wl.display);
wl_registry_add_listener(registry, &registry_listener, &appdata);
wl_display_roundtrip(appdata.wl.display);
wl_registry_destroy(registry);
appdata.wl.surface = wl_compositor_create_surface(appdata.wl.compositor);
appdata.xdg.surface = xdg_wm_base_get_xdg_surface(appdata.xdg.wm_base, appdata.wl.surface);
xdg_surface_add_listener(appdata.xdg.surface, &surface_listener, &appdata);
appdata.xdg.toplevel = xdg_surface_get_toplevel(appdata.xdg.surface);
xdg_toplevel_set_title(appdata.xdg.toplevel, "vulkan-app");
const int width = appdata.width;
const int height = appdata.height;
const int stride = width * 4;
const int shm_pool_size = height * stride * 2;
appdata.wl.shm_fd = AllocateShmFile(shm_pool_size);
appdata.wl.shm_pool = wl_shm_create_pool(appdata.wl.shm, appdata.wl.shm_fd, shm_pool_size);
int index = 0;
int offset = height * stride * index;
appdata.wl.buffer = wl_shm_pool_create_buffer(
appdata.wl.shm_pool, offset, width, height, stride, WL_SHM_FORMAT_XRGB8888);
wl_surface_attach(appdata.wl.surface, appdata.wl.buffer, 0, 0);
wl_surface_damage(appdata.wl.surface, 0, 0, UINT32_MAX, UINT32_MAX);
wl_surface_commit(appdata.wl.surface);
}
createInfo->sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
createInfo->display = appdata.wl.display;
createInfo->surface = appdata.wl.surface;
}
void UpdateWindowSize(uint32_t width, uint32_t height, uint32_t pretransform, WaylandApp& appdata)
{
appdata.width = width;
appdata.height = height;
}
size_t LoadBinaryData(const char* filename,
size_t file_offset,
void* buffer,
size_t offset,
size_t data_size,
WaylandApp& appdata)
{
(void)appdata; // Unused
FILE* fp = fopen(filename, "rb");
if (fp == nullptr)
{
throw std::runtime_error("Error while opening file: " + std::string(filename));
}
fseek(fp, file_offset, SEEK_SET);
size_t read_size = fread((uint8_t *)buffer + offset, sizeof(uint8_t), data_size, fp);
if (read_size != data_size)
{
fclose(fp);
throw std::runtime_error("Error while reading file: " + std::string(filename));
}
fclose(fp);
return read_size;
}
WaylandApp appdata(%d, %d);
)";

static const char* sWaylandCMakeFile = R"(
cmake_minimum_required(VERSION 3.7)
project(vulkan_app)
set (CMAKE_CXX_STANDARD 11)
find_program(WAYLAND_SCANNER NAMES wayland-scanner REQUIRED)
set(XDG_SHELL_PROTOCOL_C ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-protocol.c)
set(XDG_SHELL_CLIENT_PROTOCOL_H ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h)
set(XDG_SHELL_XML /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml)
add_custom_command(
OUTPUT ${XDG_SHELL_CLIENT_PROTOCOL_H} ${XDG_SHELL_PROTOCOL_C}
COMMAND ${WAYLAND_SCANNER} client-header ${XDG_SHELL_XML} ${XDG_SHELL_CLIENT_PROTOCOL_H}
COMMAND ${WAYLAND_SCANNER} private-code ${XDG_SHELL_XML} ${XDG_SHELL_PROTOCOL_C}
DEPENDS ${XDG_SHELL_XML}
)
include_directories(${PROJECT_SOURCE_DIR}/src/ ${CMAKE_CURRENT_BINARY_DIR})
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_FILE ${PROJECT_SOURCE_DIR}/*.cpp)
add_executable(vulkan_app ${SRC_FILES} ${MAIN_FILE} ${XDG_SHELL_PROTOCOL_C})
find_package(Vulkan REQUIRED)
find_package(PkgConfig)
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
target_link_libraries(vulkan_app Vulkan::Vulkan ${WAYLAND_CLIENT_LIBRARIES})
)";
// End of Wayland template strings

// Beginning of Android template strings
static const char* sAndroidOutputHeadersPlatform = R"(
// This file is a generated source, follow the instructions under tools/tocpp/README.md to build.
Expand Down
Loading

0 comments on commit dfa5685

Please sign in to comment.