mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-07 06:28:08 +01:00
Merge remote-tracking branch 'origin/feat/switch-fastenings' into feat/renderers-cleanup
This commit is contained in:
@@ -213,6 +213,7 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
|
||||
for (auto &shadowcull : m_shadowcull)
|
||||
shadowcull.init(&m_instancecull);
|
||||
m_hiz.init();
|
||||
m_timbers.init();
|
||||
m_shadowfit.init();
|
||||
m_exposure.init();
|
||||
m_ao.init();
|
||||
@@ -718,6 +719,7 @@ bool opengl46_renderer::Render()
|
||||
// the same for the model blocks of the draws
|
||||
m_instancestream->next_frame();
|
||||
Bind_Instance_Stream();
|
||||
m_timbers.next_frame();
|
||||
model_ubo->next_frame();
|
||||
if (m_drawblockstream)
|
||||
m_drawblockstream->next_frame();
|
||||
@@ -3604,6 +3606,16 @@ std::uint32_t opengl46_renderer::Upload_Instance_Modelviews( glm::mat4 const *Mo
|
||||
return static_cast<std::uint32_t>( offset / static_cast<GLintptr>( sizeof( glm::mat4 ) ) );
|
||||
}
|
||||
|
||||
std::uint32_t opengl46_renderer::Reserve_Instance_Modelviews( std::size_t const Count )
|
||||
{
|
||||
auto const generation { m_instancestream->generation() };
|
||||
auto const offset { m_instancestream->reserve( static_cast<GLsizeiptr>( Count * sizeof( glm::mat4 ) ) ) };
|
||||
if( m_instancestream->generation() != generation ) {
|
||||
Bind_Instance_Stream();
|
||||
}
|
||||
return static_cast<std::uint32_t>( offset / static_cast<GLintptr>( sizeof( glm::mat4 ) ) );
|
||||
}
|
||||
|
||||
void opengl46_renderer::Bind_Instance_Stream() const
|
||||
{
|
||||
GLuint const buffer { m_instancestream->buffer() };
|
||||
@@ -4995,6 +5007,31 @@ std::uint32_t opengl46_renderer::walk_instances(glm::mat4 const *Modelviews, std
|
||||
return Upload_Instance_Modelviews(Modelviews, Count);
|
||||
}
|
||||
|
||||
bool opengl46_renderer::walk_timbers_gpu() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool opengl46_renderer::walk_timbers_place(std::vector<TTrack *> const &Tracks, bool const Restart)
|
||||
{
|
||||
return m_timbers.place(Tracks, Restart);
|
||||
}
|
||||
|
||||
std::uint32_t opengl46_renderer::walk_timbers_first(TTrack const &Track) const
|
||||
{
|
||||
return m_timbers.first(Track);
|
||||
}
|
||||
|
||||
std::uint32_t opengl46_renderer::walk_instances_reserve(std::size_t const Count)
|
||||
{
|
||||
return Reserve_Instance_Modelviews(Count);
|
||||
}
|
||||
|
||||
void opengl46_renderer::walk_timbers_expand(std::vector<glm::mat4> const &Origins, std::vector<gl::timber_range> const &Ranges)
|
||||
{
|
||||
m_timbers.expand(Origins, Ranges, m_instancestream->buffer());
|
||||
}
|
||||
|
||||
void opengl46_renderer::walk_cull_face(bool const Enabled)
|
||||
{
|
||||
if (Enabled)
|
||||
|
||||
@@ -47,6 +47,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "rendering/opengl46/opengl46skyocclusion.h"
|
||||
#include "rendering/opengl46/opengl46instancecull.h"
|
||||
#include "rendering/opengl46/opengl46hiz.h"
|
||||
#include "rendering/opengl46/opengl46timbers.h"
|
||||
#include "rendering/opengl46/opengl46shadowfit.h"
|
||||
#include "rendering/common/scenewalk.h"
|
||||
#include "rendering/common/temporalaa.h"
|
||||
@@ -217,6 +218,12 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
|
||||
void walk_draw(gfx::geometry_handle const &Geometry) override;
|
||||
void walk_draw(std::vector<gfx::geometrybank_handle>::iterator First, std::vector<gfx::geometrybank_handle>::iterator Last) override;
|
||||
std::uint32_t walk_instances(glm::mat4 const *Modelviews, std::size_t const Count) override;
|
||||
// the instances of the sleepers and timbers of the tracks on the gpu (m_timbers)
|
||||
bool walk_timbers_gpu() const override;
|
||||
bool walk_timbers_place(std::vector<TTrack *> const &Tracks, bool const Restart) override;
|
||||
std::uint32_t walk_timbers_first(TTrack const &Track) const override;
|
||||
std::uint32_t walk_instances_reserve(std::size_t const Count) override;
|
||||
void walk_timbers_expand(std::vector<glm::mat4> const &Origins, std::vector<gl::timber_range> const &Ranges) override;
|
||||
void walk_cull_face(bool const Enabled) override;
|
||||
void walk_glare(bool const Enabled) override;
|
||||
void walk_glare_draw(TSubModel *Submodel, gfx::geometry_handle const &Geometry) override;
|
||||
@@ -348,6 +355,8 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
|
||||
bool Render(world_environment *Environment);
|
||||
// places supplied modelview matrices in the instance buffer of the frame. returns: base instance of the first of them
|
||||
std::uint32_t Upload_Instance_Modelviews( glm::mat4 const *Modelviews, std::size_t const Count );
|
||||
// the room for Count modelviews in the instance buffer of the frame, for the gpu to write. returns: base instance of the first
|
||||
std::uint32_t Reserve_Instance_Modelviews( std::size_t const Count );
|
||||
// binds the instance buffer of the frame for the vertex shaders (INSTANCE_SSBO_BINDING)
|
||||
void Bind_Instance_Stream() const;
|
||||
// draws the instances queued in the pass from the result of the gpu culling (Global.gfx_gpucull 1): makes the depth
|
||||
@@ -600,6 +609,7 @@ class opengl46_renderer : public gfx_renderer, public gfx::scene_walk {
|
||||
int m_shadowcascade { -1 }; // the region is drawn for this cascade of the sun shadows
|
||||
// depth pyramid for the occlusion test of the gpu culling
|
||||
opengl46_hiz m_hiz;
|
||||
opengl46_timbers m_timbers; // the instances of the sleepers and timbers of the tracks on the gpu
|
||||
// the cascades of the sun shadows fitted to the depth of the main view (Global.gfx_shadow_sdsm)
|
||||
opengl46_shadow_fit m_shadowfit;
|
||||
// with a cascade fitted: the corners of the area its map is to cover, for setup_pass()
|
||||
|
||||
152
rendering/opengl46/opengl46timbers.cpp
Normal file
152
rendering/opengl46/opengl46timbers.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
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/opengl46/opengl46timbers.h"
|
||||
|
||||
#include "utilities/Globals.h"
|
||||
#include "world/Track.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
// the buffer to start with, and how soon after being started over it's too small for the tracks in sight
|
||||
std::uint32_t constexpr initial_capacity{65536};
|
||||
unsigned int constexpr restart_frames{600};
|
||||
|
||||
// the instances of a track, in the order they lie in the buffer
|
||||
std::uint32_t count_of(track_sleepers::laid const &Laid)
|
||||
{
|
||||
std::size_t count{Laid.whole.size() + Laid.plain.size()};
|
||||
for (auto const &instances : Laid.instances)
|
||||
count += instances.size();
|
||||
return static_cast<std::uint32_t>(count);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
opengl46_timbers::~opengl46_timbers()
|
||||
{
|
||||
if (m_buffer != 0)
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
void opengl46_timbers::init()
|
||||
{
|
||||
gl::shader shader("timber_instances.comp");
|
||||
m_program = std::make_unique<gl::program>(std::vector<std::reference_wrapper<const gl::shader>>{shader});
|
||||
// the modelviews of the origins and the runs, both placed at whole matrices
|
||||
m_ranges = std::make_unique<gl::frame_stream>(
|
||||
static_cast<GLsizeiptr>(4096 * sizeof(gl::timber_range)), static_cast<GLsizeiptr>(sizeof(glm::mat4)), Global.gfx_bufferstreaming);
|
||||
restart(0);
|
||||
}
|
||||
|
||||
void opengl46_timbers::restart(std::uint32_t const Needed)
|
||||
{
|
||||
auto capacity{std::max(m_capacity, initial_capacity)};
|
||||
if ((m_capacity > 0) && (m_frame - m_restartframe < restart_frames))
|
||||
capacity *= 2;
|
||||
while (capacity < 2 * Needed)
|
||||
capacity *= 2;
|
||||
// the draws and passes issued with the old buffer keep it until the gpu is done with them
|
||||
if (m_buffer != 0)
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
glCreateBuffers(1, &m_buffer);
|
||||
glNamedBufferStorage(m_buffer, static_cast<GLsizeiptr>(capacity) * static_cast<GLsizeiptr>(sizeof(glm::mat4)), nullptr, GL_DYNAMIC_STORAGE_BIT);
|
||||
m_capacity = capacity;
|
||||
m_fill = 0;
|
||||
m_restartframe = m_frame;
|
||||
m_tracks.clear();
|
||||
}
|
||||
|
||||
bool opengl46_timbers::place(std::vector<TTrack *> const &Tracks, bool const Restart)
|
||||
{
|
||||
auto const placed_now = [&](TTrack const &Track) {
|
||||
auto const found{m_tracks.find(&Track)};
|
||||
return (found != m_tracks.end()) && (found->second.made == Track.m_sleepers3d.made);
|
||||
};
|
||||
std::uint32_t needed{0};
|
||||
std::uint32_t all{0};
|
||||
for (auto const *track : Tracks)
|
||||
{
|
||||
auto const count{count_of(track->m_sleepers3d)};
|
||||
all += count;
|
||||
if (false == placed_now(*track))
|
||||
needed += count;
|
||||
}
|
||||
if (needed == 0)
|
||||
return true;
|
||||
if (m_fill + needed > m_capacity)
|
||||
{
|
||||
if (false == Restart)
|
||||
return false;
|
||||
restart(all);
|
||||
}
|
||||
for (auto const *track : Tracks)
|
||||
{
|
||||
if (placed_now(*track))
|
||||
continue;
|
||||
auto const &laid{track->m_sleepers3d};
|
||||
auto const first{m_fill};
|
||||
auto const send = [&](std::vector<glm::mat4> const &Instances) {
|
||||
if (false == Instances.empty())
|
||||
glNamedBufferSubData(m_buffer, static_cast<GLintptr>(m_fill) * static_cast<GLintptr>(sizeof(glm::mat4)),
|
||||
static_cast<GLsizeiptr>(Instances.size() * sizeof(glm::mat4)), Instances.data());
|
||||
m_fill += static_cast<std::uint32_t>(Instances.size());
|
||||
};
|
||||
for (auto const &instances : laid.instances)
|
||||
send(instances);
|
||||
send(laid.whole);
|
||||
send(laid.plain);
|
||||
m_tracks[track] = {laid.made, first};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint32_t opengl46_timbers::first(TTrack const &Track) const
|
||||
{
|
||||
auto const found{m_tracks.find(&Track)};
|
||||
return (found != m_tracks.end() ? found->second.first : 0);
|
||||
}
|
||||
|
||||
void opengl46_timbers::expand(std::vector<glm::mat4> const &Origins, std::vector<gl::timber_range> const &Ranges, GLuint const Output)
|
||||
{
|
||||
if (Ranges.empty())
|
||||
return;
|
||||
// sent together, in one buffer of the stream
|
||||
auto const originbytes{Origins.size() * sizeof(glm::mat4)};
|
||||
m_upload.resize(originbytes + Ranges.size() * sizeof(gl::timber_range));
|
||||
std::memcpy(m_upload.data(), Origins.data(), originbytes);
|
||||
std::memcpy(m_upload.data() + originbytes, Ranges.data(), Ranges.size() * sizeof(gl::timber_range));
|
||||
auto const origins{m_ranges->push(m_upload.data(), static_cast<GLsizeiptr>(m_upload.size()))};
|
||||
auto const ranges{origins + static_cast<GLintptr>(originbytes)};
|
||||
GLuint const buffers[]{m_buffer, m_ranges->buffer()};
|
||||
::glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, gl::TIMBER_LOCAL_SSBO_BINDING, 1, &buffers[0]);
|
||||
::glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, gl::TIMBER_RANGE_SSBO_BINDING, 1, &buffers[1]);
|
||||
::glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, gl::TIMBER_OUTPUT_SSBO_BINDING, 1, &Output);
|
||||
::glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, gl::TIMBER_ORIGIN_SSBO_BINDING, 1, &buffers[1]);
|
||||
// a dispatch takes at most 65535 work groups
|
||||
auto const first{static_cast<std::uint32_t>(ranges / static_cast<GLintptr>(sizeof(gl::timber_range)))};
|
||||
auto const origin{static_cast<std::uint32_t>(origins / static_cast<GLintptr>(sizeof(glm::mat4)))};
|
||||
for (std::size_t done = 0; done < Ranges.size();)
|
||||
{
|
||||
auto const count{std::min<std::size_t>(Ranges.size() - done, 65535)};
|
||||
::glProgramUniform4ui(*m_program, 0, first + static_cast<std::uint32_t>(done), origin, 0, 0);
|
||||
m_program->dispatch(static_cast<GLuint>(count));
|
||||
done += count;
|
||||
}
|
||||
::glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
void opengl46_timbers::next_frame()
|
||||
{
|
||||
++m_frame;
|
||||
m_ranges->next_frame();
|
||||
}
|
||||
66
rendering/opengl46/opengl46timbers.h
Normal file
66
rendering/opengl46/opengl46timbers.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "gl/shader.h"
|
||||
#include "gl/streambuffer.h"
|
||||
#include "gl/ubo.h"
|
||||
|
||||
class TTrack;
|
||||
|
||||
// the instances of the timbers and sleepers of the tracks (track_sleepers::laid) kept on the gpu, those of a track sent once as
|
||||
// it's laid, and the runs of them drawn made into the modelviews of the instance buffer of the frame by a compute pass
|
||||
// (timber_instances.comp): for a run the cpu gives only where it lies and where it goes, not its matrices
|
||||
class opengl46_timbers
|
||||
{
|
||||
public:
|
||||
opengl46_timbers() = default;
|
||||
opengl46_timbers(opengl46_timbers const &) = delete;
|
||||
opengl46_timbers &operator=(opengl46_timbers const &) = delete;
|
||||
~opengl46_timbers();
|
||||
|
||||
// throws gl::shader_exception
|
||||
void init();
|
||||
// the instances of the tracks on the gpu, sent again for a track laid anew since; when those to send don't fit in what's left
|
||||
// of the buffer, it's started over for all the tracks, a bigger one when it was started over not long before. without
|
||||
// Restart nothing is sent then, and false returned: the runs of the instances placed before are to be expanded first
|
||||
bool place(std::vector<TTrack *> const &Tracks, bool const Restart);
|
||||
// where the instances of a track placed lie in the buffer: the first of the parts in turn, then of the whole timbers, then of
|
||||
// the plain sleepers
|
||||
std::uint32_t first(TTrack const &Track) const;
|
||||
// the runs written to the instance buffer Output, each as the modelview of its origin times its transforms, for the draws after
|
||||
void expand(std::vector<glm::mat4> const &Origins, std::vector<gl::timber_range> const &Ranges, GLuint const Output);
|
||||
void next_frame();
|
||||
|
||||
private:
|
||||
struct placed
|
||||
{
|
||||
std::uint64_t made; // the making of the instances of the track sent
|
||||
std::uint32_t first;
|
||||
};
|
||||
|
||||
// a new buffer, room for Needed instances at least, the tracks to be sent again
|
||||
void restart(std::uint32_t const Needed);
|
||||
|
||||
std::unique_ptr<gl::program> m_program;
|
||||
std::unique_ptr<gl::frame_stream> m_ranges;
|
||||
GLuint m_buffer{0};
|
||||
std::uint32_t m_capacity{0}; // in instances
|
||||
std::uint32_t m_fill{0};
|
||||
unsigned int m_frame{0};
|
||||
unsigned int m_restartframe{0};
|
||||
std::unordered_map<TTrack const *, placed> m_tracks;
|
||||
std::vector<std::uint8_t> m_upload; // the origins and the runs of an expand(), as they're sent
|
||||
};
|
||||
Reference in New Issue
Block a user