Lately I started writing some PS development tutorials / advise articles that provide some directions to users who would like to get involved in the topic or for those interested in tackling the system in more efficient ways. So far I came up with two articles, but I have a third one already written and scheduled for release; this one talks about setting up light/color matrices for the GTE, with some code samples to avoid tl;dr effects. Article 1: The do’s and don’ts of PlayStation programming Article 2: Writing a good replacement for LibGS Article 3: Light sources: how they work and what you can do with them Article 4: Working around 2D primitives Article 5: 3D graphics and controller handling Are these articles any easy to follow or interesting to read? I'm thinking of writing more, but I need some directions to check if I'm making any sense.
Hey that's pretty cool.. I'll have to read it in more dept and get back to you. The Overlay section is good intro, but how's it done? I assume the Net Yaroze (gcc) do it also? found some general info: ftp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_22.html http://davis.lbl.gov/Manuals/GDB/gdb_11.html The GS lib replacement tut is really a good start, but it you should also mention the helper functions, ie rot/trans/scale I see you did the light tut I'm using the NY lib, I know the GS lib stuff is bloated and 6 times slower.. I'm creating my own dynamic TMD's any tips on how to better use GS libs would be good The 2D lib tut and code is good to, very clear and clean, thank you!
Not sure about the NY toolchain, but on PSY-Q you can configure linker scripts to dump code to whatever binary you need. I'll make sure to include them in a following article. You mean the scaling on sprites? That will be done at some point or added as subcode for another demo. Then the newest article might come in handy: 3D graphics and controller handling It does rendering in at least 3 different ways and comes with all inlined GTE code. Should be useful to get rid of TMD. Glad to know somebody might actually be using it.
Sprites & 3D objects, I know it's just basic math stuff I can't just not use TMD, the Yaroze (GS) lib only supports TMD objects.. (and I'm not going to use PSYQ) If you know how to speed up GS lib, any tips would be great ie: is it possible to use GTE inline codes with GS lib? Oh that controller demo is really good.. haven't looked much at it yet. You should have a readme or a link or txt copy of your tut in side the zip, so people know where it came from.
Might do that as a "silent update" for the next article. Something like a cracktro call back could make use of similar effects, tho the 3D objects should be at least covered in the last article. Besides pre-emptive packet allocation (I think one of the object link methods has this), there is very little you can do for speed. LibGS is horribly written and pretty much kills any performance unless you find a way to gather primitives of the same type and merge them together to take advantage of the code cache with some custom procedure. My advise is to just analyze a TMD and organize the data better. HMD did something like that, but performance is killed due to all the poorly optimized code using ZERO handshake between CPU and GTE. As long as you have the inline macros and dmpsx (to which I made a free alternative), yes. Inline code is as low level as it gets and can be integrated into anything. Good idea, I didn't think of adding something like that. I will update the packages, just in case.
Interesting, my few additions would be to maybe qualify your comments on dynamic allocation some. Weather or not to use dynamic allocation in embedded systems is an argument that has been done to death. Personally I love it and use it all the time. I would first verify (maybe you have) that the underlying allocator is indeed a first-fit algorithm, and not something more complex like a slab/block allocator. We use these quite frequently on systems down to about 32kb of RAM with high uptime and no fragmentation whatsoever. Also maybe go into the benefits of grouping your allocations and limiting them to initialization time only, and writing a wrapper utility to keep track of leaks. Most game programmers I have met have a horrible habits and understandings of system-level issues. Sort of in-line with that, I would maybe steer people away from stack allocations. They are certainly useful but without a real solid understanding of scope or object lifetime it is asking for trouble. For instance, DMA transferring a stack object without waiting for the operation to finish can result in some seriously difficult to track down memory corruption issues if the stack descends back over your start address before the operation completes. On the whole, looks very good though.
The problem with dynamic allocation is really that you can have way too many variables going on at once and very little memory to manage, which becomes awful when you start pushing overlays and your main exe is already gigantic. A custom allocator sure helps to avoid stuff accidentally overlapping on code or other resources, especially when one of them is supposed to overlap the other at some point. As for stack allocation, I was thinking of making a detailed article on how to use incremental allocation and parallel operations with DMA working in parallel (especially CD requests + VRAM uploads), but that will require some complexity. I'm counting on talking about that in an article about threads (should call them Fibers really) so that I don't need to come up with monkey code to simulate a scheduler.
New article is up: Intro coding and CD-rom usage I'm open to tutorial requests at this point. Thinking of doing cooperative threading and async CD reads, unless something more demanded/interesting comes up.
There is lots of stuff to get into I suppose. Admittedly I do embedded work and only have passing experience with the PSX, but some topics to consider: Threading - models, cooperative, pre-emptive, how to implement, pitfalls, etc. DMA - synchronization and pitfalls. Caching - PSX's setup, how to utilize scratchpad, cached vs. non-cached segments, etc. GPU model - how to keep the pipeline full, what to offload to the GPU, how to do so effectively. Input - handling asyc input in a thread-safe manner. Overlays - how this aligns with low-level system calls, resource usage, etc. Maybe get into some system-level stuff as well, and talk about how to effectively manage resources. Also I don't see a lot of people cover sound output.
I haven't compiled it, so it's not tested. But I'd code it more like this. I think it makes it look simpler and I would guess that it's smaller. I don't know if you can skip the second seek. Code: void Cd_read(u32 lba, u32 size, u32 *dest) { CdlLOC loc; u32 sectors; u32 bytes; // full sectors sectors = size / 2048; // bytes from last sector bytes = size % 2048; if (sectors) { // convert lba to MSF and seek CdIntToPos(lba, &loc); CdControlB(CdlSetloc, (u8*)&loc, NULL); // read sectors into destination CdRead(sectors, dest, CdlModeSpeed); CdReadSync(0, NULL); } if (bytes) { // seek to last sectors CdIntToPos(lba + sectors, &loc); CdControlB(CdlSetloc, (u8*)&loc, NULL); // read reminder in a separate buffer CdRead(1, (u32*)buffer, CdlModeSpeed); CdReadSync(0, NULL); // copy reminder to destination memcpy(&((u8*)dest)[size - bytes], buffer, bytes); } }
Yeah, your approach seems better and more well-thought in general. As for the second seek, it's always mandatory. The CD unit, no matter where the disk ends up with a read, still requires a seek command for any new read command issued (which takes effect almost immediately as the laser is already there, but the internal CD status ignores this). Threading on PlayStation is just of one kind (cooperative), but that can be used along with a number of those topics, like async handling. Caching is already covered, I guess I could expand it a bit more and provide more examples of usage and why it's important to take advantage of both cache types.
I have seen a few times where the vsync handler or a root counter interrupt is used as a systick timer to get a scheduler and preemptive threading models working on it, but that may be off a bit into OS design rather than specifics to the Playstation.
That is more or less how you would execute code related to vsync interrupts (or anything else a root counter can provide), which usually gives you a robust base for specific tasks that need to be executed independently from program code and on a constant basis, say music trackers. Actual cooperative threading allows you to switch around code with ease and from any point of the code. For example, you could have a main loop with just a bunch of system functions (pad, display swap, mdec playback, etc.) while a scheduler (i.e. thread tasks) executes game logic/rendering, async cd operations, and such. To give an even better example: - you have your game loop as task 0 executing as an infinite loop with a switch command at the end of said loop to pass on to the next task - task 1 takes care of cd reads and switches task as soon as it enters a wait state. You don't even need to add a million jumps to specific parts of either task because cooperative threading takes care of it and even restores the full state of your environment (i.e. no global variables required for local scope), meaning you can leave and go back with almost no need to change your logic.
I think we are saying the same thing essentially, what you do is offload your kernel's context switch routine to the interrupt fired by the vsync timer or the root counter and get the next task served up by whatever scheduler you wanted to write. I guess it depends on if you want determinism on both PAL and NTSC systems as to which interrupt source you select. I can't remember if the library primitives for task switching could be called from an interrupt context or not, otherwise you would have to write a manual context switching routine as well.
this tutorial seems really great ! I always had difficulties understanding the 3D part in PS1 dev and producing TMD file is just a nightmare. I will need to take some times reading this tutorial ! Thank you for your work ! I made some PS1 dev tutorials too, but it's more about 2D, and the basics on how the PS1 hardware works. http://onorisoft.free.fr/psx/psx.htm http://onorisoft.free.fr/psx/tutorial/tuto.htm