我正在修补Vulkan,我偶然发现了一个问题:线程池和资源提交。
我目前的代码不会导致验证层错误或程序退出错误(即分配等),但我在应用程序中使用的纹理是错误的-在我目前的情况下,它只是纯粉色,而不是我期待的冲锋队头盔😬
我使用这个线程池库来处理池,我已经重命名了类以适合我的代码风格。
作为参考,通过简单地加载图像image:: image ("my/texture/dir/texture.png")和image::invalidate(),一切工作。这个用例不使用命令缓冲区,而是从全局上下文中请求命令缓冲区。
我猜我误解了一些基本的东西,我很想接受教育:
void ImageCache<T>::load_from_directory(const std::filesystem::path& shader_directory) {
auto sorted_images_in_directory
= IO::in_directory<std::string>(shader_directory, { ".tga", ".png", ".jpeg", ".jpg" }, true);
ThreadPool pool { 8 };
std::mutex mutex;
buffer->begin();
for (const auto& entry : sorted_images_in_directory) {
const auto image_name = remove_extension<std::filesystem::path>(entry);
ImageProps props { .path = entry };
// Load all images and obtain pixels from image data (png, jpg etc)
Image image = Image(props);
// Push a function into the thread pool which should:
pool.push([&images = images, &buffer = buffer, image_name, &image, &mutex](int) {
std::unique_lock lock(mutex); // Lock the mutex
// This is the work horse:
// Submit into the common (for all images) VkCommandBuffer
// 1) Move pixel data of image to staging buffer,
// 2) create VkImage.
// 3) transition image from undefined to dst_optimal (in same CB)
// 4) copy pixel data from staging to VkImage (in same CB)
// 5) transition from dst_optimal to shader_read_optimal (in same CB)
// 6) Create VkImageView and VkSampler
image.invalidate(buffer);
// invalidate also adds a 'destructor' callback to the command buffer, which
// just prior to vkQueueSubmit deallocates the staging buffer, like so:
// buffer->add_destruction_callback([&staging_buffer_allocation, &staging_buffer]
// (Allocator& allocator) { allocator.destroy_buffer(staging_buffer, staging_buffer_allocation); });
images.try_emplace(image_name, image); // Push into image/texture cache
lock.unlock(); // Unlock the mux
});
}
pool.stop();
buffer->end();
buffer->submit();
}
正如评论中所述,这里没有太多要讨论的内容。但是有些东西我会看:
- 验证命令缓冲区正在从适当的线程提交。虽然你可以从任何线程记录命令缓冲区,但你应该同步提交(通常是从主线程)。
- 我假设你正在记录多个命令缓冲区。验证你的提交顺序是正确的(例如,你提交了填充图像的缓冲区,然后才提交了消耗它的缓冲区) 这很难从你的伪代码中看出,但我怀疑你可能有一个围绕图像集合本身的线程错误。您在开始时捕获互斥锁,但随后(可能?)为每个图像生成一个线程。每个线程在访问任何集合对象之前都应该持有互斥锁。所以你的try_emplace至少应该有人把守。
但是,这里没有真正的代码,很难确切地说出根本原因是什么。从你观察到的情况来看,我确实认为围绕集合的线程错误是最有可能的罪魁祸首。