Foundation
Loading...
Searching...
No Matches
MipGeneration.cpp

Generate mipmaps for a texture using compute shaders, with ImGui and image loading.

#include "Examples.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
namespace Examples
{
class MipGenerationApp : public RenderApplication
{
public:
// Q: Why is a custom destructor needed?
// A: TexturePool resource got imported into the @ref Renderer - see @ref Renderer::createResource
// We need to ensure that the TexturePool outlives the Renderer.
UniquePtr<TexturePool> mTexturePool;
~MipGenerationApp() override
{
mRenderer.reset();
mTexturePool.reset();
// Follows Device destruction, etc.
}
TexturePoolHandle mSampleImage{kInvalidTexturePoolHandle};
ResourceHandle mRenderedSRV{kInvalidHandle};
float mBlur = 1.0f;
void OnDeviceSetup() override
{
mTexturePool = ConstructUnique<TexturePool>(GetAllocator(), mDevice.Get(), GetAllocator());
// Load into mip 0
UploadContext upload(mDevice.Get(), GetAllocator());
int x, y, n;
stbi_uc* data = stbi_load("data/assets/cameraman.jpg", &x, &y, &n, 4);
RHITextureDesc{.usage = RHITextureUsageBits::SampledImage | RHITextureUsageBits::StorageImage |
RHITextureUsageBits::TransferDestination,
.extent = {x, y, 1},
.format = RHIResourceFormat::R8G8B8A8Unorm,
.mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::min(x, y))))});
Span<char> span(reinterpret_cast<char*>(data), reinterpret_cast<char*>(data) + x * y * 4);
upload.Upload(mTexturePool->GetTexture(mSampleImage), span);
upload.SubmitAndWait();
}
void OnRendererSetup() override
{
auto* srcTex = mTexturePool->GetTexture(mSampleImage);
ResourceHandle srcHandle = createResource(mRenderer.get(), "Image", srcTex);
ResourceHandle renderedHandle =
createResource(mRenderer.get(), "Rendered Image",
RHITextureDesc{
.usage = RHITextureUsageBits::SampledImage | RHITextureUsageBits::RenderTarget,
.extent = srcTex->mDesc.extent,
.format = RHIResourceFormat::R8G8B8A8Unorm,
});
ResourceHandle sampler = createSampler(mRenderer.get(), {});
createCSMipGenerationPasses(mRenderer.get(), "Mip Gen", RHIDeviceQueueType::Compute, srcHandle, srcHandle,
RHITextureAspectFlagBits::Color, RHIResourceFormat::R8G8B8A8Unorm,
RHITextureAspectFlagBits::Color, RHIResourceFormat::R8G8B8A8Unorm, 16, 0);
createPass(
mRenderer.get(), "Blur", RHIDeviceQueueType::Graphics,
[=](PassHandle self, Renderer* r)
{
r->BindShader(self, RHIShaderStageBits::Vertex, "vertMain", "data/shaders/VSFullscreen.spv");
r->BindShader(self, RHIShaderStageBits::Fragment, "fragMain", "data/shaders/MipGenerationBlur.spv");
r->BindTextureSRV(self, srcHandle, "srcTexture", RHIPipelineStageBits::FragmentShader,
{.format = RHIResourceFormat::R8G8B8A8Unorm,
.range = RHITextureSubresourceRange::Create(RHITextureAspectFlagBits::Color, 0,
srcTex->mDesc.mipLevels)});
r->BindTextureSampler(self, sampler, "srcSampler");
r->BindTextureRTV(
self, renderedHandle,
{.format = RHIResourceFormat::R8G8B8A8Unorm, .range = RHITextureSubresourceRange::Create()});
r->BindPushConstant(self, RHIShaderStageBits::Fragment, 0, sizeof(float));
},
[=, this](PassHandle self, Renderer* r, RHICommandList* cmd)
{
auto const& img_wh = r->DerefResource(renderedHandle).Get<RHITexture*>()->mDesc.extent;
r->CmdBeginGraphics(self, cmd, img_wh, {}, {});
r->CmdSetPipeline(self, cmd);
r->CmdSetPushConstant(self, cmd, RHIShaderStageBits::Fragment, 0, mBlur);
cmd->SetViewport(0, 0, img_wh.x, img_wh.y).SetScissor(0, 0, img_wh.x, img_wh.y);
cmd->Draw(3);
cmd->EndGraphics();
});
[=, this](PassHandle self, Renderer* r)
{
mRenderedSRV =
r->BindTextureSRV(self, renderedHandle, kBindpointIgnored,
RHIPipelineStageBits::FragmentShader,
{
.format = RHIResourceFormat::R8G8B8A8Unorm,
.range = RHITextureSubresourceRange::Create(),
});
});
}
ImTextureID mRenderedImageID{0};
void OnRendererPostSetup() override
{
if (mRenderedImageID != 0)
auto* srv = mRenderer->DerefTextureView(mRenderedSRV);
mRenderedImageID = ImGui_ImplFoundation_AddImage(srv);
}
void OnBeforeFrame() override
{
ImGui::NewFrame();
ImGui::SetNextWindowPos({0, 0});
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::Begin("Viewer");
ImGui::Image(mRenderedImageID, ImVec2(512, 512));
ImGui::SliderFloat("Blur", &mBlur, 0.0f, 10.0f);
ImGui::End();
}
};
} // namespace Examples
int main(int argc, char** argv)
{
app.Initialize<VulkanApplication>({.windowTitle = "Mipmap Generation"});
app.RunForever();
}
int main(int argc, char **argv)
Definition ImGui.cpp:26
auto * ImGui_ImplFoundation_CreatePass(Foundation::RenderCore::Renderer *renderer, Foundation::Core::StringView name, bool clear, FSetup &&setup)
Creates a render pass that will draw the ImGui UI.
Definition ImGui.hpp:97
void ImGui_ImplFoundation_Init(RHIDevice *device, Native::NativeWindow *window, Allocator *allocator)
Definition ImGui.cpp:35
void ImGui_ImplFoundation_NewFrame()
Starts a new ImGui frame.
Definition ImGui.cpp:52
void ImGui_ImplFoundation_Shutdown()
Shuts down the ImGui backend and releases all resources.
Definition ImGui.cpp:57
void ImGui_ImplFoundation_SetupContextWithDefaultStyles()
Applies a default, vaguely stylish theme to the ImGui context.
Definition ImGui.cpp:296
void ImGui_ImplFoundation_RemoveImage(ImTextureID textureID)
Unregisters a texture from the ImGui backend.
Definition ImGui.cpp:135
ImTextureID ImGui_ImplFoundation_AddImage(RHITextureView *textureView, ImGui_ImplFoundation_ImageSampler sampler)
Registers a texture with the ImGui backend so it can be displayed in the UI.
Definition ImGui.cpp:129
Definition MipGeneration.cpp:16
float mBlur
Definition MipGeneration.cpp:30
ResourceHandle mRenderedSRV
Definition MipGeneration.cpp:29
TexturePoolHandle mSampleImage
Definition MipGeneration.cpp:28
void OnRendererSetup() override
Set up the renderer by creating passes, resources, and other configurations.
Definition MipGeneration.cpp:50
UniquePtr< TexturePool > mTexturePool
Definition MipGeneration.cpp:21
~MipGenerationApp() override
Definition MipGeneration.cpp:22
void OnDeviceSetup() override
Actions to take after device specific resources has been set up.
Definition MipGeneration.cpp:31
Allocator * Ptr()
Definition Allocator.hpp:38
Allocator * GetAllocator()
Retrieve the allocator used for general application allocations.
Definition Application.hpp:244
ApplicationInitDesc mDesc
Definition Application.hpp:93
void Initialize(ApplicationInitDesc const &desc={}, Args &&... args)
Initialize the application with the specified RHI backend.
Definition Application.hpp:205
RHIApplicationScopedObjectHandle< RHIDevice > mDevice
Definition Application.hpp:99
Native::NativeWindow * GetNativeWindow()
Retrieve the current NativeWindow instance.
Definition Application.hpp:240
DefaultAllocator mAlloc
Definition Application.hpp:95
UniquePtr< Renderer > mRenderer
Definition Application.hpp:102
void RunForever()
Start the Render thread and run the application loop indefinitely, until the window is closed or the ...
Definition Application.cpp:127
For a complete list of examples, see the Examples Page.
Definition Examples.hpp:12