279 lines
9.2 KiB
C++
279 lines
9.2 KiB
C++
// vulkan_engine.h : Include file for standard system include files,
|
|
// or project specific include files.
|
|
|
|
#pragma once
|
|
|
|
#include <core/types.h>
|
|
#include <core/world.h>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <cstdint>
|
|
#include "vk_mem_alloc.h"
|
|
#include <deque>
|
|
#include <functional>
|
|
#include "descriptor/descriptors.h"
|
|
#include "scene/vk_loader.h"
|
|
#include "compute/vk_compute.h"
|
|
#include <scene/camera.h>
|
|
|
|
#include "device/device.h"
|
|
#include "render/renderpass.h"
|
|
#include "render/passes/background.h"
|
|
#include "device/resource.h"
|
|
#include "device/swapchain.h"
|
|
#include "scene/vk_scene.h"
|
|
#include "render/materials.h"
|
|
|
|
#include "frame/resources.h"
|
|
#include "descriptor/manager.h"
|
|
#include "pipeline/sampler.h"
|
|
#include "render/passes/ssr.h"
|
|
#include "core/context.h"
|
|
#include "core/pipeline/manager.h"
|
|
#include "core/assets/manager.h"
|
|
#include "core/assets/async_loader.h"
|
|
#include "render/graph/graph.h"
|
|
#include "core/raytracing/raytracing.h"
|
|
#include "core/assets/texture_cache.h"
|
|
#include "core/assets/ibl_manager.h"
|
|
#include "core/ui/imgui_system.h"
|
|
#include "core/picking/picking_system.h"
|
|
|
|
class InputSystem;
|
|
class DebugDrawSystem;
|
|
|
|
struct DebugDrawDeleter
|
|
{
|
|
void operator()(DebugDrawSystem *p) const;
|
|
};
|
|
|
|
// Number of frames-in-flight. Affects per-frame command buffers, fences,
|
|
// semaphores, and transient descriptor pools in FrameResources.
|
|
constexpr unsigned int FRAME_OVERLAP = 2;
|
|
|
|
// Compute push constants and effects are declared in compute/vk_compute.h now.
|
|
|
|
|
|
struct RenderPass
|
|
{
|
|
std::string name;
|
|
std::function<void(VkCommandBuffer)> execute;
|
|
};
|
|
|
|
struct MeshNode : public Node
|
|
{
|
|
std::shared_ptr<MeshAsset> mesh;
|
|
// Owning glTF scene (for picking/debug); may be null for non-gltf meshes.
|
|
LoadedGLTF *scene = nullptr;
|
|
|
|
virtual void Draw(const glm::mat4 &topMatrix, DrawContext &ctx) override;
|
|
};
|
|
|
|
class VulkanEngine
|
|
{
|
|
public:
|
|
enum class WindowMode : uint8_t
|
|
{
|
|
Windowed = 0,
|
|
FullscreenDesktop = 1, // borderless fullscreen ("fullscreen windowed")
|
|
FullscreenExclusive = 2 // exclusive fullscreen (may change display mode)
|
|
};
|
|
|
|
~VulkanEngine();
|
|
|
|
bool _isInitialized{false};
|
|
int _frameNumber{0};
|
|
|
|
std::shared_ptr<DeviceManager> _deviceManager;
|
|
std::unique_ptr<SwapchainManager> _swapchainManager;
|
|
std::shared_ptr<ResourceManager> _resourceManager;
|
|
std::unique_ptr<RenderPassManager> _renderPassManager;
|
|
std::unique_ptr<ImGuiSystem> _ui;
|
|
std::unique_ptr<SceneManager> _sceneManager;
|
|
std::unique_ptr<PickingSystem> _picking;
|
|
std::unique_ptr<InputSystem> _input;
|
|
std::unique_ptr<DebugDrawSystem, DebugDrawDeleter> _debugDraw;
|
|
std::unique_ptr<PipelineManager> _pipelineManager;
|
|
std::unique_ptr<AssetManager> _assetManager;
|
|
std::unique_ptr<AsyncAssetLoader> _asyncLoader;
|
|
std::unique_ptr<RenderGraph> _renderGraph;
|
|
std::unique_ptr<RayTracingManager> _rayManager;
|
|
std::unique_ptr<TextureCache> _textureCache;
|
|
std::unique_ptr<IBLManager> _iblManager;
|
|
|
|
struct SDL_Window *_window{nullptr};
|
|
|
|
WindowMode _windowMode{WindowMode::Windowed};
|
|
int _windowDisplayIndex{0};
|
|
|
|
// HiDPI: allow high-DPI drawables (Retina / Windows scaling).
|
|
// Window coordinates from SDL events may be in "points" while the drawable/swapchain is in pixels.
|
|
bool _hiDpiEnabled{true};
|
|
|
|
FrameResources _frames[FRAME_OVERLAP];
|
|
|
|
FrameResources &get_current_frame() { return _frames[_frameNumber % FRAME_OVERLAP]; };
|
|
|
|
VkExtent2D _drawExtent;
|
|
VkExtent2D _logicalRenderExtent{};
|
|
float renderScale = 1.f;
|
|
|
|
std::unique_ptr<DescriptorManager> _descriptorManager;
|
|
std::unique_ptr<SamplerManager> _samplerManager;
|
|
ComputeManager compute;
|
|
|
|
std::shared_ptr<EngineContext> _context;
|
|
|
|
std::vector<VkFramebuffer> _framebuffers;
|
|
|
|
DeletionQueue _mainDeletionQueue;
|
|
|
|
VkPipelineLayout _meshPipelineLayout;
|
|
VkPipeline _meshPipeline;
|
|
|
|
std::shared_ptr<MeshAsset> cubeMesh;
|
|
std::shared_ptr<MeshAsset> sphereMesh;
|
|
|
|
AllocatedImage _whiteImage;
|
|
AllocatedImage _blackImage;
|
|
AllocatedImage _greyImage;
|
|
AllocatedImage _errorCheckerboardImage;
|
|
AllocatedImage _flatNormalImage; // 1x1 (0.5,0.5,1.0)
|
|
|
|
MaterialInstance defaultData;
|
|
|
|
GLTFMetallic_Roughness metalRoughMaterial;
|
|
|
|
EngineStats stats;
|
|
|
|
std::vector<RenderPass> renderPasses;
|
|
|
|
// Debug helpers: track spawned IBL test meshes to remove them easily
|
|
std::vector<std::string> _iblTestNames;
|
|
|
|
// Simple world-space IBL reflection volumes (axis-aligned boxes).
|
|
struct IBLVolume
|
|
{
|
|
WorldVec3 center_world{0.0, 0.0, 0.0};
|
|
glm::vec3 halfExtents{10.0f, 10.0f, 10.0f};
|
|
IBLPaths paths{}; // HDRI paths for this volume
|
|
bool enabled{true};
|
|
};
|
|
// Global/default IBL used when no volume contains the camera.
|
|
IBLPaths _globalIBLPaths{};
|
|
bool _hasGlobalIBL{false};
|
|
// User-defined local IBL volumes and currently active index (-1 = global).
|
|
std::vector<IBLVolume> _iblVolumes;
|
|
int _activeIBLVolume{-1};
|
|
// Pending async IBL request (global or volume). targetVolume = -1 means global.
|
|
struct PendingIBLRequest
|
|
{
|
|
bool active{false};
|
|
int targetVolume{-1};
|
|
IBLPaths paths{};
|
|
} _pendingIBLRequest;
|
|
|
|
ImGuiSystem *ui() { return _ui.get(); }
|
|
const ImGuiSystem *ui() const { return _ui.get(); }
|
|
|
|
PickingSystem *picking() { return _picking.get(); }
|
|
const PickingSystem *picking() const { return _picking.get(); }
|
|
|
|
InputSystem *input() { return _input.get(); }
|
|
const InputSystem *input() const { return _input.get(); }
|
|
|
|
// Debug: persistent pass enable overrides (by pass name)
|
|
std::unordered_map<std::string, bool> _rgPassToggles;
|
|
|
|
//initializes everything in the engine
|
|
void init();
|
|
|
|
//shuts down the engine
|
|
void cleanup();
|
|
|
|
//draw loop
|
|
void draw();
|
|
|
|
//run main loop
|
|
void run();
|
|
|
|
// Window controls (runtime)
|
|
void set_window_mode(WindowMode mode, int display_index);
|
|
|
|
// Rendering resolution controls:
|
|
// - logicalRenderExtent controls camera aspect and picking (letterboxed view).
|
|
// - renderScale controls the internal render target pixel count (logical * scale).
|
|
void set_logical_render_extent(VkExtent2D extent);
|
|
void set_render_scale(float scale);
|
|
|
|
// Query a conservative streaming texture budget for the texture cache.
|
|
size_t query_texture_budget_bytes() const;
|
|
|
|
// Convenience helper: load a glTF from assets/models and add it as a runtime instance.
|
|
// modelRelativePath is relative to the AssetManager model root.
|
|
// If preloadTextures is true, textures will be immediately marked for loading to VRAM.
|
|
bool addGLTFInstance(const std::string &instanceName,
|
|
const std::string &modelRelativePath,
|
|
const glm::mat4 &transform = glm::mat4(1.f),
|
|
bool preloadTextures = false);
|
|
|
|
// Spawn a runtime primitive mesh instance (cube/sphere/plane/capsule).
|
|
// - instanceName is the unique key for this object in SceneManager.
|
|
// - geomType selects which analytic primitive to build.
|
|
// - material controls whether the primitive uses the default PBR material
|
|
// or a textured material (see AssetManager::MeshMaterialDesc).
|
|
// - boundsTypeOverride can force a specific bounds type for picking.
|
|
// The underlying mesh is cached in AssetManager using a per-primitive name,
|
|
// so multiple instances share GPU buffers.
|
|
bool addPrimitiveInstance(const std::string &instanceName,
|
|
AssetManager::MeshGeometryDesc::Type geomType,
|
|
const glm::mat4 &transform = glm::mat4(1.f),
|
|
const AssetManager::MeshMaterialDesc &material = {},
|
|
std::optional<BoundsType> boundsTypeOverride = {});
|
|
|
|
// Asynchronous glTF load that reports progress via AsyncAssetLoader.
|
|
// Returns a JobID that can be queried via AsyncAssetLoader.
|
|
// If preloadTextures is true, textures will be immediately marked for loading to VRAM.
|
|
uint32_t loadGLTFAsync(const std::string &sceneName,
|
|
const std::string &modelRelativePath,
|
|
const glm::mat4 &transform = glm::mat4(1.f),
|
|
bool preloadTextures = false);
|
|
|
|
uint32_t loadGLTFAsync(const std::string &sceneName,
|
|
const std::string &modelRelativePath,
|
|
const WorldVec3 &translationWorld,
|
|
const glm::quat &rotation,
|
|
const glm::vec3 &scale,
|
|
bool preloadTextures = false);
|
|
|
|
// Preload textures for an already-loaded scene instance so they are
|
|
// available before the object becomes visible (visibility-driven loading).
|
|
void preloadInstanceTextures(const std::string &instanceName);
|
|
|
|
bool resize_requested{false};
|
|
bool freeze_rendering{false};
|
|
|
|
private:
|
|
struct WindowedRect
|
|
{
|
|
int x{0};
|
|
int y{0};
|
|
int w{0};
|
|
int h{0};
|
|
bool valid{false};
|
|
} _windowedRect;
|
|
|
|
void init_frame_resources();
|
|
|
|
void init_pipelines();
|
|
|
|
void init_mesh_pipeline();
|
|
|
|
void init_default_data();
|
|
|
|
// Debounce swapchain recreation during live window resizing.
|
|
uint32_t _last_resize_event_ms{0};
|
|
static constexpr uint32_t RESIZE_DEBOUNCE_MS = 150;
|
|
};
|