mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 10:51:13 +00:00
GPU instancing: streamer, viewport, shaders rewritten
Commit A of the instancing migration (Phase 3a). The streamer now runs the iterator with use-world-coords=false and dedupes by the geometry's representation id, emitting a MeshChunk once per unique geometry and an InstanceChunk per placement. The viewport keeps geometry in local coordinates (28 B/vertex, down from 32) and applies the per-instance transform in the vertex shader via an std430 SSBO indexed by gl_InstanceID + a per-draw uniform offset. After streaming finishes finalizeModel() stable-sorts instances by mesh_id, assigns each mesh a contiguous range, and uploads the SSBO; render then issues one glDrawElementsInstancedBaseVertex per mesh. BvhAccel is reshaped to operate on a generic BvhItem (world AABB + model_id) so it can drive instance-level culling, but the path is not wired in yet -- every instance is drawn every frame in this commit. Progressive-during-streaming rendering is likewise disabled: a model appears when its SSBO is uploaded, not incrementally. Sidecar cache is stubbed (reads miss, writes are no-ops); the v4 on-disk format with MeshInfo + InstanceGpu sections lands in Commit B. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,58 +28,43 @@
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector3D>
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#include "BvhAccel.h"
|
||||
#include "InstancedGeometry.h"
|
||||
#include "SidecarCache.h"
|
||||
|
||||
struct MaterialInfo {
|
||||
float r = 0.75f, g = 0.75f, b = 0.78f, a = 1.0f;
|
||||
};
|
||||
|
||||
struct UploadChunk {
|
||||
// Interleaved per-vertex layout (8 floats / 32 bytes per vertex):
|
||||
// pos(3 float) + normal(3 float) + object_id(1 float bitcast from uint)
|
||||
// + color(1 float holding RGBA8 packed bytes, read on the GPU as
|
||||
// GL_UNSIGNED_BYTE * 4 normalized).
|
||||
std::vector<float> vertices;
|
||||
std::vector<uint32_t> indices; // local to this chunk's vertices
|
||||
uint32_t object_id = 0;
|
||||
uint32_t model_id = 0;
|
||||
};
|
||||
|
||||
// Per-model GPU state: own VAO, VBO, EBO, draw info, BVH.
|
||||
// Per-model GPU state for the instanced render path.
|
||||
//
|
||||
// VBO: local-coord interleaved verts (pos3 + normal3 + color1_packed) — 28 B.
|
||||
// EBO: mesh-local indices (uint32).
|
||||
// meshes[]: per-unique-representation metadata; indexed by local_mesh_id.
|
||||
// instances[]: CPU-side per-instance records; sorted by mesh_id at finalize.
|
||||
// ssbo: InstanceGpu[]; populated at finalize.
|
||||
//
|
||||
// A model is drawable once `finalized == true`.
|
||||
struct ModelGpuData {
|
||||
GLuint vao = 0;
|
||||
GLuint vbo = 0;
|
||||
GLuint ebo = 0;
|
||||
GLuint ssbo = 0;
|
||||
|
||||
size_t vbo_capacity = 0;
|
||||
size_t ebo_capacity = 0;
|
||||
size_t vbo_used = 0; // bytes
|
||||
size_t ebo_used = 0; // bytes
|
||||
uint32_t vertex_count = 0;
|
||||
size_t vbo_used = 0;
|
||||
size_t ebo_used = 0;
|
||||
uint32_t vertex_count = 0; // total (across all meshes)
|
||||
uint32_t total_triangles = 0;
|
||||
std::vector<ObjectDrawInfo> draw_info;
|
||||
uint32_t active_draw_count = 0; // how many objects are drawable (progressive upload)
|
||||
bool hidden = false;
|
||||
};
|
||||
|
||||
// Pending progressive upload — VBO first, then EBO.
|
||||
struct PendingUpload {
|
||||
uint32_t model_id = 0;
|
||||
std::vector<float> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
std::shared_ptr<BvhSet> bvh_set;
|
||||
size_t vbo_uploaded = 0; // bytes
|
||||
size_t ebo_uploaded = 0; // bytes
|
||||
std::vector<MeshInfo> meshes;
|
||||
std::vector<InstanceCpu> instances; // unsorted until finalize
|
||||
uint32_t ssbo_instance_count = 0;
|
||||
|
||||
bool finalized = false;
|
||||
bool hidden = false;
|
||||
};
|
||||
|
||||
class ViewportWindow : public QWindow {
|
||||
@@ -88,32 +73,21 @@ public:
|
||||
explicit ViewportWindow(QWindow* parent = nullptr);
|
||||
~ViewportWindow();
|
||||
|
||||
void uploadChunk(const UploadChunk& chunk);
|
||||
void resetScene();
|
||||
// Streaming ingress.
|
||||
void uploadMeshChunk(const MeshChunk& chunk);
|
||||
void uploadInstanceChunk(const InstanceChunk& chunk);
|
||||
|
||||
// Bulk upload pre-built geometry from a sidecar cache.
|
||||
// Creates a perfectly-sized per-model buffer set. No copy.
|
||||
void uploadBulk(uint32_t model_id,
|
||||
std::vector<float> vertices,
|
||||
std::vector<uint32_t> indices,
|
||||
const std::vector<ObjectDrawInfo>& draw_info,
|
||||
std::shared_ptr<BvhSet> bvh_set);
|
||||
// Called once all chunks for a model have arrived: sorts instances by
|
||||
// mesh_id, assigns each mesh its contiguous range, and uploads the
|
||||
// instance SSBO. The model becomes drawable.
|
||||
void finalizeModel(uint32_t model_id);
|
||||
|
||||
void resetScene();
|
||||
|
||||
void hideModel(uint32_t model_id);
|
||||
void showModel(uint32_t model_id);
|
||||
void removeModel(uint32_t model_id);
|
||||
|
||||
// Build BVH and optionally write a sidecar cache.
|
||||
void buildBvhAsync(uint32_t model_id,
|
||||
const std::string& ifc_path = "",
|
||||
uint64_t ifc_file_size = 0,
|
||||
std::vector<PackedElementInfo> sidecar_elements = {},
|
||||
std::string sidecar_string_table = {});
|
||||
|
||||
// Read snapshots of a model's GPU buffers into CPU vectors.
|
||||
std::vector<uint32_t> readbackEbo(uint32_t model_id) const;
|
||||
std::vector<float> readbackVbo(uint32_t model_id) const;
|
||||
|
||||
void setSelectedObjectId(uint32_t id);
|
||||
uint32_t pickObjectAt(int x, int y);
|
||||
|
||||
@@ -124,6 +98,8 @@ public:
|
||||
uint32_t visible_objects;
|
||||
uint32_t total_triangles;
|
||||
uint32_t visible_triangles;
|
||||
uint32_t unique_meshes;
|
||||
uint32_t instanced_draws;
|
||||
};
|
||||
|
||||
signals:
|
||||
@@ -147,13 +123,7 @@ private:
|
||||
void setupVaoLayout(GLuint vao, GLuint vbo, GLuint ebo);
|
||||
bool growModelVbo(ModelGpuData& m, size_t needed_total);
|
||||
bool growModelEbo(ModelGpuData& m, size_t needed_total);
|
||||
void buildVisibleList(const QMatrix4x4& vp);
|
||||
void traverseBvh(const ModelBvh& mbvh, const ModelGpuData& mgpu,
|
||||
const float planes[6][4]);
|
||||
static bool aabbInFrustum(const float aabb_min[3], const float aabb_max[3],
|
||||
const float planes[6][4]);
|
||||
void applyBvhResult();
|
||||
void processPendingUploads();
|
||||
ModelGpuData& getOrCreateModel(uint32_t model_id);
|
||||
|
||||
// Mouse interaction
|
||||
void handleMousePress(QMouseEvent* event);
|
||||
@@ -172,13 +142,12 @@ private:
|
||||
GLuint pick_program_ = 0;
|
||||
GLuint axis_program_ = 0;
|
||||
|
||||
// Axis gizmo (separate VAO/VBO since vertex layout differs from scene)
|
||||
// Axis gizmo
|
||||
GLuint axis_vao_ = 0;
|
||||
GLuint axis_vbo_ = 0;
|
||||
|
||||
// Per-model GPU data
|
||||
std::unordered_map<uint32_t, ModelGpuData> models_gpu_;
|
||||
std::mutex models_mutex_;
|
||||
|
||||
// Pick framebuffer
|
||||
GLuint pick_fbo_ = 0;
|
||||
@@ -187,21 +156,10 @@ private:
|
||||
int pick_width_ = 0;
|
||||
int pick_height_ = 0;
|
||||
|
||||
// Per-model BVH
|
||||
std::unordered_map<uint32_t, std::shared_ptr<const BvhSet>> model_bvhs_;
|
||||
|
||||
// Progressive upload queue
|
||||
std::deque<PendingUpload> pending_uploads_;
|
||||
|
||||
// Scratch buffers reused each frame to avoid allocation.
|
||||
struct ModelDrawCmd {
|
||||
GLuint vao;
|
||||
std::vector<GLsizei> counts;
|
||||
std::vector<const void*> offsets;
|
||||
};
|
||||
std::vector<ModelDrawCmd> frame_draw_cmds_;
|
||||
// Per-frame stats
|
||||
uint32_t visible_triangles_ = 0;
|
||||
uint32_t visible_objects_ = 0;
|
||||
uint32_t instanced_draws_ = 0;
|
||||
|
||||
// Camera
|
||||
QVector3D camera_target_{0, 0, 0};
|
||||
@@ -211,26 +169,14 @@ private:
|
||||
QMatrix4x4 view_matrix_;
|
||||
QMatrix4x4 proj_matrix_;
|
||||
|
||||
// Mouse state
|
||||
// Mouse
|
||||
Qt::MouseButton active_button_ = Qt::NoButton;
|
||||
QPoint last_mouse_pos_;
|
||||
|
||||
// Selection
|
||||
uint32_t selected_object_id_ = 0;
|
||||
bool pick_requested_ = false;
|
||||
int pick_x_ = 0, pick_y_ = 0;
|
||||
|
||||
// BVH build (phase 2)
|
||||
struct PendingBvh {
|
||||
uint32_t model_id;
|
||||
std::shared_ptr<BvhSet> bvh_set;
|
||||
EboReorderResult ebo_reorder;
|
||||
};
|
||||
std::unique_ptr<PendingBvh> pending_bvh_;
|
||||
std::mutex bvh_result_mutex_;
|
||||
std::thread bvh_build_thread_;
|
||||
|
||||
// Stats
|
||||
// FPS smoothing
|
||||
int frame_count_ = 0;
|
||||
float accumulated_time_ = 0.0f;
|
||||
float last_fps_ = 0.0f;
|
||||
|
||||
Reference in New Issue
Block a user