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

WIP: Vulkan Instance Builder #471

Closed
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
10 changes: 7 additions & 3 deletions bldsys/cmake/test_helpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ add_custom_target(vkb_tests)
function(vkb__register_tests)
set(options)
set(oneValueArgs NAME)
set(multiValueArgs SRC LIBS)
set(multiValueArgs SRC LINK_LIBS INCLUDE_DIRS)

if(NOT ((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) OR VKB_BUILD_TESTS))
return() # testing not enabled
Expand All @@ -45,8 +45,12 @@ function(vkb__register_tests)
add_executable(${TARGET_NAME} ${TARGET_SRC})
target_link_libraries(${TARGET_NAME} PUBLIC Catch2::Catch2WithMain)

if (TARGET_LIBS)
target_link_libraries(${TARGET_NAME} PUBLIC ${TARGET_LIBS})
if (TARGET_LINK_LIBS)
target_link_libraries(${TARGET_NAME} PUBLIC ${TARGET_LINK_LIBS})
endif()

if (TARGET_INCLUDE_DIRS)
target_include_directories(${TARGET_NAME} PUBLIC ${TARGET_INCLUDE_DIRS})
endif()

add_test(NAME ${TARGET_NAME}
Expand Down
3 changes: 3 additions & 0 deletions components/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_subdirectory(common)

add_subdirectory(vulkan)
27 changes: 27 additions & 0 deletions components/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (c) 2022, Arm Limited and Contributors
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 the "License";
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

add_library(components__common INTERFACE)
target_include_directories(components__common INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(Components::Common ALIAS components__common)

vkb__register_tests(
NAME "common_tests"
SRC
tests/stack_error.test.cpp
LINK_LIBS
components__common
)
131 changes: 131 additions & 0 deletions components/common/include/components/common/stack_error.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* Copyright (c) 2022, Arm Limited and Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <string.h>

#include <deque>
#include <exception>
#include <memory>
#include <sstream>
#include <string>

namespace components
{
class StackError;
using StackErrorPtr = std::unique_ptr<StackError>;

class StackError : std::exception
{
public:
StackError() = default;
~StackError() = default;

StackError(const std::string &reason, const char *file = nullptr, int line = 0)
{
push(reason, file, line);
}

static StackErrorPtr combine(StackErrorPtr &&first, StackErrorPtr &&second)
{
auto combined = std::make_unique<StackError>();

for (auto &err : first->m_stack)
{
combined->push(err);
}

for (auto &err : second->m_stack)
{
combined->push(err);
}

return std::move(combined);
}

void push(const std::string &reason, const char *file = nullptr, int line = 0)
{
std::stringstream stream;

if (file && strlen(file) > 0)
{
stream << "[" << file << ":" << line << "] ";
}

stream << reason.c_str();

m_stack.push_back(stream.str());
}

inline size_t size() const
{
return m_stack.size();
}

/**
* @brief Returns the Vulkan error code as string
* @return String message of exception
*/
const char *what() const noexcept override
{
if (m_stack.empty())
{
return nullptr;
}

std::deque<std::string> queue{m_stack};

m_final = "";

while (!queue.empty())
{
auto first = queue.front();

m_final += first;
m_final += "\n";

queue.pop_front();
}

return m_final.c_str();
}

static std::unique_ptr<StackError> unique(const std::string &reason, const char *file = nullptr, int line = 0)
{
return std::make_unique<StackError>(reason, file, line);
}

private:
StackError &operator+=(const StackError &b)
{
std::deque<std::string> queue{b.m_stack};

while (!queue.empty())
{
m_stack.push_front(queue.back());
queue.pop_back();
}

return *this;
}

std::deque<std::string> m_stack;
mutable std::string m_final;
};

} // namespace components
101 changes: 101 additions & 0 deletions components/common/tests/stack_error.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/* Copyright (c) 2022, Arm Limited and Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <catch2/catch_test_macros.hpp>

#include <string>
#include <vector>

#include <components/common/stack_error.hpp>

using namespace components;

TEST_CASE("what() exists and is as expected", "[common]")
{
struct Test
{
std::string message;
std::string file;
uint32_t line;
std::string expected;
};

std::vector<Test> tests{
{
"this is an error",
"some/file.cpp",
24,
"[some/file.cpp:24] this is an error\n",
},
{
"this is another error",
"some/file.cpp",
0,
"[some/file.cpp:0] this is another error\n",
},
{
"this is another error",
"",
0,
"this is another error\n",
},
};

for (auto &test : tests)
{
auto error = StackError::unique(test.message, test.file.c_str(), test.line);
REQUIRE(error->what() != nullptr);
REQUIRE(std::string{error->what()} == test.expected);
}
}

TEST_CASE("multiple stack errors", "[common]")
{
auto error = StackError::unique("this is a test message", "file.cpp", 1);
error->push("this is a another test message", "file.cpp", 2);
error->push("this is a final test message");
REQUIRE(error->size() == 3);
REQUIRE(std::string{error->what()} == "[file.cpp:1] this is a test message\n[file.cpp:2] this is a another test message\nthis is a final test message\n");
}

TEST_CASE("combine stack errors", "[common]")
{
auto error1 = StackError::unique("this is a test message", "file.cpp", 1);
auto error2 = StackError::unique("this is a test message", "another_file.cpp", 2);
auto error = StackError::combine(std::move(error1), std::move(error2));
REQUIRE(error->size() == 2);
REQUIRE(std::string{error->what()} == "[file.cpp:1] this is a test message\n[another_file.cpp:2] this is a test message\n");
}

TEST_CASE("combine larger stack errors", "[common]")
{
auto error1 = StackError::unique("this is a test message", "file.cpp", 1);
error1->push("this is a test message", "file.cpp", 1);
error1->push("this is a test message", "file.cpp", 1);
error1->push("this is a test message", "file.cpp", 1);
REQUIRE(error1->size() == 4);

auto error2 = StackError::unique("this is a test message", "another_file.cpp", 2);
error2->push("this is a test message", "another_file.cpp", 2);
error2->push("this is a test message", "another_file.cpp", 2);
REQUIRE(error2->size() == 3);

auto error = StackError::combine(std::move(error1), std::move(error2));
REQUIRE(error->size() == 7);

REQUIRE(std::string{error->what()} == "[file.cpp:1] this is a test message\n[file.cpp:1] this is a test message\n[file.cpp:1] this is a test message\n[file.cpp:1] this is a test message\n[another_file.cpp:2] this is a test message\n[another_file.cpp:2] this is a test message\n[another_file.cpp:2] this is a test message\n");
}
47 changes: 47 additions & 0 deletions components/vulkan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# volk
set(VOLK_DIR "${CMAKE_SOURCE_DIR}/third_party/volk")
set(VOLK_SRC ${VOLK_DIR}/volk.c)

set(SRC
${VOLK_SRC}
src/instance.cpp
)

add_library(components__vulkan STATIC ${SRC})
target_include_directories(components__vulkan PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${VOLK_DIR})
target_link_libraries(components__vulkan PUBLIC
vulkan
${CMAKE_DL_LIBS}
components__common)

if (VKB_WSI_SELECTION STREQUAL XCB)
target_include_directories(components__vulkan PUBLIC ${XCB_INCLUDE_DIRS})
elseif (VKB_WSI_SELECTION STREQUAL XLIB)
target_include_directories(components__vulkan PUBLIC ${X11_INCLUDE_DIRS})
elseif (VKB_WSI_SELECTION STREQUAL WAYLAND)
target_include_directories(components__vulkan PUBLIC ${WAYLAND_INCLUDE_DIRS})
endif()



## Vulkan unit tests overrite the Volk vulkan function definitions with custom written ones
## In the custom vulkan function implementations we can add test logic to verify that our code is using Vulkan as expected
## This does not remove the need to out of box test on specific platforms as drivers can contain bugs

## This library must contain all source, libraries and include dirs as components__vulkan. It must be a single compile target to avoid linker errors when compiling on Mac

vkb__register_tests(
NAME "vulkan_tests"
SRC
${SRC}
tests/vulkan_test_functions.cpp
tests/instance.test.cpp
LINK_LIBS
vulkan
${CMAKE_DL_LIBS}
components__common
INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/tests
${VOLK_DIR}
)
Loading