1
- // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
1
+ // Copyright (C) 2018-2023 - DevSH Graphics Programming Sp. z O.O.
2
2
// This file is part of the "Nabla Engine".
3
3
// 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_
7
6
8
7
#include " nbl/asset/IImage.h"
9
8
@@ -16,8 +15,8 @@ template<class ImageType>
16
15
class IImageView : public IDescriptor
17
16
{
18
17
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 );
21
20
22
21
// no flags for now, yet
23
22
enum E_CREATE_FLAGS
@@ -80,12 +79,18 @@ class IImageView : public IDescriptor
80
79
};
81
80
struct SCreationParams
82
81
{
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};
89
94
};
90
95
// !
91
96
inline static bool validateCreationParameters (const SCreationParams& _params)
@@ -97,11 +102,45 @@ class IImageView : public IDescriptor
97
102
return false ;
98
103
99
104
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 ;
101
120
if (mutableFormat)
102
121
{
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 ;
105
144
106
145
/*
107
146
TODO: if the format of the image is a multi-planar format, and if subresourceRange.aspectMask
@@ -110,90 +149,51 @@ class IImageView : public IDescriptor
110
149
as defined in Compatible formats of planes of multi-planar formats
111
150
*/
112
151
}
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 )
139
153
{
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
151
155
return false ;
152
- */
156
+ }
157
+
158
+ // ! sanity checks
153
159
160
+ // we have some layers
161
+ if (subresourceRange.layerCount ==0u )
162
+ return false ;
163
+
164
+ // mip level ranges
154
165
if (subresourceRange.baseMipLevel >=imgParams.mipLevels )
155
166
return false ;
156
167
if (subresourceRange.levelCount !=remaining_mip_levels &&
157
168
(subresourceRange.levelCount ==0u ||
158
169
subresourceRange.baseMipLevel +subresourceRange.levelCount >imgParams.mipLevels ))
159
170
return false ;
171
+
160
172
auto mipExtent = _params.image ->getMipSize (subresourceRange.baseMipLevel );
161
-
162
- if (subresourceRange.layerCount ==0u )
163
- return false ;
173
+ auto actualLayerCount = subresourceRange.layerCount ;
164
174
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)
171
178
{
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 ;
182
181
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 ;
196
195
196
+ bool checkLayers = true ;
197
197
switch (_params.viewType )
198
198
{
199
199
case ET_1D:
@@ -203,8 +203,6 @@ class IImageView : public IDescriptor
203
203
return false ;
204
204
[[fallthrough]];
205
205
case ET_1D_ARRAY:
206
- if (imgParams.extent .height >1u || imgParams.extent .depth >1u )
207
- return false ;
208
206
break ;
209
207
case ET_2D:
210
208
if (imgParams.type ==IImage::ET_1D)
@@ -213,7 +211,7 @@ class IImageView : public IDescriptor
213
211
return false ;
214
212
[[fallthrough]];
215
213
case ET_2D_ARRAY:
216
- if (sourceIs3D )
214
+ if (imgParams. type ==IImage::ET_3D )
217
215
{
218
216
if (!sourceIs2DCompat)
219
217
return false ;
@@ -226,16 +224,22 @@ class IImageView : public IDescriptor
226
224
return false ;
227
225
if (subresourceRange.baseArrayLayer >=mipExtent.z )
228
226
return false ;
229
- if (subresourceRange. baseArrayLayer +actualLayerCount >mipExtent.z )
227
+ if (endLayer >mipExtent.z )
230
228
return false ;
231
229
}
232
230
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]];
233
237
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 )
235
241
return false ;
236
- break ;
237
- case ET_CUBE_MAP:
238
- if (!hasCubemapProporties (false ))
242
+ if (!imgParams.flags .hasFlags (IImage::ECF_CUBE_COMPATIBLE_BIT))
239
243
return false ;
240
244
break ;
241
245
case ET_3D:
@@ -245,15 +249,14 @@ class IImageView : public IDescriptor
245
249
return false ;
246
250
break ;
247
251
}
252
+
248
253
if (checkLayers)
249
254
{
250
255
if (subresourceRange.baseArrayLayer >=imgParams.arrayLayers )
251
256
return false ;
252
- if (subresourceRange.layerCount !=remaining_array_layers &&
253
- (subresourceRange.baseArrayLayer +subresourceRange.layerCount >imgParams.arrayLayers ))
257
+ if (endLayer>imgParams.arrayLayers )
254
258
return false ;
255
259
}
256
-
257
260
return true ;
258
261
}
259
262
0 commit comments