Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vulkan] Less sync overhead for GGUI & Device API Examples #5880

Merged
merged 21 commits into from
Sep 1, 2022
Merged
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
13 changes: 9 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,12 @@ if (TI_BUILD_TESTS)
endif()

option(TI_BUILD_EXAMPLES "Build the CPP examples" ON)
option(TI_BUILD_RHI_EXAMPLES "Build the Unified Device API examples" OFF)

if(NOT TI_WITH_LLVM OR NOT TI_WITH_METAL)
set(TI_BUILD_EXAMPLES OFF)
endif()

if (TI_BUILD_EXAMPLES)
include(cmake/TaichiExamples.cmake)
endif()

message("C++ Flags: ${CMAKE_CXX_FLAGS}")
message("Build type: ${CMAKE_BUILD_TYPE}")

Expand Down Expand Up @@ -201,3 +198,11 @@ if (TI_WITH_C_API)
include(cmake/TaichiCAPITests.cmake)
endif()
endif()

if (TI_BUILD_EXAMPLES)
include(cmake/TaichiExamples.cmake)
endif()

if (TI_BUILD_RHI_EXAMPLES)
add_subdirectory(cpp_examples/rhi_examples)
endif()
6 changes: 3 additions & 3 deletions c_api/src/taichi_core_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ TiTexture ti_allocate_texture(TiRuntime runtime,

switch ((taichi::lang::ImageDimension)allocate_info->dimension) {
#define PER_IMAGE_DIMENSION(x) case taichi::lang::ImageDimension::x:
#include "taichi/inc/image_dimension.inc.h"
#include "taichi/inc/rhi_constants.inc.h"
#undef PER_IMAGE_DIMENSION
break;
default: {
Expand All @@ -250,7 +250,7 @@ TiTexture ti_allocate_texture(TiRuntime runtime,

switch ((taichi::lang::BufferFormat)allocate_info->format) {
#define PER_BUFFER_FORMAT(x) case taichi::lang::BufferFormat::x:
#include "taichi/inc/buffer_format.inc.h"
#include "taichi/inc/rhi_constants.inc.h"
#undef PER_BUFFER_FORMAT
break;
default: {
Expand Down Expand Up @@ -351,7 +351,7 @@ void ti_transition_texture(TiRuntime runtime,

switch ((taichi::lang::ImageLayout)layout) {
#define PER_IMAGE_LAYOUT(x) case taichi::lang::ImageLayout::x:
#include "taichi/inc/image_layout.inc.h"
#include "taichi/inc/rhi_constants.inc.h"
#undef PER_IMAGE_LAYOUT
break;
default: {
Expand Down
10 changes: 6 additions & 4 deletions cmake/TaichiCXXFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,26 @@ if (WIN32)
endif()
endif()

set(CMAKE_CXX_STANDARD 17)

if (WIN32)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/lib)
if (MSVC)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} /Zc:__cplusplus /std:c++17 /bigobj /wd4244 /wd4267 /nologo /Zi /D \"_CRT_SECURE_NO_WARNINGS\" /D \"_ENABLE_EXTENDED_ALIGNED_STORAGE\"")
"${CMAKE_CXX_FLAGS} /Zc:__cplusplus /bigobj /wd4244 /wd4267 /nologo /Zi /D \"_CRT_SECURE_NO_WARNINGS\" /D \"_ENABLE_EXTENDED_ALIGNED_STORAGE\"")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fsized-deallocation -target x86_64-pc-windows-msvc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation -target x86_64-pc-windows-msvc")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gcodeview")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -gcodeview")
endif()
else()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
message("Clang compiler detected. Using std=c++17.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fsized-deallocation -Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation -Wno-deprecated-declarations")
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
message("GNU compiler detected. Using std=c++17.")
message(WARNING "It is detected that you are using gcc as the compiler. This is an experimental feature. Consider adding -DCMAKE_CXX_COMPILER=clang argument to CMake to switch to clang (or MSVC on Windows).")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fsized-deallocation -Wno-class-memaccess -Wno-comment -Wno-sign-compare")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation -Wno-class-memaccess -Wno-comment -Wno-sign-compare")
else()
message("Invalid compiler ${CMAKE_CXX_COMPILER_ID} detected.")
message(FATAL_ERROR "clang and MSVC are the only supported compilers for Taichi compiler development. Consider using 'cmake -DCMAKE_CXX_COMPILER=clang' if you are on Linux.")
Expand Down
30 changes: 30 additions & 0 deletions cpp_examples/rhi_examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
macro(make_sample executable_name src_file)
add_executable(${executable_name})
set_property(TARGET ${executable_name} PROPERTY CXX_STANDARD 23)
set_property(TARGET ${executable_name} PROPERTY C_STANDARD 23)
target_sources(${executable_name} PRIVATE ${src_file} "common.h")
target_include_directories(${executable_name}
PRIVATE
${PROJECT_SOURCE_DIR}

${PROJECT_SOURCE_DIR}/external/SPIRV-Tools/include
${PROJECT_SOURCE_DIR}/external/eigen
${PROJECT_SOURCE_DIR}/external/FP16/include
${PROJECT_SOURCE_DIR}/external/SPIRV-Reflect
${PROJECT_SOURCE_DIR}/external/spdlog/include
${LLVM_INCLUDE_DIRS}

${PROJECT_SOURCE_DIR}/external/volk
${PROJECT_SOURCE_DIR}/external/Vulkan-Headers/include
${PROJECT_SOURCE_DIR}/external/glfw/include
${PROJECT_SOURCE_DIR}/external/glm
)
target_include_directories(${executable_name} SYSTEM
PUBLIC
${PROJECT_SOURCE_DIR}/external/VulkanMemoryAllocator/include
)
target_link_libraries(${executable_name} taichi_c_api glfw)
endmacro()

make_sample(sample_1_window sample_1_window.cpp)
make_sample(sample_2_triangle sample_2_triangle.cpp)
129 changes: 129 additions & 0 deletions cpp_examples/rhi_examples/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#pragma once

#include "taichi/rhi/vulkan/vulkan_device.h"
#include "taichi/rhi/vulkan/vulkan_common.h"
#include "taichi/rhi/vulkan/vulkan_loader.h"
#include "taichi/rhi/vulkan/vulkan_device_creator.h"

#define GLFW_INCLUDE_NONE
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"

using namespace taichi::lang;

static void glfw_error_callback(int code, const char *description) {
TI_WARN("GLFW Error {}: {}", code, description);
}

std::vector<std::string> get_required_instance_extensions() {
std::vector<std::string> extensions;

uint32_t glfw_ext_count = 0;
const char **glfw_extensions;
glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_ext_count);

for (int i = 0; i < glfw_ext_count; ++i) {
extensions.push_back(glfw_extensions[i]);
}
// VulkanDeviceCreator will check that these are supported
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);

return extensions;
}

std::vector<std::string> get_required_device_extensions() {
static std::vector<std::string> extensions{
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};

return extensions;
}

class App {
public:
App(int width, int height, const std::string &title) {
TI_INFO("Creating App '{}' of {}x{}", title, width, height);

TI_ASSERT(taichi::lang::vulkan::is_vulkan_api_available());

if (glfwInit()) {
TI_INFO("Initialized GLFW");

glfwSetErrorCallback(glfw_error_callback);

glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfw_window =
glfwCreateWindow(width, height, "Sample Window", nullptr, nullptr);

TI_INFO("Initialized GLFWWindow");
} else {
TI_ERROR("failed to init GLFW");
}

{
vulkan::VulkanDeviceCreator::Params evd_params;
evd_params.api_version = std::nullopt;
evd_params.additional_instance_extensions =
get_required_instance_extensions();
evd_params.additional_device_extensions =
get_required_device_extensions();
evd_params.is_for_ui = true;
evd_params.surface_creator = [&](VkInstance instance) -> VkSurfaceKHR {
VkSurfaceKHR surface = VK_NULL_HANDLE;

if (glfwCreateWindowSurface(instance, glfw_window, nullptr, &surface) !=
VK_SUCCESS) {
TI_ERROR("failed to create window surface!");
}
return surface;
};
evd_params.enable_validation_layer = true;

device_creator =
std::make_unique<vulkan::VulkanDeviceCreator>(evd_params);
device = device_creator->device();

TI_INFO("Initialized VulkanDevice");
}

{
SurfaceConfig config;
config.window_handle = glfw_window;
config.native_surface_handle = device_creator->get_surface();

surface = device->create_surface(config);
}
}

virtual ~App() {
surface.reset();
device_creator.reset();
glfwDestroyWindow(glfw_window);
glfwTerminate();
}

virtual std::vector<StreamSemaphore> render_loop(
StreamSemaphore image_available_semaphore) {
return {};
}

void run() {
while (!glfwWindowShouldClose(glfw_window)) {
auto image_available_semaphore = surface->acquire_next_image();

glfwPollEvents();

surface->present_image(render_loop(image_available_semaphore));
}
}

public:
// Owned
GLFWwindow *glfw_window;
std::unique_ptr<vulkan::VulkanDeviceCreator> device_creator;
std::unique_ptr<Surface> surface;

// Weak references
vulkan::VulkanDevice *device;
};
21 changes: 21 additions & 0 deletions cpp_examples/rhi_examples/sample_1_window.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "common.h"

class SampleApp : public App {
public:
SampleApp() : App(1920, 1080, "Sample 1: Window") {
}

std::vector<StreamSemaphore> render_loop(
StreamSemaphore image_available_semaphore) override {
return {};
}

public:
};

int main() {
std::unique_ptr<SampleApp> app = std::make_unique<SampleApp>();
app->run();

return 0;
}
115 changes: 115 additions & 0 deletions cpp_examples/rhi_examples/sample_2_triangle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "common.h"

std::vector<uint32_t> frag_spv =
#include "shaders/2_triangle.frag.spv.h"
;

std::vector<uint32_t> vert_spv =
#include "shaders/2_triangle.vert.spv.h"
;

struct Vertex {
glm::vec2 pos;
glm::vec3 color;
};

class SampleApp : public App {
public:
SampleApp() : App(1920, 1080, "Sample 2: Triangle") {
// Create the triangle raster pipeline
{
// Load the SPIRV source
std::vector<PipelineSourceDesc> src_desc(2);

src_desc[0].data = (void *)frag_spv.data();
src_desc[0].size = frag_spv.size() * sizeof(uint32_t);
src_desc[0].type = PipelineSourceType::spirv_binary;
src_desc[0].stage = PipelineStageType::fragment;

src_desc[1].data = (void *)vert_spv.data();
src_desc[1].size = vert_spv.size() * sizeof(uint32_t);
src_desc[1].type = PipelineSourceType::spirv_binary;
src_desc[1].stage = PipelineStageType::vertex;

// Setup rasterizer parameters
RasterParams raster_params; // use default

// Setup vertex input parameters
std::vector<VertexInputBinding> vertex_inputs = {
{.binding = 0, .stride = sizeof(Vertex), .instance = false}};
std::vector<VertexInputAttribute> vertex_attrs = {
{.location = 0,
.binding = 0,
.format = BufferFormat::rg32f,
.offset = offsetof(Vertex, pos)},
{.location = 1,
.binding = 0,
.format = BufferFormat::rgb32f,
.offset = offsetof(Vertex, color)}};

// Create pipeline
pipeline = device->create_raster_pipeline(src_desc, raster_params,
vertex_inputs, vertex_attrs);
}

// Create the vertex buffer
{
vertex_buffer = device->allocate_memory_unique(
Device::AllocParams{.size = 3 * sizeof(Vertex),
.host_write = true,
.usage = AllocUsage::Vertex});
Vertex *mapped = (Vertex *)device->map(*vertex_buffer);
mapped[0] = {{0.0, 0.5}, {1.0, 0.0, 0.0}};
mapped[1] = {{0.5, -0.5}, {0.0, 1.0, 0.0}};
mapped[2] = {{-0.5, -0.5}, {0.0, 0.0, 1.0}};
device->unmap(*vertex_buffer);
}

TI_INFO("App Init Done");
}

std::vector<StreamSemaphore> render_loop(
StreamSemaphore image_available_semaphore) override {
auto cmdlist = device->get_graphics_stream()->new_command_list();

// Set-up our frame buffer attachment
DeviceAllocation surface_image = surface->get_target_image();
cmdlist->image_transition(surface_image, ImageLayout::undefined,
ImageLayout::color_attachment);

// Renderpass: render to surface image, clear color values
bool clear = true;
std::vector<float> clear_color = {0.1, 0.2, 0.3, 1.0};
const auto &[width, height] = surface->get_size();
cmdlist->begin_renderpass(0, 0, width, height, 1, &surface_image, &clear,
&clear_color, nullptr, false);

// Bind our triangle pipeline
cmdlist->bind_pipeline(pipeline.get());
// Get the binder and bind our vertex buffer
auto resource_binder = pipeline->resource_binder();
resource_binder->vertex_buffer(vertex_buffer->get_ptr(0), 0);
cmdlist->bind_resources(resource_binder);
// Render the triangle
cmdlist->draw(3, 0);
// End rendering
cmdlist->end_renderpass();

// Submit command list, returns render complete semaphore
auto render_complete_semaphore = device->get_graphics_stream()->submit(
cmdlist.get(), {image_available_semaphore});
return {render_complete_semaphore};
}

public:
std::unique_ptr<Pipeline> pipeline;

std::unique_ptr<DeviceAllocationGuard> vertex_buffer;
};

int main() {
std::unique_ptr<SampleApp> app = std::make_unique<SampleApp>();
app->run();

return 0;
}
9 changes: 9 additions & 0 deletions cpp_examples/rhi_examples/shaders/2_triangle.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#version 460

layout(location = 0) in vec3 color;

layout(location = 0) out vec4 frag_output;

void main() {
frag_output = vec4(color, 1.0);
}
Loading