55#include " ../common/SimpleWindowedApplication.hpp"
66
77#include " nbl/video/surface/CSurfaceVulkan.h"
8+ #include " nbl/asset/interchange/IAssetLoader.h"
89
910using namespace nbl ;
1011using 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+
2529public:
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
83259protected:
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
88275NBL_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