Dev cycle (job stuff)
At least I finally got my travel/hotel/etc. reimbursement today so I can actually start buying furniture.
Today I implemented the cache mechanism for loading commonly-used stuff from ROM into RAM, as well as the filesystem. There were also two meetings, one for the entire game team and one for just the developers. The developer one was particularly enlightening, as I found out how little James actually understood about the difference between programming for an embedded system and for a PC, not to mention the right way to make an abstraction layer for multiple targets. (The way he selected was okay if you have multiple targets on a single platform which has a lot of memory. We don't.)
He also showed an almost-cute naivete when it came to how the layered graphics in the DS worked. Unfortunately, it means that there's going to have to be a lot of changes in a lot of his code, because you know what? The layers and multiple screens on the DS are absolutely nothing like pooting textured quads to a single display surface in DirectX. Sorry.
Anyway, some future notes to people who want to develop apps on the DS:
- The screen is not an ordinary framebuffer, and it has very specific rules for how layers can interact with each other and what can go into which parts of memory
- virtual methods don't seem like they have an impact on a PC, but that's because PCs have 128MB of RAM and really fast CPUs. vtables are something to avoid on a 66MHz CPU with 4MB, especially when the vtable is being used as a stupid half-assed PImpl mechanism, which in turn is something which probably isn't necessary for what you're trying to do.
newanddeletehave real consequences. You don't want to just wrap every piece of data into a nice big object layer. Further, on the DS you have to actually implementnewanddeleteyourself if you want to use them. (I don't know if he even realized that they're implemented as overloaded operators which usually just callmallocandfree.)- True OO models are crap, especially when you're incurring lots of overhead just for the convenience of thinking about an image as something which knows how to display itself (by associating a lot of redundant data with it), except that it actually doesn't anyway.
- Dynamically creating and destroying objects actually wastes more memory than using reasonably-sized tables. Every byte lost due to fragmentation is a byte lost; memory can't just be defragmented or anything. (On modern desktop OSes it kinda-sorta is thanks to the magic of paging, but game consoles don't have a swap file.)
- Using hardware to scroll an image is way faster than repeatedly blitting it.
- Some image compression algorithms intermix the decompression and the blitting partially to save memory, but mostly in order to speed it up. So, why the hell would you use the nice blit-accelerating image CODEC to decompress an 8k image to 48k of (precious) memory just so that you can spend about 30x as much time to put it on the screen?
- The STL is great when you have unbounded memory. 4MB is not unbounded.
- We're not reading our data from a disk, and no amount of begging is going to get me to implement an fopen()/fread() abstraction layer to what should be done using an iterator paradigm to begin with. There is no such thing as file I/O, and it's easier to thunk files into an array than it is to thunk an array into files.
- Having an empty class for the purpose of a placeholder "for the sake of having a pointer to something" isn't clever, it's stupid. When I ask you to print out the API to an object class it's because I'm assuming that an object class serves a purpose. Also, don't be a prick about it. You're only allowed to be a prick after you've demonstrated that you know what you're doing.
Comments
I'd love to see what some of the young kids today would think of the machine I spent half my career on. 4 Mb of RAM? Try 128k of RAM in a 64k address space, accessed with bank switching.
It's not just the amount of RAM and CPU. It's the way that the VRAM is accessed, and which parts of the hardware are allowed to do which things with which banks, and what services the operating system and standard library provide, and so on.
Also, 'powerful enough' for applications is far different than 'powerful enough' for games.
Also, if you saw the way he was using virtual methods, you'd probably be ranting too.
But remember, I said bank-switching...this was a device that had no memory management. No malloc. No free. All memory was either static, on the stack, or in an 8k bank that had to be manually switched in. It had no standard library...just some bastardized printf workalikes for output. Oh, and some of the banks held code, to, but since both the data and code banks had to be swapped into the same 8k address area.
Heaven help you if your code overflowed the main 40k bank, or any of the smaller banks. Yes, I have experienced days where a victory was making something ten bytes smaller.
DX2/66DX/25 comment.Also, how do you think the C128 (a system with a 16-bit address space) worked? Monkeys?
vector<void *>. A game programmer friend and former coworker has described the STL as having "taken [...] the skankiest little tricks the game industry used to optimize code and built [a library] on it." and went on to suggest that the mere fact that game programmers are (at least initially) attracted to the STL indicates that there's something terribly wrong with it.66 MHz processor? SLOTH!
Layered graphics? VANITY!
Seriously, though, with that little memory, using C++ at all sounds like a bad idea to me. Heck, dynamic memory allocation for such a simple system is stupid. Just draw up a big memory map - 0x0000 to 0x1fff is globals, 0x4000 to 0x4fff is for sound mixing, 0x5000 to 0x5fff is the sprite tables... (I'm making up the names as I go along.) Who needs malloc() when you're doing basically the same thing every time?
zetawoof: Yeah. C++ is a great abstraction layer but all of my code uses static and in-stack objects all the time, aside from the ROM cache. There is absolutely no reason for him to dynamically create and destroy these objects, especially since it's basically a vector<Image *>, where Image is, in turn, just a wrapper class for the platform-specific Image type, and on the DS it'll just be another pointer and a size value. Hello, memory fragmentation! I also haven't seen precisely how gimpy his code is, but he says he only does the creation and destruction at the beginning and end of a scene — so what? That just means he's not being totally retarded.
Have you ever had a boss who wasn't an incompetent ass? If the answer is yes, then please remove the incompetent and answer again.