WEBVTT

00:00:00.030 --> 00:00:02.420
The following content is
provided under a Creative

00:00:02.420 --> 00:00:03.840
Commons license.

00:00:03.840 --> 00:00:06.860
Your support will help MIT
OpenCourseWare continue to

00:00:06.860 --> 00:00:10.560
offer high quality educational
resources for free.

00:00:10.560 --> 00:00:13.420
To make a donation, or view
additional materials from

00:00:13.420 --> 00:00:17.520
hundreds of MIT courses, visit
MIT OpenCourseWare at

00:00:17.520 --> 00:00:18.770
ocw.mit.edu.

00:00:21.690 --> 00:00:25.800
PROFESSOR: Mike Acton today
who has done a lot of

00:00:25.800 --> 00:00:27.320
programming on cell and also
done a lot of game

00:00:27.320 --> 00:00:28.480
development.

00:00:28.480 --> 00:00:32.270
He came from California just
like this today and

00:00:32.270 --> 00:00:33.560
[OBSCURED].

00:00:33.560 --> 00:00:34.548
MIKE ACTON: Yeah, it's
really cool.

00:00:34.548 --> 00:00:36.580
I'll tell you.

00:00:36.580 --> 00:00:40.790
PROFESSOR: He's going to talk
about what it's really like to

00:00:40.790 --> 00:00:44.880
use cell and PS3 and what it's
like to program games.

00:00:44.880 --> 00:00:47.980
So I think it's going
to be a fun lecture.

00:00:47.980 --> 00:00:52.130
MIKE ACTON: All right, so
anyway, I'm the Engine

00:00:52.130 --> 00:00:54.430
Director at Insomniac Games.

00:00:54.430 --> 00:00:58.890
I've only recently taken that
position, previously I was

00:00:58.890 --> 00:01:02.530
working on PS3 technology at
Highmoon studios, which is

00:01:02.530 --> 00:01:06.100
with vin studios.

00:01:06.100 --> 00:01:08.350
And I've worked at Sony.

00:01:08.350 --> 00:01:18.550
I've worked for Titus, and
Bluesky Studios in San Diego.

00:01:18.550 --> 00:01:23.670
And I've been doing game
development, 11, 12 years.

00:01:23.670 --> 00:01:26.750
Before that I was working
in simulation.

00:01:26.750 --> 00:01:33.200
So, the PlayStation 3 is
a really fun platform.

00:01:33.200 --> 00:01:36.900
And I know you guys have been
working on cell development.

00:01:36.900 --> 00:01:39.220
Working with the PS3
under Linux.

00:01:39.220 --> 00:01:41.750
Working as developers for the
PS3 is definitely a different

00:01:41.750 --> 00:01:44.340
environment from that.

00:01:44.340 --> 00:01:46.430
I think I'm going to concentrate
more on the

00:01:46.430 --> 00:01:50.850
high-level aspects of how you
design a game for the cell.

00:01:50.850 --> 00:01:54.360
And how the cell would impact
the design, and what are the

00:01:54.360 --> 00:01:56.960
elements of the game.

00:01:56.960 --> 00:02:00.800
Just stuff that you probably
haven't had as part of this

00:02:00.800 --> 00:02:02.950
course that you might
find interesting.

00:02:02.950 --> 00:02:05.530
And you can feel free to
interrupt me at any time with

00:02:05.530 --> 00:02:07.640
questions or whatever
you'd like.

00:02:12.820 --> 00:02:16.130
So just, I wanted to go over,
briefly, some of the different

00:02:16.130 --> 00:02:19.370
types of game development and
what the trade-offs for each

00:02:19.370 --> 00:02:20.700
one of them are.

00:02:20.700 --> 00:02:24.380
Casual games, console games,
PC games, blah, blah, blah.

00:02:24.380 --> 00:02:27.763
Casual games, basically, are the
small, simple games that

00:02:27.763 --> 00:02:30.485
you would download on
the PC, or you would

00:02:30.485 --> 00:02:31.750
see on Yahoo or whatever.

00:02:31.750 --> 00:02:34.150
And those generally don't have
really strict performance

00:02:34.150 --> 00:02:34.970
requirements.

00:02:34.970 --> 00:02:38.780
Where a console game, we have
this particular advantage of

00:02:38.780 --> 00:02:41.005
knowing the hardware and the
hardware doesn't change for an

00:02:41.005 --> 00:02:41.870
entire cycle.

00:02:41.870 --> 00:02:44.100
So for five, six years, we have

00:02:44.100 --> 00:02:46.320
exactly the same hardware.

00:02:46.320 --> 00:02:48.750
And that's definitely an
advantage from a performance

00:02:48.750 --> 00:02:50.350
point anyway.

00:02:50.350 --> 00:02:52.250
In this case, it's
PlayStation 3.

00:02:57.240 --> 00:02:58.750
As far as develpment priorities,
development

00:02:58.750 --> 00:03:01.610
priorities for a console game--
and especially a PS3

00:03:01.610 --> 00:03:03.810
game-- development would be
completely different than you

00:03:03.810 --> 00:03:07.480
might find on another
kind of application.

00:03:07.480 --> 00:03:11.890
We don't really consider the
code itself important at all.

00:03:11.890 --> 00:03:13.790
The real value is in
the programmers.

00:03:13.790 --> 00:03:15.950
The real value is in
the experience,

00:03:15.950 --> 00:03:18.600
and is in those skills.

00:03:18.600 --> 00:03:20.690
Code is disposable.

00:03:20.690 --> 00:03:24.020
After six years, when we start
a new platform we pretty much

00:03:24.020 --> 00:03:27.780
have to rewrite it anyway, so
there's not much point in

00:03:27.780 --> 00:03:31.190
trying to plan for a long
life span of code.

00:03:31.190 --> 00:03:33.090
Especially when you have
optimized code written in

00:03:33.090 --> 00:03:34.920
assembly for a particular
platform.

00:03:38.500 --> 00:03:42.646
And to that end, the data is
way more significant to the

00:03:42.646 --> 00:03:43.850
performance than the
code, anyway.

00:03:43.850 --> 00:03:47.500
And the data is specific
to a particular game.

00:03:47.500 --> 00:03:50.450
Or specific to a particular
type of game.

00:03:50.450 --> 00:03:56.280
And certainly specific to
a studios pipeline.

00:03:56.280 --> 00:03:58.670
And it's the design of the data
where you really want to

00:03:58.670 --> 00:04:00.870
spend your time concentrating,
especially for the PS3.

00:04:03.430 --> 00:04:05.795
Ease of programming-- whether
or not it's easier to do

00:04:05.795 --> 00:04:08.150
parallelism is not a major
concern at all.

00:04:08.150 --> 00:04:09.680
If it's hard, so what?

00:04:09.680 --> 00:04:10.680
You do it.

00:04:10.680 --> 00:04:12.420
That's it.

00:04:12.420 --> 00:04:14.580
Portability, runs on PlayStation
3, doesn't run

00:04:14.580 --> 00:04:15.280
anywhere else.

00:04:15.280 --> 00:04:17.700
That's a non-concern.

00:04:17.700 --> 00:04:19.310
And everything is about
performance.

00:04:19.310 --> 00:04:20.440
Everything we do.

00:04:20.440 --> 00:04:23.330
A vast majority of our code is
either hand up from IC, or

00:04:23.330 --> 00:04:26.380
assembly, very little
high level code.

00:04:26.380 --> 00:04:28.220
Some of our gameplay programmers
will write C plus

00:04:28.220 --> 00:04:33.750
plus for the high level logic,
but as a general, most of the

00:04:33.750 --> 00:04:36.700
code that's running most the
time is definitely optimized.

00:04:36.700 --> 00:04:38.950
Yeah?

00:04:38.950 --> 00:04:43.060
AUDIENCE: If programming is a
non-priority, does that mean

00:04:43.060 --> 00:04:45.060
to say that if you're developing
more than one

00:04:45.060 --> 00:04:47.447
product or game, they don't
share any common

00:04:47.447 --> 00:04:48.240
infrastructure or need?

00:04:48.240 --> 00:04:49.300
MIKE ACTION: No, that's
not necessarily true.

00:04:49.300 --> 00:04:53.440
If we have games that share
similar needs, they can

00:04:53.440 --> 00:04:55.140
definitely share similar code.

00:04:55.140 --> 00:04:58.850
I mean, the point I'm trying to
make is, let's say in order

00:04:58.850 --> 00:05:02.640
to make something fast it
has to be complicated.

00:05:02.640 --> 00:05:05.990
So be it, it's complicated.

00:05:05.990 --> 00:05:09.710
Whether or not it's easy to use
for another programmer is

00:05:09.710 --> 00:05:11.260
not a major concern.

00:05:11.260 --> 00:05:14.060
AUDIENCE: So you wish
it was easier?

00:05:14.060 --> 00:05:14.540
MIKE ACTION: No.

00:05:14.540 --> 00:05:16.600
I don't care.

00:05:16.600 --> 00:05:18.780
That's my point.

00:05:18.780 --> 00:05:20.259
AUDIENCE: Well, it's not as
important as performance, but

00:05:20.259 --> 00:05:22.360
if someone came to you with a
high performance tool, you

00:05:22.360 --> 00:05:23.330
would like to use it?

00:05:23.330 --> 00:05:24.580
MIKE ACTION: I doubt
they could.

00:05:26.840 --> 00:05:29.460
The highest performance tool
that exists is the brains of

00:05:29.460 --> 00:05:31.150
the programmers on our team.

00:05:31.150 --> 00:05:33.220
You can not create--

00:05:33.220 --> 00:05:35.040
it's theoretically impossible.

00:05:35.040 --> 00:05:39.570
You can not out perform people
who are customizing for the

00:05:39.570 --> 00:05:42.520
data, for the context
for the game.

00:05:42.520 --> 00:05:46.730
It is not even remotely
theoretically possible.

00:05:46.730 --> 00:05:48.620
AUDIENCE: That didn't come out
in assembly programming for

00:05:48.620 --> 00:05:53.550
general purpose but we'll
take this offline?

00:05:53.550 --> 00:05:54.790
And there was a day when that
was also true for general

00:05:54.790 --> 00:05:57.950
preferred cleary at the time,
but it's no longer true.

00:05:57.950 --> 00:05:58.120
MIKE ACTION: It is
absolutely--

00:05:58.120 --> 00:05:59.050
AUDIENCE: So the average person
prefers to go on --

00:05:59.050 --> 00:06:00.300
take it offline.

00:06:01.890 --> 00:06:02.800
MIKE ACTION: Average person.

00:06:02.800 --> 00:06:03.860
We're not the average people.

00:06:03.860 --> 00:06:05.720
We're game programmers.

00:06:05.720 --> 00:06:06.030
Yeah?

00:06:06.030 --> 00:06:08.580
AUDIENCE: So does cost
ever become an issue?

00:06:08.580 --> 00:06:08.870
I mean--

00:06:08.870 --> 00:06:10.640
MIKE ACTION: Absolutely, cost
does become an issue.

00:06:10.640 --> 00:06:15.210
At a certain pont, something
is so difficult that you

00:06:15.210 --> 00:06:18.350
either have to throw up
your hands or you

00:06:18.350 --> 00:06:19.060
can't finish in time.

00:06:19.060 --> 00:06:20.900
AUDIENCE: Do you ever
hit that point?

00:06:20.900 --> 00:06:22.720
MIKE ACTION: Or you figure out
a new way of doing it.

00:06:22.720 --> 00:06:24.120
Or do a little bit less.

00:06:24.120 --> 00:06:25.350
I mean we do have to prioritize

00:06:25.350 --> 00:06:27.060
what you want to do.

00:06:27.060 --> 00:06:28.750
At the end of the day you can't
do everything you want

00:06:28.750 --> 00:06:30.990
to do, and you have another
game you need to ship

00:06:30.990 --> 00:06:32.520
eventually, anyway.

00:06:32.520 --> 00:06:34.550
So, a lot of times you do
end up tabling things.

00:06:34.550 --> 00:06:38.300
And say, look we can get 50%
more performance out of this,

00:06:38.300 --> 00:06:40.650
but we're going to have to table
that for now and scale

00:06:40.650 --> 00:06:42.190
back on the content.

00:06:42.190 --> 00:06:44.340
And that's why you have six
years of development.

00:06:44.340 --> 00:06:47.270
You know, maybe in the next
cycle, in the next game,

00:06:47.270 --> 00:06:48.520
you'll be able to squeeze
out a little bit more.

00:06:48.520 --> 00:06:50.370
And the next one you squeeze
out a little bit more.

00:06:50.370 --> 00:06:52.560
That's sort of this continuous
development, and continuous

00:06:52.560 --> 00:06:57.740
optimization over the course
of a platform.

00:06:57.740 --> 00:07:00.750
And sometimes, yeah, I mean
occasionally you just say

00:07:00.750 --> 00:07:03.720
yeah, we can't do it or
whatever, it doesn't work.

00:07:03.720 --> 00:07:07.290
I mean, that's part and parcel
of development in general.

00:07:07.290 --> 00:07:08.900
Some ideas just don't pan out.

00:07:11.890 --> 00:07:12.200
But--

00:07:12.200 --> 00:07:14.961
AUDIENCE: Have you ever come
into a situation where

00:07:14.961 --> 00:07:17.283
programming conflicts just
kills a project?

00:07:17.283 --> 00:07:20.137
Like Microsoft had had a few
times, like they couldn't put

00:07:20.137 --> 00:07:20.620
out [OBSCURED].

00:07:20.620 --> 00:07:22.930
Couldn't release for--

00:07:22.930 --> 00:07:24.160
MIKE ACTION: Sure, there's
plenty of studios where the

00:07:24.160 --> 00:07:26.090
programming complexity has
killed the studio, or killed

00:07:26.090 --> 00:07:27.180
the project.

00:07:27.180 --> 00:07:29.870
But I find it hard to believe--
or it's very

00:07:29.870 --> 00:07:32.730
rarely-- because it's complexity
that has to do

00:07:32.730 --> 00:07:34.860
specifically with
optimization.

00:07:34.860 --> 00:07:38.160
That complexity usually has
to do with unnecessary

00:07:38.160 --> 00:07:38.740
complexity.

00:07:38.740 --> 00:07:41.410
Complexity that doesn't
achieve anything.

00:07:41.410 --> 00:07:43.500
Organization for the sake
of organization.

00:07:43.500 --> 00:07:46.740
So you have these sort of over
designed C plus plus

00:07:46.740 --> 00:07:51.870
hierarchies just for the sake
of over organizing things.

00:07:51.870 --> 00:07:53.650
That's what will generally
kill a project.

00:07:53.650 --> 00:07:57.760
But in performance, the
complexity tends to come from

00:07:57.760 --> 00:08:00.010
the rule set-- what you need
to do to set it up.

00:08:00.010 --> 00:08:03.700
But the code tends to be smaller
when it's faster.

00:08:03.700 --> 00:08:05.810
You tend to be doing one
thing and doing one

00:08:05.810 --> 00:08:07.390
thing really well.

00:08:07.390 --> 00:08:08.980
So it doesn't tend to
get out of hand.

00:08:08.980 --> 00:08:12.750
I mean, it occasionally
happens but, yeah?

00:08:12.750 --> 00:08:16.395
AUDIENCE: So in terms of the
overall cost, how big is this

00:08:16.395 --> 00:08:18.020
programming versus the
other aspect of

00:08:18.020 --> 00:08:19.040
coming up with the game?

00:08:19.040 --> 00:08:23.220
Like the game design,
the graphics--

00:08:23.220 --> 00:08:26.520
AUDIENCE: So, for example,
do you have--

00:08:26.520 --> 00:08:27.990
MIKE ACTION: OK, development
team?

00:08:30.830 --> 00:08:31.450
So--

00:08:31.450 --> 00:08:33.612
AUDIENCE: So how many
programmers, how many

00:08:33.612 --> 00:08:34.020
artists, how many--

00:08:34.020 --> 00:08:37.620
PROFESSOR: Maybe, let's-- so
for example, like, now it's

00:08:37.620 --> 00:08:39.720
like, what, $20 million
to deliver a PS3 game?

00:08:39.720 --> 00:08:42.476
MIKE ACTION: Between $10
and $20 million, yeah.

00:08:42.476 --> 00:08:44.800
PROFESSOR: So let's
develop [OBSCURED]

00:08:44.800 --> 00:08:48.630
MIKE ACTION: So artists
are by far the most--

00:08:48.630 --> 00:08:51.550
the largest group
of developers.

00:08:51.550 --> 00:08:53.680
So you have animators and shade
artists, and textual

00:08:53.680 --> 00:08:55.000
artists, and modelers,
and enviromental

00:08:55.000 --> 00:08:57.110
artists, and lighters.

00:08:57.110 --> 00:09:02.630
And so they'll often outnumber
programmers 2:1.

00:09:02.630 --> 00:09:05.580
Which is completely different
than-- certainly very

00:09:05.580 --> 00:09:09.480
different from PlayStation and
the gap is much larger than it

00:09:09.480 --> 00:09:11.750
was on PlayStation 2.

00:09:11.750 --> 00:09:16.660
With programmers you tend to
have a fairly even split or

00:09:16.660 --> 00:09:18.570
you tend to have a divide
between the high level game

00:09:18.570 --> 00:09:21.450
play programmers and the low
level engine programmers.

00:09:21.450 --> 00:09:23.700
And you will tend to have more
game play programmers than

00:09:23.700 --> 00:09:26.390
engine programmers, although
most-- the majority of the CPU

00:09:26.390 --> 00:09:29.880
time is spent in the
engine code.

00:09:29.880 --> 00:09:35.030
And that partially comes down
to education and experience.

00:09:35.030 --> 00:09:39.470
In order to get high performance
code you need to

00:09:39.470 --> 00:09:40.690
have that experience.

00:09:40.690 --> 00:09:41.970
You need to know how
to optimize.

00:09:41.970 --> 00:09:43.420
You need to understand
the machine.

00:09:43.420 --> 00:09:44.840
You need to understand the
architecture and you need to

00:09:44.840 --> 00:09:46.990
understand the data.

00:09:46.990 --> 00:09:50.050
And there's only so many people
that can do that on any

00:09:50.050 --> 00:09:50.760
particular team.

00:09:50.760 --> 00:09:56.401
AUDIENCE: Code size wise, How
is the code size divided

00:09:56.401 --> 00:09:59.120
between game playing and
AI, special effects?

00:09:59.120 --> 00:10:01.410
MIKE ACTION: Just like,
the amount of code?

00:10:01.410 --> 00:10:03.870
AUDIENCE: Yeah, it should
be small I guess.

00:10:03.870 --> 00:10:05.050
MIKE ACTION: Yeah, I mean,
it's hard to say.

00:10:05.050 --> 00:10:07.420
I mean, because it depends
on how many

00:10:07.420 --> 00:10:08.720
features you're using.

00:10:08.720 --> 00:10:11.710
And, you know sort of the scope
of the engine is how

00:10:11.710 --> 00:10:13.780
much is being used for a
particular game, especially if

00:10:13.780 --> 00:10:18.570
you're targeting multiple
games within a studio.

00:10:18.570 --> 00:10:20.460
But quite often-- interestingly
enough-- the

00:10:20.460 --> 00:10:23.210
game play code actually
overwhelms the engine code in

00:10:23.210 --> 00:10:27.590
terms of size and that is back
to basically what I was saying

00:10:27.590 --> 00:10:31.200
that the engine code tends to do
one thing really well or a

00:10:31.200 --> 00:10:32.240
series of things really well.

00:10:32.240 --> 00:10:34.790
AUDIENCE: Game play code
also C plus plus?

00:10:34.790 --> 00:10:36.745
MIKE ACTON: These days it's
much more likely that game

00:10:36.745 --> 00:10:40.220
play code is C plus plus in
the high level and kills

00:10:40.220 --> 00:10:45.290
performance and doesn't think
about things like cache.

00:10:47.870 --> 00:10:52.060
That's actually part of the
problem with PlayStation 3

00:10:52.060 --> 00:10:52.540
development.

00:10:52.540 --> 00:10:55.210
It was part of the challenge
that we've had with

00:10:55.210 --> 00:10:56.790
PlayStation 3 development.

00:10:56.790 --> 00:10:59.970
Is in the past, certainly with
PlayStation 2 and definitely

00:10:59.970 --> 00:11:03.850
on any previous console, this
divide between game play and

00:11:03.850 --> 00:11:05.600
engine worked very well.

00:11:08.120 --> 00:11:10.400
The game play programmers could
just call a function and

00:11:10.400 --> 00:11:13.200
it did its fat thing really fast
and it came back and they

00:11:13.200 --> 00:11:17.550
continue this, but in a serial
program on one process that

00:11:17.550 --> 00:11:19.390
model works very well.

00:11:19.390 --> 00:11:25.270
But now when the high level
design can destroy performance

00:11:25.270 --> 00:11:27.650
but through the simplest
decision, like for example, in

00:11:27.650 --> 00:11:33.420
collision detection if the logic
assumes that the result

00:11:33.420 --> 00:11:36.900
is immediately available there's
virtually no way of

00:11:36.900 --> 00:11:39.440
making that fast. So the
high-level design has to

00:11:39.440 --> 00:11:43.010
conform to the hardware.

00:11:43.010 --> 00:11:45.660
That's sort of a challenge
now, is introducing those

00:11:45.660 --> 00:11:48.440
concepts to the high-level
programmer who haven't

00:11:48.440 --> 00:11:49.690
traditionally had
to deal with it.

00:11:52.050 --> 00:11:56.430
Does that answer that question
as far as the split?

00:11:56.430 --> 00:11:58.610
AUDIENCE: You said 2:1, right?

00:11:58.610 --> 00:12:02.830
MIKE ACTON: Approximately 2:1,
artist to programmers.

00:12:02.830 --> 00:12:07.390
It varies studio to studio and
team to team, so it's hard to

00:12:07.390 --> 00:12:08.660
say in the industry
as a whole.

00:12:16.900 --> 00:12:20.230
So back basically to the
point of the code

00:12:20.230 --> 00:12:21.610
isn't really important.

00:12:21.610 --> 00:12:26.250
The code itself doesn't
have a lot of value.

00:12:26.250 --> 00:12:27.960
There are fundamental things
that affect how you would

00:12:27.960 --> 00:12:29.380
design it in the first place.

00:12:29.380 --> 00:12:32.260
The type of game, the kind of
engine that would run a racing

00:12:32.260 --> 00:12:34.320
game is completely different
than the kind of engine that

00:12:34.320 --> 00:12:36.430
would run a first
person shooter.

00:12:36.430 --> 00:12:39.240
The needs are different, the
optimizations are totally

00:12:39.240 --> 00:12:42.670
different, the data is totally
different, so you wouldn't try

00:12:42.670 --> 00:12:44.940
to reuse code from
one to the other.

00:12:44.940 --> 00:12:47.350
It just either wouldn't
work or would work

00:12:47.350 --> 00:12:49.020
really, really poorly.

00:12:49.020 --> 00:12:50.470
The framerate--

00:12:50.470 --> 00:12:52.840
having a target of 30 frames per
second is a much different

00:12:52.840 --> 00:12:55.450
problem than having a target
of 60 frames per second.

00:12:55.450 --> 00:12:58.710
And in the NCSC territories
those are pretty much your

00:12:58.710 --> 00:13:02.830
only two choices- 30 frames or
60, which means everything has

00:13:02.830 --> 00:13:06.430
to be done in 16 and
2/3 milliseconds.

00:13:06.430 --> 00:13:07.510
That's it, that's
what you have--

00:13:07.510 --> 00:13:12.220
432 milliseconds.

00:13:12.220 --> 00:13:16.830
Of course, back to schedule
and cost, how much?

00:13:16.830 --> 00:13:19.580
You know, do you have a two year
cycle, one year cycle,

00:13:19.580 --> 00:13:21.820
how much can you get done?

00:13:21.820 --> 00:13:23.200
The kind of hardware.

00:13:23.200 --> 00:13:26.620
So taking for example, an engine
from PlayStation 2 and

00:13:26.620 --> 00:13:29.990
trying to move it to PlayStation
3 is sort of a

00:13:29.990 --> 00:13:31.240
lost cause.

00:13:36.730 --> 00:13:38.870
The kind of optimizations that
you would do, the kind of

00:13:38.870 --> 00:13:43.400
parallelization you would do
is so completely different,

00:13:43.400 --> 00:13:46.750
although there was
parallelization in PlayStation

00:13:46.750 --> 00:13:49.350
2, the choices would have been
completely different.

00:13:53.960 --> 00:13:57.510
The loss from trying to port it
is much, much greater than

00:13:57.510 --> 00:13:59.560
the cost of just
doing it again.

00:13:59.560 --> 00:14:06.290
AUDIENCE: [OBSCURED]

00:14:06.290 --> 00:14:07.970
MIKE ACTON: I don't know that
there's an average.

00:14:07.970 --> 00:14:11.970
I mean, if you wanted to just
like homogenize the industry,

00:14:11.970 --> 00:14:17.390
it's probably 18 months.

00:14:17.390 --> 00:14:20.450
The compiler actually makes a
huge, significant difference

00:14:20.450 --> 00:14:25.040
in how you design your code.

00:14:25.040 --> 00:14:27.690
If you're working with GCC and
you have programmers who have

00:14:27.690 --> 00:14:31.900
been working with GCC for 15
years abd who understand the

00:14:31.900 --> 00:14:37.020
intricacies and issues involved
in GCC, the kind of

00:14:37.020 --> 00:14:38.660
code you would write would be
completely different than if

00:14:38.660 --> 00:14:42.440
you were using XLC for
example, on the cell.

00:14:46.670 --> 00:14:48.130
There are studios--

00:14:48.130 --> 00:14:50.240
Insomniac doesn't, but there are
other studios who do cross

00:14:50.240 --> 00:14:50.940
platform design.

00:14:50.940 --> 00:14:55.480
So for example, write
Playstation 3 games and Xbox

00:14:55.480 --> 00:14:59.260
360 games and/or PC titles.

00:14:59.260 --> 00:15:03.460
At the moment, probably the
easiest approach for that is

00:15:03.460 --> 00:15:07.920
to target the PlayStation 3.

00:15:07.920 --> 00:15:11.660
So you have these sort of SPU
friendly chunks of processing

00:15:11.660 --> 00:15:15.540
SPU chunks, friendly chunks of
data and move those onto

00:15:15.540 --> 00:15:18.910
homogenous parallel
processors.

00:15:18.910 --> 00:15:21.300
It's not the perfect solution,
but virtually all cross

00:15:21.300 --> 00:15:23.150
platform titles are not looking
for the perfect

00:15:23.150 --> 00:15:26.020
solution anyway because they
cannot fully optimize for any

00:15:26.020 --> 00:15:27.270
particular platform.

00:15:32.370 --> 00:15:33.250
I wanted to go through--

00:15:33.250 --> 00:15:38.130
these are a basic list of some
of the major modules that a

00:15:38.130 --> 00:15:39.610
game is made out of.

00:15:42.510 --> 00:15:45.950
I'll go through some of these
and explain how designing on

00:15:45.950 --> 00:15:47.680
the cell impacts the system.

00:15:47.680 --> 00:15:52.260
I'm not going to bother
reading them.

00:15:52.260 --> 00:15:53.700
I assume you all can read.

00:15:57.950 --> 00:16:00.620
So yeah, I'm going to go over
the major system, a few of the

00:16:00.620 --> 00:16:02.450
major systems and then we're
going to drive a little bit

00:16:02.450 --> 00:16:05.790
into a specific system, in this
case an animation system.

00:16:05.790 --> 00:16:11.400
And just talk it through,
basically you see how each of

00:16:11.400 --> 00:16:14.090
these steps are affected by
the hardware that we're

00:16:14.090 --> 00:16:17.470
running on it.

00:16:17.470 --> 00:16:20.060
So just to start with when
you're designing a structure,

00:16:20.060 --> 00:16:23.430
any structure, anywhere--

00:16:23.430 --> 00:16:30.460
the initial structure is
affected by the kind of

00:16:30.460 --> 00:16:32.370
hardware that you're running.

00:16:32.370 --> 00:16:37.080
And in this particular case on
the SPU and there are other

00:16:37.080 --> 00:16:40.660
processors where this is equally
true, but in this

00:16:40.660 --> 00:16:42.790
conventional structure where
you say structure class or

00:16:42.790 --> 00:16:46.660
whatever and you have
domain-constrained structures

00:16:46.660 --> 00:16:51.180
are of surprisingly
little use.

00:16:51.180 --> 00:16:56.395
In general, the data is either
compressed or is in a stram or

00:16:56.395 --> 00:16:58.500
is in blocks.

00:16:58.500 --> 00:17:01.910
It's sort of based on type,
which means that there's no

00:17:01.910 --> 00:17:06.360
fixed size struct that you
could define anyway.

00:17:06.360 --> 00:17:09.080
So as a general rule, the
structure of the data is

00:17:09.080 --> 00:17:11.130
defined within the
code as opposed

00:17:11.130 --> 00:17:13.860
to in a struct somewhere.

00:17:13.860 --> 00:17:17.540
And that's really to get the
performance from the data, you

00:17:17.540 --> 00:17:20.590
group things of similar type
together rather than for

00:17:20.590 --> 00:17:24.085
example, on SPU, having flags
that say this is of type A and

00:17:24.085 --> 00:17:28.710
this is of type B. Any flag
implies a branch, which is--

00:17:28.710 --> 00:17:31.320
I'm sure you all know at this
point-- is really poor

00:17:31.320 --> 00:17:33.330
performing on SPU.

00:17:33.330 --> 00:17:37.890
So basically, pull flags out,
resort everything and then

00:17:37.890 --> 00:17:40.680
move things in streams. And all
of these types are going

00:17:40.680 --> 00:17:43.570
to be of varying sizes.

00:17:43.570 --> 00:17:46.620
In which case there's very
little point to define those

00:17:46.620 --> 00:17:48.570
structures in the first place
because you can't change them.

00:17:52.550 --> 00:17:55.000
And the fact that you're
accessing data

00:17:55.000 --> 00:17:56.310
in quadwords anyway.

00:17:56.310 --> 00:17:58.530
You're always either loading and
storing in quadwords, not

00:17:58.530 --> 00:18:01.940
on scalars, so having scalar
fields in a structure is sort

00:18:01.940 --> 00:18:04.150
of pointless.

00:18:04.150 --> 00:18:06.300
So again, only SPU generally
speaking

00:18:06.300 --> 00:18:08.220
structures are of much use.

00:18:14.690 --> 00:18:17.020
When you go to define structures
in general you need

00:18:17.020 --> 00:18:24.910
to consider things like the
cache, the TLB, how that's

00:18:24.910 --> 00:18:27.380
going to affect you're reading
out of the structure or

00:18:27.380 --> 00:18:29.670
writing to the structure.

00:18:29.670 --> 00:18:32.940
More to the point of you cannot
just assume that if

00:18:32.940 --> 00:18:36.700
you've written some data
definition that you can port

00:18:36.700 --> 00:18:38.340
it to another platform.

00:18:38.340 --> 00:18:40.490
It's very easy to be poorly, a

00:18:40.490 --> 00:18:43.300
performing platform to platform.

00:18:43.300 --> 00:18:45.980
In this case, when we design
structures you have to

00:18:45.980 --> 00:18:48.760
consider the fundamental
units of the cell.

00:18:48.760 --> 00:18:52.960
The cache line is a fundamental
unit of the cell.

00:18:52.960 --> 00:18:55.560
Basically, you want to define
things in terms of

00:18:55.560 --> 00:18:58.690
128 bytes of wide.

00:18:58.690 --> 00:19:01.830
What can you fit in there
because you read one you read

00:19:01.830 --> 00:19:06.500
them all, so you want to pack
as much as possible into 128

00:19:06.500 --> 00:19:11.290
bytes and just deal with that
as a fundamental unit.

00:19:11.290 --> 00:19:14.270
16 bytes, of course, you're
doing load and stores through

00:19:14.270 --> 00:19:17.300
quadword load and store.

00:19:17.300 --> 00:19:20.100
So you don't want to have little
scalar bits in there

00:19:20.100 --> 00:19:21.080
that you're shuffling around.

00:19:21.080 --> 00:19:23.390
Just deal with it
as a quadword.

00:19:23.390 --> 00:19:26.280
And don't deal with anything
smaller than that.

00:19:26.280 --> 00:19:29.190
So basically the minimum working
sizes, in practice,

00:19:29.190 --> 00:19:33.460
would be 4 by 128 bits wide
and you can split that up

00:19:33.460 --> 00:19:36.030
regularly however you want.

00:19:36.030 --> 00:19:41.140
So to that point I think--

00:19:41.140 --> 00:19:43.470
here's an example--

00:19:43.470 --> 00:19:45.070
I want to talk about
a vector class.

00:19:45.070 --> 00:19:49.400
Vector class js usually the
first thing a programmer will

00:19:49.400 --> 00:19:54.050
jump onto when they might want
to make something for games.

00:19:54.050 --> 00:19:57.670
But in real life, it's probably
the most useless

00:19:57.670 --> 00:19:58.920
thing you could ever write.

00:20:01.420 --> 00:20:04.150
It doesn't actually
do anything.

00:20:04.150 --> 00:20:07.170
We have these, we know the
instruction set, it's already

00:20:07.170 --> 00:20:07.950
in quadwords.

00:20:07.950 --> 00:20:09.990
We know the loads and stores,
we've already designed your

00:20:09.990 --> 00:20:12.130
data so it fits properly.

00:20:12.130 --> 00:20:14.810
This doesn't give us anything.

00:20:14.810 --> 00:20:16.830
And it potentially makes
things worse.

00:20:20.130 --> 00:20:23.360
Allowing component access to a
quadword, especially on the

00:20:23.360 --> 00:20:28.250
PPU is ridiculously bad.

00:20:28.250 --> 00:20:31.600
In practice, if you allow
component access, high-level

00:20:31.600 --> 00:20:34.480
programs will use component
access.

00:20:34.480 --> 00:20:37.160
So if you have a vector class
that says get x, get y,

00:20:37.160 --> 00:20:40.660
whatever, somebody somewhere
is going to use it, which

00:20:40.660 --> 00:20:43.330
means the performance of the
whole thing just drops and

00:20:43.330 --> 00:20:46.390
it's impossible to optimize.

00:20:46.390 --> 00:20:48.990
So as a general rule, you pick
your fundamental unit.

00:20:48.990 --> 00:20:52.930
In this case, the 4 by 128 bit
unit that I was talking about

00:20:52.930 --> 00:20:56.150
and you don't define anything
smaller than that.

00:20:56.150 --> 00:20:58.960
Everything is packed into
a unit about that size.

00:20:58.960 --> 00:21:03.510
And yes, in practice there'll
be some wasted space at the

00:21:03.510 --> 00:21:07.950
beginning or end of streams of
data, groups of data, but it

00:21:07.950 --> 00:21:10.420
doesn't make much difference.

00:21:10.420 --> 00:21:12.930
You're going to have that wasted
space if you are--

00:21:12.930 --> 00:21:14.840
you're going to have much more
than that in wasted space if

00:21:14.840 --> 00:21:17.870
you're using dynamic memory,
for example, which

00:21:17.870 --> 00:21:20.090
when I get to it--

00:21:20.090 --> 00:21:21.340
I don't recommend
you use either.

00:21:25.930 --> 00:21:27.800
So some things to consider when
you're doing this sort of

00:21:27.800 --> 00:21:32.020
math transformation anyway is,
are you going to do floats,

00:21:32.020 --> 00:21:33.690
double, fixed point?

00:21:33.690 --> 00:21:34.840
I mean, doubles write out.

00:21:34.840 --> 00:21:36.240
There's no point.

00:21:36.240 --> 00:21:39.640
Regardless of the speed on the
SPU of a double, there's no

00:21:39.640 --> 00:21:43.170
value in it for games.

00:21:43.170 --> 00:21:46.900
We have known data, so if we
need to we can renormalize a

00:21:46.900 --> 00:21:51.140
group of around a point and
get into the range of a

00:21:51.140 --> 00:21:52.100
floating point.

00:21:52.100 --> 00:21:53.920
It's a nonissue.

00:21:53.920 --> 00:21:56.700
So there's no reason to waste
the space in a double at all,

00:21:56.700 --> 00:21:59.380
unless it was actually faster,
which it isn't.

00:21:59.380 --> 00:22:00.630
So we don't use it.

00:22:04.440 --> 00:22:06.670
Sort of the only real
problematic thing with the SPU

00:22:06.670 --> 00:22:09.570
floating point is its format
and not supporting

00:22:09.570 --> 00:22:12.860
denormalized numbers becomes
problematic, but again, you

00:22:12.860 --> 00:22:17.680
can work around it by
renormalizing your numbers

00:22:17.680 --> 00:22:20.760
within a known range so that it
won't to get to the point

00:22:20.760 --> 00:22:23.290
where it needs to
denormalize--

00:22:23.290 --> 00:22:25.270
at least for the work that
you're actually doing.

00:22:29.790 --> 00:22:30.520
Yeah?

00:22:30.520 --> 00:22:38.960
AUDIENCE: [OBSCURED]

00:22:38.960 --> 00:22:42.210
MIKE ACTON: Every program will
write its own vector class.

00:22:42.210 --> 00:22:45.290
And I'm saying that that's
a useless exercise.

00:22:45.290 --> 00:22:46.360
Don't bother doing it.

00:22:46.360 --> 00:22:47.610
Don't use anybody
else's either.

00:22:52.730 --> 00:22:55.780
If you're writing
for the cell--

00:22:55.780 --> 00:22:58.360
if you're writing in C you
have the SI intrinsics.

00:22:58.360 --> 00:23:00.330
They're already in quadwords,
you can do everything you want

00:23:00.330 --> 00:23:04.210
to do and you're not restricted
by this sort of

00:23:04.210 --> 00:23:06.110
concept of what a vector is.

00:23:06.110 --> 00:23:08.290
If you want to deal with,
especially on the SPU where

00:23:08.290 --> 00:23:12.210
you can freely deal with them
as integers or floats or

00:23:12.210 --> 00:23:17.280
whatever seamlessly without
cost, there's plenty that you

00:23:17.280 --> 00:23:18.860
can do with the floating
point number if you

00:23:18.860 --> 00:23:20.030
treat it as an integer.

00:23:20.030 --> 00:23:23.800
And when on either AltiVec or
the SPU where you can do that

00:23:23.800 --> 00:23:26.870
without cost there's
a huge advantage to

00:23:26.870 --> 00:23:28.970
just doing it straight.

00:23:28.970 --> 00:23:30.680
AUDIENCE: [OBSCURED]

00:23:30.680 --> 00:23:32.080
MIKE ACTON: Well, I'm saying
write it in assembly.

00:23:35.260 --> 00:23:37.720
But if you have to, use
the intrinsics.

00:23:37.720 --> 00:23:42.190
But certainly don't write
a vector class.

00:23:42.190 --> 00:23:44.150
So memory management.

00:23:44.150 --> 00:23:46.190
Static allocations always
prefer the dynamic.

00:23:46.190 --> 00:23:49.390
Basically, general purpose
dynamic memory allocation,

00:23:49.390 --> 00:23:53.060
malloc free, whatever has just
absolutely no place in games.

00:23:57.540 --> 00:24:00.440
We don't have enough unknowns
for that to be valuable.

00:24:00.440 --> 00:24:03.530
We can group our data
by specific types.

00:24:03.530 --> 00:24:07.000
We know basic ranges
of those types.

00:24:07.000 --> 00:24:09.620
The vast majority of the data
is known in advance, it's

00:24:09.620 --> 00:24:11.080
actually burned onto the disk.

00:24:11.080 --> 00:24:13.730
We can actually analyze that.

00:24:13.730 --> 00:24:15.350
So most of our allocations
tend to

00:24:15.350 --> 00:24:16.590
calculate it in advance.

00:24:16.590 --> 00:24:20.900
So you load the level and
oftentimes you just load

00:24:20.900 --> 00:24:24.895
memory in off the disc
into memory and

00:24:24.895 --> 00:24:26.145
then fix up the pointers.

00:24:29.120 --> 00:24:33.570
For things that change during
the runtime, just simple

00:24:33.570 --> 00:24:37.020
hierarchical allocators, block
allocators where you have

00:24:37.020 --> 00:24:42.620
fixed sizes is always the
easiest and best way to go.

00:24:42.620 --> 00:24:45.490
These are known types
of known sizes.

00:24:45.490 --> 00:24:50.150
The key to that is to organize
your data so that's actually a

00:24:50.150 --> 00:24:51.590
workable solution.

00:24:51.590 --> 00:24:54.460
So you don't have these sort of
classes or structures that

00:24:54.460 --> 00:24:55.600
are dynamically sized.

00:24:55.600 --> 00:24:58.480
That you group them in terms
of things that are similar.

00:24:58.480 --> 00:25:03.790
Physics data here and AI data
is separately here in a

00:25:03.790 --> 00:25:05.190
separate array.

00:25:05.190 --> 00:25:10.580
And that way those sort of
chunks of data are similarly

00:25:10.580 --> 00:25:12.210
sized and can be block
allocated without any

00:25:12.210 --> 00:25:13.480
fragmentation issues at all.

00:25:18.610 --> 00:25:23.590
Eventually you'll probably want
to design an allocator.

00:25:23.590 --> 00:25:25.910
Things to consider are
the page sizes.

00:25:25.910 --> 00:25:28.910
That's critically important, you
want to work within a page

00:25:28.910 --> 00:25:30.560
as much as you possibly can.

00:25:30.560 --> 00:25:33.180
So you want to group things,
not necessarily the same

00:25:33.180 --> 00:25:36.360
things, but the things that
will be read together or

00:25:36.360 --> 00:25:38.430
written together within
the same page.

00:25:38.430 --> 00:25:43.040
So you want to have a concept of
the actual page up through

00:25:43.040 --> 00:25:44.290
the system.

00:25:47.130 --> 00:25:49.180
Probably the most common mistake
I see in a block

00:25:49.180 --> 00:25:51.510
allocator, so somebody says--

00:25:51.510 --> 00:25:54.000
everybody knows what I mean
by block allocator?

00:25:54.000 --> 00:25:54.540
Yeah?

00:25:54.540 --> 00:25:55.000
OK.

00:25:55.000 --> 00:25:57.890
So the most common mistake I see
people make is that they

00:25:57.890 --> 00:25:59.040
do least recently used.

00:25:59.040 --> 00:26:02.780
They just grab the most least
recently used block and use

00:26:02.780 --> 00:26:06.510
that when summoning a request.
That's actually pretty much

00:26:06.510 --> 00:26:08.930
the worst thing you can possibly
do because that's the

00:26:08.930 --> 00:26:11.530
most likely thing
to be called.

00:26:11.530 --> 00:26:13.850
That's the most likely thing to
be out of cache, both out

00:26:13.850 --> 00:26:15.630
of L1 and L2.

00:26:15.630 --> 00:26:19.340
Just the easiest thing you can
do to change that is just use

00:26:19.340 --> 00:26:20.310
most recently used.

00:26:20.310 --> 00:26:21.170
Just go up the other way.

00:26:21.170 --> 00:26:24.280
I mean, there are much more
complicated systems you can

00:26:24.280 --> 00:26:28.120
use, but just that one small
change where you're much more

00:26:28.120 --> 00:26:33.010
likely to get warm data is going
to give you a big boost.

00:26:33.010 --> 00:26:35.220
And again, like I said, use
hierarchies of allocations

00:26:35.220 --> 00:26:38.990
instead of these sort of static
block allocations.

00:26:38.990 --> 00:26:42.190
Instead of trying to have one
general purpose super mega

00:26:42.190 --> 00:26:46.230
allocator that does
everything.

00:26:46.230 --> 00:26:48.130
And again, if it's well planned,
fragmentation is a

00:26:48.130 --> 00:26:51.450
non-issue, it's impossible.

00:26:51.450 --> 00:26:54.810
Cache line, oh, and probably
another important concept to

00:26:54.810 --> 00:26:57.150
keep in mind as you're writing
your allocator is the transfer

00:26:57.150 --> 00:26:59.920
block size of the SPU.

00:26:59.920 --> 00:27:06.110
If you have a 16K block and the
system is aware of fixing

00:27:06.110 --> 00:27:11.080
K blocks then there are plenty
of cases where you don't have

00:27:11.080 --> 00:27:14.190
to keep track of-- in the
system-- the size of things.

00:27:14.190 --> 00:27:17.800
It's just how many blocks, how
many SPU blocks do you have?

00:27:17.800 --> 00:27:20.990
Or what percentage of
SPU blocks you have?

00:27:20.990 --> 00:27:25.000
And that will help you can sort
of compress down your

00:27:25.000 --> 00:27:27.570
memory requirements when you're
referring to blocks and

00:27:27.570 --> 00:27:28.820
memory streams and memory.

00:27:33.230 --> 00:27:36.476
AUDIENCE: About the memory
management for data here, you

00:27:36.476 --> 00:27:40.620
also write overlay managers
for code for the user?

00:27:40.620 --> 00:27:43.840
MIKE ACTON: Well, it basically
amounts to the same thing.

00:27:43.840 --> 00:27:46.900
I mean, the code is just data,
you just load it in and fix up

00:27:46.900 --> 00:27:48.860
the pointers and you're done.

00:27:48.860 --> 00:27:52.292
AUDIENCE: I was just wondering
whether IBM gives you

00:27:52.292 --> 00:27:55.130
embedding --

00:27:55.130 --> 00:27:56.630
MIKE ACTON: We don't
usse any of the IBM

00:27:56.630 --> 00:27:58.920
systems at all for games.

00:28:01.880 --> 00:28:06.100
I know IBM has an overlay
manager as part of the SDK.

00:28:06.100 --> 00:28:07.450
AUDIENCE: Well, not really.

00:28:07.450 --> 00:28:09.400
It's --

00:28:09.400 --> 00:28:11.970
MIKE ACTON: Well, they have some
overlay support, right?

00:28:11.970 --> 00:28:15.920
That's not something
we would ever use.

00:28:15.920 --> 00:28:18.170
And in general, I mean, I
guess that's probably an

00:28:18.170 --> 00:28:19.700
interesting question of how--

00:28:19.700 --> 00:28:20.810
AUDIENCE: So it's
all ground up?

00:28:20.810 --> 00:28:21.510
MIKE ACTON: What's that?

00:28:21.510 --> 00:28:24.080
AUDIENCE: All your development
is ground up?

00:28:24.080 --> 00:28:25.340
MIKE ACTON: Yeah, for
the most part.

00:28:28.400 --> 00:28:30.600
For us, that's definitely
true.

00:28:30.600 --> 00:28:33.610
There are studios that,
especially cross platform

00:28:33.610 --> 00:28:36.020
studios that will take
middleware development and

00:28:36.020 --> 00:28:37.270
just sort of use it
on a high-level.

00:28:39.680 --> 00:28:43.280
But especially when you're
starting a first generation

00:28:43.280 --> 00:28:47.220
platform game, there's virtually
nothing there to use

00:28:47.220 --> 00:28:48.690
because the hardware hasn't been
around long enough for

00:28:48.690 --> 00:28:51.530
anybody else to write
anything either.

00:28:51.530 --> 00:28:55.000
So if you need it, you
write it yourself.

00:28:55.000 --> 00:28:57.240
Plus that's just sort of the
general theme of game

00:28:57.240 --> 00:28:58.850
development.

00:28:58.850 --> 00:29:02.700
It's custom to your situation,
to your data.

00:29:02.700 --> 00:29:04.740
And anything that's general
purpose enough to sell as

00:29:04.740 --> 00:29:10.350
middleware is probably not going
to be fast enough to run

00:29:10.350 --> 00:29:11.920
a triple A title.

00:29:11.920 --> 00:29:13.920
Not always true, but
as a general

00:29:13.920 --> 00:29:15.640
rule, it's pretty valid.

00:29:20.240 --> 00:29:24.920
OK, so-- wait, so how'd
I get here?

00:29:24.920 --> 00:29:28.370
All right, this is next.

00:29:28.370 --> 00:29:33.100
So here's another example
of how the cell

00:29:33.100 --> 00:29:34.760
might affect design.

00:29:34.760 --> 00:29:37.540
So you're writing a collision
detection system.

00:29:43.460 --> 00:29:47.650
It's obvious that you cannot or
should not expect immediate

00:29:47.650 --> 00:29:50.820
results from a collision
detection system, otherwise

00:29:50.820 --> 00:29:54.030
you're going to be sitting and
syncing all the time for one

00:29:54.030 --> 00:29:56.670
result and performance just goes
out the window, you may

00:29:56.670 --> 00:29:58.710
as well just have a
serial program.

00:29:58.710 --> 00:30:03.090
So you want to group results,
you want to group queries and

00:30:03.090 --> 00:30:06.410
you want potentially, for those
queries to be deferred

00:30:06.410 --> 00:30:09.920
so that you can store them, you
can just DMA them out and

00:30:09.920 --> 00:30:12.150
then whatever process needed
then we'll come back and grab

00:30:12.150 --> 00:30:14.590
them later.

00:30:14.590 --> 00:30:17.475
So conceptually that's the
design you want to build into

00:30:17.475 --> 00:30:22.590
a collision detection system,
which then in turn affects the

00:30:22.590 --> 00:30:24.030
high-level design.

00:30:24.030 --> 00:30:29.800
So AI, scripts, any game code
that might have previously

00:30:29.800 --> 00:30:32.040
depended on a result being
immediately available, as in

00:30:32.040 --> 00:30:36.120
they have characters that shoot
rays around the room to

00:30:36.120 --> 00:30:38.910
decide what they're going to
do next or bullets that are

00:30:38.910 --> 00:30:42.730
flying through the air or
whatever, can no longer make

00:30:42.730 --> 00:30:43.710
that assumption.

00:30:43.710 --> 00:30:46.580
So they have to be able to group
up their queries and

00:30:46.580 --> 00:30:48.450
look them up later and
have other work

00:30:48.450 --> 00:30:50.070
to do in the meantime.

00:30:50.070 --> 00:30:54.470
So this is a perfect example
of how you cannot take old

00:30:54.470 --> 00:30:57.630
code and move it to the PS3.

00:30:57.630 --> 00:31:01.330
Because old code, serial code
would have definitely assumed

00:31:01.330 --> 00:31:03.040
that the results were
immediately available because

00:31:03.040 --> 00:31:04.700
honestly, that was the
fastest way to do it.

00:31:09.300 --> 00:31:13.230
So on a separate issue, we have
SPU decomposition for the

00:31:13.230 --> 00:31:15.000
geometry look up.

00:31:15.000 --> 00:31:18.710
So from a high-level you have
your entire scene in the level

00:31:18.710 --> 00:31:24.640
of the world or whatever and you
have the set of queries in

00:31:24.640 --> 00:31:26.480
the case of static--
did I collide with

00:31:26.480 --> 00:31:27.710
anything in the world?

00:31:27.710 --> 00:31:29.820
Or you have a RAID that, where
does this RAID collide with

00:31:29.820 --> 00:31:30.880
something in the world?

00:31:30.880 --> 00:31:33.640
And so you have this problem of
you have this large sort of

00:31:33.640 --> 00:31:37.520
memory database in main RAM
and you have the smallest

00:31:37.520 --> 00:31:40.680
spew, which obviously cannot
read in the whole database,

00:31:40.680 --> 00:31:42.670
analyze it, and spit
out the result.

00:31:42.670 --> 00:31:46.410
It has to go back and forth
to main RAM in order

00:31:46.410 --> 00:31:49.340
to build its result.

00:31:49.340 --> 00:31:52.270
So the question is how do you
decompose the memory in the

00:31:52.270 --> 00:31:54.700
first place to make
that at least

00:31:54.700 --> 00:31:58.160
somewhat reasonably efficient?

00:31:58.160 --> 00:32:04.660
The first sort of instinct I
think, based on history is

00:32:04.660 --> 00:32:07.960
sort of the traditional scene
graph structures like BSP tree

00:32:07.960 --> 00:32:09.680
or off tree or something
like that.

00:32:13.720 --> 00:32:16.310
Particularly, on the SPU because
if TLB misses that

00:32:16.310 --> 00:32:19.070
becomes really expensive, really
quickly when you're

00:32:19.070 --> 00:32:21.550
basically hitting random
memory on every

00:32:21.550 --> 00:32:25.400
single node on the tree.

00:32:25.400 --> 00:32:28.090
So what you want to do is you
want to make that hierarchy as

00:32:28.090 --> 00:32:31.120
flat as you possibly can.

00:32:31.120 --> 00:32:35.480
If the leafs have to be bigger
that's fine because it turns

00:32:35.480 --> 00:32:40.190
out it's much, much cheaper to
stream in a bigger group of--

00:32:40.190 --> 00:32:43.280
as much data as you can fit into
the SPU and run through

00:32:43.280 --> 00:32:46.820
it and make your decisions and
spit it back out than it is to

00:32:46.820 --> 00:32:49.190
traverse the hierarchy.

00:32:49.190 --> 00:32:53.640
So basically, the depth of your
hierarchy in your scene

00:32:53.640 --> 00:32:55.960
database is completely
determined by how much data

00:32:55.960 --> 00:32:58.080
you can fit into the
SPU by the maximum

00:32:58.080 --> 00:33:02.230
size of the leaf node.

00:33:02.230 --> 00:33:05.230
The rest of the dep is only
because you don't have any

00:33:05.230 --> 00:33:06.010
other choice.

00:33:06.010 --> 00:33:10.690
You know, And basically the same
thing goes with dynamic

00:33:10.690 --> 00:33:12.860
geometry as you have geometry
moving around in the scene,

00:33:12.860 --> 00:33:15.110
characters moving around
in the scene--

00:33:15.110 --> 00:33:18.730
they basically need to update
themselves into their own

00:33:18.730 --> 00:33:22.020
database, into their
own leaves and

00:33:22.020 --> 00:33:24.180
they'll do this in groups.

00:33:24.180 --> 00:33:26.790
And then when you query, you
basically want it to query as

00:33:26.790 --> 00:33:28.820
many of those as possible,
as you can

00:33:28.820 --> 00:33:30.920
possibly fit in at once.

00:33:30.920 --> 00:33:34.410
So you could have sort of a
broad faced collision first,

00:33:34.410 --> 00:33:36.910
where you have all of the groups
of characters that are

00:33:36.910 --> 00:33:39.800
potentially maximum
in this leaf, so

00:33:39.800 --> 00:33:41.500
bound and box or whatever.

00:33:41.500 --> 00:33:45.780
So even though you could in
theory, in principle narrow

00:33:45.780 --> 00:33:49.230
that down even more, the cost
for that, the cost for the

00:33:49.230 --> 00:33:53.790
potential memory miss for that
is so high that you just want

00:33:53.790 --> 00:33:55.760
to do a linear search through
as many as you

00:33:55.760 --> 00:33:57.510
possibly can on SPU.

00:33:57.510 --> 00:33:59.170
Does that make sense?

00:34:04.220 --> 00:34:06.610
Procedural graphics--

00:34:06.610 --> 00:34:12.630
so although we have a GPU on
the PlayStation 3, it does

00:34:12.630 --> 00:34:14.880
turn out that the SPU
is a lot better at

00:34:14.880 --> 00:34:16.130
doing a lot of things.

00:34:19.590 --> 00:34:22.490
Things basically where
you create

00:34:22.490 --> 00:34:27.630
geometry for RSX to render.

00:34:27.630 --> 00:34:31.540
So particle system, dynamic
particle systems. Especially

00:34:31.540 --> 00:34:34.990
where their systems have to
interact with the world in

00:34:34.990 --> 00:34:41.000
some way, which will be much
more expensive on the GPU.

00:34:41.000 --> 00:34:45.200
Sort of a dynamic systems
like cloth.

00:34:45.200 --> 00:34:48.460
Fonts is actually really
interesting because typically

00:34:48.460 --> 00:34:51.880
you'll just see bitmap
fonts in which

00:34:51.880 --> 00:34:53.840
case are just textures.

00:34:53.840 --> 00:34:56.930
But if you have a very complex
user interface then just the

00:34:56.930 --> 00:35:02.800
size of the bitmap becomes
extreme and if you compressed

00:35:02.800 --> 00:35:04.370
them they look terrible,
especially fonts.

00:35:04.370 --> 00:35:06.620
Fonts need to look perfect.

00:35:06.620 --> 00:35:08.980
So if you do do procedural
fonts, for example, two type

00:35:08.980 --> 00:35:12.750
fonts, the cost of rendering
a font actually gets

00:35:12.750 --> 00:35:15.040
significant.

00:35:15.040 --> 00:35:18.830
And in this case, the SPU is
actually a great use for

00:35:18.830 --> 00:35:22.210
rendering a procedural font.

00:35:22.210 --> 00:35:24.020
Rendering textures
is basically the

00:35:24.020 --> 00:35:25.510
same case as font.

00:35:25.510 --> 00:35:29.200
Procedural textures like if you
do noise-based clouds or

00:35:29.200 --> 00:35:30.750
something like that.

00:35:30.750 --> 00:35:33.700
And parametric geometry, it's
like nurbs or subdivision

00:35:33.700 --> 00:35:35.300
services or something like
that, is a perfect

00:35:35.300 --> 00:35:36.700
case for the SPU.

00:35:42.260 --> 00:35:43.754
Is there a question?

00:35:48.060 --> 00:35:49.190
Geometry database, OK.

00:35:49.190 --> 00:35:53.970
First thing scene graphs
are worthless.

00:35:53.970 --> 00:35:55.550
Yeah?

00:35:55.550 --> 00:35:58.700
AUDIENCE: So of those sort of
differnet conceptualized

00:35:58.700 --> 00:36:02.936
paths, are you literally
swapping code in and out of

00:36:02.936 --> 00:36:06.560
the SPUs with the data
many times per frame?

00:36:06.560 --> 00:36:07.900
Or is it more of a static---

00:36:07.900 --> 00:36:10.520
MIKE ACTON: OK, that's an
excellent question.

00:36:10.520 --> 00:36:12.660
It totally depends.

00:36:12.660 --> 00:36:16.470
I mean, in general through a
game or through, at least a

00:36:16.470 --> 00:36:20.480
particular area of a game the
SPU set up is stable.

00:36:20.480 --> 00:36:24.770
So if we decide you're going to
have this SPU dedicated to

00:36:24.770 --> 00:36:29.060
physics for example, it is very
likely that that SPU is

00:36:29.060 --> 00:36:31.860
stable and it's going to be
dedicated physics, at least

00:36:31.860 --> 00:36:34.840
for some period of time through
the level or through

00:36:34.840 --> 00:36:36.360
the zone or wherever it is.

00:36:36.360 --> 00:36:39.920
Sometimes through
an entire game.

00:36:39.920 --> 00:36:42.790
So there are going to be
elements of that where it's

00:36:42.790 --> 00:36:45.260
sort of a well balanced
problem.

00:36:45.260 --> 00:36:47.620
There's basically no way you're
going to get waste.

00:36:47.620 --> 00:36:51.350
It's always going to be full,
it's always going to be busy.

00:36:51.350 --> 00:36:54.470
Collision detection and physics
are the two things

00:36:54.470 --> 00:36:58.910
that you'll never have
enough CPU to do.

00:36:58.910 --> 00:37:02.300
You can always use more
and more CPU.

00:37:02.300 --> 00:37:06.790
And basically, the rest can
be dynamically scheduled.

00:37:06.790 --> 00:37:09.360
And the question of how to
schedule it, is actually an

00:37:09.360 --> 00:37:12.230
interesting problem.

00:37:12.230 --> 00:37:15.810
It's my opinion that sort of
looking for the universal

00:37:15.810 --> 00:37:18.820
scheduler that solves all
problems and magically makes

00:37:18.820 --> 00:37:23.180
everything work is a
total lost cause.

00:37:23.180 --> 00:37:27.880
You have more than enough data
to work with and in your game

00:37:27.880 --> 00:37:33.480
to decide how to schedule your
SPUs basically, manually.

00:37:33.480 --> 00:37:35.320
And it's just not that
complicated.

00:37:35.320 --> 00:37:36.590
We have six SPUs.

00:37:36.590 --> 00:37:39.380
How to schedule six SPUs is just
not that complicated a

00:37:39.380 --> 00:37:41.920
problem, you could write it
down on a piece of paper.

00:37:46.990 --> 00:37:52.040
OK, so scene graphs are almost
always, universally a complete

00:37:52.040 --> 00:37:53.620
waste time.

00:37:53.620 --> 00:37:57.640
They store way too much data
for no apparent reason.

00:37:57.640 --> 00:38:00.170
Store your databases
independently based on what

00:38:00.170 --> 00:38:02.400
you're actually doing with
them, optimize your data

00:38:02.400 --> 00:38:04.860
separately because you're
accessing it separately.

00:38:04.860 --> 00:38:09.070
The only thing that should be
linking your sort of domain

00:38:09.070 --> 00:38:11.910
object is a key that says all
right, we'll exist in this

00:38:11.910 --> 00:38:15.290
database and the database
and this database.

00:38:15.290 --> 00:38:18.510
But to have this sort of giant
structure that keeps all of

00:38:18.510 --> 00:38:24.820
the data for each element in the
scene is about the poorest

00:38:24.820 --> 00:38:30.580
performing you can imagine for
both cache and TLB and SPU

00:38:30.580 --> 00:38:32.620
because you can't fit it in
individual node on the SPU.

00:38:38.130 --> 00:38:39.380
I think I covered that.

00:38:42.620 --> 00:38:45.540
Here's an interesting example,
so what you want to do is if

00:38:45.540 --> 00:38:48.690
you have the table of queries
that you have-- bunch of

00:38:48.690 --> 00:38:51.910
people over the course of a
frame say I want to know if I

00:38:51.910 --> 00:38:54.110
collided with something.

00:38:54.110 --> 00:38:57.040
And then if you basically make
a pre-sort pass on that and

00:38:57.040 --> 00:39:01.150
basically, spatially sort these
guys together, so let's

00:39:01.150 --> 00:39:03.300
say you have however many
you can fit in a SPU.

00:39:03.300 --> 00:39:06.330
So you have four of these
queries together.

00:39:06.330 --> 00:39:10.050
Although they might be a little
further apart then you

00:39:10.050 --> 00:39:13.510
would hope, you could basically
create a baling box

00:39:13.510 --> 00:39:16.720
through a single query on the
database that's the sum of all

00:39:16.720 --> 00:39:20.320
of them and then as I said,
now you have a linear list

00:39:20.320 --> 00:39:21.930
that you can just stream through
for all of them.

00:39:21.930 --> 00:39:24.585
So even though it's doing more
work for any individual one,

00:39:24.585 --> 00:39:29.230
the overhead is reduced so
significantly that the end

00:39:29.230 --> 00:39:31.050
result is that it's
significantly faster.

00:39:34.200 --> 00:39:37.780
And that's also what I mean by
multiple simultaneous lookups.

00:39:37.780 --> 00:39:41.530
Basically you want to group
queries together, but make

00:39:41.530 --> 00:39:44.240
sure that there's some
advantage to that.

00:39:44.240 --> 00:39:47.170
By spatially pre-sorting them
there is an advantage to that

00:39:47.170 --> 00:39:50.050
because it's more likely
that they will have

00:39:50.050 --> 00:39:53.370
overlap in your queries.

00:39:53.370 --> 00:39:54.100
So game logic.

00:39:54.100 --> 00:39:58.110
Stuff that the cell would
affect in game logic.

00:39:58.110 --> 00:40:02.570
State machines are
a good example.

00:40:02.570 --> 00:40:06.330
If you defer your logic lines
and defer your results, SPUs

00:40:06.330 --> 00:40:10.610
are amazingly perfect for
defining state machines.

00:40:10.610 --> 00:40:13.130
If you expect your logic lines
to be immediately available

00:40:13.130 --> 00:40:17.970
across the entire system, SPU
is absolutely horrid.

00:40:17.970 --> 00:40:20.920
So if you basically write
buffers into your state

00:40:20.920 --> 00:40:26.760
machines or your logic machines
then each SPU can be

00:40:26.760 --> 00:40:30.760
cranking on multiple state
machines at once where all the

00:40:30.760 --> 00:40:34.500
input and all the output lines
are assumed to be deferred and

00:40:34.500 --> 00:40:36.640
it's just an extremely
straightforward process.

00:40:39.480 --> 00:40:41.380
Scripting, so scripting
things like--

00:40:41.380 --> 00:40:44.020
I don't know, lewis script
or C script or

00:40:44.020 --> 00:40:47.080
something like that.

00:40:47.080 --> 00:40:49.550
I mean, obviously the first
thing to look at is the size

00:40:49.550 --> 00:40:50.940
of the interpreter.

00:40:50.940 --> 00:40:54.420
Will it fit into an
SPU to begin with?

00:40:54.420 --> 00:41:00.100
Another option to consider is,
can it be converted into SPU

00:41:00.100 --> 00:41:03.900
code, either offline
or dynamically?

00:41:03.900 --> 00:41:05.990
Because you'll find that most
off the shelf scripting

00:41:05.990 --> 00:41:08.190
languages are scalar,

00:41:08.190 --> 00:41:11.220
sequential scripting languages.

00:41:11.220 --> 00:41:16.720
So all of a P code within the
scripting language itself

00:41:16.720 --> 00:41:18.300
basically defines
scalar access.

00:41:18.300 --> 00:41:21.970
So not only are you switching
on every byte to every two

00:41:21.970 --> 00:41:24.750
bytes or whatever, so it's sort
of poorly performing code

00:41:24.750 --> 00:41:27.600
from an SPU point of view, but
it's also poorly performing

00:41:27.600 --> 00:41:29.760
code from a memory
point of view.

00:41:29.760 --> 00:41:31.810
So I guess the question is
whether or not you can

00:41:31.810 --> 00:41:35.700
optimize the script itself and
turn turn it into SPU code

00:41:35.700 --> 00:41:39.380
that you can then dynamically
load or come up with a new

00:41:39.380 --> 00:41:42.780
script that's just much more
friendly for the SPUs.

00:41:45.410 --> 00:41:49.880
Another option if you have to
use a single, sort of scalar

00:41:49.880 --> 00:41:55.550
scripting language like lua or
C script or whatever, if you

00:41:55.550 --> 00:41:59.120
can run multiple streams
simultaneously so that while

00:41:59.120 --> 00:42:01.980
you're doing these sort of
individual offline memory

00:42:01.980 --> 00:42:06.140
lookups and reads and writes to
main memory, that once one

00:42:06.140 --> 00:42:08.550
blocks you can start moving
on another one.

00:42:08.550 --> 00:42:12.070
As long as there's no
dependencies between these two

00:42:12.070 --> 00:42:14.600
scripts we should be able
to stream them both

00:42:14.600 --> 00:42:17.640
simultaneously.

00:42:17.640 --> 00:42:21.620
Motion control actually turns
out to be a critical problem

00:42:21.620 --> 00:42:23.850
in games in general that's
often overlooked.

00:42:23.850 --> 00:42:28.300
It's who controls the
motion in the game.

00:42:28.300 --> 00:42:29.750
Is is the AI?

00:42:29.750 --> 00:42:34.590
So is it the controller in
the case of the player?

00:42:34.590 --> 00:42:36.720
I say, push forward, so
the guy moves forward.

00:42:36.720 --> 00:42:39.090
Is that really what
controls it?

00:42:39.090 --> 00:42:40.950
Or is it the physics?

00:42:40.950 --> 00:42:43.660
So all the AI does is say, I
want to move forward, tells

00:42:43.660 --> 00:42:45.360
the physic system I want to move
forward and the physics

00:42:45.360 --> 00:42:47.000
tries to follow it.

00:42:47.000 --> 00:42:48.660
Or is it the animation?

00:42:48.660 --> 00:42:50.710
That you have the animators
actually put translation in

00:42:50.710 --> 00:42:52.530
the animation, so is that
translation the thing that's

00:42:52.530 --> 00:42:54.607
actually driving the motion and
everything else is trying

00:42:54.607 --> 00:42:56.170
to follow it?

00:42:56.170 --> 00:42:59.830
Turns out to be a surprisingly
difficult problem to solve and

00:42:59.830 --> 00:43:06.180
every studio ends up with
their own solution.

00:43:06.180 --> 00:43:08.590
I forget what point I was
making on how the cell

00:43:08.590 --> 00:43:09.840
affected that decision.

00:43:12.040 --> 00:43:13.210
But--

00:43:13.210 --> 00:43:18.780
AUDIENCE: [OBSCURED]

00:43:18.780 --> 00:43:21.120
MIKE ACTON: I think the point,
probably that I was trying to

00:43:21.120 --> 00:43:24.670
make is that because you want
everything to be deferred

00:43:24.670 --> 00:43:29.700
anyway, then the order does
become a clearer sort of

00:43:29.700 --> 00:43:32.530
winner in that order.

00:43:32.530 --> 00:43:37.780
Where you want the immediate
feedback from the controls,

00:43:37.780 --> 00:43:39.900
the control leads the way.

00:43:39.900 --> 00:43:42.740
You have the physics, which then
follows, perhaps, even a

00:43:42.740 --> 00:43:46.960
frame behind that to say how
that new position is impacted

00:43:46.960 --> 00:43:49.320
by the physical reality
of the world.

00:43:49.320 --> 00:43:52.230
And then potentially a frame
behind that or half a frame

00:43:52.230 --> 00:43:55.560
behind that you have the
animation system, which in

00:43:55.560 --> 00:43:58.050
that case would just be
basically, a visual

00:43:58.050 --> 00:44:00.520
representation of what's
going on rather

00:44:00.520 --> 00:44:01.540
than leading anything.

00:44:01.540 --> 00:44:04.190
It's basically an icon for
what's happening in the

00:44:04.190 --> 00:44:06.600
physics and the AI.

00:44:09.390 --> 00:44:12.680
The limitations of your system
are that it has to be deferred

00:44:12.680 --> 00:44:14.470
and that it has to be
done in groups.

00:44:14.470 --> 00:44:17.430
Basically, some of these sort of
really difficult decisions

00:44:17.430 --> 00:44:19.350
have only one or two
obvious answers.

00:44:24.570 --> 00:44:26.550
All right, well I wanted to dig
into animation a little

00:44:26.550 --> 00:44:29.520
bit, so does anybody have any
questions on anything?

00:44:29.520 --> 00:44:31.300
Any of the sort of the
high-level stuff that I've

00:44:31.300 --> 00:44:32.570
covered up to this point?

00:44:35.603 --> 00:44:36.853
Yeah?

00:44:38.700 --> 00:44:43.196
AUDIENCE: So does the need for
deferral and breaking into

00:44:43.196 --> 00:44:48.230
groups and staging, does this
need break the desire for the

00:44:48.230 --> 00:44:51.500
higher-level programmers to
abstract what's going on at

00:44:51.500 --> 00:44:54.176
the data engine level?

00:44:54.176 --> 00:44:57.770
Or is that not quite
the issue?

00:44:57.770 --> 00:45:01.130
MIKE ACTON: Well, let's
say we get a game

00:45:01.130 --> 00:45:02.500
play programmer, right?

00:45:02.500 --> 00:45:05.430
Fresh out of school, he's
taught in school, C

00:45:05.430 --> 00:45:06.680
plus plus in school.

00:45:06.680 --> 00:45:11.090
Taught to decompose the world
into sort of the main classes

00:45:11.090 --> 00:45:13.460
and that they all communicate
through each other maybe

00:45:13.460 --> 00:45:15.650
through messaging.

00:45:15.650 --> 00:45:17.920
All right, well the first thing
we tell him is that all

00:45:17.920 --> 00:45:19.710
that is complete crap.

00:45:19.710 --> 00:45:22.970
None of that will actually
work in practice.

00:45:22.970 --> 00:45:26.260
So in some sense, yes, there is
a sort of tendency for them

00:45:26.260 --> 00:45:31.310
to want this interface, this
sort of clean abstraction, but

00:45:31.310 --> 00:45:34.450
abstraction doesn't
have any value.

00:45:34.450 --> 00:45:37.085
It doesn't make the game faster,
it doesn't make the

00:45:37.085 --> 00:45:38.590
game cheaper.

00:45:38.590 --> 00:45:39.370
It doesn't make--

00:45:39.370 --> 00:45:42.540
AUDIENCE: [OBSCURED]

00:45:42.540 --> 00:45:44.860
PROFESSOR: There's a
bit of a religious.

00:45:44.860 --> 00:45:45.780
Let's move on.

00:45:45.780 --> 00:45:47.980
He has a lot of other
interesting things to say.

00:45:47.980 --> 00:45:50.050
And we can get to
that question--

00:45:50.050 --> 00:45:51.860
AUDIENCE: It sounds like
there's two completely

00:45:51.860 --> 00:45:53.790
different communities involved
in the development.

00:45:53.790 --> 00:45:56.320
There's the engine developers
and there's the higher-level--

00:45:56.320 --> 00:45:57.540
MIKE ACTON: That's a fair
enough assessment.

00:45:57.540 --> 00:45:59.430
There are different
communities.

00:45:59.430 --> 00:46:02.476
There is a community of the game
play programmers and the

00:46:02.476 --> 00:46:04.110
community of engine
programmers.

00:46:04.110 --> 00:46:06.390
And they have different
priorities and they have

00:46:06.390 --> 00:46:08.760
different experiences.

00:46:08.760 --> 00:46:13.190
So yeah, in that way there
is a division.

00:46:13.190 --> 00:46:14.830
PROFESSOR: I will
let you go on.

00:46:14.830 --> 00:46:15.890
You said you had a lot
of interesting

00:46:15.890 --> 00:46:18.160
information to cover.

00:46:18.160 --> 00:46:20.210
MIKE ACTON: OK.

00:46:20.210 --> 00:46:21.270
AUDIENCE: I can bitch
about that.

00:46:21.270 --> 00:46:23.950
Don't worry.

00:46:23.950 --> 00:46:26.790
MIKE ACTON: So just to get into
animation a little bit.

00:46:26.790 --> 00:46:31.030
Let's start with trying to
build a simple animation

00:46:31.030 --> 00:46:33.520
system and see what problems
come creep up as we're trying

00:46:33.520 --> 00:46:34.820
to implement it on the cell.

00:46:38.270 --> 00:46:41.080
So in the simplest case we
have a set of animation

00:46:41.080 --> 00:46:43.116
channels defined for
a character, which

00:46:43.116 --> 00:46:44.330
is made up of joints.

00:46:44.330 --> 00:46:47.200
We're just talking about sort
of a simple hierarchical

00:46:47.200 --> 00:46:49.630
transformation here.

00:46:49.630 --> 00:46:51.900
And some of those channels
are related.

00:46:51.900 --> 00:46:56.600
So in the case of rotation plus
translation plus scale

00:46:56.600 --> 00:47:00.570
equals any individual joint.

00:47:00.570 --> 00:47:04.780
So the first thing, typically
that you'll have to answer is

00:47:04.780 --> 00:47:12.900
whether or not you want to do
euler or quaternion rotation.

00:47:12.900 --> 00:47:18.640
Now the tendency I guess,
especially for new programmers

00:47:18.640 --> 00:47:21.370
is to go with quaternion.

00:47:21.370 --> 00:47:24.970
They're taught that gimbal
lock is a sort of

00:47:24.970 --> 00:47:28.860
insurmountable problem that
only quaternion solves.

00:47:28.860 --> 00:47:30.260
That's just simply not true.

00:47:30.260 --> 00:47:31.940
I mean, gimbal lock
is completely

00:47:31.940 --> 00:47:33.500
manageable in practice.

00:47:36.230 --> 00:47:39.830
When you're trying to rotate
on three axes and two axes

00:47:39.830 --> 00:47:42.940
rotate 90 degrees apart and
the third axis can't be

00:47:42.940 --> 00:47:44.570
resolved or 180 degrees apart.

00:47:44.570 --> 00:47:46.390
So you can't resolve one
of the axes, right?

00:47:46.390 --> 00:47:48.950
AUDIENCE: [OBSCURED]

00:47:48.950 --> 00:47:51.830
MIKE ACTON: Yeah, it's where
it's impossible to resolve one

00:47:51.830 --> 00:47:53.990
of the axes and that's
the nature of

00:47:53.990 --> 00:47:56.320
euler sort of rotation.

00:48:00.670 --> 00:48:02.820
But sort of a quaternion
rotation completely solves

00:48:02.820 --> 00:48:06.800
that mathematical problem, it's
always resolvable and

00:48:06.800 --> 00:48:08.290
it's not very messy at all.

00:48:08.290 --> 00:48:11.550
I mean, from a sort of C
programmers perspective, it

00:48:11.550 --> 00:48:14.330
looks clean, the math's clean,
everything's clean about it.

00:48:14.330 --> 00:48:18.850
Unfortunately, it doesn't
compress very well at all.

00:48:18.850 --> 00:48:23.720
Where if you used euler
rotation, which basically just

00:48:23.720 --> 00:48:27.640
means that the individual
rotation for every axis.

00:48:27.640 --> 00:48:30.830
So x rotation, y rotation,
z rotation.

00:48:30.830 --> 00:48:33.300
That's much, much more
compressible because each one

00:48:33.300 --> 00:48:36.410
of those axes can be
individually compressed.

00:48:36.410 --> 00:48:38.665
It's very unlikely that you're
always rotating all three

00:48:38.665 --> 00:48:42.060
axes, all the time, especially
in a human character.

00:48:42.060 --> 00:48:44.596
It's much more likely that only
one axis is rotating on

00:48:44.596 --> 00:48:49.690
any one given time and
so that makes it--

00:48:49.690 --> 00:48:52.660
just without any change,
without any additional

00:48:52.660 --> 00:48:57.368
compression-- it tends to make
it about 1/3 of the size.

00:48:57.368 --> 00:48:59.910
AUDIENCE: [OBSCURED]

00:48:59.910 --> 00:49:03.070
MIKE ACTON: The animation
data.

00:49:03.070 --> 00:49:05.810
So you have this frame of
animation, which is all these

00:49:05.810 --> 00:49:07.720
animation channels, right?

00:49:07.720 --> 00:49:11.000
And then over time you have
these different frames of

00:49:11.000 --> 00:49:12.080
animation, right?

00:49:12.080 --> 00:49:15.100
If you store-- for every joint,
for every rotation you

00:49:15.100 --> 00:49:18.190
store a quaternion over time,
it's hard to compress across

00:49:18.190 --> 00:49:21.680
time because you're basically,
essentially rotating all three

00:49:21.680 --> 00:49:22.970
axes, all the time.

00:49:22.970 --> 00:49:24.900
Well, with--

00:49:24.900 --> 00:49:25.420
yeah?

00:49:25.420 --> 00:49:26.670
All right.

00:49:28.950 --> 00:49:32.720
So let's say, of course, the
next step is how do we store

00:49:32.720 --> 00:49:35.170
the actual rotation itself?

00:49:35.170 --> 00:49:39.120
Do we store it in cloth, double,
half precision, fixed

00:49:39.120 --> 00:49:40.370
point precision?

00:49:43.500 --> 00:49:45.670
Probably the national tendency
at this point would be to

00:49:45.670 --> 00:49:49.030
store it in a floating point
number, but if you look at the

00:49:49.030 --> 00:49:51.630
actual range of rotation, which
is extremely limited on

00:49:51.630 --> 00:49:55.900
a character, on any particular
joint there are very few

00:49:55.900 --> 00:50:00.270
joints that would even
rotate 180 degrees.

00:50:00.270 --> 00:50:05.360
So a floating point
is overkill, by a

00:50:05.360 --> 00:50:07.810
large margin on rotation--

00:50:11.720 --> 00:50:12.440
for the range.

00:50:12.440 --> 00:50:15.940
For the precision, however
it's fairly good.

00:50:15.940 --> 00:50:18.160
Especially if you're doing very
small rotations over a

00:50:18.160 --> 00:50:21.170
long period of time.

00:50:21.170 --> 00:50:23.980
So probably a more balanced
approach would be to go with a

00:50:23.980 --> 00:50:27.280
16 bit floating point from a
half format where you keep

00:50:27.280 --> 00:50:29.270
most of the precision, but
you reduce the range

00:50:29.270 --> 00:50:31.340
significantly.

00:50:31.340 --> 00:50:33.465
There's also the potential for
going with an 8 bit floating

00:50:33.465 --> 00:50:37.840
point format depending
on the kind of

00:50:37.840 --> 00:50:39.490
animation that you're doing.

00:50:39.490 --> 00:50:43.190
And I'll probably have this on
another slide, but it really

00:50:43.190 --> 00:50:44.710
depends on how close--

00:50:44.710 --> 00:50:48.940
how compressible a joint is
depends on how close to the

00:50:48.940 --> 00:50:49.880
root it is.

00:50:49.880 --> 00:50:52.530
The further away from the root
the less it matters.

00:50:52.530 --> 00:50:54.950
So the joint at your fingertip,
you can compress a

00:50:54.950 --> 00:50:57.017
whole lot more because it
doesn't matter as much, it's

00:50:57.017 --> 00:50:58.420
not going to affect
anything else.

00:50:58.420 --> 00:51:01.520
Where a joint at the actual
root, the smallest change in

00:51:01.520 --> 00:51:04.720
motion will affect the entire
system in animation and will

00:51:04.720 --> 00:51:07.150
make it virtually impossible for
you to line up animations

00:51:07.150 --> 00:51:09.580
with each other, so that that
particular joint needs to be

00:51:09.580 --> 00:51:12.030
nearly perfect.

00:51:12.030 --> 00:51:13.220
And how do you store rotation?

00:51:13.220 --> 00:51:17.150
Do you store them in degrees,
radians, or normalized?

00:51:17.150 --> 00:51:19.230
I have seen people store
them in degrees.

00:51:19.230 --> 00:51:21.800
I don't understand why you
would ever do that.

00:51:21.800 --> 00:51:26.430
It's just adding math
to the problem.

00:51:26.430 --> 00:51:31.920
Radians is perfectly fine if
you're using off the shelf

00:51:31.920 --> 00:51:35.150
trigonometric functions-
tan, sine whatever.

00:51:35.150 --> 00:51:37.080
But typically, if you're going
to optimize those functions

00:51:37.080 --> 00:51:39.970
yourself anyway, it's going to
be much more effective go with

00:51:39.970 --> 00:51:42.800
a normalized rotational value.

00:51:42.800 --> 00:51:46.860
So basically between
zero and 1.

00:51:46.860 --> 00:51:52.970
Makes it a lot easier to do
tricks based on the circle.

00:51:52.970 --> 00:51:55.560
Basically you can just take the
fractional value and just

00:51:55.560 --> 00:51:58.050
deal with that.

00:51:58.050 --> 00:52:01.150
So normalized rotation is
generally the way to go and

00:52:01.150 --> 00:52:07.250
normalizing a half precision is
probably the even bet for

00:52:07.250 --> 00:52:08.500
how you would store.

00:52:12.890 --> 00:52:16.210
So looking at what we need to
fit into an SPU if we're going

00:52:16.210 --> 00:52:17.090
to running to an end machine.

00:52:17.090 --> 00:52:17.652
Yeah?

00:52:17.652 --> 00:52:20.472
AUDIENCE: You talked a lot about
compressing because of

00:52:20.472 --> 00:52:24.590
the way it's impacting data,
what's the key driver of that?

00:52:24.590 --> 00:52:25.940
MIKE ACTON: The SPU has
very little space.

00:52:25.940 --> 00:52:28.380
AUDIENCE: OK, so it's just
the amount of space.

00:52:28.380 --> 00:52:29.800
MIKE ACTON: Yeah, well OK.

00:52:29.800 --> 00:52:33.450
There's two factors really,
in all honesty.

00:52:33.450 --> 00:52:34.820
So starting with the SPU.

00:52:34.820 --> 00:52:37.090
That you have to be able
to work through

00:52:37.090 --> 00:52:39.660
this data on the SPU.

00:52:39.660 --> 00:52:42.070
But you also have the
DMA transfer itself.

00:52:42.070 --> 00:52:45.360
The SPU can actually calculate
really, really fast, right?

00:52:45.360 --> 00:52:47.800
I mean, that's the
whole point.

00:52:47.800 --> 00:52:51.740
So if you can transfer less
data, burn through it a little

00:52:51.740 --> 00:52:55.960
bit to expand it, it's
actually a huge win.

00:52:55.960 --> 00:52:59.310
And on top of that we have a
big, big game and only 256

00:52:59.310 --> 00:53:02.160
megs of main ram.

00:53:02.160 --> 00:53:08.150
And the amount of geometry that
people require from a

00:53:08.150 --> 00:53:14.070
current generation game or
next generation game has

00:53:14.070 --> 00:53:16.470
scaled up way more than the
amount of memory we've been

00:53:16.470 --> 00:53:20.270
given, so we've only been given
eight times as much

00:53:20.270 --> 00:53:21.480
memory as we had in the
previous generation.

00:53:21.480 --> 00:53:24.480
People expect significantly more
than eight times as much

00:53:24.480 --> 00:53:29.780
geometry on the screen and
where do we store that?

00:53:29.780 --> 00:53:32.145
We have the Blu-Ray, we can't
be streaming everything off

00:53:32.145 --> 00:53:36.470
the disc all the time, which
is to another point.

00:53:36.470 --> 00:53:41.250
You have 40 gigs of data
on your disc, but

00:53:41.250 --> 00:53:43.030
only 256 megs of RAM.

00:53:43.030 --> 00:53:46.620
So there's this sort of a
series of compression,

00:53:46.620 --> 00:53:50.600
decompression to keep
everything--

00:53:50.600 --> 00:53:55.640
basically, think of RAM
as your L3 cache.

00:54:00.830 --> 00:54:03.090
So we look at what we want
to store on an SPU.

00:54:03.090 --> 00:54:06.140
Basically, the goal of this is
we want to get an entire

00:54:06.140 --> 00:54:10.570
animation for a particular
skeleton on an SPU so that we

00:54:10.570 --> 00:54:12.710
can transform the skeleton
and output the

00:54:12.710 --> 00:54:17.040
resulting joint data.

00:54:17.040 --> 00:54:19.690
So let's look at how big
that would have to be.

00:54:19.690 --> 00:54:22.580
So first we start with the basic
nine channels per joint.

00:54:22.580 --> 00:54:25.390
That's not assuming and again,
you'd probably have additional

00:54:25.390 --> 00:54:29.000
channels, like foot step
channels and sound channels

00:54:29.000 --> 00:54:30.660
and other sort of animation
channels to help

00:54:30.660 --> 00:54:32.000
actually make a game.

00:54:32.000 --> 00:54:33.810
In this case, we just want
to animate the character.

00:54:33.810 --> 00:54:37.550
So we have rotation times 3,
translations times 3, and

00:54:37.550 --> 00:54:39.960
scales times 3.

00:54:39.960 --> 00:54:44.590
So the first thing to drop and
this will cover, this will

00:54:44.590 --> 00:54:49.370
reduce your data by 70%, is
all the uniform channels.

00:54:49.370 --> 00:54:52.130
So any data that doesn't
actually change across the

00:54:52.130 --> 00:54:53.380
entire length of
the animation.

00:54:53.380 --> 00:54:56.110
It may not be zero, but it could
be just one thing, one

00:54:56.110 --> 00:54:57.232
value that doesn't
change across

00:54:57.232 --> 00:54:59.270
length of the animation.

00:54:59.270 --> 00:55:01.990
So you pull all the uniform
channels out.

00:55:01.990 --> 00:55:04.370
And most things that's going to
be scale, for example, most

00:55:04.370 --> 00:55:06.100
joints don't scale.

00:55:06.100 --> 00:55:08.580
Although occasionally they do.

00:55:08.580 --> 00:55:12.870
And translation, in a human our
joints don't translate.

00:55:12.870 --> 00:55:17.710
However, when you actually
animate a character in order

00:55:17.710 --> 00:55:19.830
to get particular effects, in
order to make it look more

00:55:19.830 --> 00:55:24.650
human you do end up needing
to translate joints.

00:55:24.650 --> 00:55:31.680
So we can reduce, but in order
to that we need to build a

00:55:31.680 --> 00:55:34.190
map, basically, a table of
these uniform channels.

00:55:34.190 --> 00:55:36.340
So now we know this table of
uniform channels has to be

00:55:36.340 --> 00:55:40.110
stored in the SPU along with
now the remaining actual

00:55:40.110 --> 00:55:41.620
animation data.

00:55:41.620 --> 00:55:44.880
Of course, multiplied by
the number of joints.

00:55:47.780 --> 00:55:49.670
So now we have what
is essentially

00:55:49.670 --> 00:55:52.520
raw animation data.

00:55:52.520 --> 00:55:55.130
So for the sake of argument,
let's say the animation data

00:55:55.130 --> 00:55:58.860
has been baked out by
Maya or whatever

00:55:58.860 --> 00:56:01.120
at 30 frames a second.

00:56:01.120 --> 00:56:04.990
We've pulled out the uniform
data, so now for the joints

00:56:04.990 --> 00:56:07.420
that do move we have these
curves over time of the entire

00:56:07.420 --> 00:56:08.780
length of the animation.

00:56:08.780 --> 00:56:13.620
The problem is if that animation
is 10 seconds long,

00:56:13.620 --> 00:56:18.540
it's now way too big to fit in
the SPU by a large margin.

00:56:18.540 --> 00:56:22.600
So how do we sort of compress
it down so that it

00:56:22.600 --> 00:56:24.410
actually will fit?

00:56:24.410 --> 00:56:27.630
Again, just first of all, the
easiest thing to do to start

00:56:27.630 --> 00:56:31.050
with is just do simple curve
fitting to get rid of the

00:56:31.050 --> 00:56:32.910
things that don't need to be
there that you can easily

00:56:32.910 --> 00:56:35.380
calculate out.

00:56:35.380 --> 00:56:37.310
And again, the closer that you
are to the root, the tighter

00:56:37.310 --> 00:56:38.400
that fits need to be.

00:56:38.400 --> 00:56:41.070
Conversely, the further away you
are from the root, you can

00:56:41.070 --> 00:56:44.460
loosen up the restrictions a
little bit and have a little

00:56:44.460 --> 00:56:46.640
bit looser fit on the
curve and compress

00:56:46.640 --> 00:56:47.890
a little bit more.

00:56:49.860 --> 00:56:52.760
So if you're doing a curve
fitting with the simple

00:56:52.760 --> 00:56:57.880
spline, basically you have to
store your time values in the

00:56:57.880 --> 00:57:00.290
places that were calculated.

00:57:00.290 --> 00:57:03.130
Part of the problem is now you
have sort of these individual

00:57:03.130 --> 00:57:05.970
scalars with time can be
randomly spread throughout the

00:57:05.970 --> 00:57:07.050
entire animation.

00:57:07.050 --> 00:57:09.260
So any point where there's
basically a knot in the curve,

00:57:09.260 --> 00:57:10.960
there's a time value.

00:57:10.960 --> 00:57:13.460
And none of these knots are
going to line up with each

00:57:13.460 --> 00:57:15.930
other in any of these
animation channels.

00:57:15.930 --> 00:57:18.350
So in principle, if you wanted
to code this you would have to

00:57:18.350 --> 00:57:23.520
basically say, what is time
right now and loop through

00:57:23.520 --> 00:57:26.440
each of these scalar values,
find out where time is,

00:57:26.440 --> 00:57:28.525
calculate the postition
on the curve and then

00:57:28.525 --> 00:57:31.930
spit out the result.

00:57:31.930 --> 00:57:37.030
So one, you still have to have
the unlimited length of data

00:57:37.030 --> 00:57:39.100
and two, you're looping through
scalar values on the

00:57:39.100 --> 00:57:42.740
SPU, which is really
actually, horrible.

00:57:42.740 --> 00:57:45.210
So we want to find a way
to solve that problem.

00:57:48.470 --> 00:57:49.855
Probably the most trivial
solution is

00:57:49.855 --> 00:57:51.690
just do spline segemnts.

00:57:51.690 --> 00:57:55.240
You lose some compressibility,
but it solves the problem.

00:57:55.240 --> 00:57:59.170
Basically you split up the
spline into say, sections of

00:57:59.170 --> 00:58:03.190
16 knots and you just do that.

00:58:03.190 --> 00:58:06.690
And in order to do that you just
need a table, you need to

00:58:06.690 --> 00:58:11.170
add a table that says what the
range of time are in each of

00:58:11.170 --> 00:58:15.620
those groups of 16 knots
for every channel.

00:58:15.620 --> 00:58:17.690
So when you're going to
transform the animation, first

00:58:17.690 --> 00:58:20.120
you load this table in, you say,
what's my time right now

00:58:20.120 --> 00:58:21.010
at time, t?

00:58:21.010 --> 00:58:24.000
You go and say which blocks,
which segments of the spline

00:58:24.000 --> 00:58:26.580
you need to load in for each
channel, you load those in.

00:58:26.580 --> 00:58:31.520
So now you have basically one
section of the spline, which

00:58:31.520 --> 00:58:35.400
is too big probably for the
current t, but it covers what

00:58:35.400 --> 00:58:36.510
t you're actually in.

00:58:36.510 --> 00:58:40.660
So one block of spline for
every single channel.

00:58:43.270 --> 00:58:46.520
So the advantage of this, now
that the spline is sorted into

00:58:46.520 --> 00:58:49.420
sections is that rather than
having all the spline data

00:58:49.420 --> 00:58:53.680
stored, sort of linearly, you
can now reorder the blocks so

00:58:53.680 --> 00:59:00.590
that the spline data from
different channels is actually

00:59:00.590 --> 00:59:01.780
tiled next to each other.

00:59:01.780 --> 00:59:03.900
So that when you actually go
to do a load it's much more

00:59:03.900 --> 00:59:07.380
likely because you know you're
going to be requesting all

00:59:07.380 --> 00:59:11.030
these channel at once and all
on the same time, t, you can

00:59:11.030 --> 00:59:15.470
find a more or less, optimal
ordering that will allow more

00:59:15.470 --> 00:59:17.630
of these group things to be
grouped in the same cache or

00:59:17.630 --> 00:59:19.620
at least the same page.

00:59:23.500 --> 00:59:26.840
And the advantage of course
again, is now the length of

00:59:26.840 --> 00:59:29.830
animation makes absolutely
no difference at all.

00:59:29.830 --> 00:59:31.790
The disadvantage is its less
compressible because you can

00:59:31.790 --> 00:59:36.920
only basically compress this one
section of the curve, but

00:59:36.920 --> 00:59:40.820
a huge advantage is it solves
the scalar loop problem.

00:59:40.820 --> 00:59:46.240
So now you can take four of
these scalar values all with a

00:59:46.240 --> 00:59:50.560
fixed known number of knots in
it and just loop through all

00:59:50.560 --> 00:59:53.070
of the knots.

00:59:53.070 --> 00:59:55.240
In principle you could search
through and find a minimum

00:59:55.240 --> 00:59:57.190
number of knots to look through
for each one of the

00:59:57.190 --> 00:59:59.330
scalars, but in practice it's
much faster just to loop

00:59:59.330 --> 01:00:03.190
through all four simultaneously
for all 16

01:00:03.190 --> 01:00:07.150
knots and just throw away the
results that are invalid as

01:00:07.150 --> 01:00:08.590
you're going through it.

01:00:08.590 --> 01:00:11.220
That way you can use the
SPU instruction set.

01:00:11.220 --> 01:00:14.620
You can load quadwords, store
quadwords, and do everything

01:00:14.620 --> 01:00:17.690
in the minimum single
loop, which you

01:00:17.690 --> 01:00:18.940
can completely unroll.

01:00:23.560 --> 01:00:26.785
Does anybody have the time?

01:00:26.785 --> 01:00:29.190
PROFESSOR: It's [OBSCURED]

01:00:29.190 --> 01:00:30.190
MIKE ACTON: So I'm OK.

01:00:30.190 --> 01:00:33.620
PROFESSOR: [OBSCURED]

01:00:33.620 --> 01:00:34.427
MIKE ACTON: Yeah?

01:00:34.427 --> 01:00:34.985
AUDIENCE: In

01:00:34.985 --> 01:00:38.550
context do you make like
rendering the animation or it

01:00:38.550 --> 01:00:40.860
seems like there would be a blow
to whatever you're doing

01:00:40.860 --> 01:00:42.170
on the SPUs.

01:00:42.170 --> 01:00:44.430
MIKE ACTON: Basically the SPUs
are taking this channel

01:00:44.430 --> 01:00:48.360
animation data and baking it
out into-- well, in the

01:00:48.360 --> 01:00:50.530
easiest case baking
it out into a 4 by

01:00:50.530 --> 01:00:54.090
4 matrix per joint.

01:00:54.090 --> 01:00:56.010
AUDIENCE: So the output
time's much bigger

01:00:56.010 --> 01:00:56.810
than the input time?

01:00:56.810 --> 01:00:59.570
I mean, you're compressing
the input by animation?

01:00:59.570 --> 01:01:01.620
MIKE ACTON: No, the output size
is significant, but it's

01:01:01.620 --> 01:01:03.586
much smaller.

01:01:03.586 --> 01:01:05.700
PROFESSOR: [OBSCURED]

01:01:05.700 --> 01:01:08.160
AUDIENCE: So the animation
data it's [OBSCURED]

01:01:08.160 --> 01:01:09.410
[INTERPOSING VOICES]

01:01:11.470 --> 01:01:12.460
MIKE ACTON: No.

01:01:12.460 --> 01:01:14.700
I was just outputting the
joint information.

01:01:14.700 --> 01:01:19.820
PROFESSOR: [OBSCURED]

01:01:19.820 --> 01:01:22.120
MIKE ACTON: Independently we
have this skimming problem.

01:01:22.120 --> 01:01:24.250
Independently there's
a rendering problem.

01:01:24.250 --> 01:01:26.250
This is just baking animation.

01:01:26.250 --> 01:01:28.050
This is purely animation
channel problem.

01:01:28.050 --> 01:01:33.060
PROFESSOR: [OBSCURED]

01:01:33.060 --> 01:01:34.910
MIKE ACTON: OK, I'm just going
to skip through this because

01:01:34.910 --> 01:01:36.860
this could take a long
time to talk about.

01:01:36.860 --> 01:01:39.560
Basically, what I wanted to say
here was let's take the

01:01:39.560 --> 01:01:40.955
next step with animation,
let's add

01:01:40.955 --> 01:01:43.050
some dynamic support.

01:01:43.050 --> 01:01:47.080
The easiest thing to do is just
create a second uniform

01:01:47.080 --> 01:01:50.380
data table that you then
blend with the first

01:01:50.380 --> 01:01:51.510
one and that one.

01:01:51.510 --> 01:01:55.450
In principle, is basically all
of the channels and then now a

01:01:55.450 --> 01:01:56.440
game play programmer can go and

01:01:56.440 --> 01:01:57.990
individually set any of those.

01:01:57.990 --> 01:02:00.750
So they can tweak the head or
tweak the elbow or whatever.

01:02:00.750 --> 01:02:02.080
And that's definitely
compressible because it's very

01:02:02.080 --> 01:02:05.170
unlikely thet're going to be
moving all the joints at once.

01:02:05.170 --> 01:02:08.050
You can create a secondary map
that says, this is the number

01:02:08.050 --> 01:02:11.450
of joints that are dynamic, this
is how they map to the

01:02:11.450 --> 01:02:12.700
uniform values.

01:02:15.350 --> 01:02:18.897
But then once you add any kind
of dynamic support, you have

01:02:18.897 --> 01:02:21.760
now complicated the problem
significantly.

01:02:21.760 --> 01:02:25.690
Because now in reality, what
you need are constraints.

01:02:25.690 --> 01:02:29.650
You need to be able to have a
limit to how high the head can

01:02:29.650 --> 01:02:31.900
move because what's going to
happen is although you could

01:02:31.900 --> 01:02:35.850
just say the head could only
move so much, if that movement

01:02:35.850 --> 01:02:37.380
is algorithmic, so let's
say follow a

01:02:37.380 --> 01:02:39.570
character or whatever--

01:02:39.570 --> 01:02:41.760
it is going to go outside
of reasonable

01:02:41.760 --> 01:02:42.930
constraints really quickly.

01:02:42.930 --> 01:02:48.360
So it's much cleaner and simpler
to support that on the

01:02:48.360 --> 01:02:50.250
engine side, so basically define
constraints for the

01:02:50.250 --> 01:02:57.250
joints and then let the
high-level code point

01:02:57.250 --> 01:02:58.060
wherever they want.

01:02:58.060 --> 01:02:58.500
AUDIENCE: [OBSCURED]

01:02:58.500 --> 01:03:00.330
MIKE ACTON: Yeah.

01:03:00.330 --> 01:03:03.090
Yeah, you can have max change
over time so it only can move

01:03:03.090 --> 01:03:08.080
so fast. The max range of
motion, the max acceleration

01:03:08.080 --> 01:03:11.770
is actually a much harder
problem because it implies

01:03:11.770 --> 01:03:15.780
that you need to store the
change over time, which we're

01:03:15.780 --> 01:03:17.360
not actually storing.

01:03:17.360 --> 01:03:20.440
Which would probably blow
our memory on the SPU.

01:03:20.440 --> 01:03:25.990
So as far as impacting
animation, I would immediately

01:03:25.990 --> 01:03:28.880
throw out max acceleration if an
animator were to come to me

01:03:28.880 --> 01:03:32.020
and say, this is a feature
that I wanted.

01:03:32.020 --> 01:03:35.060
I would say, it's unlikely
because it's unlikely we can

01:03:35.060 --> 01:03:36.880
fit it on the SPU.

01:03:36.880 --> 01:03:41.400
Whereas, on the PC, it might
be a different story.

01:03:41.400 --> 01:03:42.800
And blending information,
how you blend

01:03:42.800 --> 01:03:44.050
these things together.

01:03:52.180 --> 01:03:52.700
What's that?

01:03:52.700 --> 01:03:56.040
AUDIENCE: [OBSCURED]

01:03:56.040 --> 01:03:57.290
MIKE ACTON: OK.

01:03:59.710 --> 01:04:03.840
So as far as mixing, there's
plenty of additional problems

01:04:03.840 --> 01:04:05.550
in mixing animation.

01:04:05.550 --> 01:04:08.270
Phase matching, so for example,
you have a running

01:04:08.270 --> 01:04:09.800
and a walk.

01:04:09.800 --> 01:04:12.355
Basically all that means is if
you were going to blend from a

01:04:12.355 --> 01:04:15.070
run to a walk you kind of want
to blend in basically the

01:04:15.070 --> 01:04:17.490
essentially same leg position.

01:04:17.490 --> 01:04:19.330
Because if you just blend from
the middle of an animation to

01:04:19.330 --> 01:04:21.760
the beginning of the animation,
it's unlikely the

01:04:21.760 --> 01:04:23.820
legs are going to match and for
the transition time you're

01:04:23.820 --> 01:04:25.940
going to see the scissoring
of the legs.

01:04:25.940 --> 01:04:29.700
Which you see that in plenty
of games, but especially in

01:04:29.700 --> 01:04:32.200
next generation, especially
as characters look more

01:04:32.200 --> 01:04:37.100
complicated they are expected
to act more complicated.

01:04:37.100 --> 01:04:42.390
Transitions handling either
programmatic transitions

01:04:42.390 --> 01:04:46.220
between animations, so we have
an animation that's standing

01:04:46.220 --> 01:04:49.165
and animation that's crouching
and with constraints, move

01:04:49.165 --> 01:04:52.790
them down; or artist
driven animated

01:04:52.790 --> 01:04:56.540
transitions and/or both.

01:04:56.540 --> 01:04:57.735
Translation matching
is actually

01:04:57.735 --> 01:04:58.820
an interesting problem.

01:04:58.820 --> 01:05:01.290
So you have an animation that's
running and you have an

01:05:01.290 --> 01:05:02.180
animation that's walking.

01:05:02.180 --> 01:05:04.170
They both translate obviously,
at different speeds,

01:05:04.170 --> 01:05:10.080
nonlinearly and you want to
slowly run down into a walk,

01:05:10.080 --> 01:05:13.940
but you have to match these sort
of nonlinear translations

01:05:13.940 --> 01:05:16.520
as his feet are stepping
onto the ground.

01:05:16.520 --> 01:05:18.690
Turns out to be a really
difficult problem to get

01:05:18.690 --> 01:05:22.520
perfectly right, especially if
you have eye key on the feet

01:05:22.520 --> 01:05:24.980
where he's walking on the ground
or maybe walking uphill

01:05:24.980 --> 01:05:28.010
or downhill and the translation
is being affected

01:05:28.010 --> 01:05:30.170
by the world.

01:05:30.170 --> 01:05:33.760
In a lot of cases you'll see
people pretty much just ignore

01:05:33.760 --> 01:05:36.970
this problem.

01:05:36.970 --> 01:05:38.950
But it is something to consider
going forward and

01:05:38.950 --> 01:05:41.860
this is something that we would
consider how to solve,

01:05:41.860 --> 01:05:46.970
regardless of whether or
not we could get it in.

01:05:46.970 --> 01:05:51.920
As far as actually rendering
the geometry goes, you now

01:05:51.920 --> 01:05:55.920
have your sort of matrices
of joints and you have--

01:05:59.510 --> 01:06:03.070
let's say you want to send those
to the GPU along with

01:06:03.070 --> 01:06:06.350
the geometry to skin
and render.

01:06:06.350 --> 01:06:08.230
Now the question is, do
you single or double

01:06:08.230 --> 01:06:10.280
buffer those joints?

01:06:10.280 --> 01:06:14.480
Because right now basically, the
GPU can be reading these

01:06:14.480 --> 01:06:16.320
joints in parallel
to when you're

01:06:16.320 --> 01:06:17.890
actually outputting them.

01:06:17.890 --> 01:06:20.495
So the traditional approach or
the easiest approach is just

01:06:20.495 --> 01:06:21.850
to double buffer the joints.

01:06:21.850 --> 01:06:23.880
So just output into a different
buffer that the R6

01:06:23.880 --> 01:06:24.650
is reading from.

01:06:24.650 --> 01:06:29.070
It's one frame or half a frame
behind, doesn't much matter.

01:06:29.070 --> 01:06:33.080
But it also doubles now the
space of your joints.

01:06:33.080 --> 01:06:36.740
One advantage that games have
is that a frame is a well

01:06:36.740 --> 01:06:39.900
defined element in the games.

01:06:39.900 --> 01:06:43.810
We know what needs to happen
across the course of a frame.

01:06:43.810 --> 01:06:48.735
So these characters need to be
rendered, the collisions of

01:06:48.735 --> 01:06:49.690
this background needs
to happen, physics

01:06:49.690 --> 01:06:51.480
need to happen here.

01:06:51.480 --> 01:06:56.500
So you can within a frame, set
it up so that the update from

01:06:56.500 --> 01:07:03.350
the SPUs and the read from the
GPU can never overlap.

01:07:03.350 --> 01:07:07.970
Even without any kind of
synchronization or lock, it

01:07:07.970 --> 01:07:10.450
can be a well known fact that
it's impossible for these two

01:07:10.450 --> 01:07:12.230
things because there's actually
something in the

01:07:12.230 --> 01:07:15.770
middle happening that has its
own synchronization primitive.

01:07:18.370 --> 01:07:21.370
That will allow you to do single
buffering of the data.

01:07:21.370 --> 01:07:23.220
But it does require
more organization.

01:07:23.220 --> 01:07:26.190
Especially if you're doing it
on more than just one case.

01:07:26.190 --> 01:07:28.520
So you have all these things
that you want single buffered,

01:07:28.520 --> 01:07:31.360
so you need to organize them
within the frames so they're

01:07:31.360 --> 01:07:33.520
never updating and reading
at the same time.

01:07:38.910 --> 01:07:42.850
So I'll make this the last
point I'll make.

01:07:42.850 --> 01:07:46.640
Optimization, one of the things
that you'll hear, save

01:07:46.640 --> 01:07:47.980
optimization till the end.

01:07:47.980 --> 01:07:50.490
My point here being is if you
save optimization till the

01:07:50.490 --> 01:07:52.800
end, you don't know how to
do it because you haven't

01:07:52.800 --> 01:07:53.970
actually practiced it.

01:07:53.970 --> 01:07:57.750
If you haven't practiced it
you don't know what to do.

01:07:57.750 --> 01:07:59.100
So it will take much longer.

01:07:59.100 --> 01:08:01.090
You should always be optimizing
in order to

01:08:01.090 --> 01:08:05.500
understand, when it actually
counts, what to do.

01:08:05.500 --> 01:08:08.655
And the fact that real
optimization does impact the

01:08:08.655 --> 01:08:10.420
design all the way up.

01:08:10.420 --> 01:08:13.400
Optimization of the hardware
impacts how an engine is

01:08:13.400 --> 01:08:17.550
designed to be fast does impact
the data, it impacts

01:08:17.550 --> 01:08:21.263
how game play needs to be
written, high-level code needs

01:08:21.263 --> 01:08:23.400
to be called.

01:08:23.400 --> 01:08:26.060
So if you save optimization till
last, what you're doing

01:08:26.060 --> 01:08:30.310
is completely limiting what
you can optimize.

01:08:30.310 --> 01:08:33.010
And the idea that it's the root
of all evil certainly

01:08:33.010 --> 01:08:36.580
didn't come from a game
developer, I have to say.

01:08:36.580 --> 01:08:37.940
Anyway, that's it.

01:08:37.940 --> 01:08:39.690
I hope that was helpful.

01:08:44.800 --> 01:08:46.700
PROFESSOR: Any questions?

01:08:46.700 --> 01:08:49.005
I think it's very interesting
because there is a lot of

01:08:49.005 --> 01:08:50.255
things you learn at MIT.

01:08:57.950 --> 01:09:00.530
Forget everything you learned
so I think there's a very

01:09:00.530 --> 01:09:03.440
interesting perspective in there
and for some of us it's

01:09:03.440 --> 01:09:06.990
kind of hard to even digest a
little bit, but Question?

01:09:06.990 --> 01:09:09.540
AUDIENCE: Call of Duty 3 came
out on the Xbox and on the

01:09:09.540 --> 01:09:15.180
PS3, is Call of Duty 3 on the
PS3 just running on the GPU

01:09:15.180 --> 01:09:16.580
then or is it--

01:09:16.580 --> 01:09:18.420
MIKE ACTON: No, it's very
likely using the SPUs.

01:09:18.420 --> 01:09:19.050
I mean, I don't know.

01:09:19.050 --> 01:09:20.950
I haven't looked at the source
code, but I suspect that it's

01:09:20.950 --> 01:09:22.550
using the SPUs.

01:09:22.550 --> 01:09:24.200
How efficiently it's
using them is an

01:09:24.200 --> 01:09:26.150
entirely different question.

01:09:26.150 --> 01:09:31.280
But it's easy to take the most
trivial things right, say you

01:09:31.280 --> 01:09:37.140
do hot spot analysis on your
sequential code and say, OK,

01:09:37.140 --> 01:09:39.120
well I can grab this section of
thing and put it on the SPU

01:09:39.120 --> 01:09:41.970
right and just the heaviest
hitters and

01:09:41.970 --> 01:09:42.910
put them on the SPU.

01:09:42.910 --> 01:09:44.590
That's pretty easy to do.

01:09:44.590 --> 01:09:47.230
It's taking it to the next level
though, and to really

01:09:47.230 --> 01:09:51.820
have sort of the next
gen of game--

01:09:51.820 --> 01:09:54.260
now there's nowhere
to go from there.

01:09:54.260 --> 01:09:56.250
There's nowhere to go from that
analysis, you've already

01:09:56.250 --> 01:09:58.460
sort of hit the limit of what
you can do with that.

01:09:58.460 --> 01:10:00.970
It has to be redesigned.

01:10:00.970 --> 01:10:03.970
So I don't know what they're
doing honestly and certainly

01:10:03.970 --> 01:10:05.290
I'm being recorded so--

01:10:08.470 --> 01:10:09.940
yeah?

01:10:09.940 --> 01:10:14.390
AUDIENCE: You guys have shipped
a game, on the PS3?

01:10:14.390 --> 01:10:16.080
MIKE ACTON: Yeah, it
was on action list.

01:10:16.080 --> 01:10:18.480
AUDIENCE: OK, so that was
more like the [OBSCURED]

01:10:18.480 --> 01:10:23.890
games and whatever You seem to
talk a lot about all these

01:10:23.890 --> 01:10:24.586
things you've had to redo.

01:10:24.586 --> 01:10:26.940
What else is there--

01:10:26.940 --> 01:10:30.220
games look better as a console
was built on, what else is

01:10:30.220 --> 01:10:34.300
there that you guys plan on
changing as far as working

01:10:34.300 --> 01:10:36.530
with the cell processor,
or do you think

01:10:36.530 --> 01:10:37.950
you've got it all ready?

01:10:37.950 --> 01:10:38.450
MIKE ACTON: Oh, no.

01:10:38.450 --> 01:10:40.110
There's plenty of work.

01:10:40.110 --> 01:10:42.180
There's plenty more
to be optimized.

01:10:42.180 --> 01:10:45.330
It's down to cost in scheduling
those things.

01:10:45.330 --> 01:10:47.170
I mean, we have a team of
people who now really

01:10:47.170 --> 01:10:52.420
understand the platform and
whereas a lot of what went

01:10:52.420 --> 01:10:58.120
into previous titles was mixed
with learning curve.

01:10:58.120 --> 01:11:01.053
So there's definitely a
potential for going back and

01:11:01.053 --> 01:11:03.990
improving things and making
things better.

01:11:03.990 --> 01:11:07.060
That's what a cycle of game
development is all about.

01:11:07.060 --> 01:11:09.580
I mean, games at the end of the
lifetime of PlayStation 3

01:11:09.580 --> 01:11:11.970
will look significantly better
than release titles.

01:11:11.970 --> 01:11:13.710
That's the way it always is.

01:11:13.710 --> 01:11:17.120
AUDIENCE: The head of Sony
computer and gaming said that

01:11:17.120 --> 01:11:18.970
PS3 pretty soon would
be customizable.

01:11:18.970 --> 01:11:20.460
You're be able to get different

01:11:20.460 --> 01:11:21.800
amounts of RAM and whatnot.

01:11:21.800 --> 01:11:24.330
MIKE ACTON: Well, I think in
that case he was talking

01:11:24.330 --> 01:11:30.320
specifically about a PS3 based,
like Tivo kind of weird

01:11:30.320 --> 01:11:34.318
media thing, which has nothing
to do with us.

01:11:34.318 --> 01:11:36.730
AUDIENCE: [OBSCURED]

01:11:36.730 --> 01:11:37.510
MIKE ACTON: We're not stuck.

01:11:37.510 --> 01:11:40.250
That's what we have. I mean,
I don't see it as stuck.

01:11:40.250 --> 01:11:41.810
I would much rather have the--

01:11:41.810 --> 01:11:45.150
I mean, that's what console
development is about, really.

01:11:45.150 --> 01:11:48.530
We have a machine, we have a set
of limitations of it and

01:11:48.530 --> 01:11:51.080
we can push that machine over
the lifetime of the platform.

01:11:51.080 --> 01:11:53.830
If it changes out from under us,
it becomes PC development.

01:11:53.830 --> 01:11:54.820
AUDIENCE: Are you allowed
to use the

01:11:54.820 --> 01:11:57.380
seven SPUs or are you--

01:11:57.380 --> 01:11:57.690
[OBSCURED]

01:11:57.690 --> 01:12:09.020
PROFESSOR: [OBSCURED]

01:12:09.020 --> 01:12:13.220
MIKE ACTON: I don't know how
much I can answer this just

01:12:13.220 --> 01:12:14.030
from NDA point-of-view.

01:12:14.030 --> 01:12:17.180
But let's say hypothetically,
there magically became more

01:12:17.180 --> 01:12:19.640
SPUs on the PS3, right?

01:12:19.640 --> 01:12:20.920
Probably nothing would happen.

01:12:20.920 --> 01:12:24.620
The game has to be optimized
for the minimum case, so

01:12:24.620 --> 01:12:25.870
nothing would change.

01:12:29.132 --> 01:12:31.750
Anything else?

01:12:31.750 --> 01:12:32.640
Yeah?

01:12:32.640 --> 01:12:35.130
AUDIENCE: So what's the
development life cycle like

01:12:35.130 --> 01:12:37.010
for the engine part
of the game.

01:12:37.010 --> 01:12:42.006
And I don't assume you start by
prototyping in higher-level

01:12:42.006 --> 01:12:45.910
mechanisms. Then you'll
completely miss the design for

01:12:45.910 --> 01:12:47.500
performance aspects of it.

01:12:47.500 --> 01:12:54.140
How do you build up from
empty [OBSCURED]

01:12:54.140 --> 01:12:55.610
MIKE ACTON: No, you don't
start with an empty.

01:12:55.610 --> 01:12:57.300
That's the perspective
difference.

01:12:57.300 --> 01:12:59.620
You don't start with code,
code's not important.

01:12:59.620 --> 01:13:00.700
Start with the data.

01:13:00.700 --> 01:13:02.130
You sit down with an artist
and they say, what

01:13:02.130 --> 01:13:04.150
do you want to do?

01:13:04.150 --> 01:13:05.140
And then you look at the data.

01:13:05.140 --> 01:13:06.450
What does that data look like?

01:13:06.450 --> 01:13:07.530
What does this animation
data look like?

01:13:07.530 --> 01:13:09.730
PROFESSOR: Data size matters.

01:13:09.730 --> 01:13:12.960
[OBSCURED]

01:13:12.960 --> 01:13:13.080
MIKE ACTON: Right.

01:13:13.080 --> 01:13:15.080
We have to figure out how
to make it smaller.

01:13:15.080 --> 01:13:16.640
But it all starts
with the data.

01:13:16.640 --> 01:13:19.940
It all starts with that concept
of what do we want to

01:13:19.940 --> 01:13:20.330
see on the screen?

01:13:20.330 --> 01:13:21.820
What do we even want to
hear on the speakers?

01:13:21.820 --> 01:13:23.580
What kind of effects
do we want.

01:13:23.580 --> 01:13:28.430
And actually look at that from
the perspective of the content

01:13:28.430 --> 01:13:31.490
creator and what they're
generating and what we can do

01:13:31.490 --> 01:13:32.550
with that data.

01:13:32.550 --> 01:13:36.440
Because game development is just
this black box between

01:13:36.440 --> 01:13:39.150
the artists and the screen.

01:13:39.150 --> 01:13:41.490
We're providing a transformation
engine that

01:13:41.490 --> 01:13:44.570
takes the vision of the
designers and the artists and

01:13:44.570 --> 01:13:48.810
just transforming it and
spitting it on to screen.

01:13:48.810 --> 01:13:51.340
So where you really need
to start is with the

01:13:51.340 --> 01:13:53.380
source of the data.

01:13:53.380 --> 01:13:55.040
AUDIENCE: You've been doing game
developoment for 11 years

01:13:55.040 --> 01:13:56.330
now is what you said.

01:13:56.330 --> 01:13:57.660
Have you had a favorite
platform

01:13:57.660 --> 01:14:00.050
and a nightmare platform?

01:14:00.050 --> 01:14:01.740
MIKE ACTON: I've been pretty
much with the PlayStation

01:14:01.740 --> 01:14:07.920
platform since there was a
PlayStation platform and I

01:14:07.920 --> 01:14:09.660
don't know, it's hard to get
perspective because you're

01:14:09.660 --> 01:14:12.610
getting it and you always really
love plarform you're

01:14:12.610 --> 01:14:15.030
working on.

01:14:15.030 --> 01:14:17.800
So it's hard.

01:14:17.800 --> 01:14:20.630
I mean, it's hard to
get perspective.

01:14:20.630 --> 01:14:22.357
In the program where I am today
is not the same program

01:14:22.357 --> 01:14:25.640
where I was 10 years ago.

01:14:25.640 --> 01:14:27.745
Personally, right now my
favorite plarform is PS3.

01:14:27.745 --> 01:14:30.770
PROFESSOR: So when put it in
perspective, there are already

01:14:30.770 --> 01:14:37.190
some platforms that on the first
time round, [COUGHING],

01:14:37.190 --> 01:14:39.360
it's like cost of development.

01:14:39.360 --> 01:14:44.990
So one platform that as time
goes we have [OBSCURED]

01:14:44.990 --> 01:14:47.380
MIKE ACTON: Well, like with the
PS3, some of the things

01:14:47.380 --> 01:14:48.920
that I like about the PS3, which
is sort of a different

01:14:48.920 --> 01:14:53.450
question are the fact that the
cell is much more public than

01:14:53.450 --> 01:14:55.790
any other platform
has ever been.

01:14:55.790 --> 01:14:58.990
With IBM's documentation, with
Toshiba's support and Sony

01:14:58.990 --> 01:15:05.200
support, I've never had a
platform where I can get up on

01:15:05.200 --> 01:15:09.210
a website and actually talk
about it outside of NDA.

01:15:09.210 --> 01:15:10.980
And that for me is an
amazing change.

01:15:10.980 --> 01:15:13.710
Where I can go and talk to other
people-- exactly like

01:15:13.710 --> 01:15:15.610
this group here- that have
used the same exact

01:15:15.610 --> 01:15:17.530
platform I've used.

01:15:17.530 --> 01:15:21.280
That's never been able
to happen before.

01:15:21.280 --> 01:15:24.380
Even on PS2, for quite a long
part of the lifespan, even

01:15:24.380 --> 01:15:27.370
though there was a Linux
eventually on the PS2,

01:15:27.370 --> 01:15:29.210
virtually everything was covered
by NDA because there

01:15:29.210 --> 01:15:32.830
was no independent release
of information.

01:15:32.830 --> 01:15:38.270
So that's one of the great
things about PS3 is the public

01:15:38.270 --> 01:15:39.520
availability of cell.

01:15:43.510 --> 01:15:46.304
PROFESSOR: Thank you very much
for coming all the way from

01:15:46.304 --> 01:15:48.230
California and giving
us some insight.