mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-09 01:20:32 +01:00
Improve rain shader
This commit is contained in:
@@ -71,7 +71,9 @@ constexpr std::uint32_t HEADLIGHT_SHADOW_TEX = 23;
|
||||
constexpr std::uint32_t SCENE_DEPTH_TEX = 24;
|
||||
// the image of the last frame of the main view with its mipmaps, which the screen space reflections take their colour from
|
||||
constexpr std::uint32_t SSR_HISTORY_TEX = 25;
|
||||
constexpr std::uint32_t PASS_BINDING_COUNT = 26;
|
||||
// the water on the windscreens (gfx::windscreen_water): the drops, their grids and the wetted paths the glasses read
|
||||
constexpr std::uint32_t WATER_SSBO = 26;
|
||||
constexpr std::uint32_t PASS_BINDING_COUNT = 27;
|
||||
// the offsets of the bindings above with dynamic offsets, in the order of the bindings
|
||||
constexpr std::uint32_t PASS_DYNAMIC_OFFSETS = 6;
|
||||
// the textures of a material take the bindings of their units (#pragma texture(name, unit, ...)), 0 .. MAX_TEXTURES - 1
|
||||
|
||||
@@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "rendering/vulkan14/vulkan14terrain.h"
|
||||
#include "rendering/vulkan14/vulkan14grass.h"
|
||||
#include "rendering/vulkan14/vulkan14particles.h"
|
||||
#include "rendering/vulkan14/vulkan14water.h"
|
||||
#include "rendering/vulkan14/vulkan14commands.h"
|
||||
#include "rendering/vulkan14/vulkan14raytracing.h"
|
||||
#include "rendering/vulkan14/vulkan14dlss.h"
|
||||
@@ -397,6 +398,8 @@ struct scene_state
|
||||
bool grass_tried{false};
|
||||
// the smoke and the rain or snow of the gpu
|
||||
gpu_particles particles;
|
||||
// the water on the windscreens of the cab of the train; its storage is held by the pass sets (WATER_SSBO)
|
||||
windscreen_water water;
|
||||
// the ray traced reflections (gfx.raytracing), on a device with ray queries; its set is set RT_SET of the pipelines of the scene
|
||||
std::unique_ptr<ray_tracing> raytracing;
|
||||
// the heatmap of the light clusters (gfx.lights.clusterheatmap), made when it's first drawn
|
||||
|
||||
@@ -168,7 +168,7 @@ std::string vulkan14_renderer::scene_info()
|
||||
line(" shapes: ", colour.shapes, shadowstats.shapes) + " traction: " + to_string(colour.traction, 7) + "\n" + " lines: " + to_string(colour.lines, 7) + "\n" +
|
||||
"particles: " + to_string(colour.particles, 7) + "\nlights: " + to_string(static_cast<int>(m_lights_lit), 7) + " (" + std::to_string(m_lights_dropped) + " over capacity), " +
|
||||
(Global.gfx_lights_clustered ? "clustered" : "first " + std::to_string(std::max(Global.DynamicLightCount, 0))) + "\n" + m_locallights.info() + scene.lamps.info() +
|
||||
scene.particles.info();
|
||||
scene.particles.info() + scene.water.info();
|
||||
auto const &stats{scene.clusters.stats};
|
||||
if (stats.valid && (Global.gfx_lights_clustered || Global.gfx_lights_clusterheatmap))
|
||||
{
|
||||
|
||||
@@ -990,6 +990,8 @@ void vulkan14_renderer::render_scene()
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
// the water on the windscreens of the cab: a step of its simulation once a frame, before the passes which draw the glasses
|
||||
scene.water.update(Timer::GetDeltaTime());
|
||||
if (scene.targets.size() < m_viewports.size())
|
||||
{
|
||||
scene.targets.resize(m_viewports.size());
|
||||
@@ -1406,6 +1408,16 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
float percipitation_intensity = glm::saturate(Global.Overcast - 1.);
|
||||
scene_ubs.rain_params.x = percipitation_intensity;
|
||||
scene_ubs.rain_params.y = glm::mix(15., 1., percipitation_intensity);
|
||||
scene_ubs.rain_params.z = (Global.Weather == "snow:" ? 1.f : 0.f); // flakes on the glass in place of the drops
|
||||
scene_ubs.rain_params.w = Global.AirTemperature; // how fast the flakes melt
|
||||
{
|
||||
// the air the drops on the glass are blown with: the wind as the particles drift with it, less the velocity of the
|
||||
// vehicle (V is along the front of the vehicle)
|
||||
glm::dvec3 air{glm::dvec3{simulation::Environment.wind()} * 0.5};
|
||||
if (TDynamicObject const *owner = Global.pCamera.m_owner)
|
||||
air -= owner->VectorFront() * owner->MoverParameters->V;
|
||||
scene_ubs.rain_wind = glm::vec4{glm::vec3{air}, 0.f};
|
||||
}
|
||||
if (TDynamicObject const *owner = Global.pCamera.m_owner; owner && !!owner->MoverParameters->CabActive)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
|
||||
@@ -150,6 +150,7 @@ VkDescriptorType pass_binding_type(std::uint32_t const Binding)
|
||||
case CLUSTER_RANGE_SSBO:
|
||||
case CLUSTER_INDEX_SSBO:
|
||||
case SKY_SSBO:
|
||||
case WATER_SSBO:
|
||||
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
case ATMOSPHERE_UBO:
|
||||
case WEATHER_HORIZON_UBO:
|
||||
@@ -708,6 +709,40 @@ bool vulkan14_renderer::init_scene(std::string &Reason)
|
||||
scene.particles.init(device, ctx.pipelines, ctx.shaders, scene.pass_layout, ctx.memory, ctx.uploads, ctx.deletions, ctx.ring, ctx.device.caps().limits.minUniformBufferOffsetAlignment, frames,
|
||||
std::move(host));
|
||||
}
|
||||
{
|
||||
vk14::windscreen_water::host host;
|
||||
host.commands = [this]() {
|
||||
suspend_rendering();
|
||||
return m_context->commands;
|
||||
};
|
||||
host.texture = [this](texture_handle const Texture, VkImageView &View, VkSampler &Sampler) {
|
||||
auto &ctx{*m_context};
|
||||
if ((Texture == null_handle) || (false == bool(ctx.textures)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto &source{ctx.textures->mark_as_used(Texture)};
|
||||
if (false == source.create())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto const *entry{ctx.images.find(source.get_id())};
|
||||
if (entry == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
View = entry->target->view();
|
||||
Sampler = entry->sampler;
|
||||
return true;
|
||||
};
|
||||
if (false == scene.water.init(device, ctx.pipelines, ctx.shaders, scene.pass_layout, ctx.memory, ctx.uploads, ctx.deletions, ctx.ring, ctx.device.caps().limits.minUniformBufferOffsetAlignment,
|
||||
std::move(host)))
|
||||
{
|
||||
Reason = "no storage of the water on the windscreens";
|
||||
return false;
|
||||
}
|
||||
scene.water.set_host({[this](material_handle const Material) { return &m_materials.material(Material); }});
|
||||
}
|
||||
scene.terrain->init(ctx.resources, [this](vk14::command_stream *const Commands, VkImageView const Target, VkFormat const Format, VkExtent2D const Extent, VkImageView const Source, VkSampler const Sampler) {
|
||||
auto &scene{m_context->scene};
|
||||
auto const pipeline{post_pipeline("copy.frag", static_cast<int>(Format))};
|
||||
@@ -779,6 +814,7 @@ void vulkan14_renderer::destroy_scene()
|
||||
scene.terrain.reset();
|
||||
scene.grass.destroy();
|
||||
scene.particles.destroy();
|
||||
scene.water.destroy();
|
||||
scene.grass_program.reset();
|
||||
scene.grass_tried = false;
|
||||
scene.cluster_heatmap.reset();
|
||||
@@ -931,6 +967,7 @@ void vulkan14_renderer::write_pass_sets(vk14::instance_cull *Cull)
|
||||
VkDescriptorBufferInfo const atmosphereblock{scene.sky.atmosphere.handle(), 0, sizeof(gl::atmosphere_ubs)};
|
||||
VkDescriptorBufferInfo const weatherblock{ctx.ring.handle(), 0, offsetof(gl::weather_ubs, fog_horizon)};
|
||||
VkDescriptorBufferInfo const horizonblock{scene.weather_horizon.handle(), 0, sizeof(glm::vec4) * gl::FOG_HORIZON_SAMPLES};
|
||||
VkDescriptorBufferInfo const water{scene.water.storage(), 0, VK_WHOLE_SIZE};
|
||||
VkDescriptorImageInfo const headlightsinfo{scene.headlights_sampler, scene.headlights_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
|
||||
std::vector<VkWriteDescriptorSet> writes;
|
||||
std::vector<std::unique_ptr<VkDescriptorImageInfo>> images;
|
||||
@@ -964,6 +1001,7 @@ void vulkan14_renderer::write_pass_sets(vk14::instance_cull *Cull)
|
||||
write(handle, ATMOSPHERE_UBO, &atmosphereblock, nullptr);
|
||||
write(handle, WEATHER_UBO, &weatherblock, nullptr);
|
||||
write(handle, WEATHER_HORIZON_UBO, &horizonblock, nullptr);
|
||||
write(handle, WATER_SSBO, &water, nullptr);
|
||||
write(handle, HEADLIGHT_TEX, nullptr, &headlightsinfo);
|
||||
write(handle, SHADOW_TEX, nullptr, image(ctx.sampling.shadow, views[SHADOW_TEX]));
|
||||
write(handle, ENV_TEX, nullptr, image(ctx.sampling.clamp_linear, views[ENV_TEX]));
|
||||
|
||||
@@ -802,6 +802,7 @@ std::string binding_preamble(bool const Raytracing)
|
||||
define("HEADLIGHT_SHADOW_TEX", HEADLIGHT_SHADOW_TEX);
|
||||
define("SCENE_DEPTH_TEX", SCENE_DEPTH_TEX);
|
||||
define("SSR_HISTORY_TEX", SSR_HISTORY_TEX);
|
||||
define("WATER_SSBO", WATER_SSBO);
|
||||
define("PASS_BINDING_COUNT", PASS_BINDING_COUNT);
|
||||
define("MATERIAL_TEXTURE_FIRST", MATERIAL_TEXTURE_FIRST);
|
||||
define("CL_CLUSTER_UBO", CL_CLUSTER_UBO);
|
||||
@@ -865,6 +866,13 @@ std::string binding_preamble(bool const Raytracing)
|
||||
define("SHADOW_FIT_GROUP_SIZE", gl::SHADOW_FIT_GROUP_SIZE);
|
||||
preamble += "#define LOCAL_SHADOW_NEAR " + std::to_string(gfx::local_shadows::shadow_near) + "\n";
|
||||
define("PARTICLE_GROUP_SIZE", gl::PARTICLE_GROUP_SIZE);
|
||||
define("WATER_SLOTS", gl::WATER_SLOTS);
|
||||
define("WATER_DROPS", gl::WATER_DROPS);
|
||||
define("WATER_GRID", gl::WATER_GRID);
|
||||
define("WATER_CELL_DROPS", gl::WATER_CELL_DROPS);
|
||||
define("WATER_TRAIL", gl::WATER_TRAIL);
|
||||
define("WATER_MAP", gl::WATER_MAP);
|
||||
define("WATER_GROUP_SIZE", gl::WATER_GROUP_SIZE);
|
||||
return preamble;
|
||||
}
|
||||
|
||||
|
||||
244
rendering/vulkan14/vulkan14water.cpp
Normal file
244
rendering/vulkan14/vulkan14water.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "rendering/vulkan14/vulkan14water.h"
|
||||
#include "rendering/vulkan14/vulkan14commands.h"
|
||||
#include "utilities/Logs.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace vk14
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::uint32_t groups(std::size_t const Count)
|
||||
{
|
||||
return static_cast<std::uint32_t>((Count + gl::WATER_GROUP_SIZE - 1) / gl::WATER_GROUP_SIZE);
|
||||
}
|
||||
|
||||
VkBufferUsageFlags constexpr storage_usage{VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT};
|
||||
|
||||
} // namespace
|
||||
|
||||
windscreen_water::~windscreen_water()
|
||||
{
|
||||
// the materials may be gone already
|
||||
set_host({});
|
||||
destroy();
|
||||
}
|
||||
|
||||
bool windscreen_water::init(VkDevice const Device, pipeline_library &Pipelines, shader_library &Shaders, VkDescriptorSetLayout const Passlayout, allocator &Memory, uploader &Uploads,
|
||||
deletion_queue &Deletions, frame_ring &Ring, VkDeviceSize const Alignment, host Host)
|
||||
{
|
||||
m_device = Device;
|
||||
m_pipelines = &Pipelines;
|
||||
m_shaders = &Shaders;
|
||||
m_passlayout = Passlayout;
|
||||
m_memory = &Memory;
|
||||
m_uploads = &Uploads;
|
||||
m_deletions = &Deletions;
|
||||
m_ring = &Ring;
|
||||
m_alignment = std::max<VkDeviceSize>(Alignment, 16);
|
||||
m_host = std::move(Host);
|
||||
m_storage = std::make_shared<buffer>();
|
||||
m_full = m_storage->create(Memory, static_cast<VkDeviceSize>(gl::WATER_STORAGE_SIZE), storage_usage, memory_kind::device, "windscreen water");
|
||||
if (false == m_full)
|
||||
{
|
||||
// the pass sets need a buffer to hold: a small one, which no glass reads (none gets a slot)
|
||||
ErrorLog("windscreen water: no storage of " + std::to_string(gl::WATER_STORAGE_SIZE / (1024 * 1024)) + " MiB, the windscreens make their water up");
|
||||
m_storage = std::make_shared<buffer>();
|
||||
if (false == m_storage->create(Memory, 65536, storage_usage, memory_kind::device, "windscreen water"))
|
||||
{
|
||||
m_storage.reset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void windscreen_water::destroy()
|
||||
{
|
||||
if (m_device == VK_NULL_HANDLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (auto &kernel : m_kernels)
|
||||
{
|
||||
kernel.destroy(m_device);
|
||||
}
|
||||
m_storage.reset();
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_cleared = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
bool windscreen_water::gpu_init()
|
||||
{
|
||||
if ((m_device == VK_NULL_HANDLE) || (false == m_full) || (false == bool(m_host.commands)) || (false == bool(m_host.texture)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
std::array<char const *, pass::count> const names{"water_trail.comp", "water_spawn.comp", "water_move.comp", "water_clear.comp", "water_grid.comp",
|
||||
"water_merge.comp", "water_gather.comp", "water_settle.comp", "water_bake.comp"};
|
||||
for (std::size_t i = 0; i < names.size(); ++i)
|
||||
{
|
||||
if (false == m_kernels[i].create(m_device, *m_pipelines, m_shaders->get(names[i]), m_passlayout, {}, names[i]))
|
||||
{
|
||||
throw gfx::shader_exception(std::string("no compute pipeline of ") + names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (gfx::shader_exception const &e)
|
||||
{
|
||||
ErrorLog("windscreen water: can't use the programs of the simulation: " + std::string(e.what()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void windscreen_water::begin(command_stream *const Commands)
|
||||
{
|
||||
// the glasses of the frames before read the storage, the fills and the copies write it
|
||||
memory_barrier(Commands, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_2_CLEAR_BIT, VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT);
|
||||
if (false == m_cleared)
|
||||
{
|
||||
// nothing in the storage yet
|
||||
m_cleared = true;
|
||||
Commands->fill_buffer(m_storage->handle(), 0, VK_WHOLE_SIZE, 0);
|
||||
compute_barrier(Commands);
|
||||
}
|
||||
}
|
||||
|
||||
void windscreen_water::gpu_setup(std::size_t const Slot, std::vector<glm::vec4> const &Axes)
|
||||
{
|
||||
auto const commands{m_host.commands()};
|
||||
if ((commands == nullptr) || (false == m_full))
|
||||
{
|
||||
return;
|
||||
}
|
||||
begin(commands);
|
||||
// the drops, the grid, the paths, the header and the counts of the slot cleared with the commands of the frame
|
||||
auto const parts{gl::water_slot_parts(Slot)};
|
||||
for (std::size_t part = 0; part < parts.size(); ++part)
|
||||
{
|
||||
if (part != 1)
|
||||
{
|
||||
commands->fill_buffer(m_storage->handle(), static_cast<VkDeviceSize>(parts[part].first), static_cast<VkDeviceSize>(parts[part].second), 0);
|
||||
}
|
||||
}
|
||||
// the axes of the map copied after that, from a staging buffer kept until the gpu is done with the frame
|
||||
auto const size{std::min<VkDeviceSize>(static_cast<VkDeviceSize>(parts[1].second), static_cast<VkDeviceSize>(Axes.size() * sizeof(glm::vec4)))};
|
||||
auto staging{std::make_shared<buffer>()};
|
||||
if ((false == staging->create(*m_memory, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, memory_kind::upload, "windscreen water map")) || (staging->mapped() == nullptr))
|
||||
{
|
||||
ErrorLog("windscreen water: no staging buffer for the map of a glass");
|
||||
compute_barrier(commands);
|
||||
return;
|
||||
}
|
||||
std::memcpy(staging->mapped(), Axes.data(), static_cast<std::size_t>(size));
|
||||
staging->flush(0, size);
|
||||
VkBufferCopy2 region{};
|
||||
region.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2;
|
||||
region.dstOffset = static_cast<VkDeviceSize>(parts[1].first);
|
||||
region.size = size;
|
||||
VkCopyBufferInfo2 copy{};
|
||||
copy.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2;
|
||||
copy.srcBuffer = staging->handle();
|
||||
copy.dstBuffer = m_storage->handle();
|
||||
copy.regionCount = 1;
|
||||
copy.pRegions = ®ion;
|
||||
commands->copy_buffer2(©);
|
||||
compute_barrier(commands);
|
||||
m_deletions->push(m_uploads->current_value(), [staging]() {});
|
||||
}
|
||||
|
||||
ring_slice windscreen_water::block(gl::water_ubs const &Block)
|
||||
{
|
||||
auto const slice{m_ring->allocate(sizeof(gl::water_ubs), m_alignment)};
|
||||
if (slice)
|
||||
{
|
||||
std::memcpy(slice.data, &Block, sizeof(gl::water_ubs));
|
||||
}
|
||||
return slice;
|
||||
}
|
||||
|
||||
bool windscreen_water::gpu_bake(std::size_t const Slot, texture_handle const Mask, gl::water_ubs const &Block)
|
||||
{
|
||||
auto const commands{m_host.commands()};
|
||||
if ((commands == nullptr) || (false == m_full) || (Mask == null_handle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
VkImageView view{VK_NULL_HANDLE};
|
||||
VkSampler sampler{VK_NULL_HANDLE};
|
||||
if ((false == m_host.texture(Mask, view, sampler)) || (view == VK_NULL_HANDLE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto const slice{block(Block)};
|
||||
if (false == bool(slice))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
begin(commands);
|
||||
m_kernels[pass::bake].run(commands,
|
||||
{buffer_descriptor(m_storage->handle(), 0, VK_WHOLE_SIZE), buffer_descriptor(slice.buffer, slice.offset, sizeof(gl::water_ubs)),
|
||||
image_descriptor(sampler, view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)},
|
||||
groups(static_cast<std::size_t>(gl::WATER_MAP) * gl::WATER_MAP));
|
||||
compute_barrier(commands);
|
||||
return true;
|
||||
}
|
||||
|
||||
void windscreen_water::gpu_step(gl::water_ubs const &Block, std::uint32_t const Tries)
|
||||
{
|
||||
auto const commands{m_host.commands()};
|
||||
if ((commands == nullptr) || (false == m_full))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto const slice{block(Block)};
|
||||
if (false == bool(slice))
|
||||
{
|
||||
return;
|
||||
}
|
||||
begin(commands);
|
||||
std::vector<descriptor> const descriptors{buffer_descriptor(m_storage->handle(), 0, VK_WHOLE_SIZE), buffer_descriptor(slice.buffer, slice.offset, sizeof(gl::water_ubs))};
|
||||
auto const run = [&](pass const Pass, std::uint32_t const Groups) {
|
||||
if (Groups == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_kernels[Pass].run(commands, descriptors, Groups, gl::WATER_SLOTS);
|
||||
compute_barrier(commands);
|
||||
};
|
||||
auto const drops{groups(gl::WATER_DROPS)};
|
||||
auto const cells{groups(static_cast<std::size_t>(gl::WATER_GRID) * gl::WATER_GRID)};
|
||||
// the wetted paths the blades went over in the step wiped
|
||||
if (Block.blades != Block.blades_before)
|
||||
{
|
||||
run(pass::trail, groups(static_cast<std::size_t>(gl::WATER_TRAIL) * gl::WATER_TRAIL));
|
||||
}
|
||||
run(pass::spawn, groups(Tries));
|
||||
run(pass::move, drops);
|
||||
run(pass::clear, cells);
|
||||
run(pass::grid, drops);
|
||||
run(pass::merge, drops);
|
||||
run(pass::gather, drops);
|
||||
run(pass::settle, drops);
|
||||
run(pass::clear, cells);
|
||||
run(pass::grid, drops);
|
||||
}
|
||||
|
||||
} // namespace vk14
|
||||
96
rendering/vulkan14/vulkan14water.h
Normal file
96
rendering/vulkan14/vulkan14water.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// the water on the windscreens in the vulkan renderer (gfx::windscreen_water, opengl46_windscreen_water): the storage of the water,
|
||||
// which the pass sets hold for the glasses (WATER_SSBO), and the compute kernels of the simulation, run with the commands of the
|
||||
// frame before its passes (outside a rendering). the kernels push everything they read (set COMPUTE_SET: the storage, the block of
|
||||
// the step in the ring of the frame, the mask of the wipers being baked)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rendering/common/windscreenwater.h"
|
||||
#include "rendering/vulkan14/vulkan14compute.h"
|
||||
#include "rendering/vulkan14/vulkan14texture.h"
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace vk14
|
||||
{
|
||||
|
||||
class windscreen_water : public gfx::windscreen_water
|
||||
{
|
||||
public:
|
||||
// what the renderer does for the water
|
||||
struct host
|
||||
{
|
||||
// the commands of the frame, outside a rendering
|
||||
std::function<command_stream *()> commands;
|
||||
// the view and the sampler of a texture of the renderer, made when needed; false when it isn't ready
|
||||
std::function<bool(texture_handle, VkImageView &, VkSampler &)> texture;
|
||||
};
|
||||
|
||||
windscreen_water() = default;
|
||||
~windscreen_water() override;
|
||||
|
||||
// called once, before the pass sets are made: the storage made (the pass sets hold it from then on). false: no storage
|
||||
bool init(VkDevice Device, pipeline_library &Pipelines, shader_library &Shaders, VkDescriptorSetLayout Passlayout, allocator &Memory, uploader &Uploads, deletion_queue &Deletions, frame_ring &Ring,
|
||||
VkDeviceSize Alignment, host Host);
|
||||
// everything goes (the device is idle)
|
||||
void destroy();
|
||||
// the storage the pass sets hold
|
||||
VkBuffer storage() const
|
||||
{
|
||||
return m_storage ? m_storage->handle() : VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool gpu_init() override;
|
||||
void gpu_setup(std::size_t Slot, std::vector<glm::vec4> const &Axes) override;
|
||||
bool gpu_bake(std::size_t Slot, texture_handle Mask, gl::water_ubs const &Block) override;
|
||||
void gpu_step(gl::water_ubs const &Block, std::uint32_t Tries) override;
|
||||
|
||||
private:
|
||||
// the passes of the step, in their order
|
||||
enum pass
|
||||
{
|
||||
trail,
|
||||
spawn,
|
||||
move,
|
||||
clear,
|
||||
grid,
|
||||
merge,
|
||||
gather,
|
||||
settle,
|
||||
bake,
|
||||
count
|
||||
};
|
||||
// the block of the step in the ring of the frame; empty when the ring is full
|
||||
ring_slice block(gl::water_ubs const &Block);
|
||||
// the frames before are done with the storage before the commands of this one write it
|
||||
void begin(command_stream *Commands);
|
||||
|
||||
VkDevice m_device{VK_NULL_HANDLE};
|
||||
pipeline_library *m_pipelines{nullptr};
|
||||
shader_library *m_shaders{nullptr};
|
||||
VkDescriptorSetLayout m_passlayout{VK_NULL_HANDLE};
|
||||
allocator *m_memory{nullptr};
|
||||
uploader *m_uploads{nullptr};
|
||||
deletion_queue *m_deletions{nullptr};
|
||||
frame_ring *m_ring{nullptr};
|
||||
VkDeviceSize m_alignment{256};
|
||||
host m_host;
|
||||
std::array<compute_kernel, pass::count> m_kernels;
|
||||
std::shared_ptr<buffer> m_storage;
|
||||
bool m_full{false}; // the storage is as large as the simulation needs (else a stand-in, the glasses make their water up)
|
||||
bool m_cleared{false};
|
||||
};
|
||||
|
||||
} // namespace vk14
|
||||
Reference in New Issue
Block a user