Skip to content

Commit 5d014e2

Browse files
authored
Remove submodule CTPL, replace its functionality by calls to std::async (KhronosGroup#1378)
1 parent fb5c2f3 commit 5d014e2

10 files changed

Lines changed: 101 additions & 46 deletions

File tree

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@
3434
[submodule "third_party/astc"]
3535
path = third_party/astc
3636
url = https://github.com/ARM-software/astc-encoder
37-
[submodule "third_party/CTPL"]
38-
path = third_party/CTPL
39-
url = https://github.com/vit-vit/CTPL
4037
[submodule "third_party/vulkan"]
4138
path = third_party/vulkan
4239
url = https://github.com/KhronosGroup/Vulkan-Headers

framework/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
503503
vma
504504
spirv-cross-glsl
505505
spdlog
506-
ctpl
507506
plugins)
508507

509508
if(${NEED_LINK_ATOMIC})

framework/gltf_loader.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define TINYGLTF_IMPLEMENTATION
2020
#include "gltf_loader.h"
2121

22+
#include <future>
2223
#include <limits>
2324
#include <queue>
2425

@@ -51,8 +52,6 @@
5152
#include "scene_graph/scene.h"
5253
#include "scene_graph/scripts/animation.h"
5354

54-
#include <ctpl_stl.h>
55-
5655
namespace vkb
5756
{
5857
namespace
@@ -551,25 +550,19 @@ sg::Scene GLTFLoader::load_scene(int scene_index, VkBufferUsageFlags additional_
551550
timer.start();
552551

553552
// Load images
554-
auto thread_count = std::thread::hardware_concurrency();
555-
thread_count = thread_count == 0 ? 1 : thread_count;
556-
ctpl::thread_pool thread_pool(thread_count);
557-
558553
auto image_count = to_u32(model.images.size());
559554

560555
std::vector<std::future<std::unique_ptr<sg::Image>>> image_component_futures;
561556
for (size_t image_index = 0; image_index < image_count; image_index++)
562557
{
563-
auto fut = thread_pool.push(
564-
[this, image_index](size_t) {
558+
image_component_futures.push_back(std::async(
559+
[this, image_index]() {
565560
auto image = parse_image(model.images[image_index]);
566561

567562
LOGI("Loaded gltf image #{} ({})", image_index, model.images[image_index].uri.c_str());
568563

569564
return image;
570-
});
571-
572-
image_component_futures.push_back(std::move(fut));
565+
}));
573566
}
574567

575568
std::vector<std::unique_ptr<sg::Image>> image_components;
@@ -626,6 +619,8 @@ sg::Scene GLTFLoader::load_scene(int scene_index, VkBufferUsageFlags additional_
626619

627620
auto elapsed_time = timer.stop();
628621

622+
auto thread_count = std::thread::hardware_concurrency();
623+
thread_count = thread_count == 0 ? 1 : thread_count;
629624
LOGI("Time spent loading images: {} seconds across {} threads.", vkb::to_string(elapsed_time), thread_count);
630625

631626
// Load textures

samples/performance/command_buffer_usage/command_buffer_usage.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,13 @@ void CommandBufferUsage::ForwardSubpassSecondary::draw(vkb::core::CommandBufferC
369369

370370
if (state.multi_threading)
371371
{
372-
auto fut = thread_pool.push(
373-
[this, cb_count, &primary_command_buffer, &sorted_opaque_nodes, mesh_start, mesh_end](size_t thread_id) {
374-
return record_draw_secondary(primary_command_buffer, sorted_opaque_nodes, mesh_start, mesh_end, thread_id);
375-
});
372+
auto fut = thread_pool.push(std::bind(&CommandBufferUsage::ForwardSubpassSecondary::record_draw_secondary,
373+
this,
374+
std::ref(primary_command_buffer),
375+
std::cref(sorted_opaque_nodes),
376+
mesh_start,
377+
mesh_end,
378+
std::placeholders::_1));
376379

377380
secondary_cmd_buf_futures.push_back(std::move(fut));
378381
}

samples/performance/command_buffer_usage/command_buffer_usage.h

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
#pragma once
1919

20-
#include <ctpl_stl.h>
21-
2220
#include "buffer_pool.h"
2321
#include "common/utils.h"
2422
#include "rendering/render_pipeline.h"
@@ -28,6 +26,86 @@
2826
#include "scene_graph/components/perspective_camera.h"
2927
#include "vulkan_sample.h"
3028

29+
class ThreadPool
30+
{
31+
public:
32+
explicit ThreadPool() :
33+
stop_flag(false)
34+
{}
35+
36+
~ThreadPool()
37+
{
38+
shutdown();
39+
}
40+
41+
template <class F, class... Args>
42+
auto push(F &&f, Args &&...args) -> std::future<std::invoke_result_t<F, Args..., size_t>>
43+
{
44+
using return_type = std::invoke_result_t<F, Args..., size_t>;
45+
auto task_ptr = std::make_shared<std::packaged_task<return_type(size_t)>>(std::bind(std::forward<F>(f), std::forward<Args>(args)..., std::placeholders::_1));
46+
std::future<return_type> res = task_ptr->get_future();
47+
{
48+
std::unique_lock<std::mutex> lock(queue_mutex);
49+
tasks.emplace([task_ptr](size_t thread_index) { (*task_ptr)(thread_index); });
50+
}
51+
condition.notify_one();
52+
return res;
53+
}
54+
55+
void resize(size_t thread_count)
56+
{
57+
if (thread_count != workers.size())
58+
{
59+
shutdown();
60+
61+
for (size_t i = 0; i < thread_count; ++i)
62+
{
63+
workers.emplace_back([this, i] {
64+
size_t thread_index = i;
65+
while (true)
66+
{
67+
std::function<void(size_t)> task;
68+
{
69+
std::unique_lock<std::mutex> lock(queue_mutex);
70+
condition.wait(lock, [this] { return stop_flag || !tasks.empty(); });
71+
if (stop_flag && tasks.empty())
72+
return;
73+
task = std::move(tasks.front());
74+
tasks.pop();
75+
}
76+
task(thread_index);
77+
}
78+
});
79+
}
80+
}
81+
}
82+
83+
void shutdown()
84+
{
85+
{
86+
std::unique_lock<std::mutex> lock(queue_mutex);
87+
stop_flag = true;
88+
}
89+
condition.notify_all();
90+
for (auto &worker : workers)
91+
worker.join();
92+
workers.clear();
93+
stop_flag = false;
94+
}
95+
96+
size_t size() const
97+
{
98+
return workers.size();
99+
}
100+
101+
private:
102+
std::vector<std::thread> workers;
103+
std::queue<std::function<void(size_t)>> tasks;
104+
std::mutex queue_mutex;
105+
std::condition_variable condition;
106+
std::atomic<bool> stop_flag;
107+
};
108+
31109
/**
32110
* @brief Sample showing the use of secondary command buffers for
33111
* multi-threaded recording, as well as the different
@@ -124,7 +202,7 @@ class CommandBufferUsage : public vkb::VulkanSampleC
124202

125203
float avg_draws_per_buffer{0};
126204

127-
ctpl::thread_pool thread_pool;
205+
ThreadPool thread_pool;
128206
};
129207

130208
private:

samples/performance/multithreading_render_passes/multithreading_render_passes.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,6 @@ std::vector<std::shared_ptr<vkb::core::CommandBufferC>>
198198
auto use_multithreading = multithreading_mode != static_cast<int>(MultithreadingMode::None);
199199
shadow_subpass->set_thread_index(use_multithreading ? 1 : 0);
200200

201-
if (use_multithreading && thread_pool.size() < 1)
202-
{
203-
thread_pool.resize(1);
204-
}
205-
206201
switch (multithreading_mode)
207202
{
208203
case static_cast<int>(MultithreadingMode::PrimaryCommandBuffers):
@@ -234,8 +229,8 @@ void MultithreadingRenderPasses::record_separate_primary_command_buffers(std::ve
234229
get_render_context().get_active_frame().get_command_pool(queue, reset_mode, 1).request_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
235230

236231
// Recording shadow command buffer
237-
auto shadow_buffer_future = thread_pool.push(
238-
[this, shadow_command_buffer](size_t thread_id) {
232+
auto shadow_buffer_future = std::async(
233+
[this, shadow_command_buffer]() {
239234
shadow_command_buffer->begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
240235
draw_shadow_pass(*shadow_command_buffer);
241236
shadow_command_buffer->end();
@@ -278,9 +273,10 @@ void MultithreadingRenderPasses::record_separate_secondary_command_buffers(std::
278273
auto &scene_framebuffer = get_device().get_resource_cache().request_framebuffer(scene_render_target, scene_render_pass);
279274

280275
// Recording shadow command buffer
281-
auto shadow_buffer_future = thread_pool.push(
282-
[this, shadow_command_buffer, &shadow_render_pass, &shadow_framebuffer](size_t thread_id) {
283-
shadow_command_buffer->begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &shadow_render_pass, &shadow_framebuffer, 0);
276+
auto shadow_buffer_future = std::async(
277+
[this, shadow_command_buffer, &shadow_render_pass, &shadow_framebuffer]() {
278+
shadow_command_buffer->begin(
279+
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &shadow_render_pass, &shadow_framebuffer, 0);
284280
draw_shadow_pass(*shadow_command_buffer);
285281
shadow_command_buffer->end();
286282
});

samples/performance/multithreading_render_passes/multithreading_render_passes.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
#pragma once
1919

20-
#include <ctpl_stl.h>
21-
2220
#include "core/command_buffer.h"
2321
#include "rendering/render_pipeline.h"
2422
#include "rendering/subpasses/forward_subpass.h"
@@ -150,8 +148,6 @@ class MultithreadingRenderPasses : public vkb::VulkanSampleC
150148
*/
151149
vkb::sg::Camera *camera{};
152150

153-
ctpl::thread_pool thread_pool;
154-
155151
uint32_t swapchain_attachment_index{0};
156152

157153
uint32_t depth_attachment_index{1};

third_party/CMakeLists.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,12 +371,6 @@ set(SPDLOG_FMT_EXTERNAL ON)
371371
add_subdirectory(spdlog)
372372
set_property(TARGET spdlog PROPERTY FOLDER "ThirdParty")
373373

374-
# ctpl
375-
add_library(ctpl INTERFACE)
376-
set(CTPL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CTPL)
377-
target_sources(ctpl INTERFACE ${CTPL_DIR}/ctpl_stl.h)
378-
target_include_directories(ctpl SYSTEM INTERFACE ${CTPL_DIR})
379-
380374
# OpenCL
381375
add_library(opencl INTERFACE)
382376
set(OPENCL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/opencl)

third_party/CTPL

Lines changed: 0 additions & 1 deletion
This file was deleted.

third_party/README.adoc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
////
2-
- Copyright (c) 2019-2024, Arm Limited and Contributors
2+
- Copyright (c) 2019-2025, Arm Limited and Contributors
33
-
44
- SPDX-License-Identifier: Apache-2.0
55
-
@@ -23,9 +23,7 @@
2323
This project has multiple third-party dependencies, each of which may have independent licensing:
2424

2525
* https://github.com/ARM-software/astc-encoder[astc-encoder]: ASTC Evaluation Codec
26-
* https://github.com/catchorg/Catch2[Catch2]: Modern C++ test framework
2726
* https://github.com/CLIUtils/CLI11[CLI11] Command line parser for C++11 and beyond
28-
* https://github.com/vit-vit/CTPL[CTPL]: Thread Pool Library
2927
* https://github.com/fmtlib/fmt[fmt]: A modern formating library
3028
* https://github.com/glfw/glfw[glfw]: A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input
3129
* https://github.com/g-truc/glm[glm]: OpenGL Mathematics

0 commit comments

Comments
 (0)