Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions frame/opengl/buffer.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,63 @@
#include "buffer.h"

#include <algorithm>
#include <cstring>
#include <exception>
#include <stdexcept>

namespace frame::opengl
{

namespace
{

bool MatchesRawBytes(
const std::vector<std::uint8_t>& raw_data,
std::size_t size,
const void* data)
{
if (raw_data.size() != size)
{
return false;
}
if (size == 0)
{
return true;
}
if (!data)
{
return std::all_of(
raw_data.begin(),
raw_data.end(),
[](std::uint8_t byte) { return byte == 0; });
}
return std::memcmp(raw_data.data(), data, size) == 0;
}

template <typename T>
bool MatchesRawVector(
const std::vector<std::uint8_t>& raw_data,
const std::vector<T>& vector)
{
const std::size_t size = vector.size() * sizeof(T);
if (raw_data.size() != size)
{
return false;
}
if (size == 0)
{
return true;
}
return std::memcmp(raw_data.data(), vector.data(), size) == 0;
}

void IncrementGeneration(std::uint64_t& generation)
{
++generation;
}

} // namespace

Buffer::Buffer(
const BufferTypeEnum buffer_type /*= BufferTypeEnum::ARRAY_BUFFER*/,
const BufferUsageEnum buffer_usage /*= BufferUsageEnum::STATIC_DRAW*/)
Expand Down Expand Up @@ -42,6 +93,10 @@ void Buffer::BindBase(int binding) const

void Buffer::Copy(const std::size_t size, const void* data /*= nullptr*/) const
{
if (MatchesRawBytes(raw_data_, size, data))
{
return;
}
raw_data_.assign(size, 0);
if (data && size > 0)
{
Expand All @@ -54,10 +109,15 @@ void Buffer::Copy(const std::size_t size, const void* data /*= nullptr*/) const
data,
static_cast<GLenum>(buffer_usage_));
UnBind();
IncrementGeneration(generation_);
}

void Buffer::Copy(const std::vector<float>& vector) const
{
if (MatchesRawVector(raw_data_, vector))
{
return;
}
raw_data_.resize(vector.size() * sizeof(float));
if (!vector.empty())
{
Expand All @@ -73,10 +133,15 @@ void Buffer::Copy(const std::vector<float>& vector) const
vector.data(),
static_cast<GLenum>(buffer_usage_));
UnBind();
IncrementGeneration(generation_);
}

void Buffer::Copy(const std::vector<unsigned int>& vector) const
{
if (MatchesRawVector(raw_data_, vector))
{
return;
}
raw_data_.resize(vector.size() * sizeof(unsigned int));
if (!vector.empty())
{
Expand All @@ -92,10 +157,15 @@ void Buffer::Copy(const std::vector<unsigned int>& vector) const
vector.data(),
static_cast<GLenum>(buffer_usage_));
UnBind();
IncrementGeneration(generation_);
}

void Buffer::Copy(const std::vector<std::uint8_t>& vector) const
{
if (raw_data_ == vector)
{
return;
}
raw_data_ = vector;
Bind();
glBufferData(
Expand All @@ -104,6 +174,7 @@ void Buffer::Copy(const std::vector<std::uint8_t>& vector) const
vector.data(),
static_cast<GLenum>(buffer_usage_));
UnBind();
IncrementGeneration(generation_);
}

std::size_t Buffer::GetSize() const
Expand All @@ -120,6 +191,14 @@ std::size_t Buffer::GetSize() const

void Buffer::Clear() const
{
const bool already_zero = std::all_of(
raw_data_.begin(),
raw_data_.end(),
[](std::uint8_t byte) { return byte == 0; });
if (already_zero)
{
return;
}
std::fill(raw_data_.begin(), raw_data_.end(), 0);
Bind();
glClearBufferData(
Expand All @@ -129,6 +208,7 @@ void Buffer::Clear() const
GL_UNSIGNED_INT,
nullptr);
UnBind();
IncrementGeneration(generation_);
}

std::unique_ptr<frame::BufferInterface> CreatePointBuffer(
Expand Down
5 changes: 5 additions & 0 deletions frame/opengl/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ class Buffer : public BindInterface, public BufferInterface
{
return raw_data_;
}
std::uint64_t GetGeneration() const
{
return generation_;
}

public:
/**
Expand Down Expand Up @@ -162,6 +166,7 @@ class Buffer : public BindInterface, public BufferInterface
std::string name_ = "buffer???";
mutable bool locked_bind_ = false;
mutable std::vector<std::uint8_t> raw_data_ = {};
mutable std::uint64_t generation_ = 0;
const BufferTypeEnum buffer_type_ = BufferTypeEnum::ARRAY_BUFFER;
const BufferUsageEnum buffer_usage_ = BufferUsageEnum::STATIC_DRAW;
unsigned int buffer_object_ = 0;
Expand Down
106 changes: 95 additions & 11 deletions frame/opengl/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <functional>
#include <format>
#include <glad/glad.h>
#include <glm/gtc/type_ptr.hpp>
Expand Down Expand Up @@ -129,11 +131,6 @@ bool RaytraceSceneRequiresWorldSpaceBuffers(frame::LevelInterface& level)
return false;
}

bool HasRaytracingSourceMeshes(frame::LevelInterface& level)
{
return !GetRaytracingSourceMeshMaterials(level).empty();
}

std::vector<std::pair<EntityId, std::string>> GetActiveTextureBindings(
const MaterialInterface& material,
const ProgramInterface& program)
Expand Down Expand Up @@ -342,6 +339,93 @@ std::array<float, 4> ResolveRaytracingColorMultiplier(
return multiplier;
}

template <typename T>
void HashCombine(std::size_t& seed, const T& value)
{
seed ^= std::hash<T>{}(value) + 0x9e3779b9u + (seed << 6u) + (seed >> 2u);
}

void HashFloat(std::size_t& seed, float value)
{
std::uint32_t bits = 0;
std::memcpy(&bits, &value, sizeof(bits));
HashCombine(seed, bits);
}

void HashColor(std::size_t& seed, const std::array<float, 4>& color)
{
for (const float channel : color)
{
HashFloat(seed, channel);
}
}

void HashMatrix(std::size_t& seed, const glm::mat4& matrix)
{
const float* values = glm::value_ptr(matrix);
for (int i = 0; i < 16; ++i)
{
HashFloat(seed, values[i]);
}
}

std::size_t BuildRaytracingSourceStateHash(
frame::LevelInterface& level,
double time_seconds)
{
std::size_t state_hash = 0;
const auto source_mesh_materials = GetRaytracingSourceMeshMaterials(level);
HashCombine(state_hash, source_mesh_materials.size());
for (const auto& [source_node_id, source_material_id] : source_mesh_materials)
{
HashCombine(state_hash, static_cast<std::uint64_t>(source_node_id));
HashCombine(state_hash, static_cast<std::uint64_t>(source_material_id));

auto* node =
dynamic_cast<NodeMesh*>(&level.GetSceneNodeFromId(source_node_id));
if (!node)
{
continue;
}

HashMatrix(state_hash, node->GetLocalModel(time_seconds));
HashCombine(
state_hash,
IsTransmissiveMaterial(level, source_material_id));
HashColor(
state_hash,
ResolveRaytracingSourceMaterialColor(level, source_material_id));

const auto mesh_id = node->GetLocalMesh();
HashCombine(state_hash, static_cast<std::uint64_t>(mesh_id));
if (!mesh_id)
{
continue;
}

const auto triangle_buffer_id =
level.GetMeshFromId(mesh_id).GetTriangleBufferId();
HashCombine(
state_hash,
static_cast<std::uint64_t>(triangle_buffer_id));
if (!triangle_buffer_id)
{
continue;
}

auto* triangle_buffer = dynamic_cast<Buffer*>(
&level.GetBufferFromId(triangle_buffer_id));
if (!triangle_buffer)
{
continue;
}

HashCombine(state_hash, triangle_buffer->GetGeneration());
HashCombine(state_hash, triangle_buffer->GetRawData().size());
}
return state_hash;
}

constexpr std::size_t kRaytraceFloatsPerVertex = 12;
constexpr std::size_t kRaytraceTriangleVertexStrideBytes =
sizeof(float) * kRaytraceFloatsPerVertex;
Expand Down Expand Up @@ -622,15 +706,14 @@ void Renderer::UpdateRaytraceBuffersIfNeeded(SkinnedMesh& skinned_mesh)
}
}

if (HasRaytracingSourceMeshes(level_))
{
UpdateAggregateRaytraceSceneBuffers();
}
}

void Renderer::UpdateAggregateRaytraceSceneBuffers()
{
if (last_raytrace_scene_buffer_update_time_ == delta_time_)
const std::size_t scene_state_hash =
BuildRaytracingSourceStateHash(level_, delta_time_);
if (has_raytrace_scene_state_hash_ &&
last_raytrace_scene_state_hash_ == scene_state_hash)
{
return;
}
Expand Down Expand Up @@ -689,7 +772,8 @@ void Renderer::UpdateAggregateRaytraceSceneBuffers()
update_named_buffer(material, "BvhBufferOpaque", opaque_bvh);
}

last_raytrace_scene_buffer_update_time_ = delta_time_;
last_raytrace_scene_state_hash_ = scene_state_hash;
has_raytrace_scene_state_hash_ = true;
}

std::optional<glm::mat4> Renderer::RenderNode(
Expand Down
3 changes: 2 additions & 1 deletion frame/opengl/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ class Renderer : public RendererInterface
// Texture frame (used in render mesh).
frame::proto::TextureFrame texture_frame_;
bool first_render_ = true;
double last_raytrace_scene_buffer_update_time_ = -1.0;
std::size_t last_raytrace_scene_state_hash_ = 0;
bool has_raytrace_scene_state_hash_ = false;
// The render callback it will be called once per mesh.
RenderCallback callback_ = [](UniformCollectionInterface&,
MeshInterface&,
Expand Down
Loading
Loading