@@ -90,32 +90,49 @@ bool ReplacedTexture::IsReady(double budget) {
90
90
91
91
_assert_ (!threadWaitable_);
92
92
threadWaitable_ = new LimitedWaitable ();
93
+ SetState (ReplacementState::PENDING);
93
94
g_threadManager.EnqueueTask (new ReplacedTextureTask (vfs_, *this , threadWaitable_));
94
95
if (threadWaitable_->WaitFor (budget)) {
95
96
// If we successfully wait here, we're done. The thread will set state accordingly.
96
97
_assert_ (State () == ReplacementState::ACTIVE || State () == ReplacementState::NOT_FOUND || State () == ReplacementState::CANCEL_INIT);
97
98
return true ;
98
99
}
99
- SetState (ReplacementState::PENDING);
100
100
// Still pending on thread.
101
101
return false ;
102
102
}
103
103
104
- void ReplacedTexture::FinishPopulate (const ReplacementDesc &desc) {
105
- logId_ = desc.logId ;
106
- levelData_ = desc.cache ;
104
+ void ReplacedTexture::FinishPopulate (ReplacementDesc *desc) {
105
+ logId_ = desc->logId ;
106
+ levelData_ = desc->cache ;
107
+ desc_ = desc;
108
+ SetState (ReplacementState::POPULATED);
109
+
110
+ // TODO: What used to be here is now done on the thread task.
111
+ }
107
112
108
- // TODO: The rest can be done on the thread.
113
+ void ReplacedTexture::Prepare (VFSBackend *vfs) {
114
+ this ->vfs_ = vfs;
115
+
116
+ std::unique_lock<std::mutex> lock (mutex_);
117
+
118
+ _assert_msg_ (levelData_ != nullptr , " Level cache not set" );
119
+
120
+ // We must lock around access to levelData_ in case two textures try to load it at once.
121
+ std::lock_guard<std::mutex> guard (levelData_->lock );
122
+
123
+ for (int i = 0 ; i < std::min (MAX_REPLACEMENT_MIP_LEVELS, (int )desc_->filenames .size ()); ++i) {
124
+ if (State () == ReplacementState::CANCEL_INIT) {
125
+ break ;
126
+ }
109
127
110
- for (int i = 0 ; i < std::min (MAX_REPLACEMENT_MIP_LEVELS, (int )desc.filenames .size ()); ++i) {
111
- if (desc.filenames [i].empty ()) {
128
+ if (desc_->filenames [i].empty ()) {
112
129
// Out of valid mip levels. Bail out.
113
130
break ;
114
131
}
115
132
116
- const Path filename = desc. basePath / desc. filenames [i];
133
+ const Path filename = desc_-> basePath / desc_-> filenames [i];
117
134
118
- VFSFileReference *fileRef = vfs_->GetFile (desc. filenames [i].c_str ());
135
+ VFSFileReference *fileRef = vfs_->GetFile (desc_-> filenames [i].c_str ());
119
136
if (!fileRef) {
120
137
// If the file doesn't exist, let's just bail immediately here.
121
138
break ;
@@ -130,58 +147,43 @@ void ReplacedTexture::FinishPopulate(const ReplacementDesc &desc) {
130
147
fmt = Draw::DataFormat::R8G8B8A8_UNORM;
131
148
}
132
149
133
- bool good;
134
-
135
150
level.fileRef = fileRef;
136
- good = PopulateLevel (level, false );
137
-
138
- // We pad files that have been hashrange'd so they are the same texture size.
139
- level.w = (level.w * desc.w ) / desc.newW ;
140
- level.h = (level.h * desc.h ) / desc.newH ;
141
-
142
- if (good && i != 0 ) {
143
- // Check that the mipmap size is correct. Can't load mips of the wrong size.
144
- if (level.w != (levels_[0 ].w >> i) || level.h != (levels_[0 ].h >> i)) {
145
- WARN_LOG (G3D, " Replacement mipmap invalid: size=%dx%d, expected=%dx%d (level %d, '%s')" , level.w , level.h , levels_[0 ].w >> i, levels_[0 ].h >> i, i, filename.c_str ());
146
- good = false ;
147
- }
148
- }
149
151
150
- if (good)
152
+ if (LoadLevelData (level, i)) {
151
153
levels_.push_back (level);
152
- // Otherwise, we're done loading mips (bad PNG or bad size, either way.)
153
- else
154
+ } else {
155
+ // Otherwise, we're done loading mips (bad PNG or bad size, either way.)
154
156
break ;
157
+ }
155
158
}
156
159
160
+ delete desc_;
161
+ desc_ = nullptr ;
162
+
157
163
if (levels_.empty ()) {
158
164
// Bad.
159
165
SetState (ReplacementState::NOT_FOUND);
160
166
levelData_ = nullptr ;
161
167
return ;
162
168
}
163
169
164
- // Populate the data pointer.
165
- SetState (ReplacementState::POPULATED);
170
+ SetState (ReplacementState::ACTIVE);
171
+
172
+ if (threadWaitable_)
173
+ threadWaitable_->Notify ();
166
174
}
167
175
168
- bool ReplacedTexture::PopulateLevel (ReplacedTextureLevel &level, bool ignoreError ) {
176
+ bool ReplacedTexture::LoadLevelData (ReplacedTextureLevel &level, int mipLevel ) {
169
177
bool good = false ;
170
178
171
- if (!level.fileRef ) {
172
- if (!ignoreError)
173
- ERROR_LOG (G3D, " Error opening replacement texture file '%s' in textures.zip" , level.file .c_str ());
174
- return false ;
175
- }
176
-
177
179
size_t fileSize;
178
- VFSOpenFile *file = vfs_->OpenFileForRead (level.fileRef , &fileSize);
179
- if (!file ) {
180
+ VFSOpenFile *openFile = vfs_->OpenFileForRead (level.fileRef , &fileSize);
181
+ if (!openFile ) {
180
182
return false ;
181
183
}
182
184
183
185
std::string magic;
184
- auto imageType = Identify (vfs_, file , &magic);
186
+ ReplacedImageType imageType = Identify (vfs_, openFile , &magic);
185
187
186
188
if (imageType == ReplacedImageType::ZIM) {
187
189
uint32_t ignore = 0 ;
@@ -191,13 +193,13 @@ bool ReplacedTexture::PopulateLevel(ReplacedTextureLevel &level, bool ignoreErro
191
193
uint32_t h;
192
194
uint32_t flags;
193
195
} header;
194
- good = vfs_->Read (file , &header, sizeof (header)) == sizeof (header);
196
+ good = vfs_->Read (openFile , &header, sizeof (header)) == sizeof (header);
195
197
level.w = header.w ;
196
198
level.h = header.h ;
197
199
good = (header.flags & ZIM_FORMAT_MASK) == ZIM_RGBA8888;
198
200
} else if (imageType == ReplacedImageType::PNG) {
199
201
PNGHeaderPeek headerPeek;
200
- good = vfs_->Read (file , &headerPeek, sizeof (headerPeek)) == sizeof (headerPeek);
202
+ good = vfs_->Read (openFile , &headerPeek, sizeof (headerPeek)) == sizeof (headerPeek);
201
203
if (good && headerPeek.IsValidPNGHeader ()) {
202
204
level.w = headerPeek.Width ();
203
205
level.h = headerPeek.Height ();
@@ -209,101 +211,80 @@ bool ReplacedTexture::PopulateLevel(ReplacedTextureLevel &level, bool ignoreErro
209
211
} else {
210
212
ERROR_LOG (G3D, " Could not load texture replacement info: %s - unsupported format %s" , level.file .ToVisualString ().c_str (), magic.c_str ());
211
213
}
212
- vfs_->CloseFile (file);
213
214
214
- return good;
215
- }
216
-
217
- void ReplacedTexture::Prepare (VFSBackend *vfs) {
218
- std::unique_lock<std::mutex> lock (mutex_);
219
- this ->vfs_ = vfs;
215
+ // Is this really the right place to do it?
216
+ level.w = (level.w * desc_->w ) / desc_->newW ;
217
+ level.h = (level.h * desc_->h ) / desc_->newH ;
220
218
221
- if (State () == ReplacementState::CANCEL_INIT) {
222
- return ;
219
+ if (good && mipLevel != 0 ) {
220
+ // Check that the mipmap size is correct. Can't load mips of the wrong size.
221
+ if (level.w != (levels_[0 ].w >> mipLevel) || level.h != (levels_[0 ].h >> mipLevel)) {
222
+ WARN_LOG (G3D, " Replacement mipmap invalid: size=%dx%d, expected=%dx%d (level %d)" ,
223
+ level.w , level.h , levels_[0 ].w >> mipLevel, levels_[0 ].h >> mipLevel, mipLevel);
224
+ good = false ;
225
+ }
223
226
}
224
227
225
- for (int i = 0 ; i < (int )levels_.size (); ++i) {
226
- if (State () == ReplacementState::CANCEL_INIT)
227
- break ;
228
- PrepareData (i);
228
+ if (!good) {
229
+ return false ;
229
230
}
230
231
231
- if (threadWaitable_)
232
- threadWaitable_->Notify ();
233
- }
234
-
235
- void ReplacedTexture::PrepareData (int level) {
236
- _assert_msg_ ((size_t )level < levels_.size (), " Invalid miplevel" );
237
- _assert_msg_ (levelData_ != nullptr , " Level cache not set" );
238
-
239
- // We must lock around access to levelData_ in case two textures try to load it at once.
240
- std::lock_guard<std::mutex> guard (levelData_->lock );
241
-
242
- const ReplacedTextureLevel &info = levels_[level];
243
-
244
- if (levelData_->data .size () <= level) {
245
- levelData_->data .resize (level + 1 );
232
+ if (levelData_->data .size () <= mipLevel) {
233
+ levelData_->data .resize (mipLevel + 1 );
246
234
}
247
235
248
- std::vector<uint8_t > &out = levelData_->data [level ];
236
+ std::vector<uint8_t > &out = levelData_->data [mipLevel ];
249
237
250
238
// Already populated from cache.
251
239
if (!out.empty ()) {
252
- SetState (ReplacementState::ACTIVE);
253
- return ;
240
+ return true ;
254
241
}
255
242
256
- ReplacedImageType imageType;
257
-
258
- size_t fileSize;
259
- VFSOpenFile *openFile = vfs_->OpenFileForRead (info.fileRef , &fileSize);
260
-
261
- std::string magic;
262
- imageType = Identify (vfs_, openFile, &magic);
263
-
264
243
auto cleanup = [&] {
265
244
vfs_->CloseFile (openFile);
266
245
};
267
246
247
+ vfs_->Rewind (openFile);
248
+
268
249
if (imageType == ReplacedImageType::ZIM) {
269
250
std::unique_ptr<uint8_t []> zim (new uint8_t [fileSize]);
270
251
if (!zim) {
271
252
ERROR_LOG (G3D, " Failed to allocate memory for texture replacement" );
272
253
SetState (ReplacementState::NOT_FOUND);
273
254
cleanup ();
274
- return ;
255
+ return false ;
275
256
}
276
257
277
258
if (vfs_->Read (openFile, &zim[0 ], fileSize) != fileSize) {
278
- ERROR_LOG (G3D, " Could not load texture replacement: %s - failed to read ZIM" , info .file .c_str ());
259
+ ERROR_LOG (G3D, " Could not load texture replacement: %s - failed to read ZIM" , level .file .c_str ());
279
260
SetState (ReplacementState::NOT_FOUND);
280
261
cleanup ();
281
- return ;
262
+ return false ;
282
263
}
283
264
284
265
int w, h, f;
285
266
uint8_t *image;
286
267
if (LoadZIMPtr (&zim[0 ], fileSize, &w, &h, &f, &image)) {
287
- if (w > info .w || h > info .h ) {
288
- ERROR_LOG (G3D, " Texture replacement changed since header read: %s" , info .file .c_str ());
268
+ if (w > level .w || h > level .h ) {
269
+ ERROR_LOG (G3D, " Texture replacement changed since header read: %s" , level .file .c_str ());
289
270
SetState (ReplacementState::NOT_FOUND);
290
271
cleanup ();
291
- return ;
272
+ return false ;
292
273
}
293
274
294
- out.resize (info .w * info .h * 4 );
295
- if (w == info .w ) {
296
- memcpy (&out[0 ], image, info .w * 4 * info .h );
275
+ out.resize (level .w * level .h * 4 );
276
+ if (w == level .w ) {
277
+ memcpy (&out[0 ], image, level .w * 4 * level .h );
297
278
} else {
298
279
for (int y = 0 ; y < h; ++y) {
299
- memcpy (&out[info .w * 4 * y], image + w * 4 * y, w * 4 );
280
+ memcpy (&out[level .w * 4 * y], image + w * 4 * y, w * 4 );
300
281
}
301
282
}
302
283
free (image);
303
284
}
304
285
305
- CheckAlphaResult res = CheckAlpha32Rect ((u32 *)&out[0 ], info .w , w, h, 0xFF000000 );
306
- if (res == CHECKALPHA_ANY || level == 0 ) {
286
+ CheckAlphaResult res = CheckAlpha32Rect ((u32 *)&out[0 ], level .w , w, h, 0xFF000000 );
287
+ if (res == CHECKALPHA_ANY || mipLevel == 0 ) {
307
288
alphaStatus_ = ReplacedTextureAlpha (res);
308
289
}
309
290
} else if (imageType == ReplacedImageType::PNG) {
@@ -314,49 +295,49 @@ void ReplacedTexture::PrepareData(int level) {
314
295
pngdata.resize (fileSize);
315
296
pngdata.resize (vfs_->Read (openFile, &pngdata[0 ], fileSize));
316
297
if (!png_image_begin_read_from_memory (&png, &pngdata[0 ], pngdata.size ())) {
317
- ERROR_LOG (G3D, " Could not load texture replacement info: %s - %s (zip)" , info .file .c_str (), png.message );
298
+ ERROR_LOG (G3D, " Could not load texture replacement info: %s - %s (zip)" , level .file .c_str (), png.message );
318
299
SetState (ReplacementState::NOT_FOUND);
319
300
cleanup ();
320
- return ;
301
+ return false ;
321
302
}
322
- if (png.width > (uint32_t )info .w || png.height > (uint32_t )info .h ) {
323
- ERROR_LOG (G3D, " Texture replacement changed since header read: %s" , info .file .c_str ());
303
+ if (png.width > (uint32_t )level .w || png.height > (uint32_t )level .h ) {
304
+ ERROR_LOG (G3D, " Texture replacement changed since header read: %s" , level .file .c_str ());
324
305
SetState (ReplacementState::NOT_FOUND);
325
306
cleanup ();
326
- return ;
307
+ return false ;
327
308
}
328
309
329
310
bool checkedAlpha = false ;
330
311
if ((png.format & PNG_FORMAT_FLAG_ALPHA) == 0 ) {
331
312
// Well, we know for sure it doesn't have alpha.
332
- if (level == 0 ) {
313
+ if (mipLevel == 0 ) {
333
314
alphaStatus_ = ReplacedTextureAlpha::FULL;
334
315
}
335
316
checkedAlpha = true ;
336
317
}
337
318
png.format = PNG_FORMAT_RGBA;
338
319
339
- out.resize (info .w * info .h * 4 );
340
- if (!png_image_finish_read (&png, nullptr , &out[0 ], info .w * 4 , nullptr )) {
341
- ERROR_LOG (G3D, " Could not load texture replacement: %s - %s" , info .file .c_str (), png.message );
320
+ out.resize (level .w * level .h * 4 );
321
+ if (!png_image_finish_read (&png, nullptr , &out[0 ], level .w * 4 , nullptr )) {
322
+ ERROR_LOG (G3D, " Could not load texture replacement: %s - %s" , level .file .c_str (), png.message );
342
323
SetState (ReplacementState::NOT_FOUND);
343
324
cleanup ();
344
325
out.resize (0 );
345
- return ;
326
+ return false ;
346
327
}
347
328
png_image_free (&png);
348
329
349
330
if (!checkedAlpha) {
350
331
// This will only check the hashed bits.
351
- CheckAlphaResult res = CheckAlpha32Rect ((u32 *)&out[0 ], info .w , png.width , png.height , 0xFF000000 );
352
- if (res == CHECKALPHA_ANY || level == 0 ) {
332
+ CheckAlphaResult res = CheckAlpha32Rect ((u32 *)&out[0 ], level .w , png.width , png.height , 0xFF000000 );
333
+ if (res == CHECKALPHA_ANY || mipLevel == 0 ) {
353
334
alphaStatus_ = ReplacedTextureAlpha (res);
354
335
}
355
336
}
356
337
}
357
338
358
- SetState (ReplacementState::ACTIVE);
359
339
cleanup ();
340
+ return true ;
360
341
}
361
342
362
343
void ReplacedTexture::PurgeIfOlder (double t) {
0 commit comments