Yakoob on 18/4/2012 at 16:48
I always thought sizeof was a at-runtime funtion, not a at-compile time thing.
Al_B on 18/4/2012 at 17:03
No - in C and C++ it's compile time operator.
Yakoob on 18/4/2012 at 17:15
Ah gotcha. But I think I figured out why you get the error. Think about the process:
compiler tried to get sizeof( Snafu ) but to do that it needs to templetize class Foobar, but in order to do that it needs to get the sizeof( Snafu ), but in order to do that ...
You get the idea. Yes, statics dont affect class size, but I guess the compiler needs to have a "complete" definition of a class before it can process sizeof() directive?
Al_B on 18/4/2012 at 17:34
Correct. I'm not entirely sure why it should be a problem in this case, but it may be to prevent situation such as if, for example, Snafu contained a member variable such as:
Code:
unsigned char m_Storage[sizeof(Snafu)];
That would lead to a recursive problem as the size of the class would grow as the compiler tried to assess its own size.
zombe on 18/4/2012 at 18:53
Quote Posted by Al_B
I know you've got a work-around for it, but why not keep the class but make the template parameter simply a constructor variable?
Difficult choice :/
Pros:
* no more global namespace trashing.
Cons:
* a bit more inconvenient to use (3 macros per class instead of 2 [declaration+definition vs just definition]).
* trash (essentially) in class namespace.
Noteworthy:
* no speed difference either way (the extra lookup ends up in a code path that is pretty much never taken => branch prediction essentially removes all the code completely).
I think i pass for the time being as i value a clean class namespace dearly (oh i wish there was an auto-complete option in VC that would omit ALL options that are not accessible in a given context).
----------------
In a hurry (*) i somehow missed the construction option. Well, it was the first thing i started with, but i was not sure about the performance implications and erred on the safe side (template instantiation looked quite beneficial) - in the end, it did not matter at all as i moved all the code, that needed the value, out of common paths.
*) After quite some code found that the rendering turned into a slide show somewhy - with RELEASE target x_x. That is a major problem when i am debugging - so, it needed to be fixed, and fixed fast. After adding a bit of instrumentation i was able to pinpoint the cause => ~30000 allocations+deallocations per frame (~1.8mil per second with reasonable framerate). I'm also using threading, so the default allocator is thread safe => not really needed for any of the 30000 operations). So, time to add some containers. Opted to implement my own, for various reasons (works wonderfully, except i messed up with the thread-safe container implementation [normal container wrapped in infinite spinlock. the window for unfortunate context switch is very small, so, not worried] - some macro is off, compiler complains).
Quote Posted by Yakoob
compiler tried to get sizeof( Snafu ) but to do that it needs to templetize class Foobar, but in order to do that it needs to get the sizeof( Snafu ), but in order to do that ...
Nope, it is static variable - there is nothing preventing it from working. For example, even this:
Code:
class A {
intp foo() { return sizeof(A); } // technically, we can not know the size of A at this point, but VC looks ahead or inserts the correct number at a later pass.
int32u bar() { return xxx; } // well, xxx is not even declared at this point, but VC looks ahead / finds it and is quite happy with it.
int32u xxx;
};
will compile fine.
So, i sure as hell did not expect it to complain, especially about a static :(.
edit: it is not template specific either, "static int32u sacf[sizeof(A)]" fails too. Even "static int32u (*sacf)[sizeof(A)]" fails. I guess the compiler-masters went a bit overboard with the protectiveness or just omitted the checks for the OK cases.
Al_B on 18/4/2012 at 19:31
Quote Posted by zombe
edit: it is not template specific either, "static int32u sacf[sizeof(A)]" fails too. Even "static int32u (*sacf)[sizeof(A)]" fails. I guess the compiler-masters went a bit overboard with the protectiveness or just omitted the checks for the OK cases.
No - that should work. Just declare the variable as "static int32u sacf[]" in the class, and then define it as "int32u A::sacf[sizeof(A)]" outside the class.
zombe on 18/4/2012 at 20:08
It was just an example of what wont work without any actual reason - things that work are not terribly good examples of "not working" ;).
-----------------
Updated the crt memory leak detection (the "#define DEBUG_NEW new" stuff) to not explode when seeing a overloaded new in a class. Slight annoyances ensued:
Code:
d:\data\cpp\zfw\src\shared\mem\mem.hpp(63) : {1067} normal block at 0x0000000005E2B320, 65536 bytes long.
Data: <p > 70 B3 E2 05 00 00 00 00 C0 B3 E2 05 00 00 00 00
{1065} normal block at 0x0000000005E2B0B0, 344 bytes long.
Data: < > 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d:\data\cpp\zfw\src\shared\mem\mem.hpp(63) : {1064} normal block at 0x0000000005E1B040, 65536 bytes long.
Data: < > 00 B1 E1 05 00 00 00 00 00 B1 E1 05 00 00 00 00
* The 65536 reports are wrong actually. I am initiating the check manually and thous blocks get freed after that - annoying :/. Is there a way to ensure some function gets called at the end in VC? (I know i could do that in Borland C++ Builder, but no idea about VC :/). Perhaps some variable unload order flag/thingie?
* What the hell is that 344 block !? I seem to have a genuine leak now :(. Unfortunately, the way i made the memory leak check work with overloaded new/delete in classes was by disabling tracking in header files ... some "ass" (aka, me) allocated memory in a header file and did not free it :(. The byte pattern is not terribly useful either.
Oh, well, tomorrow is also a day.
Al_B on 18/4/2012 at 20:37
You should be able to register an exit function with atexit(), but it might not before ALL data is cleared but it's worth a shot.
To track down that 344 byte allocation, set the global _crtBreakAlloc variable to the ID number of the allocation - 1065 in this case. Of course, that assumes your code is repeatable and the allocation doesn't skip around - but it should get you close to the problem if nothing else.
zombe on 21/4/2012 at 06:43
So much for "tomorrow is also a day". :/ ... finally got time for it again.
atexit: is quite good actually, better than i expected. Won't use it this time tho as i realized that my own framework-built-in "atexit" functionality is sufficient - altered the macros to use that instead and :D.
_crtBreakAlloc: i have never actually used this before (source location has been sufficient so far) - thanks for mentioning. Made tracking down the baddie quite fast:
* First ran the program again and exited immediately - repeat - and it jumped.
* So, it happens after threads get started (i use quite a lot of threads as i mentioned earlier). No, problem - luckily, my framework has built in methods to turn off any threading without affecting anything else. "Thread::count = 1" in options.ini and only the primary thread is allowed to run.
* Ran it again twice and - it does not move anymore. :D yay! That is why every sane multithreading capable framework absolutely must have a switch to disable multithreading without changing anything else (the framework user still uses threading and runs the exact same algorithms on every thread and what not - just that actually, internally, there is only one thread). Not a silver bullet, but it sure helps.
Culprit, with amusing, in a roll-eyes kind of way, comment:
Code:
// HACK: sane state for this pass
static OGlState renderWorld = GlState::describe()->usesCullFace(EGlFace::back)->usesDepthTest(EGlFunc::less)->usesBlending(EGlTernary::disabled)->get();
edit: hm, the "new" that is buried in there is actually not in a header file - so, i am not quite finished yet (ie. it somehow avoided the macro substitution). PS. it actually was not a real leak as i have confirmed that the destructor of the static variable is being called and everything is fine - just that it happens after the leak check. Well, a hack is a hack is a hack.
edit: problem found and fixificated. Life is a flower again.
zombe on 8/5/2012 at 05:28
Among the usual, "discovering many extraordinarily inventive ways how i can NOT do this'n'that x_x" and not really having enough time, there still has been some progress.
(
http://img256.imageshack.us/img256/5482/lightwrongmaps.png)
Inline Image:
http://desmond.imageshack.us/Himg256/scaled.php?server=256&filename=lightwrongmaps.png&res=cropImplemented the dynamic ambient lighting. Currently it just spawns up to 8 light sources per chunk (~7500-15000 in visible range around viewpoint). Surprisingly fast (cannot outrun it with even x25 speed modifier). But there are problems too - my algorithm for figuring out which chunks need lighting fails sometimes. This is a very early pic and the bugs shown are fixed now (this particular bug was: old lightmap chunks were not freed properly causing it later to think that the lightmap index is valid - but is actually just pointing to some completely unrelated chunk).
(
http://img72.imageshack.us/img72/136/normalsok.png)
Inline Image:
http://desmond.imageshack.us/Himg72/scaled.php?server=72&filename=normalsok.png&res=cropMade a geometry shader to generate normals for every vertex - looks rather funny. Every line is actually drawn multiple times (i am just sending a copy of the normal INDEXED mesh data to shader - would be intelligent to just give it the vertices, but i can not be arsed atm [which i do have available at GPU side]. Besides - i am currently very far from actually overburdening the GPU and it is just for debugging anyway).
PS. The minimap thing shows the output from chunk inspection algorithm:
* white: chunk the viewpoint is in.
* blue: completely filled with solid.
* green: not completely filled with solid.
* transparent: nothing loaded as they are not needed == can not be seen any time soon.
* redish stuff: cannot calculate mesh and/or ambient light as chunks it needs for it are not ready (out of range and never seen before - or bug).
(
http://img98.imageshack.us/img98/309/coolbutwrong.png)
Inline Image:
http://desmond.imageshack.us/Himg98/scaled.php?server=98&filename=coolbutwrong.png&res=cropSome ravine feature - and there is a slight, but plainly visible, bug in the lighting shader as it resembles caustic effect. O_o ... "minimap-man"?
(
http://img232.imageshack.us/img232/3917/coolbutwrong2.png)
Inline Image:
http://desmond.imageshack.us/Himg232/scaled.php?server=232&filename=coolbutwrong2.png&res=cropAnother view. Things to note:
* triplanar mapping. Tried 3D textures too, but while they work well for some materials - they are next to useless for others.
* textures are just some random crap that does not even tile (in case it was not obvious from previous picture).
* quite happy with the base worldgen - still needs lots of work tho.
(
http://img205.imageshack.us/img205/3237/lightambient.png)
Inline Image:
http://desmond.imageshack.us/Himg205/scaled.php?server=205&filename=lightambient.png&res=cropOne final Yay! for ambient lighting. Note:
* the angle at which faces get their own normals is defined per voxel type (including other grouping preferences).
* all 6 sides of the voxel can have different material + 2 override materials.
* light does not bleed through thin walls (pic has some super thick ones, but i checked extremely thin ones too => no problems. Paper thin ones break it tho as NaN's show up [6cm walls are safe ... or was it 3cm?]).
* the entrance is deformed as the hacky-building-gen does not provide the proper lock-axis flags for any of the voxels and hence gets deformed where it cuts into the original rock-face.
* the material of the building does not actually use triplanar mapping - not that anyone could tell the difference with such a texture x_x.
* shortened the displayed normal to 0.25 x_x ... was a bit too ridiculous.