evan 2026.1.4
Evan
Loading...
Searching...
No Matches
RenderSettings.hpp
1/*
2** ETIB PROJECT, 2026
3** evan
4** File description:
5** RenderSettings
6*/
7
8#pragma once
9
10#include "evan/EvanPlatform.hpp"
11
12#include <cstdint>
13#include <limits>
14
15namespace evan
16{
24 enum class BlendMode {
25 Opaque,
27 Alpha
29 };
30
34 enum class OpaqueSortMode {
35 StateFirst,
37 FrontToBack
39 };
40
48 enum class ColorAttachmentMode {
49 DirectToSwapchain,
53 ResolveToSwapchain,
56 SwapchainImageAttachment
62 };
63
75 [[nodiscard]] inline ColorAttachmentMode
76 desktopColorAttachmentMode(VkSampleCountFlagBits msaaSamples) noexcept
77 {
78 return msaaSamples == VK_SAMPLE_COUNT_1_BIT
79 ? ColorAttachmentMode::DirectToSwapchain
80 : ColorAttachmentMode::ResolveToSwapchain;
81 }
82
91 constexpr uint32_t kOpaqueDepthBucketCount = 32;
92
102 constexpr float kUnknownDepth = std::numeric_limits<float>::max();
103
120 [[nodiscard]] inline uint32_t
121 opaqueDepthBucket(float depth, float nearest, float span,
122 uint32_t bucketCount) noexcept
123 {
124 // A draw whose distance is unknown (kUnknownDepth) or cannot be
125 // compared against the others (a NaN, or every draw when the visible
126 // range is empty) has no place inside the front-to-back order: it
127 // goes to the trailing bucket, past the last real one. The sentinel
128 // is checked explicitly because it is a finite value, so it would
129 // otherwise be clamped onto the last real bucket like any distance
130 // past the visible range.
131 if (!(span > 0.0f) || !(depth >= nearest) || depth == kUnknownDepth) {
132 return bucketCount;
133 }
134
135 const float normalized = (depth - nearest) / span;
136 // Infinity and distances past the visible range saturate on the last
137 // real bucket before the conversion to avoid an out-of-range cast.
138 if (!(normalized < 1.0f)) {
139 return bucketCount - 1;
140 }
141
142 return static_cast<uint32_t>(normalized
143 * static_cast<float>(bucketCount));
144 }
145
162 struct DrawSortKey {
163 BlendMode blendMode = BlendMode::Opaque;
164 uint32_t depthBucket = 0;
165 float depth = 0.0f;
166 uint32_t pipelineKey = 0;
167 uint32_t materialID = 0;
168 VkBuffer vertexBuffer = VK_NULL_HANDLE;
169 VkBuffer indexBuffer = VK_NULL_HANDLE;
170 uint32_t sequence = 0;
171 };
172
187 [[nodiscard]] inline bool drawSortKeyLess(const DrawSortKey &lhs,
188 const DrawSortKey &rhs) noexcept
189 {
190 if (lhs.blendMode != rhs.blendMode) {
191 return static_cast<int>(lhs.blendMode)
192 < static_cast<int>(rhs.blendMode);
193 }
194
195 if (lhs.blendMode == BlendMode::Alpha) {
196 // Blended geometry is composited back-to-front. Depth decides
197 // before state: grouping materials by pipeline first would blend
198 // them in the wrong order.
199 if (lhs.depth != rhs.depth) {
200 return lhs.depth > rhs.depth;
201 }
202 } else if (lhs.depthBucket != rhs.depthBucket) {
203 // Opaque geometry goes front-to-back. The bucket, not the exact
204 // distance, so that draws of the same bucket keep their state
205 // ordering and still merge into batching.
206 return lhs.depthBucket < rhs.depthBucket;
207 }
208
209 if (lhs.pipelineKey != rhs.pipelineKey) {
210 return lhs.pipelineKey < rhs.pipelineKey;
211 }
212 if (lhs.materialID != rhs.materialID) {
213 return lhs.materialID < rhs.materialID;
214 }
215 if (lhs.vertexBuffer != rhs.vertexBuffer) {
216 return lhs.vertexBuffer < rhs.vertexBuffer;
217 }
218 if (lhs.indexBuffer != rhs.indexBuffer) {
219 return lhs.indexBuffer < rhs.indexBuffer;
220 }
221 return lhs.sequence < rhs.sequence;
222 }
223
244
248 OpaqueSortMode opaqueSort = OpaqueSortMode::FrontToBack;
249 };
250} // namespace evan
Key that decides in which order a frame's draws are recorded.
Application-facing rendering configuration.
VkSampleCountFlagBits msaaSamples
Multisample anti-aliasing sample count.
OpaqueSortMode opaqueSort
Ordering strategy for the opaque draws of a frame.
Small result wrapper used by helpers that must return both a status and a value (e....
Definition Error.hpp:89