11#include " dds_io.hpp"
22
3+ #include < algorithm>
34#include < cstring>
45#include < filesystem>
56#include < fstream>
@@ -52,6 +53,11 @@ struct DDSHeaderDX10 {
5253static_assert (sizeof (DDSHeaderDX10) == 20 );
5354
5455constexpr uint32_t kDDSMagic = 0x20534444 ; // "DDS"
56+ constexpr uint32_t kDDSDMipmapCount = 0x00020000 ;
57+ constexpr uint32_t kDDSCapsComplex = 0x00000008 ;
58+ constexpr uint32_t kDDSCapsMipmap = 0x00400000 ;
59+ constexpr uint32_t kDDSCaps2Cubemap = 0x00000200 ;
60+ constexpr uint32_t kDDSCaps2Volume = 0x00200000 ;
5561
5662bool ensure_directory (const std::filesystem::path& dir) noexcept {
5763 std::error_code ec;
@@ -101,12 +107,36 @@ bool validate_dds_header(const DDSHeader& header) noexcept {
101107 if (header.width == 0 || header.height == 0 ) {
102108 return false ;
103109 }
104- if ((header.caps2 & (0x00000200 | 0x00200000 )) != 0 ) { // Unsupported
110+ if ((header.caps2 & (kDDSCaps2Cubemap | kDDSCaps2Volume )) != 0 ) { // Unsupported
105111 return false ;
106112 }
107113 return true ;
108114}
109115
116+ uint32_t max_mip_count (uint32_t width, uint32_t height) noexcept {
117+ uint32_t count = 1 ;
118+ while (width > 1 || height > 1 ) {
119+ width = std::max (width >> 1 , 1u );
120+ height = std::max (height >> 1 , 1u );
121+ ++count;
122+ }
123+ return count;
124+ }
125+
126+ std::optional<uint32_t > resolve_mip_count (const DDSHeader& header) noexcept {
127+ if (header.mipMapCount <= 1 ) {
128+ return 1 ;
129+ }
130+
131+ const bool hasMipFlags = (header.flags & kDDSDMipmapCount ) != 0 && (header.caps & kDDSCapsComplex ) != 0 &&
132+ (header.caps & kDDSCapsMipmap ) != 0 ;
133+ if (!hasMipFlags || header.mipMapCount > max_mip_count (header.width , header.height )) {
134+ return std::nullopt ;
135+ }
136+
137+ return header.mipMapCount ;
138+ }
139+
110140std::optional<wgpu::TextureFormat> resolve_dx10_format (uint32_t dxgiFormat) noexcept {
111141 switch (dxgiFormat) {
112142 case 28 :
@@ -253,8 +283,12 @@ std::optional<ConvertedTexture> parse_dds_bytes(ArrayRef<uint8_t> bytes) noexcep
253283 return std::nullopt ;
254284 }
255285
256- const uint32_t mipCount = 1u ;
257- const auto expectedSize = calc_texture_size (parsedLayout->format , header->width , header->height , mipCount);
286+ const auto mipCount = resolve_mip_count (*header);
287+ if (!mipCount.has_value ()) {
288+ return std::nullopt ;
289+ }
290+
291+ const auto expectedSize = calc_texture_size (parsedLayout->format , header->width , header->height , *mipCount);
258292 if (expectedSize == 0 || parsedLayout->dataOffset + expectedSize > bytes.size ()) {
259293 return std::nullopt ;
260294 }
@@ -265,7 +299,7 @@ std::optional<ConvertedTexture> parse_dds_bytes(ArrayRef<uint8_t> bytes) noexcep
265299 .format = parsedLayout->format ,
266300 .width = header->width ,
267301 .height = header->height ,
268- .mips = mipCount,
302+ .mips = * mipCount,
269303 .data = std::move (data),
270304 };
271305}
0 commit comments