Hello Triangle MSAA
This example showcases the minimal changes needed to enable multisample anti-aliasing. Read the Hello Triangle example to see the differences.
The first place to look is createRenderTarget
, where the MSAA texture and view are initialized. This function is called on initialization and on window resize.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 | void HelloTriangleMSAA::createRenderTarget()
{
// Reset depthTextureView as depthStencilAttachment view as it might
// have been recreated following a resize
m_commandRecorderOptions.depthStencilAttachment.view = m_depthTextureView;
const TextureOptions options = {
.type = TextureType::TextureType2D,
.format = m_swapchainFormat,
.extent = { .width = m_swapchainExtent.width, .height = m_swapchainExtent.height, .depth = 1 },
.mipLevels = 1,
.samples = m_samples.get(),
.usage = TextureUsageFlagBits::ColorAttachmentBit,
.memoryUsage = MemoryUsage::GpuOnly,
.initialLayout = TextureLayout::Undefined
};
m_msaaTexture = m_device.createTexture(options);
m_msaaTextureView = m_msaaTexture.createView();
if (isMsaaEnabled())
m_commandRecorderOptions.colorAttachments[0].view = m_msaaTextureView;
}
bool HelloTriangleMSAA::isMsaaEnabled() const
{
return m_samples.get() != SampleCountFlagBits::Samples1Bit;
}
void HelloTriangleMSAA::setMsaaSampleCount(SampleCountFlagBits samples)
{
if (samples == m_samples.get())
return;
// get new pipeline
for (size_t i = 0; i < m_supportedSampleCounts.size(); ++i) {
if (m_supportedSampleCounts[i] == samples) {
m_currentPipelineIndex = i;
break;
}
}
// the ExampleEngineLayer will recreate the depth view when we do this
m_samples = samples;
// we must also refresh the view(s) we handle, and reattach them
createRenderTarget();
// update the samples option that will configure the render pass
m_commandRecorderOptions.samples = samples;
}
void HelloTriangleMSAA::drawMsaaSettings(ImGuiContext *ctx)
{
constexpr ImVec2 winOffset(200, 150);
constexpr ImVec2 buttonSize(120, 40);
constexpr size_t maxMessageLen = 40;
ImGui::SetCurrentContext(ctx);
ImGui::SetNextWindowPos(ImVec2((float)m_window->width() - winOffset.x, winOffset.y));
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver);
ImGui::Begin(
"Controls",
nullptr,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
auto getButtonLabel = [](SampleCountFlagBits samples) -> const char * {
switch (samples) {
case SampleCountFlagBits::Samples1Bit:
return "No MSAA";
case SampleCountFlagBits::Samples2Bit:
return "2x MSAA";
case SampleCountFlagBits::Samples4Bit:
return "4x MSAA";
case SampleCountFlagBits::Samples8Bit:
return "8x MSAA";
case SampleCountFlagBits::Samples16Bit:
return "16x MSAA";
case SampleCountFlagBits::Samples32Bit:
return "32x MSAA";
case SampleCountFlagBits::Samples64Bit:
return "64x MSAA";
default:
return "Unknown";
}
};
int selectedIndex = m_requestedSampleCountIndex;
for (int i = 0; i < m_supportedSampleCounts.size(); ++i) {
ImGui::RadioButton(getButtonLabel(m_supportedSampleCounts[i]), &selectedIndex, i);
}
// so we can deal with it in updateScene
m_requestedSampleCountIndex = selectedIndex;
ImGui::End();
}
|
Filename: hello_triangle_msaa/hello_triangle_msaa.cpp
This creates a texture and a view with the correct multisampling configuration and new dimensions, which we will attach to the render pass option struct (KDGpu::RenderPassCommandRecorderOptions). This texture is able to hold more information (samples) per texel. Additionally, we need to configure the render pass option struct to multisample, passing in the same number of samples we did for the texture above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | m_commandRecorderOptions = {
.colorAttachments = {
{
.view = m_msaaTextureView, // The multisampled view which will change on resize.
.resolveView = {}, // Not setting the swapchain texture view just yet. That's handled at render.
.clearValue = { 0.3f, 0.3f, 0.3f, 1.0f },
.finalLayout = TextureLayout::PresentSrc
}
},
.depthStencilAttachment = {
.view = m_depthTextureView,
},
// configure for multisampling
.samples = m_samples.get()
};
|
Filename: hello_triangle_msaa/hello_triangle_msaa.cpp
Notice that the render pass options contains two separate entries: one for view
and one for resolveView
. The view
is set to the multisample texture, which has extra sampling information. During an MSAA pass, though, the multisampled texture needs to have its extra information "resolved" into a final, regular texture: the resolveView
.
Also configure the graphics pipeline (KDGpu::GraphicsPipelineOptions) to multisample:
| .multisample = {
.samples = samples
}
|
Filename: hello_triangle_msaa/hello_triangle_msaa.cpp
Lastly, on each frame, update the resolveView
with the swapchain view that we want to render to.
| // When using MSAA, we update the resolveView instead of the view
m_commandRecorderOptions.colorAttachments[0].resolveView = m_swapchainViews.at(m_currentSwapchainImageIndex);
|
Filename: hello_triangle_msaa/hello_triangle_msaa.cpp
Updated on 2024-09-08 at 00:13:11 +0000