I'd be likely to endorse the verdict that Ken Kutaragi designed it alone.
Kutaragi designed the SPC700, the sound processor used in the SNES. Like any other moderately advanced sound processor, it is part DSP — amongst other things, it contains the logic to pitch shift an audio sample, which pretty much means taking a 1d signal of m samples across and using it to produce n output samples. It also has an in-house designed on-board CPU core, albeit that is only of similar complexity to a 6502 (i.e. a generation behind the system's main processor).
So he was involved in DSP design within videogame budgets at least prior to 1990.
The step from being able to stretch or compress one-dimensional data from a source size to a destination size, to being able to stretch or compress two-dimensional data from a source size to a destination size isn't actually all that great. And that's the thing the Playstation spends the overwhelming majority of its time doing: the original machine forgets about perspective when it gets to actually painting polygon pixels, reducing the problem to merely stepping at a constant rate through a 2d source to paint a 1d output (i.e. the current scan line).
A smart engineer like Kutaragi could very easily have made that small step in the four years between working on the Super Nintendo and working on the PlayStation, while simultaneously figuring out edge scanning (which as the Playstation does it is also just a linear 2d calculation with a 1d output) and adding fairly generic multiplication-with-accumulate and divide to handle the maths prior to rasterisation. Especially as they licensed the CPU core this time around.
It's a completely separate line of development with no direct influence over Sony, but for evidence of how easily a good DSP can scale up from audio to video usage, see demos such as Quake for the Atari Falcon. That's a 68030 computer from 1992 with an off-the-shelf Motorola 56000 DSP intended to cement Atari's position in recording studios. More than twenty years after the fact, it's churning out a version of Quake that a decent 486 would be proud of (and with perspective-correct textures – take that, Kutaragi!) because the difference between audio processing and graphics processing at that level of sophistication isn't vast.
EDIT: Additional attempts to evidence the close nexus between Playstation-quality 3d and audio generation:
This is the per-channel update process for non-noise on a SID:
while(in perpetuity) {
output(sample_function_of(phase))
phase += pitch
}
Where phase is 24 bit, pitch is 16 bit, and sample_function_of
does one of (i) output the top 12 bits (for a sawtooth wave); (ii) output the one-from-top 11 bits XORd with the top bit (for a triangle wave); (iii) output one of two levels by running the top 12 bits through a comparator (for a pulse wave); (iv) do as per the triangle wave but grab the MSB from a different channel (for ring modulation).
When the SID develops into the Ensoniq, that special phase -> wave logic is removed in favour of simple lookup tables, so you're at:
while(in perpetuity) {
output(sample(phase))
phase += pitch
}
And you can see exactly the same thing arising separately in various other sources, from the early-to-mid-'80s: the Amiga does this, as does the Konami SCC that went into various MSX cartridges, it's just a natural way to perform audio synthesis, and is something the SNES chip does also.
In Mode 7, discarding the addressing that gets it into a tile map, the SNES does this to source pixels for video output:
while(not finished raster line) {
output_to_analogue_domain(sample(x, y))
x += x_step
y += y_step
}
If it isn't applying Goraud shading, then the Playstation does almost exactly the same thing, but limits it to the length of that triangle's body on a particular line:
while(not finished scan line) {
output_to_frame_buffer(sample(x, y))
x += x_step
y += y_step
}
It's just not very different, and doesn't require a huge leap in expertise.
EDIT2:
Additional on repurposing of an older 1d DSP for 2d texturing, as it cuts to my contention that the difference isn't substantial:
Suppose you have a 64x64 texture. So you decide to adopt 5.11 fixed point addressing, because that's already a whole lot of subpixel precision. Then suppose you recoded the Playstation loop as:
uint32_t position = (y << 16) + x
uint32_t adder = (y_step << 16) + x_step
while(not finished scan line) {
output_to_frame_buffer(sample(position))
position += adder
}
With sample
being a function that uses only bits 11–15 and 27–31 to look into a 1d blob of memory.
Well, if you could discard carry between bits 15 and 16 then you've got exactly Playstation-quality texturing, you've just decided to express it oddly.
But even if you're stuck using ordinary 32-bit arithmetic then: you've just wrangled 2d interpolation out of a classic 1d 32-bit interpolator. All you've lost through treating it as a 1d problem is an error of 1/2048th of a pixel any time there's carry out of the x component. Which could be every pixel if you're stepping negatively, and otherwise will occur if your texture is tiled. So call that a bit more often than 50% of the time. But is very, very unlikely to be noticeable across the number of pixels you're likely to paint.
Switch to 8.8 fixed point and you can instead do:
uint32_t position = (y << 16) + x
uint32_t adder = (y_step << 16) + x_step
while(not finished scan line) {
output_to_frame_buffer(sample(position))
position += adder
position &= 0x3fff3fff;
}
Now you've got error flowing into y only when you're trying to traverse more than four source pixels for each screen pixel, which you can either hope is unlikely or else ensure is unlikely through MIP mapping.
I'd dare imagine that logic along those lines is behind every low-end machine texturer in existence.
But more to the point: if you had silicon implementing 32-bit 1d interpolation already, then repurposing that for a modest texture size of the era isn't a lot more complicated than removing one of the carry lines from your adder and wiring the output of that to your texture lookup in an appropriate fashion. No need for actual computed shifts or ANDs.