Skip to content

Commit 7a5ea7c

Browse files
committed
Build a staging buffer and upload exr image
1 parent 87d4794 commit 7a5ea7c

File tree

1 file changed

+187
-32
lines changed

1 file changed

+187
-32
lines changed

26_Autoexposure/main.cpp

Lines changed: 187 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../common/SimpleWindowedApplication.hpp"
66

77
#include "nbl/video/surface/CSurfaceVulkan.h"
8+
#include "nbl/asset/interchange/IAssetLoader.h"
89

910
using namespace nbl;
1011
using namespace core;
@@ -22,6 +23,9 @@ class AutoexposureApp final : public examples::SimpleWindowedApplication, public
2223
using asset_base_t = application_templates::MonoAssetManagerAndBuiltinResourceApplication;
2324
using clock_t = std::chrono::steady_clock;
2425

26+
constexpr static inline std::string_view DefaultImagePathsFile = "../../media/noises/spp_benchmark_4k_512.exr";
27+
28+
2529
public:
2630
// Yay thanks to multiple inheritance we cannot forward ctors anymore
2731
inline AutoexposureApp(const path& _localInputCWD, const path& _localOutputCWD, const path& _sharedInputCWD, const path& _sharedOutputCWD) :
@@ -62,6 +66,178 @@ class AutoexposureApp final : public examples::SimpleWindowedApplication, public
6266
if (!asset_base_t::onAppInitialized(std::move(system)))
6367
return false;
6468

69+
/*
70+
* We'll be using a combined image sampler for this example, which lets us assign both a sampled image and a sampler to the same binding.
71+
* In this example we provide a sampler at descriptor set creation time, via the SBinding struct below. This specifies that the sampler for this binding is immutable,
72+
* as evidenced by the name of the field in the SBinding.
73+
* Samplers for combined image samplers can also be mutable, which for a binding of a descriptor set is specified also at creation time by leaving the immutableSamplers
74+
* field set to its default (nullptr).
75+
*/
76+
smart_refctd_ptr<IGPUDescriptorSetLayout> dsLayout;
77+
{
78+
auto defaultSampler = m_device->createSampler({
79+
.AnisotropicFilter = 0
80+
});
81+
82+
const IGPUDescriptorSetLayout::SBinding bindings[1] = { {
83+
.binding = 0,
84+
.type = IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER,
85+
.createFlags = IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE,
86+
.stageFlags = IShader::E_SHADER_STAGE::ESS_FRAGMENT,
87+
.count = 1,
88+
.immutableSamplers = &defaultSampler
89+
}
90+
};
91+
dsLayout = m_device->createDescriptorSetLayout(bindings);
92+
if (!dsLayout)
93+
return logFail("Failed to Create Descriptor Layout");
94+
95+
}
96+
97+
// create the descriptor set and with enough room for one image sampler
98+
{
99+
const uint32_t setCount = 1;
100+
auto pool = m_device->createDescriptorPoolForDSLayouts(IDescriptorPool::E_CREATE_FLAGS::ECF_NONE, { &dsLayout.get(),1 }, &setCount);
101+
if (!pool)
102+
return logFail("Failed to Create Descriptor Pool");
103+
104+
m_descriptorSets[0] = pool->createDescriptorSet(core::smart_refctd_ptr(dsLayout));
105+
if (!m_descriptorSets[0])
106+
return logFail("Could not create Descriptor Set!");
107+
}
108+
109+
auto queue = getGraphicsQueue();
110+
111+
// need resetttable commandbuffers for the upload utility
112+
{
113+
m_cmdPool = m_device->createCommandPool(queue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT);
114+
// create the commandbuffers
115+
if (!m_cmdPool)
116+
return logFail("Couldn't create Command Pool!");
117+
if (!m_cmdPool->createCommandBuffers(IGPUCommandPool::BUFFER_LEVEL::PRIMARY, { m_cmdBufs.data(), 1 }))
118+
return logFail("Couldn't create Command Buffer!");
119+
}
120+
121+
// things for IUtilities
122+
{
123+
m_scratchSemaphore = m_device->createSemaphore(0);
124+
if (!m_scratchSemaphore)
125+
return logFail("Could not create Scratch Semaphore");
126+
m_scratchSemaphore->setObjectDebugName("Scratch Semaphore");
127+
// we don't want to overcomplicate the example with multi-queue
128+
m_intendedSubmit.queue = queue;
129+
// wait for nothing before upload
130+
m_intendedSubmit.waitSemaphores = {};
131+
// fill later
132+
m_intendedSubmit.commandBuffers = {};
133+
m_intendedSubmit.scratchSemaphore = {
134+
.semaphore = m_scratchSemaphore.get(),
135+
.value = 0,
136+
.stageMask = PIPELINE_STAGE_FLAGS::ALL_TRANSFER_BITS
137+
};
138+
}
139+
140+
// Allocate and Leave 1/4 for image uploads, to test image copy with small memory remaining
141+
{
142+
uint32_t localOffset = video::StreamingTransientDataBufferMT<>::invalid_value;
143+
uint32_t maxFreeBlock = m_utils->getDefaultUpStreamingBuffer()->max_size();
144+
const uint32_t allocationAlignment = 64u;
145+
const uint32_t allocationSize = (maxFreeBlock / 4) * 3;
146+
m_utils->getDefaultUpStreamingBuffer()->multi_allocate(std::chrono::steady_clock::now() + std::chrono::microseconds(500u), 1u, &localOffset, &allocationSize, &allocationAlignment);
147+
}
148+
149+
// Load exr file into gpu
150+
{
151+
IAssetLoader::SAssetLoadParams params;
152+
auto imageBundle = m_assetMgr->getAsset(DefaultImagePathsFile.data(), params);
153+
auto cpuImg = IAsset::castDown<ICPUImage>(imageBundle.getContents().begin()[0]);
154+
auto format = cpuImg->getCreationParameters().format;
155+
156+
ICPUImageView::SCreationParams viewParams = {
157+
.flags = ICPUImageView::E_CREATE_FLAGS::ECF_NONE,
158+
.image = std::move(cpuImg),
159+
.viewType = IImageView<ICPUImage>::E_TYPE::ET_2D,
160+
.format = format,
161+
.subresourceRange = {
162+
.aspectMask = IImage::E_ASPECT_FLAGS::EAF_COLOR_BIT,
163+
.baseMipLevel = 0u,
164+
.levelCount = ICPUImageView::remaining_mip_levels,
165+
.baseArrayLayer = 0u,
166+
.layerCount = ICPUImageView::remaining_array_layers
167+
}
168+
};
169+
170+
const auto cpuImgView = ICPUImageView::create(std::move(viewParams));
171+
const auto& cpuImgParams = cpuImgView->getCreationParameters();
172+
173+
// create matching size image
174+
IGPUImage::SCreationParams imageParams = {};
175+
imageParams = cpuImgParams.image->getCreationParameters();
176+
imageParams.usage |= IGPUImage::EUF_TRANSFER_DST_BIT | IGPUImage::EUF_SAMPLED_BIT | IGPUImage::E_USAGE_FLAGS::EUF_TRANSFER_SRC_BIT;
177+
// promote format because RGB8 and friends don't actually exist in HW
178+
{
179+
const IPhysicalDevice::SImageFormatPromotionRequest request = {
180+
.originalFormat = imageParams.format,
181+
.usages = IPhysicalDevice::SFormatImageUsages::SUsage(imageParams.usage)
182+
};
183+
imageParams.format = m_physicalDevice->promoteImageFormat(request, imageParams.tiling);
184+
}
185+
if (imageParams.type == IGPUImage::ET_3D)
186+
imageParams.flags |= IGPUImage::ECF_2D_ARRAY_COMPATIBLE_BIT;
187+
m_gpuImg = m_device->createImage(std::move(imageParams));
188+
if (!m_gpuImg || !m_device->allocate(m_gpuImg->getMemoryReqs(), m_gpuImg.get()).isValid())
189+
return false;
190+
m_gpuImg->setObjectDebugName("Autoexposure Image");
191+
192+
// we don't want to overcomplicate the example with multi-queue
193+
auto queue = getGraphicsQueue();
194+
auto cmdbuf = m_cmdBufs[0].get();
195+
IQueue::SSubmitInfo::SCommandBufferInfo cmdbufInfo = { cmdbuf };
196+
m_intendedSubmit.commandBuffers = { &cmdbufInfo, 1 };
197+
198+
// there's no previous operation to wait for
199+
const SMemoryBarrier toTransferBarrier = {
200+
.dstStageMask = PIPELINE_STAGE_FLAGS::COPY_BIT,
201+
.dstAccessMask = ACCESS_FLAGS::TRANSFER_WRITE_BIT
202+
};
203+
204+
// upload image and write to descriptor set
205+
queue->startCapture();
206+
auto ds = m_descriptorSets[0].get();
207+
208+
cmdbuf->begin(IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT);
209+
// change the layout of the image
210+
const IGPUCommandBuffer::SImageMemoryBarrier<IGPUCommandBuffer::SOwnershipTransferBarrier> imgBarriers[] = { {
211+
.barrier = {
212+
.dep = toTransferBarrier
213+
// no ownership transfers
214+
},
215+
.image = m_gpuImg.get(),
216+
// transition the whole view
217+
.subresourceRange = cpuImgParams.subresourceRange,
218+
// a wiping transition
219+
.newLayout = IGPUImage::LAYOUT::TRANSFER_DST_OPTIMAL
220+
} };
221+
cmdbuf->pipelineBarrier(E_DEPENDENCY_FLAGS::EDF_NONE, { .imgBarriers = imgBarriers });
222+
// upload contents and submit right away
223+
m_utils->updateImageViaStagingBufferAutoSubmit(
224+
m_intendedSubmit,
225+
cpuImgParams.image->getBuffer(),
226+
cpuImgParams.image->getCreationParameters().format,
227+
m_gpuImg.get(),
228+
IGPUImage::LAYOUT::TRANSFER_DST_OPTIMAL,
229+
cpuImgParams.image->getRegions()
230+
);
231+
232+
IGPUImageView::SCreationParams gpuImgViewParams = {
233+
.image = m_gpuImg,
234+
.viewType = IGPUImageView::ET_2D_ARRAY,
235+
.format = m_gpuImg->getCreationParameters().format
236+
};
237+
238+
m_gpuImgView = m_device->createImageView(std::move(gpuImgViewParams));
239+
}
240+
65241
return true;
66242
}
67243

@@ -83,6 +259,17 @@ class AutoexposureApp final : public examples::SimpleWindowedApplication, public
83259
protected:
84260
smart_refctd_ptr<IWindow> m_window;
85261
smart_refctd_ptr<CSimpleResizeSurface<CDefaultSwapchainFramebuffers>> m_surface;
262+
smart_refctd_ptr<IGPUImage> m_gpuImg;
263+
smart_refctd_ptr<IGPUImageView> m_gpuImgView;
264+
265+
// for image uploads
266+
smart_refctd_ptr<ISemaphore> m_scratchSemaphore;
267+
SIntendedSubmitInfo m_intendedSubmit;
268+
269+
// Command Buffers and other resources
270+
std::array<smart_refctd_ptr<IGPUDescriptorSet>, ISwapchain::MaxImages> m_descriptorSets;
271+
smart_refctd_ptr<IGPUCommandPool> m_cmdPool;
272+
std::array<smart_refctd_ptr<IGPUCommandBuffer>, ISwapchain::MaxImages> m_cmdBufs;
86273
};
87274

88275
NBL_MAIN_FUNC(AutoexposureApp)
@@ -136,38 +323,6 @@ int main()
136323
IAssetLoader::SAssetLoadParams lp;
137324
auto imageBundle = am->getAsset("../../media/noises/spp_benchmark_4k_512.exr", lp);
138325

139-
E_FORMAT inFormat;
140-
constexpr auto outFormat = EF_R8G8B8A8_SRGB;
141-
smart_refctd_ptr<IGPUImage> outImg;
142-
smart_refctd_ptr<IGPUImageView> imgToTonemapView,outImgView;
143-
{
144-
auto cpuImg = IAsset::castDown<ICPUImage>(imageBundle.getContents().begin()[0]);
145-
IGPUImage::SCreationParams imgInfo = cpuImg->getCreationParameters();
146-
inFormat = imgInfo.format;
147-
148-
auto gpuImages = driver->getGPUObjectsFromAssets(&cpuImg.get(),&cpuImg.get()+1);
149-
auto gpuImage = gpuImages->operator[](0u);
150-
151-
IGPUImageView::SCreationParams imgViewInfo;
152-
imgViewInfo.flags = static_cast<IGPUImageView::E_CREATE_FLAGS>(0u);
153-
imgViewInfo.image = std::move(gpuImage);
154-
imgViewInfo.viewType = IGPUImageView::ET_2D_ARRAY;
155-
imgViewInfo.format = inFormat;
156-
imgViewInfo.subresourceRange.aspectMask = static_cast<IImage::E_ASPECT_FLAGS>(0u);
157-
imgViewInfo.subresourceRange.baseMipLevel = 0;
158-
imgViewInfo.subresourceRange.levelCount = 1;
159-
imgViewInfo.subresourceRange.baseArrayLayer = 0;
160-
imgViewInfo.subresourceRange.layerCount = 1;
161-
imgToTonemapView = driver->createImageView(IGPUImageView::SCreationParams(imgViewInfo));
162-
163-
imgInfo.format = outFormat;
164-
outImg = driver->createDeviceLocalGPUImageOnDedMem(std::move(imgInfo));
165-
166-
imgViewInfo.image = outImg;
167-
imgViewInfo.format = outFormat;
168-
outImgView = driver->createImageView(IGPUImageView::SCreationParams(imgViewInfo));
169-
}
170-
171326
auto glslCompiler = am->getCompilerSet();
172327
const auto inputColorSpace = std::make_tuple(inFormat,ECP_SRGB,EOTF_IDENTITY);
173328

0 commit comments

Comments
 (0)