scraft
Joined 11 years ago
Joined 11 years ago
#ifdef MGBALOG
#define mgbalog(level, format, ...) \
do { _mgbalog(level, format, ##__VA_ARGS__); } while (0)
#else
#define mgbalog(level, format, ...) \
do { } while (0)
#endif
For the exact usage shown here, "mgbalog(...);" will mostly work with the empty replacement-list version, since it just leaves a bare ";". So this is not a guaranteed bug.The reason I prefer the "do { } while (0)" form is that it keeps the macro structurally equivalent to a single statement in both debug and release builds. With the empty disabled macro, this:
if (failed)
mgbalog(ERROR, "failed");
becomes: if (failed)
;
That is valid C, but it can trigger empty-body / suspicious-semicolon warnings, for example GCC’s "-Wempty-body", which matters if the project builds with "-Wextra" or warnings-as-errors.It also means the enabled case is already set up correctly if the macro later grows beyond a single function call. For example, if you later add another statement to the macro:
#define LOG(x) printf("log\n"); printf("%s\n", x)
if (failed)
LOG("failed");
else
recover();
then the expansion breaks because the "else" no longer attaches to the intended "if".So in this specific case the empty macro is probably fine for ordinary "mgbalog(...);" calls, but wrapping both versions in "do { } while (0)" is the more conventional and future-proof C macro shape.
One of those was Word.
In Word you could write macros and use shell to launch other applications.
Suddenly the locked down computer that exposed a handful of applications could run anything (well anything a Windows 3.11 machine in 1995 could run).
It was quite exciting at the time, I don't feel like I have hit the same sort of issues since. Ocassionally I see people say that some touch screen information displays (in shops/shopping centres etc) have ways to escape from kiosk mode (locked to an app) so you can use them for anything, I guess that is similar.
In general most developers struggled to do much with it, it was just too small (combined with the fiddlyness of using it).
PS2 programmer's were very used to thinking in this way as it's how the rendering had to be done. There is a couple of vector units, and one of them is connected to the GPU, so the general structure most developers followed was to have 4 buffers in the VU memory (I think it only had 16kb of memory or something pretty small), but essentially in parallel you'd have:
1. New data being DMAd in from main memory to VU memory (into say buffer 1/4). 2. Previous data in buffer 3/4 being transformed, lit, coloured, etc and output into buffer 4/4. 3. Data from buffer 2/4 being sent/rendered by the GPU.
Then once the above had finished it would flip, so you'd alternate like:
Data in: B1 (main memory to VU) Data out: B2 (VU to GPU) Data process from: B3 (VU processing) Data process to: B4 (VU processing)
Data in: B3 Data out: B4 Data process from: B1 Data process to: B2
The VU has two pipelines running in parallel (float and integer), and every instruction had an exact number of cycles to process, if you read a result before it is ready you stall the pipeline, so you had to painstakingly interleave and order your instructions to process three verts at a time and be very clever about register pressure etc.
There is obviously some clever syncing logic to allow all of this to work, allowing the DMA to wait until the VU kicks off the next GPU batch etc.
It was complex to get your head around, set up all the moving parts and debug when it goes wrong. When it goes wrong it pretty much just hangs, so you had to write a lot of validators. On PS2 you basically spend the frame building up a huge DMA list, and then at the end of the frame kick it off and it renders everything, so the DMA will transfer VU programs to the VU, upload data to the VU, wait for it to process and upload next batch, at the end upload next program, upload settings to GPU registers, bacially everything. Once that DMA is kicked off no more CPU code is involved in rendering the frame, so you have a MB or so of pure memory transfer instructions firing off, if any of them are wrong you are in a world of pain.
Then throw in, just to keep things interesting, the fact that anything you write to memory is likely stuck in caches, and DMA doesn't seem caches, so extra care has to be taken to make sure caches are flushed before using DMA.
It was a magical, horrible, wonderful, painful, joyous, impossible, satisfying, sickening, amazing time.
That’s not just "relativistically instant", that’s literally instant in your frame. The time dilation becomes total at light speed, and length contraction collapses the entire distance in the direction of travel to zero.
Now, it’s true we can’t really assign a rest frame to a photon, so this is a thought experiment. But if you extrapolate the math, the conclusion holds: no time passes for something traveling at light speed.
For a few reasons, but the most common is that when you write a file, you 'fwrite' operation doesn't typically immediately write blocks to the disk, instead it gets written to caches that will be written to disk in due course. Changes to the disk, tables with crucial data, etc again are just updated in memory, and written to the disk at a 'sensible' time. It's possible that you aren't actively performing operations to modify the disk, but various previous changes are sitting in memory waiting to be synced. If you kill the power then these changes aren't flushed so you can end up with corruption/filesystem problems. The main reason things work this way is for performance.
I remember a long time ago (25 years?) someone 'invented' a device where you plug your TV into it, and it has an IR receiver to go with it, you program it to respond to your TVs power button (on the remote control), and then when you go to put your TV into standby, the plug then turns off too, and when you switch it on it does the opposite. At the time it was being touted as the money saver, and I got the impression (although never actually tested!) TVs back then did draw a lot in standby, so this 'invention' was a legitimately good one. But it didn't seem to really take off, I am assume because standby was rapidly implemented in a way where there is such minimal electrical draw that it would be pointless.