1- // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
1+ // Copyright (C) 2018-2023 - DevSH Graphics Programming Sp. z O.O.
22// This file is part of the "Nabla Engine".
33// For conditions of distribution and use, see copyright notice in nabla.h
4-
5- #ifndef __NBL_ASSET_I_IMAGE_VIEW_H_INCLUDED__
6- #define __NBL_ASSET_I_IMAGE_VIEW_H_INCLUDED__
4+ #ifndef _NBL_ASSET_I_IMAGE_VIEW_H_INCLUDED_
5+ #define _NBL_ASSET_I_IMAGE_VIEW_H_INCLUDED_
76
87#include " nbl/asset/IImage.h"
98
@@ -16,8 +15,8 @@ template<class ImageType>
1615class IImageView : public IDescriptor
1716{
1817 public:
19- _NBL_STATIC_INLINE_CONSTEXPR size_t remaining_mip_levels = ~static_cast <size_t >(0u );
20- _NBL_STATIC_INLINE_CONSTEXPR size_t remaining_array_layers = ~static_cast <size_t >(0u );
18+ static inline constexpr uint32_t remaining_mip_levels = ~static_cast <uint32_t >(0u );
19+ static inline constexpr uint32_t remaining_array_layers = ~static_cast <uint32_t >(0u );
2120
2221 // no flags for now, yet
2322 enum E_CREATE_FLAGS
@@ -80,12 +79,18 @@ class IImageView : public IDescriptor
8079 };
8180 struct SCreationParams
8281 {
83- E_CREATE_FLAGS flags = static_cast <E_CREATE_FLAGS>(0 );
84- core::smart_refctd_ptr<ImageType> image;
85- E_TYPE viewType;
86- E_FORMAT format;
87- SComponentMapping components;
88- IImage::SSubresourceRange subresourceRange;
82+ E_CREATE_FLAGS flags = static_cast <E_CREATE_FLAGS>(0 );
83+ // These are the set of usages for this ImageView, they must be a subset of the usages that `image` was created with.
84+ // If you leave it as the default NONE we'll inherit all usages from the `image`, setting it to anything else is
85+ // ONLY useful when creating multiple views of an image created with EXTENDED_USAGE to use different view formats.
86+ // Example: Create SRGB image with usage STORAGE, and two views with formats SRGB and R32_UINT. Then the SRGB view
87+ // CANNOT have STORAGE usage because the format doesn't support it, but the R32_UINT can.
88+ core::bitflag<IImage::E_USAGE_FLAGS> subUsages = IImage::EUF_NONE;
89+ core::smart_refctd_ptr<ImageType> image;
90+ E_TYPE viewType;
91+ E_FORMAT format;
92+ SComponentMapping components = {};
93+ IImage::SSubresourceRange subresourceRange = {IImage::EAF_COLOR_BIT,0 ,remaining_mip_levels,0 ,remaining_array_layers};
8994 };
9095 // !
9196 inline static bool validateCreationParameters (const SCreationParams& _params)
@@ -97,11 +102,45 @@ class IImageView : public IDescriptor
97102 return false ;
98103
99104 const auto & imgParams = _params.image ->getCreationParameters ();
100- bool mutableFormat = imgParams.flags .hasFlags (IImage::ECF_MUTABLE_FORMAT_BIT);
105+ /* TODO: LAter
106+ image must have been created with a usage value containing at least one of VK_IMAGE_USAGE_SAMPLED_BIT,
107+ VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
108+ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, or VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT
109+ if (imgParams.)
110+ return false;
111+ */
112+
113+ // declared usages that are not a subset
114+ if (!imgParams.usage .hasFlags (_params.subUsages ))
115+ return false ;
116+
117+ const bool mutableFormat = imgParams.flags .hasFlags (IImage::ECF_MUTABLE_FORMAT_BIT);
118+ const bool blockTexelViewCompatible = imgParams.flags .hasFlags (IImage::ECF_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT);
119+ const auto & subresourceRange = _params.subresourceRange ;
101120 if (mutableFormat)
102121 {
103- // if (!isFormatCompatible(_params.format,imgParams.format))
104- // return false;
122+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageCreateInfo-flags-01573
123+ // BlockTexelViewCompatible implies MutableFormat
124+ if (blockTexelViewCompatible)
125+ {
126+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01583
127+ // If image was created with the VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flag, format must be compatible with,
128+ // or must be an uncompressed format that is size-compatible with, the format used to create image
129+ if (getTexelOrBlockBytesize (_params.format )!=getTexelOrBlockBytesize (imgParams.format ))
130+ return false ;
131+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-image-07072
132+ // If image was created with the VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flag and
133+ // format is a non-compressed format, the levelCount and layerCount members of subresourceRange must both be 1
134+ if (!asset::isBlockCompressionFormat (_params.format ) && (subresourceRange.levelCount !=1u || subresourceRange.layerCount !=1u ))
135+ return false ;
136+ }
137+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-image-01761
138+ // If image was created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag, but without the VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flag,
139+ // and if the format of the image is not a multi-planar format, format must be compatible with the format used to create image
140+ else if (getFormatClass (_params.format )!=getFormatClass (imgParams.format ))
141+ return false ;
142+ else if (asset::isBlockCompressionFormat (_params.format )!=asset::isBlockCompressionFormat (imgParams.format ))
143+ return false ;
105144
106145 /*
107146 TODO: if the format of the image is a multi-planar format, and if subresourceRange.aspectMask
@@ -110,90 +149,51 @@ class IImageView : public IDescriptor
110149 as defined in Compatible formats of planes of multi-planar formats
111150 */
112151 }
113-
114-
115- const auto & subresourceRange = _params.subresourceRange ;
116-
117- if (imgParams.flags .hasFlags (IImage::ECF_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT))
118- {
119- /*
120- TODO: format must be compatible with, or must be an uncompressed format that is size-compatible with,
121- the format used to create image.
122- */
123- if (subresourceRange.levelCount !=1u || subresourceRange.layerCount !=1u )
124- return false ;
125- }
126- else
127- {
128- if (mutableFormat)
129- {
130- /*
131- TODO: if the format of the image is not a multi-planar format,
132- format must be compatible with the format used to create image,
133- as defined in Format Compatibility Classes
134- */
135- }
136- }
137-
138- if (!mutableFormat || asset::isPlanarFormat (imgParams.format ))
152+ else if (_params.format !=imgParams.format )
139153 {
140- /*
141- TODO: format must be compatible with, or must be an uncompressed format that is size-compatible with,
142- the format used to create image.
143- */
144- }
145-
146- /*
147- image must have been created with a usage value containing at least one of VK_IMAGE_USAGE_SAMPLED_BIT,
148- VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
149- VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, or VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT
150- if (imgParams.)
154+ // TODO: multi-planar exceptions
151155 return false ;
152- */
156+ }
157+
158+ // ! sanity checks
153159
160+ // we have some layers
161+ if (subresourceRange.layerCount ==0u )
162+ return false ;
163+
164+ // mip level ranges
154165 if (subresourceRange.baseMipLevel >=imgParams.mipLevels )
155166 return false ;
156167 if (subresourceRange.levelCount !=remaining_mip_levels &&
157168 (subresourceRange.levelCount ==0u ||
158169 subresourceRange.baseMipLevel +subresourceRange.levelCount >imgParams.mipLevels ))
159170 return false ;
171+
160172 auto mipExtent = _params.image ->getMipSize (subresourceRange.baseMipLevel );
161-
162- if (subresourceRange.layerCount ==0u )
163- return false ;
173+ auto actualLayerCount = subresourceRange.layerCount ;
164174
165- bool sourceIs3D = imgParams.type ==IImage::ET_3D;
166- bool sourceIs2DCompat = imgParams.flags .hasFlags (IImage::ECF_2D_ARRAY_COMPATIBLE_BIT) && (_params.viewType ==ET_2D||_params.viewType ==ET_2D_ARRAY);
167- auto actualLayerCount = subresourceRange.layerCount !=remaining_array_layers ? subresourceRange.layerCount :
168- ((sourceIs3D&&sourceIs2DCompat ? mipExtent.z :imgParams.arrayLayers )-subresourceRange.baseArrayLayer );
169- bool checkLayers = true ;
170- auto hasCubemapProporties = [&](bool isItACubemapArray = false )
175+ // the fact that source is 3D is implied by IImage::validateCreationParams
176+ const bool sourceIs2DCompat = imgParams.flags .hasFlags (IImage::ECF_2D_ARRAY_COMPATIBLE_BIT);
177+ if (subresourceRange.layerCount ==remaining_array_layers)
171178 {
172- if (!imgParams.flags .hasFlags (IImage::ECF_CUBE_COMPATIBLE_BIT))
173- return false ;
174- if (imgParams.samples > 1u )
175- return false ;
176- if (imgParams.extent .height != imgParams.extent .width )
177- return false ;
178- if (imgParams.extent .depth > 1u )
179- return false ;
180- if (actualLayerCount % 6u )
181- return false ;
179+ if (sourceIs2DCompat && _params.viewType !=ET_3D)
180+ actualLayerCount = mipExtent.z ;
182181 else
183- if (isItACubemapArray)
184- {
185- if (imgParams. arrayLayers < 6u )
186- return false ;
187- }
188- else
189- if (imgParams. arrayLayers != 6u )
190- return false ;
191-
192- if (subresourceRange.baseArrayLayer + actualLayerCount > imgParams. arrayLayers )
193- return false ;
194- return true ;
195- } ;
182+ actualLayerCount = imgParams. arrayLayers ;
183+ actualLayerCount -= subresourceRange. baseArrayLayer ;
184+ }
185+
186+ // If image was created with the VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flag, ... or must be an uncompressed format
187+ if (blockTexelViewCompatible && ! asset::isBlockCompressionFormat (_params. format ))
188+ {
189+ // In this case, the resulting image view’s texel dimensions equal the dimensions of the selected mip level divided by the compressed texel block size and rounded up.
190+ mipExtent = _params. image -> getTexelBlockInfo (). convertTexelsToBlocks (mipExtent);
191+ if (subresourceRange.layerCount ==remaining_array_layers )
192+ actualLayerCount = 1 ;
193+ }
194+ const auto endLayer = actualLayerCount+subresourceRange. baseArrayLayer ;
196195
196+ bool checkLayers = true ;
197197 switch (_params.viewType )
198198 {
199199 case ET_1D:
@@ -203,8 +203,6 @@ class IImageView : public IDescriptor
203203 return false ;
204204 [[fallthrough]];
205205 case ET_1D_ARRAY:
206- if (imgParams.extent .height >1u || imgParams.extent .depth >1u )
207- return false ;
208206 break ;
209207 case ET_2D:
210208 if (imgParams.type ==IImage::ET_1D)
@@ -213,7 +211,7 @@ class IImageView : public IDescriptor
213211 return false ;
214212 [[fallthrough]];
215213 case ET_2D_ARRAY:
216- if (sourceIs3D )
214+ if (imgParams. type ==IImage::ET_3D )
217215 {
218216 if (!sourceIs2DCompat)
219217 return false ;
@@ -226,16 +224,22 @@ class IImageView : public IDescriptor
226224 return false ;
227225 if (subresourceRange.baseArrayLayer >=mipExtent.z )
228226 return false ;
229- if (subresourceRange. baseArrayLayer +actualLayerCount >mipExtent.z )
227+ if (endLayer >mipExtent.z )
230228 return false ;
231229 }
232230 break ;
231+ case ET_CUBE_MAP:
232+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-viewType-02960
233+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-viewType-02962
234+ if (actualLayerCount!=6u )
235+ return false ;
236+ [[fallthrough]];
233237 case ET_CUBE_MAP_ARRAY:
234- if (!hasCubemapProporties (true ))
238+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-viewType-02961
239+ // https://registry.khronos.org/vulkan/specs/1.2/html/vkspec.html#VUID-VkImageViewCreateInfo-viewType-02963
240+ if (actualLayerCount%6u )
235241 return false ;
236- break ;
237- case ET_CUBE_MAP:
238- if (!hasCubemapProporties (false ))
242+ if (!imgParams.flags .hasFlags (IImage::ECF_CUBE_COMPATIBLE_BIT))
239243 return false ;
240244 break ;
241245 case ET_3D:
@@ -245,15 +249,14 @@ class IImageView : public IDescriptor
245249 return false ;
246250 break ;
247251 }
252+
248253 if (checkLayers)
249254 {
250255 if (subresourceRange.baseArrayLayer >=imgParams.arrayLayers )
251256 return false ;
252- if (subresourceRange.layerCount !=remaining_array_layers &&
253- (subresourceRange.baseArrayLayer +subresourceRange.layerCount >imgParams.arrayLayers ))
257+ if (endLayer>imgParams.arrayLayers )
254258 return false ;
255259 }
256-
257260 return true ;
258261 }
259262
0 commit comments