MCPcopy Create free account
hub / github.com/Tom94/tev / load

Method load

src/imageio/DdsImageLoader.cpp:155–269  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

153}
154
155Task<vector<ImageData>> DdsImageLoader::load(istream& iStream, const fs::path&, string_view, const ImageLoaderSettings&, int priority) const {
156 iStream.seekg(0, iStream.end);
157 const size_t dataSize = iStream.tellg();
158 if (dataSize < 4) {
159 throw FormatNotSupported{"File is too small."};
160 }
161
162 iStream.clear();
163 iStream.seekg(0);
164
165 HeapArray<char> data{dataSize};
166 iStream.read(data.data(), 4);
167 if (data[0] != 'D' || data[1] != 'D' || data[2] != 'S' || data[3] != ' ') {
168 throw FormatNotSupported{"File is not a DDS file."};
169 }
170
171 iStream.read(data.data() + 4, dataSize - 4);
172
173 // COM must be initialized on the thread executing the following DirectX calls. Thus: when editing this file *make sure* that no
174 // co_await calls are made before the last DirectX call! Note that it is not a problem that CoInitializeEx will potentially get called
175 // multiple times across different threads, or even multiple times by the same thread pool thread. Both situations are explicitly
176 // allowed (and in the latter case, the return value is S_FALSE). See
177 // https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex
178 if (const auto res = CoInitializeEx(nullptr, COINIT_MULTITHREADED); res != S_OK && res != S_FALSE) {
179 throw ImageLoadError{"Failed to initialize COM."};
180 }
181
182 // The correct way to clean up would be to call CoUninitialize() on every task pool thread on shutdown. Using a scope guard here
183 // wouldn't work for multiple reasons: (i) the coroutine might have been scheduled to another thread once the scope ends, and (ii) it
184 // would be wasteful to repeatedly initialize and uninitialize COM for every loaded image. Instead, we'll just accept that COM won't be
185 // gracefully cleaned up on shutdown -- we don't care much about its cleanup anyway, which involved mostly handling of pending messages
186 // in the application's message queue.
187 // const auto comScopeGuard = ScopeGuard{[]() { CoUninitialize(); }};
188
189 DirectX::ScratchImage scratchImage;
190 DirectX::TexMetadata metadata;
191 if (DirectX::LoadFromDDSMemory(data.data(), dataSize, DirectX::DDS_FLAGS_NONE, &metadata, scratchImage) != S_OK) {
192 throw ImageLoadError{"Failed to read DDS file."};
193 }
194
195 DXGI_FORMAT format;
196 const size_t numChannels = getDxgiChannelCount(metadata.format);
197 switch (numChannels) {
198 case 4: format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
199 case 3: format = DXGI_FORMAT_R32G32B32_FLOAT; break;
200 case 2: format = DXGI_FORMAT_R32G32_FLOAT; break;
201 case 1: format = DXGI_FORMAT_R32_FLOAT; break;
202 default: throw ImageLoadError{fmt::format("Unsupported DXGI format: {}", static_cast<int>(metadata.format))};
203 }
204
205 // Use DirectXTex to either decompress or convert to the target floating point format.
206 if (DirectX::IsCompressed(metadata.format)) {
207 DirectX::ScratchImage decompImage;
208 if (DirectX::Decompress(*scratchImage.GetImage(0, 0, 0), format, decompImage) != S_OK) {
209 throw ImageLoadError{"Failed to decompress DDS image."};
210 }
211
212 swap(scratchImage, decompImage);

Callers

nothing calls this directly

Calls 8

getDxgiChannelCountFunction · 0.85
posProdFunction · 0.85
seekgMethod · 0.80
tellgMethod · 0.80
clearMethod · 0.80
readMethod · 0.45
dataMethod · 0.45

Tested by

no test coverage detected