After a discussion on #scp here is what we came up with:...
- Use an
intsize_t for the ID and increment it every time we need a new slot (animations are created in one call so for a frame i the ID is startID + i)
size_t plz.That would be better but bmpman currently uses ints as handles with -1 being an invalid handle. If we were to change that to a size_t we would need to check every usage of a bmpman handle to make sure that the new "invalid" value is used and not -1.
size_t plz.That would be better but bmpman currently uses ints as handles with -1 being an invalid handle. If we were to change that to a size_t we would need to check every usage of a bmpman handle to make sure that the new "invalid" value is used and not -1.
Ded forum, ded scp.
Nothing seems to get done anymore :(
But with regards to animations and scripts, is that really a problem? The smart way to do that right now is with gr.loadTexture(), with an argument to load as an animation and then you draw the frames and change the frame index every frame. The script never actually directly touch the raw files, even with effs (and as such, the script writer needs to make sure he/she unloads the texture!). Or would it break even then?I... hmm. For some reason I thought scripts were using BMPMAN slots directly, but a closer look at the only example I had on hand shows it using the animation returned by loadTexture(), so I guess they'd actually be fine.
Unless you mean scripts that intentionally use a single frame of an animation like an image from a larger eff? Or I might be misunderstanding something...
+BMP DEBUG
+General
+Warning
+Error
+BMP DEBUG
[X] only look for 3 frames to hold eff-anim instead of all frames (NEEDS TESTING)
[ ] reset 3rd frame back to _0001 after finishing playing anim (so we don't keeping using up slots)
[ ] update unload/release functions to handle the 3-frame anis
[x] see if we can release headani's between missions (don't just unload them) (looks like they are already released)
[x] correctly deal with EFFs that don't have all the frames AND are streaming - cap frames to "reset" to 3 (NEEDS TESTING)
[ ] deal with someone trying to use an EFF for streaming AND non-streaming (not sure where to store the "type" data just yet...)
[ ] Test Axem's headani script
[ ] Remove all temp debug code
- Support for S3TC
Can we also add support for ASTC (http://www.phoronix.com/scan.php?page=news_item&px=MTE1NDk) (see also here for technical comparison (https://www.opengl.org/discussion_boards/showthread.php/185568-ASTC-on-the-desktop?p=1263807&viewfull=1#post1263807))? This is Adaptive Scalable Texture Compression and is a lossy, block-based algorithm originally designed by ARM and importantly is royalty-free.ASTC is still not widely supported by the hardware so most times we would need to decompress the texture in software and then send the decompressed data to the GPU. Bmpman can obviously be designed in such a way that different compression methods can be added later and I intend to do just that.
Re Atlasing: Would the modder have to create the texutre atlas manually and then just tell FSO the layout or should FSO generate the atlas by itself?Considering I don't even have the vaguest of clues what that even means, and considering the sheer list of stuff we already have to deal with during modding, my initial response to this is "Dear FRED, not more **** to deal with, please let FSO do everything for us!"
Re Atlasing: Would the modder have to create the texutre atlas manually and then just tell FSO the layout or should FSO generate the atlas by itself?Considering I don't even have the vaguest of clues what that even means, and considering the sheer list of stuff we already have to deal with during modding, my initial response to this is "Dear FRED, not more **** to deal with, please let FSO do everything for us!"
I think I've got headanis (only) using only 3 bmpman slots each; not quite finished but close. Here's my TODO list:Code: [Select][X] only look for 3 frames to hold eff-anim instead of all frames (NEEDS TESTING)
[ ] reset 3rd frame back to _0001 after finishing playing anim (so we don't keeping using up slots)
[ ] update unload/release functions to handle the 3-frame anis
[x] see if we can release headani's between missions (don't just unload them) (looks like they are already released)
[x] correctly deal with EFFs that don't have all the frames AND are streaming - cap frames to "reset" to 3 (NEEDS TESTING)
[ ] deal with someone trying to use an EFF for streaming AND non-streaming (not sure where to store the "type" data just yet...)
[ ] Test Axem's headani script
[ ] Remove all temp debug code
Note that I'm pretty sure I can't help the effects animations (at least not easily), in the new deferred rendered these are handled differently to headanis so the same easy win doesn't apply to them. Atlasing could help, but that's a far bigger & more complicated change.
Mission | Before | After |
Beta Tester Counterattack | 3612 | 2357 |
Escape from Highschool | Crash | 2433 |
...Get Revengeance | Crash | 2902 |
Bmpman: 3814/4750 bitmap slots in use.
Bmpman: 3545/4750 bitmap slots in use.
Bmpman: 3413/4750 bitmap slots in use.
Bmpman: 3929/4750 bitmap slots in use.
Bmpman: 3848/4750 bitmap slots in use.
Bmpman: 3750/4750 bitmap slots in use.
Bmpman: 4051/4750 bitmap slots in use.
Bmpman: 3917/4750 bitmap slots in use.
Bmpman: 3949/4750 bitmap slots in use.
Bmpman: 3849/4750 bitmap slots in use.
Bmpman: 3864/4750 bitmap slots in use.
Bmpman: 3864/4750 bitmap slots in use.
Bmpman: 3877/4750 bitmap slots in use.
Bmpman: 3878/4750 bitmap slots in use.
Bmpman: 3879/4750 bitmap slots in use.
Bmpman: 4091/4750 bitmap slots in use.
(contravention II crash)
Bmpman: 3528/4750 bitmap slots in use.
Bmpman: 3639/4750 bitmap slots in use.
Bmpman: 3791/4750 bitmap slots in use.
Bmpman: 3868/4750 bitmap slots in use.
Bmpman: 3680/4750 bitmap slots in use.
Bmpman: 3844/4750 bitmap slots in use.
Bmpman: 3891/4750 bitmap slots in use.
Bmpman: 4188/4750 bitmap slots in use.
(battle cutscene crash, skipped watching it)
Bmpman: 3752/4750 bitmap slots in use.
Bmpman: 3774/4750 bitmap slots in use.
Bmpman: 3808/4750 bitmap slots in use.
Bmpman: 3822/4750 bitmap slots in use.
Bmpman: 3825/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3826/4750 bitmap slots in use.
Bmpman: 3838/4750 bitmap slots in use.
Bmpman: 3838/4750 bitmap slots in use.
Bmpman: 3839/4750 bitmap slots in use.
Bmpman: 3839/4750 bitmap slots in use.
Bmpman: 3839/4750 bitmap slots in use.
Bmpman: 3839/4750 bitmap slots in use.
Bmpman: 3839/4750 bitmap slots in use.
Bmpman: 3628/4750 bitmap slots in use.
Bmpman: 3759/4750 bitmap slots in use.
ADE_FUNC(unload, l_Texture, NULL, "Unloads a texture from memory", NULL, NULL)
{
int *idx;
if(!ade_get_args(L, "o", l_Texture.GetPtr(&idx)))
return ADE_RETURN_NIL;
if(!bm_is_valid(*idx))
return ADE_RETURN_NIL;
bm_release(*idx);
//WMC - invalidate this handle
*idx = -1;
return ADE_RETURN_NIL;
}
ADE_FUNC(__gc, l_Texture, NULL, "Auto-deletes texture", NULL, NULL)
{
int idx;
if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
return ADE_RETURN_NIL;
// Note: due to some unknown reason, in some circumstances this function
// might get called even for handles to bitmaps which are actually still in
// use, and in order to prevent that we want to double-check the load count
// here before unloading the bitmap. -zookeeper
if(idx > -1 && bm_is_valid(idx) && bm_bitmaps[bm_get_cache_slot(idx, 0)].load_count < 1)
bm_release(idx);
return ADE_RETURN_NIL;
}
$ grep -iR unload Tables/ Scripts/
Tables/mv_exp-sct.tbm: arr_D_eff[j]:unload()
Tables/proBox-sct.tbm: self.Head.Filename:unload()
Right, I should be more clear. That setup works fine, 100%! (I've even done it that way on some new stuff and confirmed the BMPMAN slots get released properly)Well, that should be as trivial as replacing the bm_unload() call with a bm_release() call.
The issue is with gr.drawBitmap() using a filename (which is what I was using 99% of the time) instead of a texture loaded with gr.loadTexture(). When gr.drawBitmap() with a filename gets called, the bitmap gets thrown into bmpman as expected (and also a ScriptImages vector). But then in game_leave_state() (freespace.cpp around line 5617), Script_system.UnloadImages() gets called to bm_unload() all of the images that were called with the scripting system. (Not bm_release() which seems to be the more correct way to do it?)
That's what I had sort of picked up anyway as a semi-literate coder reader. ;)
I've tested this 64-bit build against the eleventh mission of the mod Shattered Stars, and I've got the BMPMAN assertion:Code: [Select]Assert: bm_bitmaps[bitmapnum].handle == handle
File: bmpman.cpp
Line: 683
Invalid bitmap handle 561502 passed to bm_get_info().
This might be due to an invalid animation somewhere else.
ntdll.dll! ZwWaitForSingleObject + 12 bytes
KERNELBASE.dll! WaitForSingleObject + 18 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! SCP_DumpStack + 354 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! WinAssert + 293 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! bm_get_info + 180 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! HudGaugeWeaponEnergy::render + 2820 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! hud_render_gauges + 555 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! hud_render_all + 37 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! game_render_hud + 150 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! game_frame + 957 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! game_do_frame + 231 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! game_do_state + 403 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! gameseq_process_events + 232 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! game_main + 787 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! WinMain + 328 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! invoke_main + 30 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! __scrt_common_main_seh + 346 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! __scrt_common_main + 13 bytes
fs2_open_3_7_3_SSE2-DEBUG.exe! WinMainCRTStartup + 8 bytes
KERNEL32.DLL! BaseThreadInitThunk + 36 bytes
ntdll.dll! RtlUnicodeStringToInteger + 595 bytes
ntdll.dll! RtlUnicodeStringToInteger + 542 bytes
Why did you remove all the doxygen comments? It seems like you have reverted the bmpman files to an earlier revision, was that on purpose? And if yes, what was the purpose?
I looked through the bmpman header a bit and noticed a few unused function. Here is a github branch with those removed: https://github.com/asarium/fs2open.github.com/tree/refactor/bmpman
I've squashed these two commits already on GitHub.No you haven't; they're clearly still two separate commits.
Are there any tips for me to start working on BMPMAN. Where do I start?Well, I'd recommend not starting with BMPMAN, but if you insist, I'd make sure you understand the existing code before you try modifying it, since you still haven't explained what purpose this ID value serves that isn't served by the existing handle and signature values.
void bm_init() {
int i;
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
if (!bm_inited) {
bm_inited = 1;
atexit(bm_close);
}
for (i = 0; i<MAX_BITMAPS; i++) {
bm_bitmaps[i].filename[0] = '\0';
bm_bitmaps[i].id = 0;
bm_bitmaps[i].type = BM_TYPE_NONE;
bm_bitmaps[i].comp_type = BM_TYPE_NONE;
bm_bitmaps[i].dir_type = CF_TYPE_ANY;
bm_bitmaps[i].info.user.data = NULL;
bm_bitmaps[i].mem_taken = 0;
bm_bitmaps[i].bm.data = 0;
bm_bitmaps[i].bm.palette = NULL;
bm_bitmaps[i].info.ani.eff.type = BM_TYPE_NONE;
bm_bitmaps[i].info.ani.eff.filename[0] = '\0';
#ifdef BMPMAN_NDEBUG
bm_bitmaps[i].data_size = 0;
bm_bitmaps[i].used_count = 0;
bm_bitmaps[i].used_last_frame = 0;
bm_bitmaps[i].used_this_frame = 0;
#endif
bm_bitmaps[i].load_count = 0;
gr_bm_init(i);
bm_free_data(i); // clears flags, bbp, data, etc
}
}
struct bitmap_entry {
static size_t count;
public:
template<typename T>
static size_t get_id()
{
static size_t id = count++;
return id;
}
...
The core design flaw is that it is outdated, dating back to retail, particularly the 1990s. It was made with significant bits of Descent code (referring to Descent 2 which was released in 1996) which do not fully meets the modern requirements of today's computers and devices, including those running latest OSes such as Windows 10, released in 2015. Among them is that the animation system was plagued by invalid bitmap handling due to invalid animation somewhere else - an engine-crashing error I encountered during my testing of my Battle of Endor mission developed for Shattered Stars using 64-bit large-addressing aware builds.
The maximum number of bitmaps and repetitive items are the problems we're running into.
And here's the code snippet of the partial solution:Code: [Select]struct bitmap_entry {
static size_t count;
public:
template<typename T>
static size_t get_id()
{
static size_t id = count++;
return id;
}
...
This gives the bitmap entry a unique ID in a more fool-proof way.
The maximum number of bitmaps and repetitive items are the problems we're running into.
Two tasks.
One. Explain what the keyword "static" in C/C++ does, and what behaviour your specific usage here will result in.
Two. Explain what a "Template" in C++ is, and what it does in this code snippet of yours.
The static keyword is used to declare variables and functions at global scope, namespace scope, class scope and local scope. Static objects or variables are allocated when the program starts and is deallocated when the program ends. In this case here, an ID is initialized upon starting FSO, and it deallocated when FSO closes.
Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type. Here in my code snippet, type is a placeholder name for a data type used by the function. This name can be used within the function definition - in this case, get an ID for a bitmap entry.