5
5
#include " ../common/SimpleWindowedApplication.hpp"
6
6
7
7
#include " nbl/video/surface/CSurfaceVulkan.h"
8
+ #include " nbl/asset/interchange/IAssetLoader.h"
8
9
9
10
using namespace nbl ;
10
11
using namespace core ;
@@ -22,6 +23,9 @@ class AutoexposureApp final : public examples::SimpleWindowedApplication, public
22
23
using asset_base_t = application_templates::MonoAssetManagerAndBuiltinResourceApplication;
23
24
using clock_t = std::chrono::steady_clock;
24
25
26
+ constexpr static inline std::string_view DefaultImagePathsFile = " ../../media/noises/spp_benchmark_4k_512.exr" ;
27
+
28
+
25
29
public:
26
30
// Yay thanks to multiple inheritance we cannot forward ctors anymore
27
31
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
62
66
if (!asset_base_t::onAppInitialized (std::move (system)))
63
67
return false ;
64
68
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
+
65
241
return true ;
66
242
}
67
243
@@ -83,6 +259,17 @@ class AutoexposureApp final : public examples::SimpleWindowedApplication, public
83
259
protected:
84
260
smart_refctd_ptr<IWindow> m_window;
85
261
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;
86
273
};
87
274
88
275
NBL_MAIN_FUNC (AutoexposureApp)
@@ -136,38 +323,6 @@ int main()
136
323
IAssetLoader::SAssetLoadParams lp;
137
324
auto imageBundle = am->getAsset("../../media/noises/spp_benchmark_4k_512.exr", lp);
138
325
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
-
171
326
auto glslCompiler = am->getCompilerSet();
172
327
const auto inputColorSpace = std::make_tuple(inFormat,ECP_SRGB,EOTF_IDENTITY);
173
328
0 commit comments