17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 02:49:19 +02:00

Move light data from UBO to std430 SSBO

This commit is contained in:
2026-10-15 13:20:59 +02:00
parent 677a96c293
commit c0f45184b8
5 changed files with 74 additions and 43 deletions

View File

@@ -15,6 +15,7 @@ void gl::glsl_common_setup()
"#define MAX_CASCADES " + std::to_string(MAX_CASCADES) + "U\n" +
"#define MAX_PARAMS " + std::to_string(MAX_PARAMS) + "U\n" +
"#define MAX_INSTANCES_PER_BATCH " + std::to_string(MAX_INSTANCES_PER_BATCH) + "U\n" +
"#define LIGHT_SSBO_BINDING " + std::to_string(LIGHT_SSBO_BINDING) + "\n" +
R"STRING(
const uint LIGHT_SPOT = 0U;
const uint LIGHT_POINT = 1U;
@@ -42,15 +43,18 @@ void gl::glsl_common_setup()
vec4 headlight_weights;
};
layout(std140) uniform light_ubo
// storage blocks are guaranteed only in fragment and compute shaders (GL 4.6 minimum for the other stages is 0)
#if defined(STAGE_FRAGMENT) || defined(STAGE_COMPUTE)
layout(std430, binding = LIGHT_SSBO_BINDING) readonly buffer light_ssbo
{
vec3 ambient;
vec3 fog_color;
uint lights_count;
light_s lights[MAX_LIGHTS];
light_s lights[];
};
#endif
layout (std140) uniform model_ubo
{

View File

@@ -283,9 +283,6 @@ void gl::program::init()
if ((index = glGetUniformBlockIndex(*this, "model_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, index, 1);
if ((index = glGetUniformBlockIndex(*this, "light_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, index, 2);
if ((index = glGetUniformBlockIndex(*this, "instance_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, index, 3);
}

View File

@@ -4,6 +4,7 @@
#include "bindable.h"
#include "buffer.h"
#include <glm/glm.hpp>
#include <cstddef>
#define UBS_PAD(x) uint8_t PAD[x]
@@ -103,7 +104,14 @@ namespace gl
static_assert(sizeof(instance_ubs) == 64 * MAX_INSTANCES_PER_BATCH, "bad size of instance_ubs");
struct light_element_ubs
// layout std430 (shader storage buffers)
// structs must match with GLSL, offsets checked below
// binding points of the shader storage blocks: layout(std430, binding = ...) in glsl_common
const GLuint LIGHT_SSBO_BINDING = 0;
// one light source, element of light_ssbo.lights[] (GLSL: light_s)
struct light_element
{
enum type_e
{
@@ -132,11 +140,27 @@ namespace gl
glm::vec4 headlight_weights;
};
static_assert(sizeof(light_element_ubs) == 144, "bad size of ubs");
// std430 array stride of a struct is its size rounded up to its alignment (16, from mat4/vec4)
static_assert(sizeof(light_element) == 144, "bad size of light_element");
static_assert(sizeof(light_element) % 16 == 0, "light_element must be a whole std430 array stride");
static_assert(offsetof(light_element, pos) == 0, "bad layout of light_element");
static_assert(offsetof(light_element, type) == 12, "bad layout of light_element");
static_assert(offsetof(light_element, dir) == 16, "bad layout of light_element");
static_assert(offsetof(light_element, in_cutoff) == 28, "bad layout of light_element");
static_assert(offsetof(light_element, color) == 32, "bad layout of light_element");
static_assert(offsetof(light_element, out_cutoff) == 44, "bad layout of light_element");
static_assert(offsetof(light_element, linear) == 48, "bad layout of light_element");
static_assert(offsetof(light_element, quadratic) == 52, "bad layout of light_element");
static_assert(offsetof(light_element, intensity) == 56, "bad layout of light_element");
static_assert(offsetof(light_element, ambient) == 60, "bad layout of light_element");
static_assert(offsetof(light_element, headlight_projection) == 64, "bad layout of light_element");
static_assert(offsetof(light_element, headlight_weights) == 128, "bad layout of light_element");
// capacity of light_data.lights; slot 0 is the sun
const size_t MAX_LIGHTS = 8;
struct light_ubs
// contents of light_ssbo: global lighting header followed by the light array
struct light_data
{
packed_vec3 ambient;
UBS_PAD(4);
@@ -144,10 +168,14 @@ namespace gl
packed_vec3 fog_color;
uint32_t lights_count;
light_element_ubs lights[MAX_LIGHTS];
light_element lights[MAX_LIGHTS];
};
static_assert(sizeof(light_ubs) == 32 + sizeof(light_element_ubs) * MAX_LIGHTS, "bad size of ubs");
static_assert(offsetof(light_data, ambient) == 0, "bad layout of light_data");
static_assert(offsetof(light_data, fog_color) == 16, "bad layout of light_data");
static_assert(offsetof(light_data, lights_count) == 28, "bad layout of light_data");
static_assert(offsetof(light_data, lights) == 32, "bad layout of light_data");
static_assert(sizeof(light_data) == 32 + sizeof(light_element) * MAX_LIGHTS, "bad size of light_data");
#pragma pack(pop)
}

View File

@@ -179,16 +179,17 @@ bool opengl46_renderer::Init(GLFWwindow *Window)
scene_ubo = std::make_unique<gl::ubo>(sizeof(gl::scene_ubs), 0);
model_ubo = std::make_unique<gl::ubo>(sizeof(gl::model_ubs), 1, GL_STREAM_DRAW);
light_ubo = std::make_unique<gl::ubo>(sizeof(gl::light_ubs), 2);
light_ssbo = std::make_unique<gl::ssbo>(sizeof(gl::light_data), gl::LIGHT_SSBO_BINDING);
light_ssbo->bind_base();
instance_ubo = std::make_unique<gl::ubo>(sizeof(gl::instance_ubs), 3, GL_STREAM_DRAW);
// better initialize with 0 to not crash driver/whole system
// when we forget
memset(&light_ubs, 0, sizeof(light_ubs));
memset(&light_data, 0, sizeof(light_data));
memset(&model_ubs, 0, sizeof(model_ubs));
memset(&scene_ubs, 0, sizeof(scene_ubs));
light_ubo->update(light_ubs);
light_ssbo->update(light_data);
model_ubo->update(model_ubs);
scene_ubo->update(scene_ubs);
@@ -453,7 +454,7 @@ bool opengl46_renderer::init_viewport(viewport_config &vp)
model_ubo->bind_uniform();
scene_ubo->bind_uniform();
light_ubo->bind_uniform();
light_ssbo->bind_base();
if (!Global.gfx_skippipeline)
{
@@ -1868,9 +1869,9 @@ void opengl46_renderer::setup_environment_light(TEnvironmentType const Environme
void opengl46_renderer::setup_sunlight_intensity( float const Factor ) {
m_sunlight.apply_intensity( Factor );
light_ubs.lights[ 0 ].intensity = m_sunlight.factor * (1.0f - Global.Overcast * 0.33f);
light_ubs.ambient = m_sunlight.ambient * m_sunlight.factor;
light_ubo->update( light_ubs );
light_data.lights[ 0 ].intensity = m_sunlight.factor * (1.0f - Global.Overcast * 0.33f);
light_data.ambient = m_sunlight.ambient * m_sunlight.factor;
light_ssbo->update( light_data );
}
bool opengl46_renderer::Render(world_environment *Environment)
@@ -3831,12 +3832,12 @@ bool opengl46_renderer::Render_cab(TDynamicObject const *Dynamic, float const Li
setup_sunlight_intensity(Dynamic->fShade);
}
auto const old_ambient { light_ubs.ambient };
auto const old_ambient { light_data.ambient };
auto const luminance { Global.fLuminance * ( Dynamic->fShade > 0.0f ? Dynamic->fShade : 1.0f ) };
if( Lightlevel > 0.f ) {
// crude way to light the cabin, until we have something more complete in place
light_ubs.ambient += packed_vec3( ( Dynamic->InteriorLight * Lightlevel ) * std::clamp( 1.25f - (float)luminance, 0.f, 1.f ) );
light_ubo->update( light_ubs );
light_data.ambient += packed_vec3( ( Dynamic->InteriorLight * Lightlevel ) * std::clamp( 1.25f - (float)luminance, 0.f, 1.f ) );
light_ssbo->update( light_data );
}
// render
@@ -3851,7 +3852,7 @@ bool opengl46_renderer::Render_cab(TDynamicObject const *Dynamic, float const Li
Render(Dynamic->mdKabina, Dynamic->Material(), 0.0);
}
// post-render restore
light_ubs.ambient = old_ambient;
light_data.ambient = old_ambient;
setup_sunlight_intensity();
break;
@@ -5564,15 +5565,15 @@ void opengl46_renderer::Preview_Color(TAnimModel *Instance, float const Squaredi
scene_ubo->bind_uniform();
// the sun is the only light, and there's no fog
auto const &modelview{OpenGLMatrices.data(GL_MODELVIEW)};
light_ubs.ambient = m_sunlight.ambient;
light_ubs.fog_color = glm::vec3{1.f};
light_ubs.lights_count = 1;
light_ubs.lights[0].type = gl::light_element_ubs::DIR;
light_ubs.lights[0].dir = modelview * glm::vec4(m_sunlight.direction, 0.0f);
light_ubs.lights[0].color = m_sunlight.diffuse;
light_ubs.lights[0].ambient = 0.0f;
light_ubs.lights[0].intensity = 1.0f;
light_ubo->update(light_ubs);
light_data.ambient = m_sunlight.ambient;
light_data.fog_color = glm::vec3{1.f};
light_data.lights_count = 1;
light_data.lights[0].type = gl::light_element::DIR;
light_data.lights[0].dir = modelview * glm::vec4(m_sunlight.direction, 0.0f);
light_data.lights[0].color = m_sunlight.diffuse;
light_data.lights[0].ambient = 0.0f;
light_data.lights[0].intensity = 1.0f;
light_ssbo->update(light_data);
model_ubs.fog_density = 0.f;
model_ubs.future = glm::mat4();
model_ubs.emission = 0.f;
@@ -5914,11 +5915,11 @@ void opengl46_renderer::Update_Lights(light_array &Lights)
renderlight->apply_intensity( ( scenelight.count * 0.5 ) * ( scenelight.owner->DimHeadlights ? 0.5 : 1.0 ) );
renderlight->apply_angle();
gl::light_element_ubs *light = &light_ubs.lights[light_i];
gl::light_element *light = &light_data.lights[light_i];
light->pos = mv * glm::vec4(renderlight->position, 1.0f);
light->dir = mv * glm::vec4(renderlight->direction, 0.0f);
light->type = gl::light_element_ubs::HEADLIGHTS;
light->type = gl::light_element::HEADLIGHTS;
light->in_cutoff = headlight_config.in_cutoff;
light->out_cutoff = headlight_config.out_cutoff;
light->color = renderlight->diffuse * renderlight->factor;
@@ -5979,16 +5980,16 @@ void opengl46_renderer::Update_Lights(light_array &Lights)
++light_i;
++renderlight;
}
light_ubs.lights_count = light_i;
light_data.lights_count = light_i;
// fill sunlight data
light_ubs.ambient = m_sunlight.ambient * m_sunlight.factor;// *simulation::Environment.light_intensity();
light_ubs.lights[0].type = gl::light_element_ubs::DIR;
light_ubs.lights[0].dir = mv * glm::vec4(m_sunlight.direction, 0.0f);
light_ubs.lights[0].color = m_sunlight.diffuse * m_sunlight.factor * simulation::Environment.light_intensity();
light_ubs.lights[0].ambient = 0.0f;
light_ubs.lights[0].intensity = 1.0f;
light_data.ambient = m_sunlight.ambient * m_sunlight.factor;// *simulation::Environment.light_intensity();
light_data.lights[0].type = gl::light_element::DIR;
light_data.lights[0].dir = mv * glm::vec4(m_sunlight.direction, 0.0f);
light_data.lights[0].color = m_sunlight.diffuse * m_sunlight.factor * simulation::Environment.light_intensity();
light_data.lights[0].ambient = 0.0f;
light_data.lights[0].intensity = 1.0f;
// fill fog data
light_ubs.fog_color = Global.FogColor;
light_data.fog_color = Global.FogColor;
if (Global.fFogEnd > 0)
{
m_fogrange = Global.fFogEnd / std::max(1.f, Global.Overcast * 2.f);
@@ -6000,7 +6001,7 @@ void opengl46_renderer::Update_Lights(light_array &Lights)
}
// ship config data to the gpu
model_ubo->update(model_ubs);
light_ubo->update(light_ubs);
light_ssbo->update(light_data);
}
bool opengl46_renderer::Init_caps()

View File

@@ -21,6 +21,7 @@ http://mozilla.org/MPL/2.0/.
#include "rendering/lightarray.h"
#include "vr/vr_interface.h"
#include "gl/ubo.h"
#include "gl/ssbo.h"
#include "gl/framebuffer.h"
#include "gl/renderbuffer.h"
#include "gl/postfx.h"
@@ -450,7 +451,7 @@ class opengl46_renderer : public gfx_renderer {
std::unique_ptr<gl::ubo> scene_ubo;
std::unique_ptr<gl::ubo> model_ubo;
std::unique_ptr<gl::ubo> light_ubo;
std::unique_ptr<gl::ssbo> light_ssbo;
// per-instance modelview UBO for GPU-instanced draws.
// Slot 0 is initialized once to identity and never overwritten by non-instanced
// rendering, so existing draws (where gl_InstanceID==0) compute identity*modelview
@@ -486,7 +487,7 @@ class opengl46_renderer : public gfx_renderer {
std::vector<float> m_instance_banddistances;
gl::scene_ubs scene_ubs;
gl::model_ubs model_ubs;
gl::light_ubs light_ubs;
gl::light_data light_data;
std::unordered_map<std::string, std::shared_ptr<gl::program>> m_shaders;