Commit 0b1f6695 authored by Florian Oetke's avatar Florian Oetke
Browse files

basis for GPGPU tone-mapping

parent 7d2a23c8
......@@ -71,3 +71,5 @@ frag_shader:bloom_filter = shader/bin/bloom_filter.frag.spv
vert_shader:bloom_blur = shader/bin/bloom_blur.vert.spv
frag_shader:bloom_blur = shader/bin/bloom_blur.frag.spv
comp_shader:tone_mapping_histogram = shader/bin/tone_mapping_histogram.comp.spv
comp_shader:tone_mapping_exposure = shader/bin/tone_mapping_exposure.comp.spv
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define WIDTH 3200
#define HEIGHT 2400
#define HISTOGRAM_SLOTS 128
#define WORKGROUP_SIZE 32
layout (local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1 ) in;
layout (binding = 0, rgba16f) uniform readonly image2D input_image;
layout(std140, binding = 1) buffer Pos
{
float particles[HISTOGRAM_SLOTS + 1];
};
void main() {
if(gl_GlobalInvocationID.x >= WIDTH || gl_GlobalInvocationID.y >= HEIGHT)
return;
// vec3 rgb = imageLoad(input_image, ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y)).rgb;
}
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define WIDTH 3200
#define HEIGHT 2400
#define HISTOGRAM_SLOTS 128
#define WORKGROUP_SIZE 32
layout (local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1 ) in;
layout (binding = 0, rgba16f) uniform readonly image2D input_image;
layout(std140, binding = 1) buffer Pos
{
float particles[HISTOGRAM_SLOTS + 1];
};
void main() {
if(gl_GlobalInvocationID.x >= WIDTH || gl_GlobalInvocationID.y >= HEIGHT)
return;
// vec3 rgb = imageLoad(input_image, ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y)).rgb;
}
......@@ -28,6 +28,10 @@ elseif(MSVC)
set(MIRRAGE_DEFAULT_COMPILER_ARGS /Za)
endif()
add_definitions(-DHPC_HISTOGRAM_DEBUG_VIEW)
if(MIRRAGE_BUILD_DEMO)
add_subdirectory(demo)
endif()
......
......@@ -2,6 +2,7 @@
file(GLOB_RECURSE GLSL_SOURCE_FILES
"${ROOT_DIR}/assets/core_assets/shader/*.frag"
"${ROOT_DIR}/assets/core_assets/shader/*.vert"
"${ROOT_DIR}/assets/core_assets/shader/*.comp"
)
set(GLSL_COMPILER "glslc")
......
......@@ -35,7 +35,7 @@ namespace mirrage {
renderer::make_pass_factory<renderer::Gi_pass_factory>(),
renderer::make_pass_factory<renderer::Taa_pass_factory>(),
renderer::make_pass_factory<renderer::Tone_mapping_pass_factory>(),
renderer::make_pass_factory<renderer::Bloom_pass_factory>(),
//renderer::make_pass_factory<renderer::Bloom_pass_factory>(),
renderer::make_pass_factory<renderer::Blit_pass_factory>(),
renderer::make_pass_factory<renderer::Gui_pass_factory>())))
{
......
......@@ -69,7 +69,7 @@ namespace {
auto write_dir = asset::write_dir(argv[0], org_name, app_name);
static auto fileAppender = plog::RollingFileAppender<plog::TxtFormatter>(
(write_dir + "/mirrage.log").c_str(), 4L * 1024L, 4);
(write_dir + "/mirrage.log").c_str(), 1024L * 1024L, 4);
static auto consoleAppender = plog::ColorConsoleAppender<plog::TxtFormatter>();
plog::init(plog::debug, &fileAppender).addAppender(&consoleAppender);
......
......@@ -8,6 +8,10 @@
#include <mirrage/renderer/model_comp.hpp>
#include <mirrage/renderer/pass/gui_pass.hpp>
#ifdef HPC_HISTOGRAM_DEBUG_VIEW
#include <mirrage/renderer/pass/tone_mapping_pass.hpp>
#endif
#include <mirrage/ecs/components/transform_comp.hpp>
#include <mirrage/graphic/window.hpp>
#include <mirrage/gui/gui.hpp>
......@@ -316,6 +320,7 @@ namespace mirrage {
if(_show_ui) {
_draw_settings_window();
_draw_histogram_window();
if(_show_profiler) {
_meta_system.renderer().profiler().enable();
......@@ -604,6 +609,36 @@ namespace mirrage {
nk_end(ctx);
}
void Test_screen::_draw_histogram_window()
{
#ifdef HPC_HISTOGRAM_DEBUG_VIEW
auto tone_mapping_pass = _meta_system.renderer().find_pass<renderer::Tone_mapping_pass>();
if(tone_mapping_pass) {
auto&& histogram = tone_mapping_pass->last_histogram();
auto ctx = _gui.ctx();
if(nk_begin_titled(
ctx,
"Histogram",
"Histogram",
_gui.centered_right(300, 300),
NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_TITLE | NK_WINDOW_MINIMIZABLE)) {
nk_layout_row_dynamic(ctx, 150, 1);
nk_chart_begin(ctx, NK_CHART_COLUMN, static_cast<int>(histogram.size() - 1), 0, 50);
for(auto i : util::range(histogram.size() - 1)) {
nk_chart_push(ctx, histogram[i]);
}
nk_chart_end(ctx);
}
nk_end(ctx);
}
#endif
}
void Test_screen::_update_sun_position()
{
_sun.get<Transform_comp>().process([&](auto& transform) {
......
......@@ -77,5 +77,6 @@ namespace mirrage {
void _draw_settings_window();
void _draw_profiler_window();
void _draw_histogram_window();
};
} // namespace mirrage
......@@ -56,7 +56,7 @@ namespace mirrage::graphic {
auto create_render_pass_builder() -> Render_pass_builder;
auto create_semaphore() -> vk::UniqueSemaphore;
auto create_fence() -> Fence;
auto create_fence(bool signaled = false) -> Fence;
auto create_command_buffer_pool(Queue_tag queue_family,
bool resetable = true,
bool short_lived = false) -> Command_buffer_pool;
......@@ -147,6 +147,7 @@ namespace mirrage::graphic {
auto max_frames_in_flight() const noexcept { return _delete_queue.capacity() + 2; }
auto vk_device() const noexcept { return &*_device; }
auto pipeline_cache() const noexcept { return **_pipeline_cache; }
private:
struct Asset_loaders;
......
......@@ -130,7 +130,7 @@ namespace mirrage::graphic {
const vk::Device& _device;
vk::UniqueFence _fence;
Fence(const vk::Device& device);
Fence(const vk::Device& device, bool signaled);
};
extern auto create_fence(Device&) -> Fence;
......@@ -310,4 +310,21 @@ namespace mirrage::graphic {
vk::ImageLayout final_layout,
std::uint32_t initial_mip_level = 0,
std::uint32_t mip_levels = 0);
template <typename P>
auto find_queue_family(vk::PhysicalDevice& gpu, P&& predicat) -> util::maybe<std::uint32_t>
{
auto i = 0u;
for(auto& queue_family : gpu.getQueueFamilyProperties()) {
if(queue_family.queueCount > 0 && predicat(queue_family)) {
return i;
}
i++;
}
return util::nothing;
}
} // namespace mirrage::graphic
......@@ -345,7 +345,7 @@ namespace mirrage::graphic {
return {*_device, chunk_size, types};
}
auto Device::create_fence() -> Fence { return Fence{*_device}; }
auto Device::create_fence(bool signaled) -> Fence { return Fence{*_device, signaled}; }
auto Device::get_supported_format(std::initializer_list<vk::Format> formats,
vk::FormatFeatureFlags flags,
......
......@@ -211,8 +211,6 @@ namespace mirrage::graphic {
auto Stage_builder::shader(const asset::AID& id, Shader_stage stage, std::string entry_point)
-> Stage_builder&
{
auto in = _builder._assets.load<Shader_module>(id);
pipeline().stages.emplace_back(
stage, _builder._assets.load<Shader_module>(id), std::move(entry_point));
......
......@@ -28,7 +28,12 @@ namespace mirrage::graphic {
void Fence::reset() { _device.resetFences({*_fence}); }
void Fence::wait() { _device.waitForFences({*_fence}, true, std::numeric_limits<std::uint64_t>::max()); }
Fence::Fence(const vk::Device& device) : _device(device), _fence(_device.createFenceUnique({})) {}
Fence::Fence(const vk::Device& device, bool signaled)
: _device(device)
, _fence(_device.createFenceUnique({signaled ? vk::FenceCreateFlags{vk::FenceCreateFlagBits::eSignaled}
: vk::FenceCreateFlags{}}))
{
}
auto create_fence(Device& d) -> Fence { return d.create_fence(); }
......
......@@ -130,9 +130,13 @@ namespace mirrage::renderer {
void queue_commands(vk::CommandBuffer);
auto queue_temporary_command_buffer() -> vk::CommandBuffer;
auto create_compute_command_buffer() -> vk::UniqueCommandBuffer;
auto model_material_sampler() const noexcept { return *_model_material_sampler; }
auto model_descriptor_set_layout() const noexcept { return *_model_desc_set_layout; }
auto compute_queue() const noexcept { return _compute_queue; }
void finish_frame();
auto settings() const -> auto& { return *_settings; }
......@@ -151,11 +155,14 @@ namespace mirrage::renderer {
graphic::Window& _window;
graphic::Device_ptr _device;
graphic::Swapchain& _swapchain;
std::uint32_t _queue_family;
vk::Queue _queue;
std::uint32_t _draw_queue_family;
std::uint32_t _compute_queue_family;
vk::Queue _draw_queue;
vk::Queue _compute_queue;
vk::UniqueSemaphore _image_acquired;
vk::UniqueSemaphore _image_presented;
graphic::Command_buffer_pool _command_buffer_pool;
graphic::Command_buffer_pool _compute_command_buffer_pool;
util::maybe<std::size_t> _aquired_swapchain_image;
std::vector<vk::CommandBuffer> _queued_commands;
std::vector<Deferred_renderer*> _renderer_instances;
......@@ -208,7 +215,11 @@ namespace mirrage::renderer {
auto device() noexcept -> auto& { return *_factory->_device; }
auto window() noexcept -> auto& { return _factory->_window; }
auto swapchain() noexcept -> auto& { return _factory->_swapchain; }
auto queue_family() const noexcept { return _factory->_queue_family; }
auto queue_family() const noexcept { return _factory->_draw_queue_family; }
auto compute_queue_family() const noexcept { return _factory->_compute_queue_family; }
auto compute_queue() const noexcept { return _factory->compute_queue(); }
auto create_compute_command_buffer() { return _factory->create_compute_command_buffer(); }
auto create_descriptor_set(vk::DescriptorSetLayout, std::uint32_t bindings) -> graphic::DescriptorSet;
auto descriptor_pool() noexcept -> auto& { return _descriptor_set_pool; }
......
......@@ -21,14 +21,26 @@ namespace mirrage::renderer {
vk::DescriptorSet global_uniform_set,
std::size_t swapchain_image) override;
auto last_histogram() const noexcept -> auto& { return _last_result_data; }
auto name() const noexcept -> const char* override { return "Tone Mapping"; }
private:
Deferred_renderer& _renderer;
Deferred_renderer& _renderer;
graphic::Fence _compute_fence;
vk::UniqueCommandBuffer _last_compute_commands;
std::vector<graphic::Backed_buffer> _result_buffer;
int _ready_result = -1;
int _next_result = 0;
std::vector<float> _last_result_data;
vk::UniqueSampler _sampler;
graphic::Image_descriptor_set_layout _descriptor_set_layout;
vk::Format _luminance_format;
int _first_frame = 4;
vk::UniqueDescriptorSetLayout _compute_descriptor_set_layout;
std::vector<graphic::DescriptorSet> _compute_descriptor_set;
// calculate scene luminance for tone mapping
graphic::Render_target_2D _luminance_buffer;
......@@ -36,12 +48,13 @@ namespace mirrage::renderer {
graphic::Render_pass _calc_luminance_renderpass;
graphic::DescriptorSet _calc_luminance_desc_set;
// calculate and adapt avg luminance over time
graphic::Render_target_2D _prev_avg_luminance;
graphic::Render_target_2D _curr_avg_luminance;
graphic::Framebuffer _adapt_luminance_framebuffer;
graphic::Render_pass _adapt_luminance_renderpass;
graphic::DescriptorSet _adapt_luminance_desc_set;
vk::UniquePipelineLayout _compute_pipeline_layout;
vk::UniquePipeline _build_histogram_pipeline;
vk::UniquePipeline _compute_exposure_pipeline;
void _extract_luminance(vk::CommandBuffer&);
void _dispatch_build_histogram(vk::CommandBuffer&);
void _dispatch_compute_exposure(vk::CommandBuffer&);
};
class Tone_mapping_pass_factory : public Pass_factory {
......
......@@ -23,6 +23,9 @@ namespace mirrage::renderer {
{vk::DescriptorType::eUniformBuffer,
vk::DescriptorType::eCombinedImageSampler,
vk::DescriptorType::eInputAttachment,
vk::DescriptorType::eStorageBuffer,
vk::DescriptorType::eStorageTexelBuffer,
vk::DescriptorType::eStorageImage,
vk::DescriptorType::eSampledImage,
vk::DescriptorType::eSampler}))
, _gbuffer(std::make_unique<GBuffer>(device(), factory._window.width(), factory._window.height()))
......@@ -266,15 +269,18 @@ namespace mirrage::renderer {
, _window(window)
, _device(context.instantiate_device(FOE_SELF(_rank_device), FOE_SELF(_init_device), {&_window}, true))
, _swapchain(_device->get_single_swapchain())
, _queue_family(_device->get_queue_family("draw"_strid))
, _queue(_device->get_queue("draw"_strid))
, _draw_queue_family(_device->get_queue_family("draw"_strid))
, _compute_queue_family(_device->get_queue_family("compute"_strid))
, _draw_queue(_device->get_queue("draw"_strid))
, _compute_queue(_device->get_queue("compute"_strid))
, _image_acquired(_device->create_semaphore())
, _image_presented(_device->create_semaphore())
, _command_buffer_pool(_device->create_command_buffer_pool("draw"_strid, true, true))
, _compute_command_buffer_pool(_device->create_command_buffer_pool("compute"_strid, true, true))
, _model_material_sampler(_device->create_sampler(12))
, _model_desc_set_layout(create_material_descriptor_set_layout(*_device, *_model_material_sampler))
, _asset_loaders(std::make_unique<Asset_loaders>(
_assets, *_device, *_model_material_sampler, *_model_desc_set_layout, _queue_family))
_assets, *_device, *_model_material_sampler, *_model_desc_set_layout, _draw_queue_family))
{
auto maybe_settings = _assets.load_maybe<Renderer_settings>("cfg:renderer"_aid);
......@@ -367,17 +373,37 @@ namespace mirrage::renderer {
1,
&*_image_presented};
_queue.submit({submit_info}, frame_fence);
_draw_queue.submit({submit_info}, frame_fence);
_queued_commands.clear();
// present
if(_swapchain.present(_queue, _aquired_swapchain_image.get_or_throw(), *_image_presented)) {
if(_swapchain.present(_draw_queue, _aquired_swapchain_image.get_or_throw(), *_image_presented)) {
_recreation_pending = true;
}
_aquired_swapchain_image = util::nothing;
}
namespace {
auto find_compute_queue(vk::PhysicalDevice& gpu) -> util::maybe<std::uint32_t>
{
// try to find async compute queue first
auto queue = find_queue_family(gpu, [](auto&& q) {
return q.timestampValidBits >= 32 && q.queueFlags == vk::QueueFlagBits::eCompute;
});
// ... if their is none, fallback to any compute queue
if(queue.is_nothing()) {
queue = find_queue_family(gpu, [](auto&& q) {
return q.timestampValidBits >= 32
&& (q.queueFlags & vk::QueueFlagBits::eCompute) == vk::QueueFlagBits::eCompute;
});
}
return queue;
}
} // namespace
auto Deferred_renderer_factory::_rank_device(vk::PhysicalDevice gpu, util::maybe<std::uint32_t> gqueue)
-> int
{
......@@ -400,6 +426,10 @@ namespace mirrage::renderer {
return std::numeric_limits<int>::min();
}
if(find_compute_queue(gpu).is_some()) {
score -= 500;
}
for(auto& pass : _pass_factories) {
score = pass->rank_device(gpu, gqueue, score);
}
......@@ -415,6 +445,10 @@ namespace mirrage::renderer {
MIRRAGE_INVARIANT(gqueue.is_some(), "No useable queue family");
ret_val.queue_families.emplace("draw"_strid, Queue_create_info{gqueue.get_or_throw()});
ret_val.queue_families.emplace("compute"_strid,
Queue_create_info{find_compute_queue(gpu).get_or_throw(
"The device doesn't support compute.")});
auto supported_features = gpu.getFeatures();
MIRRAGE_INVARIANT(supported_features.samplerAnisotropy,
"Anisotropic filtering is not supported by device!");
......@@ -448,4 +482,9 @@ namespace mirrage::renderer {
return cb;
}
auto Deferred_renderer_factory::create_compute_command_buffer() -> vk::UniqueCommandBuffer
{
return std::move(_compute_command_buffer_pool.create_primary()[0]);
}
} // namespace mirrage::renderer
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment