Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 341249bb96 | |||
| 0d145f615d | |||
| 4ebae57cf8 |
+1
-1
@@ -20,7 +20,7 @@ class Editor : public sophia::Application {
|
|||||||
panels().emplace<AssetBrowserPanel>();
|
panels().emplace<AssetBrowserPanel>();
|
||||||
sophia::RenderTargetHandle sceneTarget =
|
sophia::RenderTargetHandle sceneTarget =
|
||||||
resources().create<sophia::RenderTarget>();
|
resources().create<sophia::RenderTarget>();
|
||||||
setSceneTarget(sceneTarget);
|
views().create({.scene = scenes().create(), .target = sceneTarget});
|
||||||
panels().emplace<ViewportPanel>(ui(), sceneTarget);
|
panels().emplace<ViewportPanel>(ui(), sceneTarget);
|
||||||
|
|
||||||
panels().setDefaultLayout(
|
panels().setDefaultLayout(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <sophia/math.hpp>
|
#include <sophia/math.hpp>
|
||||||
#include <sophia/resource_registry_ref.hpp>
|
#include <sophia/resource_registry_ref.hpp>
|
||||||
#include <sophia/scene_registry.hpp>
|
#include <sophia/scene_registry.hpp>
|
||||||
|
#include <sophia/scene_view_registry.hpp>
|
||||||
#include <sophia/types.hpp>
|
#include <sophia/types.hpp>
|
||||||
#include <sophia/ui/debug_ui.hpp>
|
#include <sophia/ui/debug_ui.hpp>
|
||||||
#include <sophia/ui/panel_registry.hpp>
|
#include <sophia/ui/panel_registry.hpp>
|
||||||
@@ -46,6 +47,7 @@ class Application {
|
|||||||
ResourceRegistryRef resources();
|
ResourceRegistryRef resources();
|
||||||
PanelRegistry& panels() { return this->panelRegistry; }
|
PanelRegistry& panels() { return this->panelRegistry; }
|
||||||
SceneRegistry& scenes() { return this->sceneRegistry; }
|
SceneRegistry& scenes() { return this->sceneRegistry; }
|
||||||
|
SceneViewRegistry& views() { return this->sceneViewRegistry; }
|
||||||
UI& ui() { return this->_ui; }
|
UI& ui() { return this->_ui; }
|
||||||
|
|
||||||
DebugUI& debugUI() { return this->_debugUI; }
|
DebugUI& debugUI() { return this->_debugUI; }
|
||||||
@@ -58,16 +60,6 @@ class Application {
|
|||||||
|
|
||||||
void drawMesh(MeshHandle handle, const glm::mat4& transform);
|
void drawMesh(MeshHandle handle, const glm::mat4& transform);
|
||||||
|
|
||||||
/**
|
|
||||||
* !TEMP !TODO remove this func eventually
|
|
||||||
* Chooses where the scene is rendered. An invalid handle (the default) means
|
|
||||||
* the swapchain; a target created with
|
|
||||||
* ResourceRegistryRef::create<RenderTarget>() redirects it offscreen, and the
|
|
||||||
* swapchain then only receives the UI. FrameInfo::currentFramebufferExtent
|
|
||||||
* and the camera projection follow the target's size.
|
|
||||||
*/
|
|
||||||
void setSceneTarget(RenderTargetHandle handle);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Canvas;
|
friend class Canvas;
|
||||||
|
|
||||||
@@ -79,6 +71,7 @@ class Application {
|
|||||||
|
|
||||||
PanelRegistry panelRegistry;
|
PanelRegistry panelRegistry;
|
||||||
SceneRegistry sceneRegistry;
|
SceneRegistry sceneRegistry;
|
||||||
|
SceneViewRegistry sceneViewRegistry;
|
||||||
UI _ui;
|
UI _ui;
|
||||||
|
|
||||||
DebugUI _debugUI;
|
DebugUI _debugUI;
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ class Mesh;
|
|||||||
class Panel;
|
class Panel;
|
||||||
class RenderTarget;
|
class RenderTarget;
|
||||||
class Scene;
|
class Scene;
|
||||||
|
struct SceneView;
|
||||||
|
|
||||||
using MeshHandle = Handle<Mesh>;
|
using MeshHandle = Handle<Mesh>;
|
||||||
using PanelHandle = Handle<Panel>;
|
using PanelHandle = Handle<Panel>;
|
||||||
using RenderTargetHandle = Handle<RenderTarget>;
|
using RenderTargetHandle = Handle<RenderTarget>;
|
||||||
using SceneHandle = Handle<Scene>;
|
using SceneHandle = Handle<Scene>;
|
||||||
|
using SceneViewHandle = Handle<SceneView>;
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sophia/entity.hpp>
|
||||||
|
#include <sophia/handles.hpp>
|
||||||
|
#include <sophia/math.hpp>
|
||||||
|
#include <sophia/scene.hpp>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
enum class ClearFlags : u8 {
|
||||||
|
None = 0,
|
||||||
|
Color = 1 << 0,
|
||||||
|
Depth = 1 << 1,
|
||||||
|
Stencil = 1 << 2,
|
||||||
|
All = Color | Depth | Stencil
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneView {
|
||||||
|
SceneHandle scene = INVALID_HANDLE;
|
||||||
|
RenderTargetHandle target = INVALID_HANDLE;
|
||||||
|
Entity camera;
|
||||||
|
|
||||||
|
vec4 viewport{0.0f, 0.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
vec4 clearColor{0.f, 0.f, 0.f, 1.f};
|
||||||
|
ClearFlags clearFlags = ClearFlags::All;
|
||||||
|
|
||||||
|
u32 priority = 0; // Lower priority renders first
|
||||||
|
u32 layerMask = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
bool enabled = true; // Disabled views are kept but not rendered
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sophia/handles.hpp>
|
||||||
|
#include <sophia/scene_view.hpp>
|
||||||
|
#include <sophia/util/pool.hpp>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every live SceneView. The application renders all enabled views each frame,
|
||||||
|
* in ascending priority order, before the UI.
|
||||||
|
*/
|
||||||
|
class SceneViewRegistry {
|
||||||
|
public:
|
||||||
|
SceneViewRegistry(const SceneViewRegistry&) = delete;
|
||||||
|
SceneViewRegistry& operator=(const SceneViewRegistry&) = delete;
|
||||||
|
|
||||||
|
SceneViewRegistry() = default;
|
||||||
|
~SceneViewRegistry() = default;
|
||||||
|
|
||||||
|
SceneViewHandle create(const SceneView& view = {}) {
|
||||||
|
isRenderQueueDirty = true;
|
||||||
|
return pool.create(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SceneView& get(SceneViewHandle handle) const {
|
||||||
|
return pool.get(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneView& get(SceneViewHandle handle) {
|
||||||
|
isRenderQueueDirty = true;
|
||||||
|
return pool.get(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void release(SceneViewHandle handle) {
|
||||||
|
isRenderQueueDirty = true;
|
||||||
|
pool.release(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAlive(SceneViewHandle handle) const { return pool.isAlive(handle); }
|
||||||
|
|
||||||
|
u32 size() const { return pool.size(); }
|
||||||
|
|
||||||
|
template <typename Fn>
|
||||||
|
void forEach(Fn&& fn) {
|
||||||
|
isRenderQueueDirty = true;
|
||||||
|
pool.forEach(std::forward<Fn>(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fn>
|
||||||
|
void forEach(Fn&& fn) const {
|
||||||
|
pool.forEach(std::forward<Fn>(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<SceneViewHandle>& GetRenderQueue() const {
|
||||||
|
if (isRenderQueueDirty) {
|
||||||
|
rebuildRenderQueue();
|
||||||
|
}
|
||||||
|
return renderQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void rebuildRenderQueue() const {
|
||||||
|
renderQueue.clear();
|
||||||
|
pool.forEachWithHandle([&](SceneViewHandle handle, const SceneView& view) {
|
||||||
|
if (view.enabled) {
|
||||||
|
renderQueue.push_back(handle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::ranges::stable_sort(renderQueue, {}, [this](SceneViewHandle handle) {
|
||||||
|
return pool.get(handle).priority;
|
||||||
|
});
|
||||||
|
isRenderQueueDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pool<SceneView> pool{"SceneView"};
|
||||||
|
|
||||||
|
mutable std::vector<SceneViewHandle> renderQueue;
|
||||||
|
mutable bool isRenderQueueDirty = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -75,6 +75,17 @@ class Pool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Calls `fn(handle, item)` for every live item. */
|
||||||
|
template <typename Fn>
|
||||||
|
void forEachWithHandle(Fn&& fn) const {
|
||||||
|
for (u32 index = 0; index < slots.size(); index++) {
|
||||||
|
const Slot& slot = slots[index];
|
||||||
|
if (slot.item) {
|
||||||
|
fn(Handle<T>{index, slot.generation}, *slot.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Predicate>
|
template <typename Predicate>
|
||||||
T* findIf(Predicate&& predicate) {
|
T* findIf(Predicate&& predicate) {
|
||||||
return const_cast<T*>(
|
return const_cast<T*>(
|
||||||
|
|||||||
+46
-61
@@ -1,9 +1,11 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <map>
|
||||||
#include <sophia/application.hpp>
|
#include <sophia/application.hpp>
|
||||||
#include <sophia/util/logger.hpp>
|
#include <sophia/util/logger.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -15,6 +17,7 @@
|
|||||||
#include "rendering/model_render_system.hpp"
|
#include "rendering/model_render_system.hpp"
|
||||||
#include "rendering/render_context.hpp"
|
#include "rendering/render_context.hpp"
|
||||||
#include "rendering/render_graph.hpp"
|
#include "rendering/render_graph.hpp"
|
||||||
|
#include "rendering/scene_renderer.hpp"
|
||||||
#include "resources/mesh.hpp"
|
#include "resources/mesh.hpp"
|
||||||
#include "resources/render_target.hpp"
|
#include "resources/render_target.hpp"
|
||||||
#include "resources/resource_registry.hpp"
|
#include "resources/resource_registry.hpp"
|
||||||
@@ -43,35 +46,8 @@ std::vector<std::string> commandLineArgs;
|
|||||||
|
|
||||||
constexpr ClearColor CLEAR_COLOR = {0.01f, 0.01f, 0.02f, 1.0f};
|
constexpr ClearColor CLEAR_COLOR = {0.01f, 0.01f, 0.02f, 1.0f};
|
||||||
|
|
||||||
void beginColorPass(vk::CommandBuffer commandBuffer, vk::ImageView view,
|
bool hasFlag(ClearFlags flags, ClearFlags flag) {
|
||||||
vk::Extent2D extent) {
|
return (static_cast<u8>(flags) & static_cast<u8>(flag)) != 0;
|
||||||
vk::ClearValue clearValue{};
|
|
||||||
clearValue.color = vk::ClearColorValue{CLEAR_COLOR};
|
|
||||||
|
|
||||||
vk::RenderingAttachmentInfo colorAttachment{};
|
|
||||||
colorAttachment.imageView = view;
|
|
||||||
colorAttachment.imageLayout = vk::ImageLayout::eColorAttachmentOptimal;
|
|
||||||
colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
|
|
||||||
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
|
|
||||||
colorAttachment.clearValue = clearValue;
|
|
||||||
|
|
||||||
vk::RenderingInfo renderingInfo{};
|
|
||||||
renderingInfo.renderArea = vk::Rect2D{{0, 0}, extent};
|
|
||||||
renderingInfo.layerCount = 1;
|
|
||||||
renderingInfo.colorAttachmentCount = 1;
|
|
||||||
renderingInfo.pColorAttachments = &colorAttachment;
|
|
||||||
|
|
||||||
commandBuffer.beginRendering(renderingInfo);
|
|
||||||
|
|
||||||
vk::Viewport viewport{0.0f,
|
|
||||||
0.0f,
|
|
||||||
static_cast<float>(extent.width),
|
|
||||||
static_cast<float>(extent.height),
|
|
||||||
0.0f,
|
|
||||||
1.0f};
|
|
||||||
vk::Rect2D scissor{{0, 0}, extent};
|
|
||||||
commandBuffer.setViewport(0, viewport);
|
|
||||||
commandBuffer.setScissor(0, scissor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -88,6 +64,8 @@ class Application::Impl {
|
|||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
ModelRenderSystem modelRenderSystem{device, renderContext};
|
ModelRenderSystem modelRenderSystem{device, renderContext};
|
||||||
|
SceneRenderer sceneRenderer{this->application.sceneRegistry,
|
||||||
|
this->resourceRegistry};
|
||||||
ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(),
|
ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(),
|
||||||
renderContext.getImageCount(),
|
renderContext.getImageCount(),
|
||||||
this->resourceRegistry};
|
this->resourceRegistry};
|
||||||
@@ -106,6 +84,7 @@ class Application::Impl {
|
|||||||
auto& renderTargetPool = this->resourceRegistry.renderTargetPool;
|
auto& renderTargetPool = this->resourceRegistry.renderTargetPool;
|
||||||
|
|
||||||
PanelRegistry& panelRegistry = this->application.panelRegistry;
|
PanelRegistry& panelRegistry = this->application.panelRegistry;
|
||||||
|
const SceneViewRegistry& sceneViews = this->application.sceneViewRegistry;
|
||||||
|
|
||||||
imguiRenderer.setDefaultLayout(panelRegistry.getDefaultLayout());
|
imguiRenderer.setDefaultLayout(panelRegistry.getDefaultLayout());
|
||||||
|
|
||||||
@@ -128,17 +107,10 @@ class Application::Impl {
|
|||||||
// frame's work (or ImGui's references to the targets) is recorded.
|
// frame's work (or ImGui's references to the targets) is recorded.
|
||||||
renderTargetPool.applyPendingResizes();
|
renderTargetPool.applyPendingResizes();
|
||||||
|
|
||||||
RenderTarget* sceneTarget =
|
|
||||||
this->sceneTargetHandle.isValid()
|
|
||||||
? &renderTargetPool.get(this->sceneTargetHandle)
|
|
||||||
: nullptr;
|
|
||||||
|
|
||||||
vk::Extent2D extent = renderContext.getExtent();
|
vk::Extent2D extent = renderContext.getExtent();
|
||||||
vk::Extent2D sceneExtent =
|
|
||||||
sceneTarget ? sceneTarget->getExtent() : extent;
|
|
||||||
FrameInfo frameInfo{frameIndex, elapsedTime, deltaTime,
|
FrameInfo frameInfo{frameIndex, elapsedTime, deltaTime,
|
||||||
glm::vec2(static_cast<float>(sceneExtent.width),
|
glm::vec2(static_cast<float>(extent.width),
|
||||||
static_cast<float>(sceneExtent.height)),
|
static_cast<float>(extent.height)),
|
||||||
this->application.camera};
|
this->application.camera};
|
||||||
this->application.onUpdate(frameInfo);
|
this->application.onUpdate(frameInfo);
|
||||||
this->application.camera.setProjection(
|
this->application.camera.setProjection(
|
||||||
@@ -166,31 +138,54 @@ class Application::Impl {
|
|||||||
this->drawCalls.end());
|
this->drawCalls.end());
|
||||||
this->drawCalls.clear();
|
this->drawCalls.clear();
|
||||||
|
|
||||||
if (sceneTarget) {
|
|
||||||
Image& targetImage = sceneTarget->getImage();
|
|
||||||
targetImage.transitionLayout(commandBuffer,
|
|
||||||
vk::ImageLayout::eColorAttachmentOptimal);
|
|
||||||
beginColorPass(commandBuffer, targetImage.getView(), sceneExtent);
|
|
||||||
modelRenderSystem.render(commandBuffer, instances, frameInfo);
|
|
||||||
commandBuffer.endRendering();
|
|
||||||
targetImage.transitionLayout(commandBuffer,
|
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderGraph graph;
|
RenderGraph graph;
|
||||||
ImageRef backbuffer =
|
ImageRef backbuffer =
|
||||||
graph.importImage(renderContext.getCurrentImage(), Access::Present);
|
graph.importImage(renderContext.getCurrentImage(), Access::Present);
|
||||||
|
|
||||||
|
std::map<RenderTargetHandle, ImageRef> viewTargets;
|
||||||
|
for (SceneViewHandle handle : sceneViews.GetRenderQueue()) {
|
||||||
|
const SceneView& view = sceneViews.get(handle);
|
||||||
|
if (!this->application.sceneRegistry.isAlive(view.scene) ||
|
||||||
|
!renderTargetPool.isAlive(view.target)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [it, inserted] = viewTargets.try_emplace(view.target);
|
||||||
|
if (inserted) {
|
||||||
|
it->second =
|
||||||
|
graph.importImage(renderTargetPool.get(view.target).getImage(),
|
||||||
|
Access::SampledRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
const vec4& color = view.clearColor;
|
||||||
|
graph.addPass(
|
||||||
|
"scene view",
|
||||||
|
[&](RenderGraph::PassBuilder& pass) {
|
||||||
|
pass.writeColor(it->second,
|
||||||
|
hasFlag(view.clearFlags, ClearFlags::Color)
|
||||||
|
? vk::AttachmentLoadOp::eClear
|
||||||
|
: vk::AttachmentLoadOp::eLoad,
|
||||||
|
{color.r, color.g, color.b, color.a});
|
||||||
|
},
|
||||||
|
[&sceneRenderer, &sceneViews, handle](vk::CommandBuffer) {
|
||||||
|
const SceneView& view = sceneViews.get(handle);
|
||||||
|
if (view.camera) {
|
||||||
|
sceneRenderer.render(view);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
graph.addPass(
|
graph.addPass(
|
||||||
"main",
|
"main",
|
||||||
[&](RenderGraph::PassBuilder& pass) {
|
[&](RenderGraph::PassBuilder& pass) {
|
||||||
pass.writeColor(backbuffer, vk::AttachmentLoadOp::eClear,
|
pass.writeColor(backbuffer, vk::AttachmentLoadOp::eClear,
|
||||||
CLEAR_COLOR);
|
CLEAR_COLOR);
|
||||||
|
for (const auto& [handle, target] : viewTargets) {
|
||||||
|
pass.sample(target);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[&](vk::CommandBuffer commandBuffer) {
|
[&](vk::CommandBuffer commandBuffer) {
|
||||||
if (!sceneTarget) {
|
|
||||||
modelRenderSystem.render(commandBuffer, instances, frameInfo);
|
modelRenderSystem.render(commandBuffer, instances, frameInfo);
|
||||||
}
|
|
||||||
|
|
||||||
imguiRenderer.endFrame(commandBuffer);
|
imguiRenderer.endFrame(commandBuffer);
|
||||||
});
|
});
|
||||||
@@ -237,10 +232,6 @@ class Application::Impl {
|
|||||||
this->drawCalls.push_back({&mesh, transform});
|
this->drawCalls.push_back({&mesh, transform});
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSceneTarget(RenderTargetHandle handle) {
|
|
||||||
this->sceneTargetHandle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceRegistry& getResourceRegistry() { return resourceRegistry; }
|
ResourceRegistry& getResourceRegistry() { return resourceRegistry; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -253,8 +244,6 @@ class Application::Impl {
|
|||||||
|
|
||||||
std::vector<std::unique_ptr<Mesh>> meshes;
|
std::vector<std::unique_ptr<Mesh>> meshes;
|
||||||
std::vector<ModelRenderSystem::MeshInstance> drawCalls;
|
std::vector<ModelRenderSystem::MeshInstance> drawCalls;
|
||||||
|
|
||||||
RenderTargetHandle sceneTargetHandle = RenderTargetHandle::invalid();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void Application::setCommandLineArgs(int argc, const char* const* argv) {
|
void Application::setCommandLineArgs(int argc, const char* const* argv) {
|
||||||
@@ -281,10 +270,6 @@ void Application::pushMesh(std::vector<CanvasVertex> vertices,
|
|||||||
impl->pushMesh(std::move(vertices), std::move(indices));
|
impl->pushMesh(std::move(vertices), std::move(indices));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setSceneTarget(RenderTargetHandle handle) {
|
|
||||||
impl->setSceneTarget(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::clearMeshes() { impl->clearMeshes(); }
|
void Application::clearMeshes() { impl->clearMeshes(); }
|
||||||
|
|
||||||
void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) {
|
void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <sophia/util/assert.hpp>
|
#include <sophia/util/assert.hpp>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "vulkan/debug_label.hpp"
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
ImageRef RenderGraph::importImage(Image& image, Access finalAccess) {
|
ImageRef RenderGraph::importImage(Image& image, Access finalAccess) {
|
||||||
@@ -74,6 +76,8 @@ void RenderGraph::flush(vk::CommandBuffer commandBuffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
|
void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
|
||||||
|
beginDebugLabel(commandBuffer, pass.name.c_str());
|
||||||
|
|
||||||
PendingBarriers pending;
|
PendingBarriers pending;
|
||||||
for (const ImageUse& use : pass.uses) {
|
for (const ImageUse& use : pass.uses) {
|
||||||
this->transitionTo(use.image, getAccessState(use.access), pending);
|
this->transitionTo(use.image, getAccessState(use.access), pending);
|
||||||
@@ -82,9 +86,14 @@ void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
|
|||||||
|
|
||||||
if (pass.colorAttachments.empty()) {
|
if (pass.colorAttachments.empty()) {
|
||||||
pass.execute(commandBuffer);
|
pass.execute(commandBuffer);
|
||||||
return;
|
} else {
|
||||||
|
this->recordRendering(commandBuffer, pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endDebugLabel(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderGraph::recordRendering(vk::CommandBuffer commandBuffer, Pass& pass) {
|
||||||
std::vector<vk::RenderingAttachmentInfo> attachments;
|
std::vector<vk::RenderingAttachmentInfo> attachments;
|
||||||
attachments.reserve(pass.colorAttachments.size());
|
attachments.reserve(pass.colorAttachments.size());
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ class RenderGraph {
|
|||||||
/**
|
/**
|
||||||
* Adds a pass. `setup` runs immediately and declares what the pass does to
|
* Adds a pass. `setup` runs immediately and declares what the pass does to
|
||||||
* images; `execute` runs later, from execute(), with the barriers already
|
* images; `execute` runs later, from execute(), with the barriers already
|
||||||
* recorded and (if the pass writes color) rendering begun.
|
* recorded and (if the pass writes color) rendering begun. `name` labels
|
||||||
|
* the pass's commands in debugging tools such as RenderDoc.
|
||||||
*/
|
*/
|
||||||
void addPass(std::string name, const SetupFn& setup, ExecuteFn execute);
|
void addPass(std::string name, const SetupFn& setup, ExecuteFn execute);
|
||||||
|
|
||||||
@@ -112,6 +113,7 @@ class RenderGraph {
|
|||||||
PendingBarriers& pending);
|
PendingBarriers& pending);
|
||||||
void flush(vk::CommandBuffer commandBuffer, PendingBarriers& pending);
|
void flush(vk::CommandBuffer commandBuffer, PendingBarriers& pending);
|
||||||
void recordPass(vk::CommandBuffer commandBuffer, Pass& pass);
|
void recordPass(vk::CommandBuffer commandBuffer, Pass& pass);
|
||||||
|
void recordRendering(vk::CommandBuffer commandBuffer, Pass& pass);
|
||||||
|
|
||||||
std::vector<ImportedImage> images;
|
std::vector<ImportedImage> images;
|
||||||
std::vector<Pass> passes;
|
std::vector<Pass> passes;
|
||||||
|
|||||||
@@ -12,13 +12,17 @@ struct PushConstantData {
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SceneRenderer::SceneRenderer(ResourceRegistry& resources)
|
SceneRenderer::SceneRenderer(const SceneRegistry& sceneRegistry,
|
||||||
: resources{resources} {}
|
ResourceRegistry& resources)
|
||||||
|
: sceneRegistry{sceneRegistry}, resources{resources} {}
|
||||||
|
|
||||||
SceneRenderer::~SceneRenderer() {}
|
SceneRenderer::~SceneRenderer() {}
|
||||||
|
|
||||||
void SceneRenderer::render(const Scene& scene, Entity camera,
|
void SceneRenderer::render(SceneView sceneView) {
|
||||||
RenderTargetHandle target) {
|
auto& handle = sceneView.scene;
|
||||||
|
auto& scene = this->sceneRegistry.get(handle);
|
||||||
|
|
||||||
|
auto& camera = sceneView.camera;
|
||||||
SOPHIA_ASSERT(camera.hasComponent<CameraComponent>(),
|
SOPHIA_ASSERT(camera.hasComponent<CameraComponent>(),
|
||||||
"camera does not have camera component!");
|
"camera does not have camera component!");
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sophia/handles.hpp>
|
#include <sophia/scene_registry.hpp>
|
||||||
#include <sophia/scene.hpp>
|
#include <sophia/scene_view.hpp>
|
||||||
|
|
||||||
#include "entity.hpp"
|
|
||||||
#include "resources/resource_registry.hpp"
|
#include "resources/resource_registry.hpp"
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
@@ -16,12 +15,14 @@ class SceneRenderer {
|
|||||||
SceneRenderer(const SceneRenderer&) = delete;
|
SceneRenderer(const SceneRenderer&) = delete;
|
||||||
SceneRenderer& operator=(const SceneRenderer&) = delete;
|
SceneRenderer& operator=(const SceneRenderer&) = delete;
|
||||||
|
|
||||||
SceneRenderer(ResourceRegistry& resources);
|
SceneRenderer(const SceneRegistry& sceneRegistry,
|
||||||
|
ResourceRegistry& resources);
|
||||||
~SceneRenderer();
|
~SceneRenderer();
|
||||||
|
|
||||||
void render(const Scene& scene, Entity camera, RenderTargetHandle target);
|
void render(SceneView sceneView);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const SceneRegistry& sceneRegistry;
|
||||||
ResourceRegistry& resources;
|
ResourceRegistry& resources;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ void RenderTarget::applyPendingResize() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Earlier frames may still be sampling the old image (e.g. through the UI).
|
|
||||||
this->device.waitIdle();
|
this->device.waitIdle();
|
||||||
|
|
||||||
destroy();
|
destroy();
|
||||||
create(extent.width, extent.height);
|
create(extent.width, extent.height);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "entity.hpp"
|
#include <sophia/entity.hpp>
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include "vulkan/debug_label.hpp"
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
static PFN_vkCmdBeginDebugUtilsLabelEXT cmdBeginDebugUtilsLabel = nullptr;
|
||||||
|
static PFN_vkCmdEndDebugUtilsLabelEXT cmdEndDebugUtilsLabel = nullptr;
|
||||||
|
|
||||||
|
void loadDebugLabelFunctions(vk::Instance instance) {
|
||||||
|
cmdBeginDebugUtilsLabel = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
|
||||||
|
vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"));
|
||||||
|
cmdEndDebugUtilsLabel = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(
|
||||||
|
vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void beginDebugLabel(vk::CommandBuffer commandBuffer, const char* name) {
|
||||||
|
if (!cmdBeginDebugUtilsLabel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDebugUtilsLabelEXT label{};
|
||||||
|
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||||
|
label.pLabelName = name;
|
||||||
|
cmdBeginDebugUtilsLabel(commandBuffer, &label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void endDebugLabel(vk::CommandBuffer commandBuffer) {
|
||||||
|
if (!cmdEndDebugUtilsLabel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdEndDebugUtilsLabel(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
void loadDebugLabelFunctions(vk::Instance instance);
|
||||||
|
|
||||||
|
void beginDebugLabel(vk::CommandBuffer commandBuffer, const char* name);
|
||||||
|
|
||||||
|
void endDebugLabel(vk::CommandBuffer commandBuffer);
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <sophia/util/logger.hpp>
|
#include <sophia/util/logger.hpp>
|
||||||
|
|
||||||
|
#include "vulkan/debug_label.hpp"
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
static VKAPI_ATTR vk::Bool32 VKAPI_CALL
|
static VKAPI_ATTR vk::Bool32 VKAPI_CALL
|
||||||
@@ -288,6 +290,8 @@ void Device::setupDebugMessenger() {
|
|||||||
nullptr, &this->debugMessenger) != VK_SUCCESS) {
|
nullptr, &this->debugMessenger) != VK_SUCCESS) {
|
||||||
throw std::runtime_error("failed to set up debug callback!");
|
throw std::runtime_error("failed to set up debug callback!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadDebugLabelFunctions(*instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::checkValidationLayerSupport() {
|
bool Device::checkValidationLayerSupport() {
|
||||||
|
|||||||
+10
-4
@@ -1,7 +1,9 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
#include <sophia/application.hpp>
|
#include <sophia/application.hpp>
|
||||||
|
#include <sophia/entity.hpp>
|
||||||
#include <sophia/frame_info.hpp>
|
#include <sophia/frame_info.hpp>
|
||||||
|
#include <sophia/scene_view.hpp>
|
||||||
#include <sophia/ui/panel.hpp>
|
#include <sophia/ui/panel.hpp>
|
||||||
|
|
||||||
class Viewport : public sophia::Panel {
|
class Viewport : public sophia::Panel {
|
||||||
@@ -25,11 +27,15 @@ class Testbed : public sophia::Application {
|
|||||||
Testbed() : Application{{.width = 750, .height = 1000, .name = "Testbed"}} {}
|
Testbed() : Application{{.width = 750, .height = 1000, .name = "Testbed"}} {}
|
||||||
|
|
||||||
void onCreate() override {
|
void onCreate() override {
|
||||||
sophia::RenderTargetHandle target =
|
view = views().create({.scene = scenes().create(),
|
||||||
resources().create<sophia::RenderTarget>();
|
.target = resources().create<sophia::RenderTarget>(),
|
||||||
setSceneTarget(target);
|
.clearColor = {0.1f, 0.1f, 0.15f, 1.f}});
|
||||||
panels().emplace<Viewport>(ui(), target);
|
|
||||||
|
panels().emplace<Viewport>(ui(), views().get(view).target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sophia::SceneViewHandle view;
|
||||||
};
|
};
|
||||||
|
|
||||||
SOPHIA_MAIN(Testbed)
|
SOPHIA_MAIN(Testbed)
|
||||||
|
|||||||
Reference in New Issue
Block a user