Huge changes for 3d

This commit is contained in:
2026-09-30 18:53:16 -07:00
parent cd2e80cfca
commit b5b0eb9497
53 changed files with 1313 additions and 457 deletions
+80 -28
View File
@@ -5,7 +5,9 @@
#include <chrono>
#include <cstddef>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <map>
#include <optional>
#include <set>
#include <sophia/application.hpp>
#include <sophia/util/logger.hpp>
@@ -92,8 +94,9 @@ class Application::Impl {
imguiRenderer.setDefaultLayout(panelRegistry.getDefaultLayout());
// Views already warned about having no camera, so each warns once.
// Views already warned about, so each warns once.
std::set<SceneViewHandle> viewsWithoutCamera;
std::set<SceneViewHandle> viewsOverwritingOthers;
auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = startTime;
@@ -117,17 +120,20 @@ class Application::Impl {
vk::Extent2D extent = renderContext.getExtent();
FrameInfo frameInfo{frameIndex, elapsedTime, deltaTime,
glm::vec2(static_cast<float>(extent.width),
static_cast<float>(extent.height)),
this->application.camera};
static_cast<float>(extent.height))};
{
ZoneScopedN("Application::onUpdate");
this->application.onUpdate(frameInfo);
}
this->application.camera.setProjection(
-frameInfo.currentFramebufferExtent.x / 2.f,
frameInfo.currentFramebufferExtent.x / 2.f,
-frameInfo.currentFramebufferExtent.y / 2.f,
frameInfo.currentFramebufferExtent.y / 2.f);
// Canvas draws in window pixels, origin at the center.
// TODO: replace with Debug/Gizmos drawn into scene views through their
// cameras.
glm::mat4 canvasProjection =
glm::ortho(-frameInfo.currentFramebufferExtent.x / 2.f,
frameInfo.currentFramebufferExtent.x / 2.f,
-frameInfo.currentFramebufferExtent.y / 2.f,
frameInfo.currentFramebufferExtent.y / 2.f);
vk::CommandBuffer commandBuffer = renderContext.beginFrame();
if (!commandBuffer) {
@@ -152,37 +158,78 @@ class Application::Impl {
this->drawCalls.end());
this->drawCalls.clear();
RenderGraph graph;
RenderGraph graph{renderContext.getTracyContext()};
ImageRef backbuffer =
graph.importImage(renderContext.getCurrentImage(), Access::Present);
std::map<RenderTargetHandle, ImageRef> viewTargets;
struct ViewTarget {
ImageRef color;
ImageRef depth;
};
std::map<RenderTargetHandle, ViewTarget> viewTargets;
// Views without a target render straight into the backbuffer.
std::optional<ViewTarget> swapchainTarget;
for (SceneViewHandle handle : sceneViewRegistry.GetRenderQueue()) {
const SceneView& view = sceneViewRegistry.peek(handle);
bool toSwapchain = !view.target.isValid();
if (!sceneRegistry.isAlive(view.scene) ||
!renderTargetPool.isAlive(view.target)) {
(!toSwapchain && !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);
ViewTarget target;
vk::Extent2D targetExtent;
// Whether this is the first view this frame to render to its target.
bool firstOnTarget = false;
if (toSwapchain) {
firstOnTarget = !swapchainTarget;
if (!swapchainTarget) {
swapchainTarget = {
backbuffer,
graph.importImage(renderContext.getCurrentDepthImage(),
Access::DepthWrite)};
}
target = *swapchainTarget;
targetExtent = renderContext.getExtent();
} else {
RenderTarget& renderTarget = renderTargetPool.get(view.target);
auto [it, inserted] = viewTargets.try_emplace(view.target);
firstOnTarget = inserted;
if (inserted) {
it->second = {
graph.importImage(renderTarget.getImage(), Access::SampledRead),
graph.importImage(renderTarget.getDepthImage(),
Access::DepthWrite)};
}
target = it->second;
targetExtent = renderTarget.getExtent();
}
if (!firstOnTarget && hasFlag(view.clearFlags, ClearFlags::Color) &&
viewsOverwritingOthers.insert(handle).second) {
log::warning(
"scene view clears its target after another view already "
"rendered to it this frame, hiding that view (give it clearFlags "
"without Color, or render it first with a lower priority)");
}
const vec4& color = view.clearColor;
graph.addPass(
"scene view",
"scene view " + std::to_string(handle.index),
[&](RenderGraph::PassBuilder& pass) {
pass.writeColor(it->second,
pass.writeColor(target.color,
hasFlag(view.clearFlags, ClearFlags::Color)
? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad,
{color.r, color.g, color.b, color.a});
pass.writeDepth(target.depth,
hasFlag(view.clearFlags, ClearFlags::Depth)
? vk::AttachmentLoadOp::eClear
: vk::AttachmentLoadOp::eLoad);
},
[&sceneRenderer, &sceneRegistry, &sceneViewRegistry,
&viewsWithoutCamera, handle](vk::CommandBuffer commandBuffer) {
&viewsWithoutCamera, handle,
targetExtent](vk::CommandBuffer commandBuffer) {
ZoneScopedN("scene view pass");
const SceneView& view = sceneViewRegistry.peek(handle);
Entity camera =
@@ -198,22 +245,26 @@ class Application::Impl {
}
return;
}
sceneRenderer.render(commandBuffer, view, camera);
sceneRenderer.render(commandBuffer, view, camera, targetExtent);
});
}
graph.addPass(
"main",
[&](RenderGraph::PassBuilder& pass) {
pass.writeColor(backbuffer, vk::AttachmentLoadOp::eClear,
// Keep what scene views drew into the backbuffer.
pass.writeColor(backbuffer,
swapchainTarget ? vk::AttachmentLoadOp::eLoad
: vk::AttachmentLoadOp::eClear,
CLEAR_COLOR);
for (const auto& [handle, target] : viewTargets) {
pass.sample(target);
pass.sample(target.color);
}
},
[&](vk::CommandBuffer commandBuffer) {
ZoneScopedN("main pass");
modelRenderSystem.render(commandBuffer, instances, frameInfo);
modelRenderSystem.render(commandBuffer, instances,
canvasProjection);
imguiRenderer.endFrame(commandBuffer);
});
@@ -239,14 +290,15 @@ class Application::Impl {
}
void pushMesh(std::vector<CanvasVertex> vertices, std::vector<u32> indices) {
Mesh::Builder builder{};
builder.vertices.reserve(vertices.size());
MeshData data;
data.vertices.reserve(vertices.size());
for (const CanvasVertex& vertex : vertices) {
builder.vertices.push_back({vertex.position, vertex.color});
data.vertices.push_back(
{.position = {vertex.position, 0.f}, .color = {vertex.color, 1.f}});
}
builder.indices = std::move(indices);
data.indices = std::move(indices);
this->meshes.push_back(std::make_unique<Mesh>(this->device, builder));
this->meshes.push_back(std::make_unique<Mesh>(this->device, data));
}
void clearMeshes() {
+153
View File
@@ -0,0 +1,153 @@
#include "renderer/mesh_render_system.hpp"
#include <algorithm>
#include <sophia/util/logger.hpp>
#include <tracy/Tracy.hpp>
#include "shaders/mesh.frag.spv.h"
#include "shaders/mesh.vert.spv.h"
namespace sophia {
namespace {
// Mesh::getAttributeDescriptions() takes locations below this.
constexpr u32 FIRST_INSTANCE_LOCATION = 4;
} // namespace
MeshRenderSystem::MeshRenderSystem(Device& device, vk::Format colorFormat,
vk::Format depthFormat,
ResourceRegistry& resources)
: device{device}, resources{resources} {
createPipelineLayout();
createPipeline(colorFormat, depthFormat);
createInstanceBuffers();
}
MeshRenderSystem::~MeshRenderSystem() {
log::trace("destroyed sophia::MeshRenderSystem");
}
void MeshRenderSystem::beginFrame(u32 frameIndex) {
this->frameIndex = frameIndex;
this->instanceCursor = 0;
}
void MeshRenderSystem::render(vk::CommandBuffer commandBuffer,
const glm::mat4& viewProjection,
std::span<const Instance> instances,
std::span<const Batch> batches) {
ZoneScoped;
if (instances.empty()) {
return;
}
u32 available = MAX_INSTANCES_PER_FRAME - this->instanceCursor;
if (instances.size() > available) {
log::warning("MeshRenderSystem: frame instance buffer full, dropping",
instances.size() - available, "meshes");
}
Buffer& buffer = *this->instanceBuffers[this->frameIndex];
u32 base = this->instanceCursor;
u32 count = std::min(static_cast<u32>(instances.size()), available);
buffer.writeToBuffer(const_cast<Instance*>(instances.data()),
count * sizeof(Instance), base * sizeof(Instance));
this->instanceCursor += count;
this->graphicsPipeline->bind(commandBuffer);
PushConstantData push{viewProjection};
commandBuffer.pushConstants(this->pipelineLayout.get(),
vk::ShaderStageFlagBits::eVertex, 0,
sizeof(PushConstantData), &push);
// Binding 1 stays bound across batches; each mesh rebinds binding 0.
vk::Buffer instanceBuffer = buffer.getBuffer();
vk::DeviceSize offset = 0;
commandBuffer.bindVertexBuffers(1, 1, &instanceBuffer, &offset);
for (const Batch& batch : batches) {
if (batch.firstInstance >= count) {
break;
}
u32 batchCount = std::min(batch.instanceCount, count - batch.firstInstance);
const Mesh& mesh = this->resources.meshPool.get(batch.mesh);
mesh.bind(commandBuffer);
mesh.draw(commandBuffer, batchCount, base + batch.firstInstance);
}
}
void MeshRenderSystem::createPipelineLayout() {
vk::PushConstantRange pushConstantRange{};
pushConstantRange.stageFlags = vk::ShaderStageFlagBits::eVertex;
pushConstantRange.offset = 0;
pushConstantRange.size = sizeof(PushConstantData);
vk::PipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.setLayoutCount = 0;
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
try {
this->pipelineLayout =
this->device.get()->createPipelineLayoutUnique(pipelineLayoutInfo);
log::trace("created vk::PipelineLayout");
} catch (const vk::SystemError& err) {
log::fatal("failed to create vk::PipelineLayout");
throw std::runtime_error("failed to create vk::PipelineLayout");
}
}
void MeshRenderSystem::createPipeline(vk::Format colorFormat,
vk::Format depthFormat) {
auto vertexShader = Shader::Builder()
.fromSPIRV(shaders::mesh_vert_spv)
.setStage(ShaderStage::VERTEX)
.build();
auto fragmentShader = Shader::Builder()
.fromSPIRV(shaders::mesh_frag_spv)
.setStage(ShaderStage::FRAGMENT)
.build();
std::vector<vk::VertexInputBindingDescription> bindings =
Mesh::getBindingDescriptions();
bindings.push_back({1, sizeof(Instance), vk::VertexInputRate::eInstance});
std::vector<vk::VertexInputAttributeDescription> attributes =
Mesh::getAttributeDescriptions();
// A mat4 attribute takes four consecutive locations, one per column.
for (u32 column = 0; column < 4; column++) {
attributes.push_back({FIRST_INSTANCE_LOCATION + column, 1,
vk::Format::eR32G32B32A32Sfloat,
static_cast<u32>(offsetof(Instance, model) +
column * sizeof(glm::vec4))});
}
attributes.push_back({FIRST_INSTANCE_LOCATION + 4, 1,
vk::Format::eR32G32B32A32Sfloat,
static_cast<u32>(offsetof(Instance, color))});
this->graphicsPipeline = GraphicsPipeline::Builder(this->device)
.setVertexShader(*vertexShader)
.setFragmentShader(*fragmentShader)
.setPipelineLayout(this->pipelineLayout.get())
.setColorAttachmentFormats({colorFormat})
.setDepthAttachmentFormat(depthFormat)
.setVertexInput(bindings, attributes)
.setDepthTest(true, true)
.setCullMode(vk::CullModeFlagBits::eBack)
.build();
}
void MeshRenderSystem::createInstanceBuffers() {
for (std::unique_ptr<Buffer>& buffer : this->instanceBuffers) {
buffer = std::make_unique<Buffer>(
this->device, sizeof(Instance), MAX_INSTANCES_PER_FRAME,
vk::BufferUsageFlagBits::eVertexBuffer,
vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent);
buffer->map();
}
}
} // namespace sophia
@@ -0,0 +1,80 @@
#pragma once
#include <array>
#include <memory>
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <span>
#include "renderer/render_context.hpp"
#include "resources/resource_registry.hpp"
#include "vulkan/buffer.hpp"
#include "vulkan/device.hpp"
#include "vulkan/pipelines/graphics_pipeline.hpp"
namespace sophia {
/**
* Draws batches of opaque meshes, depth tested and back-face culled. Knows
* nothing about scenes: callers hand it instances grouped into runs that
* share a mesh.
*
* Unlit for now: each pixel is the vertex color times the instance color.
* Normals and UVs reach the vertex shader but aren't used yet.
*
* Instances are written to a per-frame host-visible buffer, so every
* render() call within one frame appends to it; call beginFrame() once per
* frame before any render().
*/
class MeshRenderSystem {
public:
// Layout must match the per-instance inputs in mesh.vert.
struct Instance {
glm::mat4 model{1.f};
glm::vec4 color{1.f};
};
// A run of consecutive instances of the same mesh.
struct Batch {
MeshHandle mesh;
u32 firstInstance;
u32 instanceCount;
};
static constexpr u32 MAX_INSTANCES_PER_FRAME = 32768;
MeshRenderSystem(const MeshRenderSystem&) = delete;
MeshRenderSystem& operator=(const MeshRenderSystem&) = delete;
MeshRenderSystem(Device& device, vk::Format colorFormat,
vk::Format depthFormat, ResourceRegistry& resources);
~MeshRenderSystem();
void beginFrame(u32 frameIndex);
void render(vk::CommandBuffer commandBuffer, const glm::mat4& viewProjection,
std::span<const Instance> instances,
std::span<const Batch> batches);
private:
struct PushConstantData {
glm::mat4 viewProjection{1.f};
};
void createPipelineLayout();
void createPipeline(vk::Format colorFormat, vk::Format depthFormat);
void createInstanceBuffers();
Device& device;
ResourceRegistry& resources;
vk::UniquePipelineLayout pipelineLayout;
std::unique_ptr<GraphicsPipeline> graphicsPipeline;
std::array<std::unique_ptr<Buffer>, RenderContext::MAX_FRAMES_IN_FLIGHT>
instanceBuffers;
u32 frameIndex = 0;
u32 instanceCursor = 0;
};
} // namespace sophia
+3 -5
View File
@@ -25,8 +25,8 @@ ModelRenderSystem::ModelRenderSystem(Device& device,
.setStage(ShaderStage::FRAGMENT)
.build();
auto bindingDescriptions = Mesh::Vertex::getBindingDescriptions();
auto attributeDescriptions = Mesh::Vertex::getAttributeDescriptions();
auto bindingDescriptions = Mesh::getBindingDescriptions();
auto attributeDescriptions = Mesh::getAttributeDescriptions();
this->graphicsPipeline =
GraphicsPipeline::Builder(device)
@@ -44,10 +44,8 @@ ModelRenderSystem::~ModelRenderSystem() {
void ModelRenderSystem::render(vk::CommandBuffer commandBuffer,
std::span<const MeshInstance> instances,
const FrameInfo& frameInfo) {
const glm::mat4& viewProjection) {
ZoneScoped;
glm::mat4 viewProjection = frameInfo.camera.getViewProjection();
this->graphicsPipeline->bind(commandBuffer);
for (const MeshInstance& instance : instances) {
+2 -2
View File
@@ -1,7 +1,7 @@
#pragma once
#include <memory>
#include <sophia/frame_info.hpp>
#include <sophia/math.hpp>
#include <span>
#include "renderer/render_context.hpp"
@@ -32,7 +32,7 @@ class ModelRenderSystem {
void render(vk::CommandBuffer commandBuffer,
std::span<const MeshInstance> instances,
const FrameInfo& frameInfo);
const glm::mat4& viewProjection);
private:
void createPipelineLayout();
+29 -1
View File
@@ -14,9 +14,13 @@ RenderContext::RenderContext(Window& window, Device& device)
: window{window}, device{device} {
createFrames();
recreateSwapchain();
createTracyContext();
}
RenderContext::~RenderContext() { this->device.waitIdle(); }
RenderContext::~RenderContext() {
this->device.waitIdle();
TracyVkDestroy(this->tracyContext);
}
vk::CommandBuffer RenderContext::beginFrame() {
ZoneScoped;
@@ -75,6 +79,9 @@ vk::CommandBuffer RenderContext::beginFrame() {
throw std::runtime_error("failed to begin recording command buffer");
}
TracyVkCollect(this->tracyContext,
static_cast<VkCommandBuffer>(frame.commandBuffer));
return frame.commandBuffer;
}
@@ -158,6 +165,27 @@ void RenderContext::recreateSwapchain() {
this->imagesInFlight.assign(this->swapchain->imageCount(), vk::Fence{});
}
void RenderContext::createTracyContext() {
#ifdef TRACY_ENABLE
// Tracy records and submits a one-off command buffer to line up GPU and CPU
// clocks, and waits for it.
vk::CommandBufferAllocateInfo allocInfo{this->device.getCommandPool(),
vk::CommandBufferLevel::ePrimary, 1};
vk::CommandBuffer commandBuffer =
this->device.get()->allocateCommandBuffers(allocInfo).front();
this->tracyContext = TracyVkContext(
static_cast<VkPhysicalDevice>(this->device.getPhysicalDevice()),
static_cast<VkDevice>(*this->device.get()),
static_cast<VkQueue>(this->device.getGraphicsQueue()),
static_cast<VkCommandBuffer>(commandBuffer));
TracyVkContextName(this->tracyContext, "Graphics", 8);
this->device.get()->freeCommandBuffers(this->device.getCommandPool(),
commandBuffer);
#endif
}
void RenderContext::createFrames() {
vk::CommandBufferAllocateInfo allocInfo{this->device.getCommandPool(),
vk::CommandBufferLevel::ePrimary,
+12
View File
@@ -6,6 +6,9 @@
#include <vector>
#include <vulkan/vulkan.hpp>
/* AFTER VULKAN */
#include <tracy/TracyVulkan.hpp>
#include "vulkan/device.hpp"
#include "vulkan/swapchain.hpp"
#include "window.hpp"
@@ -35,11 +38,17 @@ class RenderContext {
return this->swapchain->getImage(static_cast<int>(this->currentImageIndex));
}
Image& getCurrentDepthImage() const {
return this->swapchain->getDepthImage(
static_cast<int>(this->currentImageIndex));
}
vk::Extent2D getExtent() const { return this->swapchain->getExtent(); }
vk::Format getImageFormat() const {
return this->swapchain->getImageFormat();
}
u32 getFrameIndex() const { return this->currentFrameIndex; }
TracyVkCtx getTracyContext() const { return this->tracyContext; }
u32 getImageCount() const {
return static_cast<u32>(this->swapchain->imageCount());
}
@@ -47,6 +56,7 @@ class RenderContext {
private:
void recreateSwapchain();
void createFrames();
void createTracyContext();
Window& window;
Device& device;
@@ -58,6 +68,8 @@ class RenderContext {
std::vector<vk::UniqueSemaphore> renderFinishedSemaphores;
std::vector<vk::Fence> imagesInFlight;
TracyVkCtx tracyContext = nullptr;
u32 currentFrameIndex = 0;
u32 currentImageIndex = 0;
bool isFrameStarted = false;
+36 -4
View File
@@ -71,6 +71,10 @@ void RenderGraph::flush(vk::CommandBuffer commandBuffer,
}
void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
ZoneTransientN(cpuZone, pass.name.c_str(), true);
TracyVkZoneTransient(this->tracyContext, gpuZone,
static_cast<VkCommandBuffer>(commandBuffer),
pass.name.c_str(), this->tracyContext != nullptr);
beginDebugLabel(commandBuffer, pass.name.c_str());
PendingBarriers pending;
@@ -79,7 +83,7 @@ void RenderGraph::recordPass(vk::CommandBuffer commandBuffer, Pass& pass) {
}
this->flush(commandBuffer, pending);
if (pass.colorAttachments.empty()) {
if (pass.colorAttachments.empty() && !pass.depthAttachment) {
pass.execute(commandBuffer);
} else {
this->recordRendering(commandBuffer, pass);
@@ -92,9 +96,10 @@ void RenderGraph::recordRendering(vk::CommandBuffer commandBuffer, Pass& pass) {
std::vector<vk::RenderingAttachmentInfo> attachments;
attachments.reserve(pass.colorAttachments.size());
vk::Extent3D imageExtent =
this->images[pass.colorAttachments.front().image.index]
.image->getExtent();
ImageRef sizedBy = pass.colorAttachments.empty()
? pass.depthAttachment->image
: pass.colorAttachments.front().image;
vk::Extent3D imageExtent = this->images[sizedBy.index].image->getExtent();
vk::Extent2D extent{imageExtent.width, imageExtent.height};
for (const ColorAttachment& color : pass.colorAttachments) {
@@ -119,6 +124,24 @@ void RenderGraph::recordRendering(vk::CommandBuffer commandBuffer, Pass& pass) {
renderingInfo.colorAttachmentCount = static_cast<u32>(attachments.size());
renderingInfo.pColorAttachments = attachments.data();
vk::RenderingAttachmentInfo depthAttachment{};
if (pass.depthAttachment) {
const Image& image = *this->images[pass.depthAttachment->image.index].image;
SOPHIA_ASSERT(image.getExtent().width == extent.width &&
image.getExtent().height == extent.height,
"Pass", pass.name,
"has a depth attachment of a different size");
depthAttachment.imageView = image.getView();
depthAttachment.imageLayout =
vk::ImageLayout::eDepthStencilAttachmentOptimal;
depthAttachment.loadOp = pass.depthAttachment->loadOp;
depthAttachment.storeOp = vk::AttachmentStoreOp::eStore;
depthAttachment.clearValue.depthStencil =
vk::ClearDepthStencilValue{pass.depthAttachment->clearDepth, 0};
renderingInfo.pDepthAttachment = &depthAttachment;
}
commandBuffer.beginRendering(renderingInfo);
vk::Viewport viewport{0.0f,
@@ -143,6 +166,15 @@ RenderGraph::PassBuilder& RenderGraph::PassBuilder::writeColor(
return *this;
}
RenderGraph::PassBuilder& RenderGraph::PassBuilder::writeDepth(
ImageRef image, vk::AttachmentLoadOp loadOp, float clearDepth) {
SOPHIA_ASSERT(!this->pass.depthAttachment, "Pass", this->pass.name,
"already has a depth attachment");
this->use(image, Access::DepthWrite);
this->pass.depthAttachment = DepthAttachment{image, loadOp, clearDepth};
return *this;
}
RenderGraph::PassBuilder& RenderGraph::PassBuilder::sample(ImageRef image) {
return this->use(image, Access::SampledRead);
}
+25 -4
View File
@@ -2,10 +2,13 @@
#include <array>
#include <functional>
#include <optional>
#include <sophia/types.hpp>
#include <string>
#include <vector>
#include <vulkan/vulkan.hpp>
// After Vulkan, which it expects to already be declared.
#include <tracy/TracyVulkan.hpp>
#include "vulkan/access.hpp"
#include "vulkan/image.hpp"
@@ -31,7 +34,7 @@ using ClearColor = std::array<float, 4>;
* buffer. Passes run in the order they were added; the graph's job is to
* work out the barriers and layout transitions between them from what each
* pass says it does to each image, and to begin/end rendering for passes that
* write color attachments.
* write color or depth attachments.
*
* Built fresh every frame:
*
@@ -53,7 +56,8 @@ class RenderGraph {
using SetupFn = std::function<void(PassBuilder&)>;
using ExecuteFn = std::function<void(vk::CommandBuffer)>;
RenderGraph() = default;
explicit RenderGraph(TracyVkCtx tracyContext = nullptr)
: tracyContext{tracyContext} {}
RenderGraph(const RenderGraph&) = delete;
RenderGraph& operator=(const RenderGraph&) = delete;
@@ -67,8 +71,8 @@ class RenderGraph {
/**
* Adds a pass. `setup` runs immediately and declares what the pass does to
* images; `execute` runs later, from execute(), with the barriers already
* recorded and (if the pass writes color) rendering begun. `name` labels
* the pass's commands in debugging tools such as RenderDoc.
* recorded and (if the pass writes color or depth) rendering begun. `name`
* labels the pass's commands in debugging tools such as RenderDoc.
*/
void addPass(std::string name, const SetupFn& setup, ExecuteFn execute);
@@ -89,10 +93,17 @@ class RenderGraph {
ClearColor clearColor;
};
struct DepthAttachment {
ImageRef image;
vk::AttachmentLoadOp loadOp;
float clearDepth;
};
struct Pass {
std::string name;
std::vector<ImageUse> uses;
std::vector<ColorAttachment> colorAttachments;
std::optional<DepthAttachment> depthAttachment;
ExecuteFn execute;
};
@@ -113,6 +124,7 @@ class RenderGraph {
void recordPass(vk::CommandBuffer commandBuffer, Pass& pass);
void recordRendering(vk::CommandBuffer commandBuffer, Pass& pass);
TracyVkCtx tracyContext;
std::vector<ImportedImage> images;
std::vector<Pass> passes;
};
@@ -129,6 +141,15 @@ class RenderGraph::PassBuilder {
vk::AttachmentLoadOp loadOp = vk::AttachmentLoadOp::eClear,
ClearColor clearColor = {0.f, 0.f, 0.f, 1.f});
/**
* Renders with `image` as the depth attachment, which must be the same size
* as any color attachments. At most one per pass.
*/
PassBuilder& writeDepth(
ImageRef image,
vk::AttachmentLoadOp loadOp = vk::AttachmentLoadOp::eClear,
float clearDepth = 1.f);
/** Samples `image` in a shader. */
PassBuilder& sample(ImageRef image);
+9
View File
@@ -0,0 +1,9 @@
#include "renderer/renderer.hpp"
namespace sophia {
Renderer::Renderer() {}
Renderer::~Renderer() {}
} // namespace sophia
+91
View File
@@ -0,0 +1,91 @@
#pragma once
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <sophia/types.hpp>
#include <string>
#include <vector>
#include "vulkan/buffer.hpp"
namespace sophia {
struct DrawPacket {
/* Geometry */
// BufferHandle vertexBuffer;
// BufferHandle indexBuffer;
u32 indexCount;
u32 firstIndex;
/* Shader & state */
// PipelineHandle pipelineState; // Contains shaders, blend state, depth
// settings
/* Bindings */
// DescriptorSetHandle resourceBindings; // Textures, Uniform Buffers,
// Storage Buffers
/* Transform / Constants */
u32 pushConstantData[16];
};
struct RenderView {
mat4 view;
mat4 projection;
vec2 viewport;
RenderTargetHandle target;
};
// struct ComputePacket {
// ComputePipelineHandle pipeline;
// DescriptorSetHandle
// resourceBindings; // Includes storage buffers, uniforms, textures
// // Grid dimensions
// uint32_t groupCountX = 1;
// uint32_t groupCountY = 1;
// uint32_t groupCountZ = 1;
// // Optional push constants for dynamic per-dispatch parameters
// uint8_t pushConstants[64];
// uint32_t pushConstantSize = 0;
// };
// !TODO move to render graph
enum class RenderPassType { Graphics, Compute };
// !TODO move to render graph (???)
struct RenderPass {
std::string name;
RenderPassType type;
// Declared for automatic barrier injection & resource synchronization
std::vector<Buffer> readBuffers; // BufferHandle instead?
std::vector<Buffer> writeBuffers; // BufferHandle instead?
// Commands in this pass
// std::vector<ComputePacket> computeDispatches;
std::vector<DrawPacket> opaqueDrawPackets;
std::vector<DrawPacket> transparentDrawPackets;
};
struct RenderPacket {
RenderView view;
std::vector<RenderPass> passes;
};
class Renderer {
public:
Renderer(const Renderer&) = delete;
Renderer& operator=(const Renderer&) = delete;
Renderer();
~Renderer();
// PipelineHandle createPipeline();
private:
};
} // namespace sophia
+116 -40
View File
@@ -13,73 +13,149 @@ SceneRenderer::SceneRenderer(const SceneRegistry& sceneRegistry,
vk::Format colorFormat)
: sceneRegistry{sceneRegistry},
resources{resources},
spriteRenderSystem{device, colorFormat, resources} {}
meshRenderSystem{device, colorFormat,
resources.renderTargetPool.getDepthFormat(), resources},
spriteRenderSystem{device, colorFormat,
resources.renderTargetPool.getDepthFormat(),
resources} {}
void SceneRenderer::beginFrame(u32 frameIndex) {
ZoneScoped;
this->meshRenderSystem.beginFrame(frameIndex);
this->spriteRenderSystem.beginFrame(frameIndex);
}
void SceneRenderer::render(vk::CommandBuffer commandBuffer,
const SceneView& sceneView, Entity camera) {
const SceneView& sceneView, Entity camera,
vk::Extent2D extent) {
ZoneScoped;
SOPHIA_ASSERT(camera.hasComponent<CameraComponent>(),
"camera does not have camera component!");
vk::Extent2D extent =
this->resources.renderTargetPool.get(sceneView.target).getExtent();
float aspect =
static_cast<float>(extent.width) / static_cast<float>(extent.height);
glm::mat4 viewProjection =
camera.getComponent<CameraComponent>().getViewProjection(
camera.getComponent<TransformComponent>(), aspect);
glm::mat4 view =
CameraComponent::getView(camera.getComponent<TransformComponent>());
glm::mat4 projection =
camera.getComponent<CameraComponent>().getProjection(aspect);
renderSprites(commandBuffer, this->sceneRegistry.get(sceneView.scene),
viewProjection);
const Scene& scene = this->sceneRegistry.get(sceneView.scene);
glm::mat4 viewProjection = projection * view;
// TODO: meshes. Group MeshComponent entities by mesh and draw each group
// (instanced), as sprites are grouped by texture.
// Opaque first, so sprites blend over the meshes behind them.
renderMeshes(commandBuffer, scene, viewProjection);
renderSprites(commandBuffer, scene, view, viewProjection);
}
void SceneRenderer::renderMeshes(vk::CommandBuffer commandBuffer,
const Scene& scene,
const glm::mat4& viewProjection) {
ZoneScoped;
this->meshDrawItems.clear();
{
ZoneScopedN("meshes: gather");
auto meshes =
scene.registry.view<const TransformComponent, const MeshComponent>();
for (auto [entity, transform, mesh] : meshes.each()) {
if (!this->resources.meshPool.isAlive(mesh.handle)) {
continue;
}
this->meshDrawItems.push_back(
{mesh.handle, {transform.mat4(), mesh.color}});
}
}
{
ZoneScopedN("meshes: sort");
// Opaque, so order only matters for batching: one batch per mesh.
std::ranges::sort(this->meshDrawItems, {},
[](const MeshDrawItem& item) { return item.mesh; });
}
{
ZoneScopedN("meshes: batch");
this->meshInstances.clear();
this->meshBatches.clear();
for (const MeshDrawItem& item : this->meshDrawItems) {
auto index = static_cast<u32>(this->meshInstances.size());
this->meshInstances.push_back(item.instance);
if (this->meshBatches.empty() ||
this->meshBatches.back().mesh != item.mesh) {
this->meshBatches.push_back({item.mesh, index, 0});
}
this->meshBatches.back().instanceCount++;
}
}
TracyPlot("mesh instances", static_cast<int64_t>(this->meshInstances.size()));
TracyPlot("mesh batches", static_cast<int64_t>(this->meshBatches.size()));
this->meshRenderSystem.render(commandBuffer, viewProjection,
this->meshInstances, this->meshBatches);
}
void SceneRenderer::renderSprites(vk::CommandBuffer commandBuffer,
const Scene& scene,
const Scene& scene, const glm::mat4& view,
const glm::mat4& viewProjection) {
ZoneScoped;
this->spriteDrawItems.clear();
auto view =
scene.registry.view<const TransformComponent, const SpriteComponent>();
for (auto [entity, transform, sprite] : view.each()) {
TextureHandle texture = this->resources.texturePool.isAlive(sprite.texture)
? sprite.texture
: this->resources.whiteTexture;
{
ZoneScopedN("sprites: gather");
auto sprites =
scene.registry.view<const TransformComponent, const SpriteComponent>();
for (auto [entity, transform, sprite] : sprites.each()) {
TextureHandle texture =
this->resources.texturePool.isAlive(sprite.texture)
? sprite.texture
: this->resources.whiteTexture;
this->spriteDrawItems.push_back(
{sprite.sortOrder,
transform.position.z,
texture,
{sprite.getModel(transform), sprite.color, sprite.uvRect}});
}
// Distance in front of the camera, which looks down view-space -Z.
float depth = -(view * glm::vec4{transform.position, 1.f}).z;
// Texture is the last key so that sprites whose order doesn't matter
// relative to each other still end up in as few batches as possible.
std::ranges::sort(this->spriteDrawItems, {}, [](const SpriteDrawItem& item) {
return std::tuple{item.sortOrder, item.depth, item.texture};
});
this->spriteInstances.clear();
this->spriteBatches.clear();
for (const SpriteDrawItem& item : this->spriteDrawItems) {
auto index = static_cast<u32>(this->spriteInstances.size());
this->spriteInstances.push_back(item.instance);
if (this->spriteBatches.empty() ||
this->spriteBatches.back().texture != item.texture) {
this->spriteBatches.push_back({item.texture, index, 0});
this->spriteDrawItems.push_back(
{sprite.sortOrder,
depth,
texture,
{sprite.getModel(transform), sprite.color, sprite.uvRect}});
}
this->spriteBatches.back().instanceCount++;
}
{
ZoneScopedN("sprites: sort");
// Within a sortOrder, back to front, so nearer sprites blend over farther
// ones. Texture is the last key so that sprites whose order doesn't
// matter relative to each other still end up in as few batches as
// possible.
std::ranges::sort(
this->spriteDrawItems, {}, [](const SpriteDrawItem& item) {
return std::tuple{item.sortOrder, -item.depth, item.texture};
});
}
{
ZoneScopedN("sprites: batch");
this->spriteInstances.clear();
this->spriteBatches.clear();
for (const SpriteDrawItem& item : this->spriteDrawItems) {
auto index = static_cast<u32>(this->spriteInstances.size());
this->spriteInstances.push_back(item.instance);
if (this->spriteBatches.empty() ||
this->spriteBatches.back().texture != item.texture) {
this->spriteBatches.push_back({item.texture, index, 0});
}
this->spriteBatches.back().instanceCount++;
}
}
TracyPlot("sprite instances",
static_cast<int64_t>(this->spriteInstances.size()));
TracyPlot("sprite batches", static_cast<int64_t>(this->spriteBatches.size()));
this->spriteRenderSystem.render(commandBuffer, viewProjection,
this->spriteInstances, this->spriteBatches);
}
+16 -3
View File
@@ -4,6 +4,7 @@
#include <sophia/scene_view.hpp>
#include <vector>
#include "renderer/mesh_render_system.hpp"
#include "renderer/sprite_render_system.hpp"
#include "resources/resource_registry.hpp"
@@ -27,27 +28,39 @@ class SceneRenderer {
// Records `sceneView` as seen through `camera` (an entity of the view's
// scene with a CameraComponent) into `commandBuffer`. Rendering into the
// view's target must already have begun.
// view's target, which is `extent` in size, must already have begun.
void render(vk::CommandBuffer commandBuffer, const SceneView& sceneView,
Entity camera);
Entity camera, vk::Extent2D extent);
private:
struct MeshDrawItem {
MeshHandle mesh;
MeshRenderSystem::Instance instance;
};
struct SpriteDrawItem {
s32 sortOrder;
// Distance in front of the camera.
float depth;
TextureHandle texture;
SpriteRenderSystem::Instance instance;
};
void renderMeshes(vk::CommandBuffer commandBuffer, const Scene& scene,
const glm::mat4& viewProjection);
void renderSprites(vk::CommandBuffer commandBuffer, const Scene& scene,
const glm::mat4& viewProjection);
const glm::mat4& view, const glm::mat4& viewProjection);
const SceneRegistry& sceneRegistry;
ResourceRegistry& resources;
MeshRenderSystem meshRenderSystem;
SpriteRenderSystem spriteRenderSystem;
// Reused across frames to avoid reallocating.
std::vector<MeshDrawItem> meshDrawItems;
std::vector<MeshRenderSystem::Instance> meshInstances;
std::vector<MeshRenderSystem::Batch> meshBatches;
std::vector<SpriteDrawItem> spriteDrawItems;
std::vector<SpriteRenderSystem::Instance> spriteInstances;
std::vector<SpriteRenderSystem::Batch> spriteBatches;
+15 -10
View File
@@ -16,11 +16,12 @@ constexpr u32 VERTICES_PER_SPRITE = 6;
} // namespace
SpriteRenderSystem::SpriteRenderSystem(Device& device, vk::Format colorFormat,
vk::Format depthFormat,
ResourceRegistry& resources)
: device{device}, resources{resources} {
createDescriptors();
createPipelineLayout();
createPipeline(colorFormat);
createPipeline(colorFormat, depthFormat);
createInstanceBuffers();
}
@@ -147,7 +148,8 @@ void SpriteRenderSystem::createPipelineLayout() {
}
}
void SpriteRenderSystem::createPipeline(vk::Format colorFormat) {
void SpriteRenderSystem::createPipeline(vk::Format colorFormat,
vk::Format depthFormat) {
auto vertexShader = Shader::Builder()
.fromSPIRV(shaders::sprite_vert_spv)
.setStage(ShaderStage::VERTEX)
@@ -172,14 +174,17 @@ void SpriteRenderSystem::createPipeline(vk::Format colorFormat) {
attributes.push_back({5, 0, vk::Format::eR32G32B32A32Sfloat,
static_cast<u32>(offsetof(Instance, uvRect))});
this->graphicsPipeline = GraphicsPipeline::Builder(this->device)
.setVertexShader(*vertexShader)
.setFragmentShader(*fragmentShader)
.setPipelineLayout(this->pipelineLayout.get())
.setColorAttachmentFormats({colorFormat})
.setVertexInput(bindings, attributes)
.setAlphaBlending()
.build();
this->graphicsPipeline =
GraphicsPipeline::Builder(this->device)
.setVertexShader(*vertexShader)
.setFragmentShader(*fragmentShader)
.setPipelineLayout(this->pipelineLayout.get())
.setColorAttachmentFormats({colorFormat})
.setDepthAttachmentFormat(depthFormat)
.setVertexInput(bindings, attributes)
.setAlphaBlending()
.setDepthTest(true, false, vk::CompareOp::eLessOrEqual)
.build();
}
void SpriteRenderSystem::createInstanceBuffers() {
+4 -2
View File
@@ -20,6 +20,8 @@ namespace sophia {
/**
* Draws batches of textured quads. Knows nothing about scenes: callers hand
* it instances already in draw order, grouped into runs that share a texture.
* Sprites are depth tested, so opaque geometry in front hides them, but
* don't write depth, since they blend.
*
* Instances are written to a per-frame host-visible buffer, so every
* render() call within one frame appends to it; call beginFrame() once per
@@ -47,7 +49,7 @@ class SpriteRenderSystem {
SpriteRenderSystem& operator=(const SpriteRenderSystem&) = delete;
SpriteRenderSystem(Device& device, vk::Format colorFormat,
ResourceRegistry& resources);
vk::Format depthFormat, ResourceRegistry& resources);
~SpriteRenderSystem();
void beginFrame(u32 frameIndex);
@@ -68,7 +70,7 @@ class SpriteRenderSystem {
void createDescriptors();
void createPipelineLayout();
void createPipeline(vk::Format colorFormat);
void createPipeline(vk::Format colorFormat, vk::Format depthFormat);
void createInstanceBuffers();
vk::DescriptorSet getDescriptorSet(TextureHandle handle);
+18 -28
View File
@@ -5,35 +5,23 @@
namespace sophia {
std::vector<vk::VertexInputBindingDescription>
Mesh::Vertex::getBindingDescriptions() {
std::vector<vk::VertexInputBindingDescription> bindingDescriptions(1);
bindingDescriptions[0].binding = 0;
bindingDescriptions[0].stride = sizeof(Vertex);
bindingDescriptions[0].inputRate = vk::VertexInputRate::eVertex;
return bindingDescriptions;
std::vector<vk::VertexInputBindingDescription> Mesh::getBindingDescriptions() {
return {{0, sizeof(MeshVertex), vk::VertexInputRate::eVertex}};
}
std::vector<vk::VertexInputAttributeDescription>
Mesh::Vertex::getAttributeDescriptions() {
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions{};
attributeDescriptions.push_back(
{0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, position)});
attributeDescriptions.push_back(
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color)});
// attributeDescriptions.push_back(
// {2, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, normal)});
// attributeDescriptions.push_back(
// {3, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, uv)});
return attributeDescriptions;
Mesh::getAttributeDescriptions() {
return {
{0, 0, vk::Format::eR32G32B32Sfloat, offsetof(MeshVertex, position)},
{1, 0, vk::Format::eR32G32B32Sfloat, offsetof(MeshVertex, normal)},
{2, 0, vk::Format::eR32G32Sfloat, offsetof(MeshVertex, uv)},
{3, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(MeshVertex, color)},
};
}
Mesh::Mesh(Device& device, const Builder& builder) : device{device} {
createVertexBuffers(builder.vertices);
createIndexBuffers(builder.indices);
Mesh::Mesh(Device& device, const MeshData& data) : device{device} {
createVertexBuffers(data.vertices);
createIndexBuffers(data.indices);
}
Mesh::~Mesh() = default;
@@ -49,15 +37,17 @@ void Mesh::bind(vk::CommandBuffer commandBuffer) const {
}
}
void Mesh::draw(vk::CommandBuffer commandBuffer) const {
void Mesh::draw(vk::CommandBuffer commandBuffer, u32 instanceCount,
u32 firstInstance) const {
if (this->hasIndexBuffer) {
commandBuffer.drawIndexed(this->indexCount, 1, 0, 0, 0);
commandBuffer.drawIndexed(this->indexCount, instanceCount, 0, 0,
firstInstance);
} else {
commandBuffer.draw(this->vertexCount, 1, 0, 0);
commandBuffer.draw(this->vertexCount, instanceCount, 0, firstInstance);
}
}
void Mesh::createVertexBuffers(const std::vector<Vertex>& vertices) {
void Mesh::createVertexBuffers(const std::vector<MeshVertex>& vertices) {
this->vertexCount = static_cast<u32>(vertices.size());
SOPHIA_ASSERT(this->vertexCount >= 3, "vertex count must be at least 3");
+10 -28
View File
@@ -3,6 +3,7 @@
#include <memory>
#include <sophia/handles.hpp>
#include <sophia/math.hpp>
#include <sophia/mesh_data.hpp>
#include <sophia/types.hpp>
#include <vector>
@@ -13,43 +14,24 @@ namespace sophia {
class Mesh {
public:
struct Vertex {
glm::vec2 position{};
glm::vec3 color{};
// glm::vec3 normal{};
// glm::vec2 uv{};
// Binding 0 (per vertex, MeshVertex) for pipelines that draw meshes.
static std::vector<vk::VertexInputBindingDescription>
getBindingDescriptions();
static std::vector<vk::VertexInputAttributeDescription>
getAttributeDescriptions();
static std::vector<vk::VertexInputBindingDescription>
getBindingDescriptions();
static std::vector<vk::VertexInputAttributeDescription>
getAttributeDescriptions();
// bool operator==(const Vertex& other) const {
// return position == other.position && color == other.color;
// }
};
struct Builder {
std::vector<Vertex> vertices{};
std::vector<uint32_t> indices{};
// void loadModel(const std::string& filepath);
};
Mesh(Device& device, const Mesh::Builder& builder);
Mesh(Device& device, const MeshData& data);
~Mesh();
Mesh(const Mesh&) = delete;
Mesh& operator=(const Mesh&) = delete;
// static std::unique_ptr<Mesh> createMeshFromFile(
// Device& device, const std::string& filepath);
void bind(vk::CommandBuffer commandBuffer) const;
void draw(vk::CommandBuffer commandBuffer) const;
void draw(vk::CommandBuffer commandBuffer, u32 instanceCount = 1,
u32 firstInstance = 0) const;
private:
void createVertexBuffers(const std::vector<Vertex>& vertices);
void createVertexBuffers(const std::vector<MeshVertex>& vertices);
void createIndexBuffers(const std::vector<u32>& indices);
Device& device;
@@ -5,10 +5,16 @@
namespace sophia {
RenderTargetPool::RenderTargetPool(Device& device, vk::Format format)
: device{device}, format{format} {}
: device{device},
format{format},
// Depth-only formats, so the images have no stencil aspect to track.
depthFormat{device.findSupportedFormat(
{vk::Format::eD32Sfloat, vk::Format::eX8D24UnormPack32},
vk::ImageTiling::eOptimal,
vk::FormatFeatureFlagBits::eDepthStencilAttachment)} {}
RenderTargetHandle RenderTargetPool::create(u32 width, u32 height) {
return pool.create(device, format, width, height);
return pool.create(device, format, depthFormat, width, height);
}
void RenderTargetPool::release(RenderTargetHandle handle) {
@@ -24,11 +24,15 @@ class RenderTargetPool {
bool isAlive(RenderTargetHandle handle) const { return pool.isAlive(handle); }
vk::Format getFormat() const { return format; }
vk::Format getDepthFormat() const { return depthFormat; }
void applyPendingResizes();
private:
Device& device;
vk::Format format;
vk::Format depthFormat;
Pool<RenderTarget> pool{"RenderTarget"};
};
+55
View File
@@ -0,0 +1,55 @@
#include <array>
#include <sophia/primitives.hpp>
namespace sophia::primitives {
MeshData cube(float size, vec4 color) {
struct Face {
vec3 normal;
// Axes across the face, with u x v = normal, so corners taken
// counter-clockwise in (u, v) wind counter-clockwise seen from outside.
vec3 u;
vec3 v;
};
constexpr std::array<Face, 6> FACES{{
{{1.f, 0.f, 0.f}, {0.f, 0.f, -1.f}, {0.f, 1.f, 0.f}},
{{-1.f, 0.f, 0.f}, {0.f, 0.f, 1.f}, {0.f, 1.f, 0.f}},
{{0.f, 1.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 0.f, -1.f}},
{{0.f, -1.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 0.f, 1.f}},
{{0.f, 0.f, 1.f}, {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}},
{{0.f, 0.f, -1.f}, {-1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}},
}};
constexpr std::array<vec2, 4> CORNERS{vec2{-1.f, -1.f}, vec2{1.f, -1.f},
vec2{1.f, 1.f}, vec2{-1.f, 1.f}};
float half = size / 2.f;
MeshData data;
data.vertices.reserve(FACES.size() * CORNERS.size());
data.indices.reserve(FACES.size() * 6);
for (const Face& face : FACES) {
auto base = static_cast<u32>(data.vertices.size());
for (vec2 corner : CORNERS) {
MeshVertex vertex;
vertex.position =
(face.normal + corner.x * face.u + corner.y * face.v) * half;
vertex.normal = face.normal;
// Texture v runs down while the face's v runs up.
vertex.uv = {(corner.x + 1.f) / 2.f, (1.f - corner.y) / 2.f};
vertex.color = color;
data.vertices.push_back(vertex);
}
for (u32 index : {0u, 1u, 2u, 2u, 3u, 0u}) {
data.indices.push_back(base + index);
}
}
return data;
}
} // namespace sophia::primitives
+13 -4
View File
@@ -4,9 +4,9 @@
namespace sophia {
RenderTarget::RenderTarget(Device& device, vk::Format format, u32 width,
u32 height)
: device{device}, format{format} {
RenderTarget::RenderTarget(Device& device, vk::Format format,
vk::Format depthFormat, u32 width, u32 height)
: device{device}, format{format}, depthFormat{depthFormat} {
create(std::max(width, 1u), std::max(height, 1u));
}
@@ -46,8 +46,17 @@ void RenderTarget::create(u32 width, u32 height) {
.asColorAttachment()
.withView()
.build();
this->depthImage = Image::Builder(this->device)
.setExtent(width, height)
.asDepthAttachment()
.setFormat(this->depthFormat)
.withView()
.build();
}
void RenderTarget::destroy() { this->image.reset(); }
void RenderTarget::destroy() {
this->image.reset();
this->depthImage.reset();
}
} // namespace sophia
+7 -3
View File
@@ -11,20 +11,22 @@
namespace sophia {
/**
* A place rendering can go. Currently always backed by an offscreen color
* image.
* A place rendering can go: an offscreen color image, plus a depth image of
* the same size.
*
* Owned by the ResourceRegistry and addressed through a RenderTargetHandle.
*/
class RenderTarget {
public:
RenderTarget(Device& device, vk::Format format, u32 width, u32 height);
RenderTarget(Device& device, vk::Format format, vk::Format depthFormat,
u32 width, u32 height);
~RenderTarget();
RenderTarget(const RenderTarget&) = delete;
RenderTarget& operator=(const RenderTarget&) = delete;
Image& getImage() const { return *this->image; }
Image& getDepthImage() const { return *this->depthImage; }
vk::Extent2D getExtent() const;
u32 getVersion() const { return this->version; }
@@ -43,8 +45,10 @@ class RenderTarget {
Device& device;
vk::Format format;
vk::Format depthFormat;
std::unique_ptr<Image> image;
std::unique_ptr<Image> depthImage;
std::optional<vk::Extent2D> pendingExtent;
u32 version = 0;
+6 -12
View File
@@ -14,7 +14,7 @@ MeshHandle ResourceRegistryRef::load<Mesh>(const std::string& path) {
(void)path;
SOPHIA_ASSERT(false,
"Mesh::load(path) is not implemented yet - no model file "
"format is supported; build one via Mesh::Builder for now");
"format is supported; build a MeshData instead");
return MeshHandle{};
}
@@ -40,6 +40,8 @@ TextureHandle ResourceRegistryRef::load<Texture>(const std::string& path) {
template <>
void ResourceRegistryRef::release<Mesh>(MeshHandle handle) {
// Frames in flight may still be drawing it.
registry->device.waitIdle();
registry->meshPool.release(handle);
}
@@ -57,17 +59,9 @@ void ResourceRegistryRef::release<Texture>(TextureHandle handle) {
registry->texturePool.release(handle);
}
MeshHandle ResourceRegistryRef::createResource(
std::type_identity<Mesh>, std::vector<CanvasVertex> vertices,
std::vector<u32> indices) {
Mesh::Builder builder{};
builder.vertices.reserve(vertices.size());
for (const CanvasVertex& vertex : vertices) {
builder.vertices.push_back({vertex.position, vertex.color});
}
builder.indices = std::move(indices);
return registry->meshPool.create(registry->device, builder);
MeshHandle ResourceRegistryRef::createResource(std::type_identity<Mesh>,
const MeshData& data) {
return registry->meshPool.create(registry->device, data);
}
RenderTargetHandle ResourceRegistryRef::createResource(
@@ -0,0 +1,9 @@
#include "scene/scene_render_packet_builder.hpp"
namespace sophia {
void SceneRenderPacketBuilder::build(SceneHandle sceneHandle,
RenderTargetHandle renderTargetHandle,
RenderPacket& renderPacket) {}
} // namespace sophia
@@ -0,0 +1,16 @@
#pragma once
#include <sophia/handles.hpp>
#include "renderer/renderer.hpp"
namespace sophia {
class SceneRenderPacketBuilder {
public:
static void build(SceneHandle sceneHandle,
RenderTargetHandle renderTargetHandle,
RenderPacket& renderPacket);
};
} // namespace sophia
+60 -89
View File
@@ -6,95 +6,66 @@
namespace sophia::shaders {
inline constexpr std::array<uint32_t, 355> fullscreen_vert_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000032,
0x00000000, 0x00020011, 0x00000001, 0x0006000b,
0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001,
0x0008000f, 0x00000000, 0x00000004, 0x6e69616d,
0x00000000, 0x00000018, 0x00000022, 0x0000002c,
0x00030003, 0x00000002, 0x000001c2, 0x000a0004,
0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70,
0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365,
0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f,
0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572,
0x00657669, 0x00040005, 0x00000004, 0x6e69616d,
0x00000000, 0x00050005, 0x0000000c, 0x69736f70,
0x6e6f6974, 0x00000073, 0x00030005, 0x00000015,
0x00736f70, 0x00060005, 0x00000018, 0x565f6c67,
0x65747265, 0x646e4978, 0x00007865, 0x00060005,
0x00000020, 0x505f6c67, 0x65567265, 0x78657472,
0x00000000, 0x00060006, 0x00000020, 0x00000000,
0x505f6c67, 0x7469736f, 0x006e6f69, 0x00070006,
0x00000020, 0x00000001, 0x505f6c67, 0x746e696f,
0x657a6953, 0x00000000, 0x00070006, 0x00000020,
0x00000002, 0x435f6c67, 0x4470696c, 0x61747369,
0x0065636e, 0x00070006, 0x00000020, 0x00000003,
0x435f6c67, 0x446c6c75, 0x61747369, 0x0065636e,
0x00030005, 0x00000022, 0x00000000, 0x00030005,
0x0000002c, 0x00007675, 0x00040047, 0x00000018,
0x0000000b, 0x0000002a, 0x00030047, 0x00000020,
0x00000002, 0x00050048, 0x00000020, 0x00000000,
0x0000000b, 0x00000000, 0x00050048, 0x00000020,
0x00000001, 0x0000000b, 0x00000001, 0x00050048,
0x00000020, 0x00000002, 0x0000000b, 0x00000003,
0x00050048, 0x00000020, 0x00000003, 0x0000000b,
0x00000004, 0x00040047, 0x0000002c, 0x0000001e,
0x00000000, 0x00020013, 0x00000002, 0x00030021,
0x00000003, 0x00000002, 0x00030016, 0x00000006,
0x00000020, 0x00040017, 0x00000007, 0x00000006,
0x00000002, 0x00040015, 0x00000008, 0x00000020,
0x00000000, 0x0004002b, 0x00000008, 0x00000009,
0x00000006, 0x0004001c, 0x0000000a, 0x00000007,
0x00000009, 0x00040020, 0x0000000b, 0x00000006,
0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c,
0x00000006, 0x0004002b, 0x00000006, 0x0000000d,
0xbf800000, 0x0005002c, 0x00000007, 0x0000000e,
0x0000000d, 0x0000000d, 0x0004002b, 0x00000006,
0x0000000f, 0x3f800000, 0x0005002c, 0x00000007,
0x00000010, 0x0000000f, 0x0000000d, 0x0005002c,
0x00000007, 0x00000011, 0x0000000d, 0x0000000f,
0x0005002c, 0x00000007, 0x00000012, 0x0000000f,
0x0000000f, 0x0009002c, 0x0000000a, 0x00000013,
0x0000000e, 0x00000010, 0x00000011, 0x00000011,
0x00000010, 0x00000012, 0x00040020, 0x00000014,
0x00000007, 0x00000007, 0x00040015, 0x00000016,
0x00000020, 0x00000001, 0x00040020, 0x00000017,
0x00000001, 0x00000016, 0x0004003b, 0x00000017,
0x00000018, 0x00000001, 0x00040020, 0x0000001a,
0x00000006, 0x00000007, 0x00040017, 0x0000001d,
0x00000006, 0x00000004, 0x0004002b, 0x00000008,
0x0000001e, 0x00000001, 0x0004001c, 0x0000001f,
0x00000006, 0x0000001e, 0x0006001e, 0x00000020,
0x0000001d, 0x00000006, 0x0000001f, 0x0000001f,
0x00040020, 0x00000021, 0x00000003, 0x00000020,
0x0004003b, 0x00000021, 0x00000022, 0x00000003,
0x0004002b, 0x00000016, 0x00000023, 0x00000000,
0x0004002b, 0x00000006, 0x00000025, 0x00000000,
0x00040020, 0x00000029, 0x00000003, 0x0000001d,
0x00040020, 0x0000002b, 0x00000003, 0x00000007,
0x0004003b, 0x0000002b, 0x0000002c, 0x00000003,
0x0004002b, 0x00000006, 0x0000002e, 0x3f000000,
0x00050036, 0x00000002, 0x00000004, 0x00000000,
0x00000003, 0x000200f8, 0x00000005, 0x0004003b,
0x00000014, 0x00000015, 0x00000007, 0x0003003e,
0x0000000c, 0x00000013, 0x0004003d, 0x00000016,
0x00000019, 0x00000018, 0x00050041, 0x0000001a,
0x0000001b, 0x0000000c, 0x00000019, 0x0004003d,
0x00000007, 0x0000001c, 0x0000001b, 0x0003003e,
0x00000015, 0x0000001c, 0x0004003d, 0x00000007,
0x00000024, 0x00000015, 0x00050051, 0x00000006,
0x00000026, 0x00000024, 0x00000000, 0x00050051,
0x00000006, 0x00000027, 0x00000024, 0x00000001,
0x00070050, 0x0000001d, 0x00000028, 0x00000026,
0x00000027, 0x00000025, 0x0000000f, 0x00050041,
0x00000029, 0x0000002a, 0x00000022, 0x00000023,
0x0003003e, 0x0000002a, 0x00000028, 0x0004003d,
0x00000007, 0x0000002d, 0x00000015, 0x0005008e,
0x00000007, 0x0000002f, 0x0000002d, 0x0000002e,
0x00050050, 0x00000007, 0x00000030, 0x0000002e,
0x0000002e, 0x00050081, 0x00000007, 0x00000031,
0x0000002f, 0x00000030, 0x0003003e, 0x0000002c,
0x00000031, 0x000100fd, 0x00010038,
0x07230203, 0x00010000, 0x000d000b, 0x00000032, 0x00000000, 0x00020011,
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0008000f, 0x00000000,
0x00000004, 0x6e69616d, 0x00000000, 0x00000018, 0x00000022, 0x0000002c,
0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f,
0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365,
0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63,
0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d,
0x00000000, 0x00050005, 0x0000000c, 0x69736f70, 0x6e6f6974, 0x00000073,
0x00030005, 0x00000015, 0x00736f70, 0x00060005, 0x00000018, 0x565f6c67,
0x65747265, 0x646e4978, 0x00007865, 0x00060005, 0x00000020, 0x505f6c67,
0x65567265, 0x78657472, 0x00000000, 0x00060006, 0x00000020, 0x00000000,
0x505f6c67, 0x7469736f, 0x006e6f69, 0x00070006, 0x00000020, 0x00000001,
0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, 0x00000020,
0x00000002, 0x435f6c67, 0x4470696c, 0x61747369, 0x0065636e, 0x00070006,
0x00000020, 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, 0x0065636e,
0x00030005, 0x00000022, 0x00000000, 0x00030005, 0x0000002c, 0x00007675,
0x00040047, 0x00000018, 0x0000000b, 0x0000002a, 0x00030047, 0x00000020,
0x00000002, 0x00050048, 0x00000020, 0x00000000, 0x0000000b, 0x00000000,
0x00050048, 0x00000020, 0x00000001, 0x0000000b, 0x00000001, 0x00050048,
0x00000020, 0x00000002, 0x0000000b, 0x00000003, 0x00050048, 0x00000020,
0x00000003, 0x0000000b, 0x00000004, 0x00040047, 0x0000002c, 0x0000001e,
0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002,
0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006,
0x00000002, 0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b,
0x00000008, 0x00000009, 0x00000006, 0x0004001c, 0x0000000a, 0x00000007,
0x00000009, 0x00040020, 0x0000000b, 0x00000006, 0x0000000a, 0x0004003b,
0x0000000b, 0x0000000c, 0x00000006, 0x0004002b, 0x00000006, 0x0000000d,
0xbf800000, 0x0005002c, 0x00000007, 0x0000000e, 0x0000000d, 0x0000000d,
0x0004002b, 0x00000006, 0x0000000f, 0x3f800000, 0x0005002c, 0x00000007,
0x00000010, 0x0000000f, 0x0000000d, 0x0005002c, 0x00000007, 0x00000011,
0x0000000d, 0x0000000f, 0x0005002c, 0x00000007, 0x00000012, 0x0000000f,
0x0000000f, 0x0009002c, 0x0000000a, 0x00000013, 0x0000000e, 0x00000010,
0x00000011, 0x00000011, 0x00000010, 0x00000012, 0x00040020, 0x00000014,
0x00000007, 0x00000007, 0x00040015, 0x00000016, 0x00000020, 0x00000001,
0x00040020, 0x00000017, 0x00000001, 0x00000016, 0x0004003b, 0x00000017,
0x00000018, 0x00000001, 0x00040020, 0x0000001a, 0x00000006, 0x00000007,
0x00040017, 0x0000001d, 0x00000006, 0x00000004, 0x0004002b, 0x00000008,
0x0000001e, 0x00000001, 0x0004001c, 0x0000001f, 0x00000006, 0x0000001e,
0x0006001e, 0x00000020, 0x0000001d, 0x00000006, 0x0000001f, 0x0000001f,
0x00040020, 0x00000021, 0x00000003, 0x00000020, 0x0004003b, 0x00000021,
0x00000022, 0x00000003, 0x0004002b, 0x00000016, 0x00000023, 0x00000000,
0x0004002b, 0x00000006, 0x00000025, 0x00000000, 0x00040020, 0x00000029,
0x00000003, 0x0000001d, 0x00040020, 0x0000002b, 0x00000003, 0x00000007,
0x0004003b, 0x0000002b, 0x0000002c, 0x00000003, 0x0004002b, 0x00000006,
0x0000002e, 0x3f000000, 0x00050036, 0x00000002, 0x00000004, 0x00000000,
0x00000003, 0x000200f8, 0x00000005, 0x0004003b, 0x00000014, 0x00000015,
0x00000007, 0x0003003e, 0x0000000c, 0x00000013, 0x0004003d, 0x00000016,
0x00000019, 0x00000018, 0x00050041, 0x0000001a, 0x0000001b, 0x0000000c,
0x00000019, 0x0004003d, 0x00000007, 0x0000001c, 0x0000001b, 0x0003003e,
0x00000015, 0x0000001c, 0x0004003d, 0x00000007, 0x00000024, 0x00000015,
0x00050051, 0x00000006, 0x00000026, 0x00000024, 0x00000000, 0x00050051,
0x00000006, 0x00000027, 0x00000024, 0x00000001, 0x00070050, 0x0000001d,
0x00000028, 0x00000026, 0x00000027, 0x00000025, 0x0000000f, 0x00050041,
0x00000029, 0x0000002a, 0x00000022, 0x00000023, 0x0003003e, 0x0000002a,
0x00000028, 0x0004003d, 0x00000007, 0x0000002d, 0x00000015, 0x0005008e,
0x00000007, 0x0000002f, 0x0000002d, 0x0000002e, 0x00050050, 0x00000007,
0x00000030, 0x0000002e, 0x0000002e, 0x00050081, 0x00000007, 0x00000031,
0x0000002f, 0x00000030, 0x0003003e, 0x0000002c, 0x00000031, 0x000100fd,
0x00010038,
};
} // namespace sophia::shaders
+9
View File
@@ -0,0 +1,9 @@
#version 450
layout (location = 0) in vec4 fragColor;
layout (location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor.rgb, 1.0);
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <array>
#include <cstdint>
namespace sophia::shaders {
inline constexpr std::array<uint32_t, 151> mesh_frag_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000014, 0x00000000, 0x00020011,
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000004,
0x00000004, 0x6e69616d, 0x00000000, 0x00000009, 0x0000000b, 0x00030010,
0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004,
0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c,
0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f,
0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005,
0x00000004, 0x6e69616d, 0x00000000, 0x00050005, 0x00000009, 0x4374756f,
0x726f6c6f, 0x00000000, 0x00050005, 0x0000000b, 0x67617266, 0x6f6c6f43,
0x00000072, 0x00040047, 0x00000009, 0x0000001e, 0x00000000, 0x00040047,
0x0000000b, 0x0000001e, 0x00000000, 0x00020013, 0x00000002, 0x00030021,
0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017,
0x00000007, 0x00000006, 0x00000004, 0x00040020, 0x00000008, 0x00000003,
0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, 0x00040020,
0x0000000a, 0x00000001, 0x00000007, 0x0004003b, 0x0000000a, 0x0000000b,
0x00000001, 0x00040017, 0x0000000c, 0x00000006, 0x00000003, 0x0004002b,
0x00000006, 0x0000000f, 0x3f800000, 0x00050036, 0x00000002, 0x00000004,
0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x00000007,
0x0000000d, 0x0000000b, 0x0008004f, 0x0000000c, 0x0000000e, 0x0000000d,
0x0000000d, 0x00000000, 0x00000001, 0x00000002, 0x00050051, 0x00000006,
0x00000010, 0x0000000e, 0x00000000, 0x00050051, 0x00000006, 0x00000011,
0x0000000e, 0x00000001, 0x00050051, 0x00000006, 0x00000012, 0x0000000e,
0x00000002, 0x00070050, 0x00000007, 0x00000013, 0x00000010, 0x00000011,
0x00000012, 0x0000000f, 0x0003003e, 0x00000009, 0x00000013, 0x000100fd,
0x00010038,
};
} // namespace sophia::shaders
+23
View File
@@ -0,0 +1,23 @@
#version 450
// Per vertex; layout must match MeshVertex. Normal and UV are unused until
// there is lighting and texturing.
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 uv;
layout (location = 3) in vec4 color;
// Per instance; layout must match MeshRenderSystem::Instance.
layout (location = 4) in mat4 model;
layout (location = 8) in vec4 instanceColor;
layout (location = 0) out vec4 fragColor;
layout (push_constant) uniform Push {
mat4 viewProjection;
} push;
void main() {
gl_Position = push.viewProjection * model * vec4(position, 1.0);
fragColor = color * instanceColor;
}
+80
View File
@@ -0,0 +1,80 @@
#pragma once
#include <array>
#include <cstdint>
namespace sophia::shaders {
inline constexpr std::array<uint32_t, 411> mesh_vert_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000032, 0x00000000, 0x00020011,
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x000d000f, 0x00000000,
0x00000004, 0x6e69616d, 0x00000000, 0x0000000d, 0x00000018, 0x0000001d,
0x00000027, 0x00000029, 0x0000002b, 0x0000002e, 0x00000031, 0x00030003,
0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45,
0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576,
0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65,
0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000,
0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, 0x78657472, 0x00000000,
0x00060006, 0x0000000b, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69,
0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, 0x746e696f, 0x657a6953,
0x00000000, 0x00070006, 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c,
0x61747369, 0x0065636e, 0x00070006, 0x0000000b, 0x00000003, 0x435f6c67,
0x446c6c75, 0x61747369, 0x0065636e, 0x00030005, 0x0000000d, 0x00000000,
0x00040005, 0x00000011, 0x68737550, 0x00000000, 0x00070006, 0x00000011,
0x00000000, 0x77656976, 0x6a6f7250, 0x69746365, 0x00006e6f, 0x00040005,
0x00000013, 0x68737570, 0x00000000, 0x00040005, 0x00000018, 0x65646f6d,
0x0000006c, 0x00050005, 0x0000001d, 0x69736f70, 0x6e6f6974, 0x00000000,
0x00050005, 0x00000027, 0x67617266, 0x6f6c6f43, 0x00000072, 0x00040005,
0x00000029, 0x6f6c6f63, 0x00000072, 0x00060005, 0x0000002b, 0x74736e69,
0x65636e61, 0x6f6c6f43, 0x00000072, 0x00040005, 0x0000002e, 0x6d726f6e,
0x00006c61, 0x00030005, 0x00000031, 0x00007675, 0x00030047, 0x0000000b,
0x00000002, 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, 0x00000000,
0x00050048, 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, 0x00050048,
0x0000000b, 0x00000002, 0x0000000b, 0x00000003, 0x00050048, 0x0000000b,
0x00000003, 0x0000000b, 0x00000004, 0x00030047, 0x00000011, 0x00000002,
0x00040048, 0x00000011, 0x00000000, 0x00000005, 0x00050048, 0x00000011,
0x00000000, 0x00000007, 0x00000010, 0x00050048, 0x00000011, 0x00000000,
0x00000023, 0x00000000, 0x00040047, 0x00000018, 0x0000001e, 0x00000004,
0x00040047, 0x0000001d, 0x0000001e, 0x00000000, 0x00040047, 0x00000027,
0x0000001e, 0x00000000, 0x00040047, 0x00000029, 0x0000001e, 0x00000003,
0x00040047, 0x0000002b, 0x0000001e, 0x00000008, 0x00040047, 0x0000002e,
0x0000001e, 0x00000001, 0x00040047, 0x00000031, 0x0000001e, 0x00000002,
0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016,
0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004,
0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b, 0x00000008,
0x00000009, 0x00000001, 0x0004001c, 0x0000000a, 0x00000006, 0x00000009,
0x0006001e, 0x0000000b, 0x00000007, 0x00000006, 0x0000000a, 0x0000000a,
0x00040020, 0x0000000c, 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c,
0x0000000d, 0x00000003, 0x00040015, 0x0000000e, 0x00000020, 0x00000001,
0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x00040018, 0x00000010,
0x00000007, 0x00000004, 0x0003001e, 0x00000011, 0x00000010, 0x00040020,
0x00000012, 0x00000009, 0x00000011, 0x0004003b, 0x00000012, 0x00000013,
0x00000009, 0x00040020, 0x00000014, 0x00000009, 0x00000010, 0x00040020,
0x00000017, 0x00000001, 0x00000010, 0x0004003b, 0x00000017, 0x00000018,
0x00000001, 0x00040017, 0x0000001b, 0x00000006, 0x00000003, 0x00040020,
0x0000001c, 0x00000001, 0x0000001b, 0x0004003b, 0x0000001c, 0x0000001d,
0x00000001, 0x0004002b, 0x00000006, 0x0000001f, 0x3f800000, 0x00040020,
0x00000025, 0x00000003, 0x00000007, 0x0004003b, 0x00000025, 0x00000027,
0x00000003, 0x00040020, 0x00000028, 0x00000001, 0x00000007, 0x0004003b,
0x00000028, 0x00000029, 0x00000001, 0x0004003b, 0x00000028, 0x0000002b,
0x00000001, 0x0004003b, 0x0000001c, 0x0000002e, 0x00000001, 0x00040017,
0x0000002f, 0x00000006, 0x00000002, 0x00040020, 0x00000030, 0x00000001,
0x0000002f, 0x0004003b, 0x00000030, 0x00000031, 0x00000001, 0x00050036,
0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005,
0x00050041, 0x00000014, 0x00000015, 0x00000013, 0x0000000f, 0x0004003d,
0x00000010, 0x00000016, 0x00000015, 0x0004003d, 0x00000010, 0x00000019,
0x00000018, 0x00050092, 0x00000010, 0x0000001a, 0x00000016, 0x00000019,
0x0004003d, 0x0000001b, 0x0000001e, 0x0000001d, 0x00050051, 0x00000006,
0x00000020, 0x0000001e, 0x00000000, 0x00050051, 0x00000006, 0x00000021,
0x0000001e, 0x00000001, 0x00050051, 0x00000006, 0x00000022, 0x0000001e,
0x00000002, 0x00070050, 0x00000007, 0x00000023, 0x00000020, 0x00000021,
0x00000022, 0x0000001f, 0x00050091, 0x00000007, 0x00000024, 0x0000001a,
0x00000023, 0x00050041, 0x00000025, 0x00000026, 0x0000000d, 0x0000000f,
0x0003003e, 0x00000026, 0x00000024, 0x0004003d, 0x00000007, 0x0000002a,
0x00000029, 0x0004003d, 0x00000007, 0x0000002c, 0x0000002b, 0x00050085,
0x00000007, 0x0000002d, 0x0000002a, 0x0000002c, 0x0003003e, 0x00000027,
0x0000002d, 0x000100fd, 0x00010038,
};
} // namespace sophia::shaders
+2 -2
View File
@@ -1,9 +1,9 @@
#version 450
layout (location = 0) in vec3 fragColor;
layout (location = 0) in vec4 fragColor;
layout (location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor, 1.0);
outColor = fragColor;
}
@@ -5,31 +5,36 @@
namespace sophia::shaders {
inline constexpr std::array<uint32_t, 143> model_render_system_frag_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000013, 0x00000000, 0x00020011,
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000004,
0x00000004, 0x6e69616d, 0x00000000, 0x00000009, 0x0000000c, 0x00030010,
0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004,
0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c,
0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f,
0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005,
0x00000004, 0x6e69616d, 0x00000000, 0x00050005, 0x00000009, 0x4374756f,
0x726f6c6f, 0x00000000, 0x00050005, 0x0000000c, 0x67617266, 0x6f6c6f43,
0x00000072, 0x00040047, 0x00000009, 0x0000001e, 0x00000000, 0x00040047,
0x0000000c, 0x0000001e, 0x00000000, 0x00020013, 0x00000002, 0x00030021,
0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017,
0x00000007, 0x00000006, 0x00000004, 0x00040020, 0x00000008, 0x00000003,
0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, 0x00040017,
0x0000000a, 0x00000006, 0x00000003, 0x00040020, 0x0000000b, 0x00000001,
0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, 0x00000001, 0x0004002b,
0x00000006, 0x0000000e, 0x3f800000, 0x00050036, 0x00000002, 0x00000004,
0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x0000000a,
0x0000000d, 0x0000000c, 0x00050051, 0x00000006, 0x0000000f, 0x0000000d,
0x00000000, 0x00050051, 0x00000006, 0x00000010, 0x0000000d, 0x00000001,
0x00050051, 0x00000006, 0x00000011, 0x0000000d, 0x00000002, 0x00070050,
0x00000007, 0x00000012, 0x0000000f, 0x00000010, 0x00000011, 0x0000000e,
0x0003003e, 0x00000009, 0x00000012, 0x000100fd, 0x00010038,
inline constexpr std::array<uint32_t, 113> model_render_system_frag_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x0000000d,
0x00000000, 0x00020011, 0x00000001, 0x0006000b,
0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001,
0x0007000f, 0x00000004, 0x00000004, 0x6e69616d,
0x00000000, 0x00000009, 0x0000000b, 0x00030010,
0x00000004, 0x00000007, 0x00030003, 0x00000002,
0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f,
0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c,
0x7269645f, 0x69746365, 0x00006576, 0x00080004,
0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63,
0x69645f65, 0x74636572, 0x00657669, 0x00040005,
0x00000004, 0x6e69616d, 0x00000000, 0x00050005,
0x00000009, 0x4374756f, 0x726f6c6f, 0x00000000,
0x00050005, 0x0000000b, 0x67617266, 0x6f6c6f43,
0x00000072, 0x00040047, 0x00000009, 0x0000001e,
0x00000000, 0x00040047, 0x0000000b, 0x0000001e,
0x00000000, 0x00020013, 0x00000002, 0x00030021,
0x00000003, 0x00000002, 0x00030016, 0x00000006,
0x00000020, 0x00040017, 0x00000007, 0x00000006,
0x00000004, 0x00040020, 0x00000008, 0x00000003,
0x00000007, 0x0004003b, 0x00000008, 0x00000009,
0x00000003, 0x00040020, 0x0000000a, 0x00000001,
0x00000007, 0x0004003b, 0x0000000a, 0x0000000b,
0x00000001, 0x00050036, 0x00000002, 0x00000004,
0x00000000, 0x00000003, 0x000200f8, 0x00000005,
0x0004003d, 0x00000007, 0x0000000c, 0x0000000b,
0x0003003e, 0x00000009, 0x0000000c, 0x000100fd,
0x00010038,
};
} // namespace sophia::shaders
+5 -4
View File
@@ -1,9 +1,10 @@
#version 450
layout (location = 0) in vec2 position;
layout (location = 1) in vec3 color;
// Per vertex; locations match Mesh::getAttributeDescriptions().
layout (location = 0) in vec3 position;
layout (location = 3) in vec4 color;
layout (location = 0) out vec3 fragColor;
layout (location = 0) out vec4 fragColor;
layout (push_constant) uniform Push {
mat4 transform;
@@ -11,6 +12,6 @@ layout (push_constant) uniform Push {
} push;
void main() {
gl_Position = vec4(push.transform * vec4(position, 0.0, 1.0));
gl_Position = push.transform * vec4(position, 1.0);
fragColor = color;
}
@@ -5,12 +5,12 @@
namespace sophia::shaders {
inline constexpr std::array<uint32_t, 345> model_render_system_vert_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000029, 0x00000000, 0x00020011,
inline constexpr std::array<uint32_t, 338> model_render_system_vert_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000027, 0x00000000, 0x00020011,
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0009000f, 0x00000000,
0x00000004, 0x6e69616d, 0x00000000, 0x0000000d, 0x00000019, 0x00000025,
0x00000027, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47,
0x00000004, 0x6e69616d, 0x00000000, 0x0000000d, 0x00000019, 0x00000023,
0x00000025, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47,
0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f,
0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45,
0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004,
@@ -24,8 +24,8 @@ inline constexpr std::array<uint32_t, 345> model_render_system_vert_spv = {
0x00060006, 0x00000011, 0x00000000, 0x6e617274, 0x726f6673, 0x0000006d,
0x00050006, 0x00000011, 0x00000001, 0x6f6c6f63, 0x00000072, 0x00040005,
0x00000013, 0x68737570, 0x00000000, 0x00050005, 0x00000019, 0x69736f70,
0x6e6f6974, 0x00000000, 0x00050005, 0x00000025, 0x67617266, 0x6f6c6f43,
0x00000072, 0x00040005, 0x00000027, 0x6f6c6f63, 0x00000072, 0x00030047,
0x6e6f6974, 0x00000000, 0x00050005, 0x00000023, 0x67617266, 0x6f6c6f43,
0x00000072, 0x00040005, 0x00000025, 0x6f6c6f63, 0x00000072, 0x00030047,
0x0000000b, 0x00000002, 0x00050048, 0x0000000b, 0x00000000, 0x0000000b,
0x00000000, 0x00050048, 0x0000000b, 0x00000001, 0x0000000b, 0x00000001,
0x00050048, 0x0000000b, 0x00000002, 0x0000000b, 0x00000003, 0x00050048,
@@ -34,8 +34,8 @@ inline constexpr std::array<uint32_t, 345> model_render_system_vert_spv = {
0x00000011, 0x00000000, 0x00000007, 0x00000010, 0x00050048, 0x00000011,
0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x00000011, 0x00000001,
0x00000023, 0x00000040, 0x00040047, 0x00000019, 0x0000001e, 0x00000000,
0x00040047, 0x00000025, 0x0000001e, 0x00000000, 0x00040047, 0x00000027,
0x0000001e, 0x00000001, 0x00020013, 0x00000002, 0x00030021, 0x00000003,
0x00040047, 0x00000023, 0x0000001e, 0x00000000, 0x00040047, 0x00000025,
0x0000001e, 0x00000003, 0x00020013, 0x00000002, 0x00030021, 0x00000003,
0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007,
0x00000006, 0x00000004, 0x00040015, 0x00000008, 0x00000020, 0x00000000,
0x0004002b, 0x00000008, 0x00000009, 0x00000001, 0x0004001c, 0x0000000a,
@@ -46,24 +46,23 @@ inline constexpr std::array<uint32_t, 345> model_render_system_vert_spv = {
0x00040018, 0x00000010, 0x00000007, 0x00000004, 0x0004001e, 0x00000011,
0x00000010, 0x00000007, 0x00040020, 0x00000012, 0x00000009, 0x00000011,
0x0004003b, 0x00000012, 0x00000013, 0x00000009, 0x00040020, 0x00000014,
0x00000009, 0x00000010, 0x00040017, 0x00000017, 0x00000006, 0x00000002,
0x00000009, 0x00000010, 0x00040017, 0x00000017, 0x00000006, 0x00000003,
0x00040020, 0x00000018, 0x00000001, 0x00000017, 0x0004003b, 0x00000018,
0x00000019, 0x00000001, 0x0004002b, 0x00000006, 0x0000001b, 0x00000000,
0x0004002b, 0x00000006, 0x0000001c, 0x3f800000, 0x00040020, 0x00000021,
0x00000003, 0x00000007, 0x00040017, 0x00000023, 0x00000006, 0x00000003,
0x00040020, 0x00000024, 0x00000003, 0x00000023, 0x0004003b, 0x00000024,
0x00000025, 0x00000003, 0x00040020, 0x00000026, 0x00000001, 0x00000023,
0x0004003b, 0x00000026, 0x00000027, 0x00000001, 0x00050036, 0x00000002,
0x00000019, 0x00000001, 0x0004002b, 0x00000006, 0x0000001b, 0x3f800000,
0x00040020, 0x00000021, 0x00000003, 0x00000007, 0x0004003b, 0x00000021,
0x00000023, 0x00000003, 0x00040020, 0x00000024, 0x00000001, 0x00000007,
0x0004003b, 0x00000024, 0x00000025, 0x00000001, 0x00050036, 0x00000002,
0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x00050041,
0x00000014, 0x00000015, 0x00000013, 0x0000000f, 0x0004003d, 0x00000010,
0x00000016, 0x00000015, 0x0004003d, 0x00000017, 0x0000001a, 0x00000019,
0x00050051, 0x00000006, 0x0000001d, 0x0000001a, 0x00000000, 0x00050051,
0x00000006, 0x0000001e, 0x0000001a, 0x00000001, 0x00070050, 0x00000007,
0x0000001f, 0x0000001d, 0x0000001e, 0x0000001b, 0x0000001c, 0x00050091,
0x00000007, 0x00000020, 0x00000016, 0x0000001f, 0x00050041, 0x00000021,
0x00000022, 0x0000000d, 0x0000000f, 0x0003003e, 0x00000022, 0x00000020,
0x0004003d, 0x00000023, 0x00000028, 0x00000027, 0x0003003e, 0x00000025,
0x00000028, 0x000100fd, 0x00010038,
0x00050051, 0x00000006, 0x0000001c, 0x0000001a, 0x00000000, 0x00050051,
0x00000006, 0x0000001d, 0x0000001a, 0x00000001, 0x00050051, 0x00000006,
0x0000001e, 0x0000001a, 0x00000002, 0x00070050, 0x00000007, 0x0000001f,
0x0000001c, 0x0000001d, 0x0000001e, 0x0000001b, 0x00050091, 0x00000007,
0x00000020, 0x00000016, 0x0000001f, 0x00050041, 0x00000021, 0x00000022,
0x0000000d, 0x0000000f, 0x0003003e, 0x00000022, 0x00000020, 0x0004003d,
0x00000007, 0x00000026, 0x00000025, 0x0003003e, 0x00000023, 0x00000026,
0x000100fd, 0x00010038,
};
} // namespace sophia::shaders
+2 -4
View File
@@ -22,10 +22,8 @@ void main() {
vec2 corner = CORNERS[gl_VertexIndex];
gl_Position = push.viewProjection * model * vec4(corner, 0.0, 1.0);
// Draw order comes from the CPU-side sort, so flatten depth; sprites should
// never be clipped by the camera's near/far planes.
gl_Position.z = 0.0;
fragColor = color;
fragUv = mix(uvRect.xy, uvRect.zw, corner);
// The quad's y runs up and the texture's v runs down.
fragUv = mix(uvRect.xy, uvRect.zw, vec2(corner.x, 1.0 - corner.y));
}
+27 -25
View File
@@ -5,12 +5,12 @@
namespace sophia::shaders {
inline constexpr std::array<uint32_t, 519> sprite_vert_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000045, 0x00000000, 0x00020011,
inline constexpr std::array<uint32_t, 534> sprite_vert_spv = {
0x07230203, 0x00010000, 0x000d000b, 0x00000049, 0x00000000, 0x00020011,
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x000c000f, 0x00000000,
0x00000004, 0x6e69616d, 0x00000000, 0x00000016, 0x00000021, 0x0000002b,
0x00000038, 0x0000003a, 0x0000003d, 0x0000003e, 0x00030003, 0x00000002,
0x00000035, 0x00000037, 0x0000003a, 0x0000003b, 0x00030003, 0x00000002,
0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70,
0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004,
0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572,
@@ -26,9 +26,9 @@ inline constexpr std::array<uint32_t, 519> sprite_vert_spv = {
0x00000021, 0x00000000, 0x00040005, 0x00000024, 0x68737550, 0x00000000,
0x00070006, 0x00000024, 0x00000000, 0x77656976, 0x6a6f7250, 0x69746365,
0x00006e6f, 0x00040005, 0x00000026, 0x68737570, 0x00000000, 0x00040005,
0x0000002b, 0x65646f6d, 0x0000006c, 0x00050005, 0x00000038, 0x67617266,
0x6f6c6f43, 0x00000072, 0x00040005, 0x0000003a, 0x6f6c6f63, 0x00000072,
0x00040005, 0x0000003d, 0x67617266, 0x00007655, 0x00040005, 0x0000003e,
0x0000002b, 0x65646f6d, 0x0000006c, 0x00050005, 0x00000035, 0x67617266,
0x6f6c6f43, 0x00000072, 0x00040005, 0x00000037, 0x6f6c6f63, 0x00000072,
0x00040005, 0x0000003a, 0x67617266, 0x00007655, 0x00040005, 0x0000003b,
0x65527675, 0x00007463, 0x00040047, 0x00000016, 0x0000000b, 0x0000002a,
0x00030047, 0x0000001f, 0x00000002, 0x00050048, 0x0000001f, 0x00000000,
0x0000000b, 0x00000000, 0x00050048, 0x0000001f, 0x00000001, 0x0000000b,
@@ -37,9 +37,9 @@ inline constexpr std::array<uint32_t, 519> sprite_vert_spv = {
0x00000024, 0x00000002, 0x00040048, 0x00000024, 0x00000000, 0x00000005,
0x00050048, 0x00000024, 0x00000000, 0x00000007, 0x00000010, 0x00050048,
0x00000024, 0x00000000, 0x00000023, 0x00000000, 0x00040047, 0x0000002b,
0x0000001e, 0x00000000, 0x00040047, 0x00000038, 0x0000001e, 0x00000000,
0x00040047, 0x0000003a, 0x0000001e, 0x00000004, 0x00040047, 0x0000003d,
0x0000001e, 0x00000001, 0x00040047, 0x0000003e, 0x0000001e, 0x00000005,
0x0000001e, 0x00000000, 0x00040047, 0x00000035, 0x0000001e, 0x00000000,
0x00040047, 0x00000037, 0x0000001e, 0x00000004, 0x00040047, 0x0000003a,
0x0000001e, 0x00000001, 0x00040047, 0x0000003b, 0x0000001e, 0x00000005,
0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016,
0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000002,
0x00040020, 0x00000008, 0x00000007, 0x00000007, 0x00040015, 0x0000000a,
@@ -63,12 +63,12 @@ inline constexpr std::array<uint32_t, 519> sprite_vert_spv = {
0x00000009, 0x00000024, 0x0004003b, 0x00000025, 0x00000026, 0x00000009,
0x00040020, 0x00000027, 0x00000009, 0x00000023, 0x00040020, 0x0000002a,
0x00000001, 0x00000023, 0x0004003b, 0x0000002a, 0x0000002b, 0x00000001,
0x00040020, 0x00000033, 0x00000003, 0x0000001c, 0x0004002b, 0x0000000a,
0x00000035, 0x00000002, 0x00040020, 0x00000036, 0x00000003, 0x00000006,
0x0004003b, 0x00000033, 0x00000038, 0x00000003, 0x00040020, 0x00000039,
0x00000001, 0x0000001c, 0x0004003b, 0x00000039, 0x0000003a, 0x00000001,
0x00040020, 0x0000003c, 0x00000003, 0x00000007, 0x0004003b, 0x0000003c,
0x0000003d, 0x00000003, 0x0004003b, 0x00000039, 0x0000003e, 0x00000001,
0x00040020, 0x00000033, 0x00000003, 0x0000001c, 0x0004003b, 0x00000033,
0x00000035, 0x00000003, 0x00040020, 0x00000036, 0x00000001, 0x0000001c,
0x0004003b, 0x00000036, 0x00000037, 0x00000001, 0x00040020, 0x00000039,
0x00000003, 0x00000007, 0x0004003b, 0x00000039, 0x0000003a, 0x00000003,
0x0004003b, 0x00000036, 0x0000003b, 0x00000001, 0x0004002b, 0x0000000a,
0x00000040, 0x00000000, 0x00040020, 0x00000041, 0x00000007, 0x00000006,
0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8,
0x00000005, 0x0004003b, 0x00000008, 0x00000009, 0x00000007, 0x0004003b,
0x00000018, 0x00000019, 0x00000007, 0x0004003d, 0x00000014, 0x00000017,
@@ -83,16 +83,18 @@ inline constexpr std::array<uint32_t, 519> sprite_vert_spv = {
0x00070050, 0x0000001c, 0x00000031, 0x0000002f, 0x00000030, 0x0000000d,
0x0000000f, 0x00050091, 0x0000001c, 0x00000032, 0x0000002d, 0x00000031,
0x00050041, 0x00000033, 0x00000034, 0x00000021, 0x00000022, 0x0003003e,
0x00000034, 0x00000032, 0x00060041, 0x00000036, 0x00000037, 0x00000021,
0x00000022, 0x00000035, 0x0003003e, 0x00000037, 0x0000000d, 0x0004003d,
0x0000001c, 0x0000003b, 0x0000003a, 0x0003003e, 0x00000038, 0x0000003b,
0x0004003d, 0x0000001c, 0x0000003f, 0x0000003e, 0x0007004f, 0x00000007,
0x00000040, 0x0000003f, 0x0000003f, 0x00000000, 0x00000001, 0x0004003d,
0x0000001c, 0x00000041, 0x0000003e, 0x0007004f, 0x00000007, 0x00000042,
0x00000041, 0x00000041, 0x00000002, 0x00000003, 0x0004003d, 0x00000007,
0x00000043, 0x00000009, 0x0008000c, 0x00000007, 0x00000044, 0x00000001,
0x0000002e, 0x00000040, 0x00000042, 0x00000043, 0x0003003e, 0x0000003d,
0x00000044, 0x000100fd, 0x00010038,
0x00000034, 0x00000032, 0x0004003d, 0x0000001c, 0x00000038, 0x00000037,
0x0003003e, 0x00000035, 0x00000038, 0x0004003d, 0x0000001c, 0x0000003c,
0x0000003b, 0x0007004f, 0x00000007, 0x0000003d, 0x0000003c, 0x0000003c,
0x00000000, 0x00000001, 0x0004003d, 0x0000001c, 0x0000003e, 0x0000003b,
0x0007004f, 0x00000007, 0x0000003f, 0x0000003e, 0x0000003e, 0x00000002,
0x00000003, 0x00050041, 0x00000041, 0x00000042, 0x00000009, 0x00000040,
0x0004003d, 0x00000006, 0x00000043, 0x00000042, 0x00050041, 0x00000041,
0x00000044, 0x00000009, 0x0000001d, 0x0004003d, 0x00000006, 0x00000045,
0x00000044, 0x00050083, 0x00000006, 0x00000046, 0x0000000f, 0x00000045,
0x00050050, 0x00000007, 0x00000047, 0x00000043, 0x00000046, 0x0008000c,
0x00000007, 0x00000048, 0x00000001, 0x0000002e, 0x0000003d, 0x0000003f,
0x00000047, 0x0003003e, 0x0000003a, 0x00000048, 0x000100fd, 0x00010038,
};
} // namespace sophia::shaders
+1
View File
@@ -48,6 +48,7 @@ class Device {
void waitIdle() { this->device->waitIdle(); }
vk::PhysicalDevice getPhysicalDevice() const { return this->physicalDevice; }
VmaAllocator getAllocator() const { return this->allocator; }
vk::CommandPool getCommandPool() const { return this->commandPool; }
vk::SurfaceKHR getSurface() const { return surface; }
@@ -101,6 +101,21 @@ GraphicsPipeline::Builder& GraphicsPipeline::Builder::setAlphaBlending(
return *this;
}
GraphicsPipeline::Builder& GraphicsPipeline::Builder::setDepthTest(
bool test, bool write, vk::CompareOp compareOp) {
this->depthTest = test;
this->depthWrite = write;
this->depthCompareOp = compareOp;
return *this;
}
GraphicsPipeline::Builder& GraphicsPipeline::Builder::setCullMode(
vk::CullModeFlags cullMode, vk::FrontFace frontFace) {
this->cullMode = cullMode;
this->frontFace = frontFace;
return *this;
}
std::unique_ptr<GraphicsPipeline> GraphicsPipeline::Builder::build() const {
if (this->vertexShader == nullptr || this->fragmentShader == nullptr) {
log::fatal(
@@ -130,26 +145,14 @@ std::unique_ptr<GraphicsPipeline> GraphicsPipeline::Builder::build() const {
"setDepthAttachmentFormat() was not called");
}
return std::unique_ptr<GraphicsPipeline>(new GraphicsPipeline(
this->device, *this->vertexShader, *this->fragmentShader,
this->pipelineLayout, this->colorAttachmentFormats,
this->depthAttachmentFormat, this->stencilAttachmentFormat,
this->bindingDescriptions, this->attributeDescriptions,
this->alphaBlending));
return std::unique_ptr<GraphicsPipeline>(new GraphicsPipeline(*this));
}
GraphicsPipeline::GraphicsPipeline(
Device& device, Shader& vertexShader, Shader& fragmentShader,
vk::PipelineLayout pipelineLayout,
std::vector<vk::Format> colorAttachmentFormats,
vk::Format depthAttachmentFormat, vk::Format stencilAttachmentFormat,
std::vector<vk::VertexInputBindingDescription> bindingDescriptions,
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions,
bool alphaBlending)
: Pipeline(device, vk::PipelineBindPoint::eGraphics) {
GraphicsPipeline::GraphicsPipeline(const Builder& builder)
: Pipeline(builder.device, vk::PipelineBindPoint::eGraphics) {
setDefaultGraphicsPipelineConfig();
if (alphaBlending) {
if (builder.alphaBlending) {
vk::PipelineColorBlendAttachmentState& blend =
this->config.colorBlendAttachment;
blend.blendEnable = vk::True;
@@ -159,17 +162,24 @@ GraphicsPipeline::GraphicsPipeline(
blend.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
}
this->config.bindingDescriptions = std::move(bindingDescriptions);
this->config.attributeDescriptions = std::move(attributeDescriptions);
this->config.pipelineLayout = pipelineLayout;
this->config.colorAttachmentFormats = std::move(colorAttachmentFormats);
this->config.depthAttachmentFormat = depthAttachmentFormat;
this->config.stencilAttachmentFormat = stencilAttachmentFormat;
this->config.depthStencilInfo.depthTestEnable = builder.depthTest;
this->config.depthStencilInfo.depthWriteEnable = builder.depthWrite;
this->config.depthStencilInfo.depthCompareOp = builder.depthCompareOp;
this->config.rasterizationInfo.cullMode = builder.cullMode;
this->config.rasterizationInfo.frontFace = builder.frontFace;
this->config.bindingDescriptions = builder.bindingDescriptions;
this->config.attributeDescriptions = builder.attributeDescriptions;
this->config.pipelineLayout = builder.pipelineLayout;
this->config.colorAttachmentFormats = builder.colorAttachmentFormats;
this->config.depthAttachmentFormat = builder.depthAttachmentFormat;
this->config.stencilAttachmentFormat = builder.stencilAttachmentFormat;
vk::UniqueShaderModule vertexShaderModule =
createShaderModule(vertexShader.getSpirv());
createShaderModule(builder.vertexShader->getSpirv());
vk::UniqueShaderModule fragmentShaderModule =
createShaderModule(fragmentShader.getSpirv());
createShaderModule(builder.fragmentShader->getSpirv());
log::trace("created graphics shader modules");
vk::PipelineShaderStageCreateInfo shaderStages[] = {
@@ -245,7 +255,7 @@ void GraphicsPipeline::setDefaultGraphicsPipelineConfig() {
this->config.rasterizationInfo.polygonMode = vk::PolygonMode::eFill;
this->config.rasterizationInfo.lineWidth = 1.0f;
this->config.rasterizationInfo.cullMode = vk::CullModeFlagBits::eNone;
this->config.rasterizationInfo.frontFace = vk::FrontFace::eClockwise;
this->config.rasterizationInfo.frontFace = vk::FrontFace::eCounterClockwise;
this->config.rasterizationInfo.depthBiasEnable = vk::False;
this->config.rasterizationInfo.depthBiasConstantFactor = 0.0f;
this->config.rasterizationInfo.depthBiasClamp = 0.0f;
@@ -41,14 +41,7 @@ class GraphicsPipeline : public Pipeline {
~GraphicsPipeline() override;
private:
GraphicsPipeline(
Device& device, Shader& vertexShader, Shader& fragmentShader,
vk::PipelineLayout pipelineLayout,
std::vector<vk::Format> colorAttachmentFormats,
vk::Format depthAttachmentFormat, vk::Format stencilAttachmentFormat,
std::vector<vk::VertexInputBindingDescription> bindingDescriptions,
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions,
bool alphaBlending);
explicit GraphicsPipeline(const Builder& builder);
void setDefaultGraphicsPipelineConfig();
@@ -72,6 +65,14 @@ class GraphicsPipeline::Builder {
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions);
// Straight (non-premultiplied) "over" blending on every color attachment.
Builder& setAlphaBlending(bool enabled = true);
// Only matters with a depth attachment. Defaults to testing and writing
// with eLess.
Builder& setDepthTest(bool test, bool write,
vk::CompareOp compareOp = vk::CompareOp::eLess);
// Defaults to no culling, with counter-clockwise triangles facing front.
Builder& setCullMode(
vk::CullModeFlags cullMode,
vk::FrontFace frontFace = vk::FrontFace::eCounterClockwise);
std::unique_ptr<GraphicsPipeline> build() const;
@@ -87,6 +88,13 @@ class GraphicsPipeline::Builder {
std::vector<vk::VertexInputBindingDescription> bindingDescriptions{};
std::vector<vk::VertexInputAttributeDescription> attributeDescriptions{};
bool alphaBlending = false;
bool depthTest = true;
bool depthWrite = true;
vk::CompareOp depthCompareOp = vk::CompareOp::eLess;
vk::CullModeFlags cullMode = vk::CullModeFlagBits::eNone;
vk::FrontFace frontFace = vk::FrontFace::eCounterClockwise;
friend class GraphicsPipeline;
};
} // namespace sophia
+1 -2
View File
@@ -215,8 +215,7 @@ vk::Extent2D Swapchain::chooseExtent(
vk::Format Swapchain::findDepthFormat() {
return this->device.findSupportedFormat(
{vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint,
vk::Format::eD24UnormS8Uint},
{vk::Format::eD32Sfloat, vk::Format::eX8D24UnormPack32},
vk::ImageTiling::eOptimal,
vk::FormatFeatureFlagBits::eDepthStencilAttachment);
}