1 #include "n64video.h"
2 #include "common.h"
3 #include "msg.h"
4 #include "vdac.h"
5 #include "parallel_al.h"
6
7 #include <memory.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11
12 #ifdef HAVE_RDP_DUMP
13 #include "rdp_dump.h"
14 #endif
15
16 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
17 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
18 #define CLAMP(x, lo, hi) (((x) > (hi)) ? (hi) : (((x) < (lo)) ? (lo) : (x)))
19
20 #define SIGN16(x) ((int16_t)(x))
21 #define SIGN8(x) ((int8_t)(x))
22
23 #define SIGN(x, numb) (((x) & ((1 << (numb)) - 1)) | -((x) & (1 << ((numb) - 1))))
24 #define SIGNF(x, numb) ((x) | -((x) & (1 << ((numb) - 1))))
25
26 #define TRELATIVE(x, y) ((x) - ((y) << 3))
27
28 #define PIXELS_TO_BYTES(pix, siz) (((pix) << (siz)) >> 1)
29
30 // RGBA5551 to RGBA8888 helper
31 #define RGBA16_R(x) (((x) >> 8) & 0xf8)
32 #define RGBA16_G(x) (((x) & 0x7c0) >> 3)
33 #define RGBA16_B(x) (((x) & 0x3e) << 2)
34
35 // RGBA8888 helper
36 #define RGBA32_R(x) (((x) >> 24) & 0xff)
37 #define RGBA32_G(x) (((x) >> 16) & 0xff)
38 #define RGBA32_B(x) (((x) >> 8) & 0xff)
39 #define RGBA32_A(x) ((x) & 0xff)
40
41 // maximum number of commands to buffer for parallel processing
42 #define CMD_BUFFER_SIZE 1024
43
44 // maximum data size of a single command in bytes
45 #define CMD_MAX_SIZE 176
46
47 // maximum data size of a single command in 32 bit integers
48 #define CMD_MAX_INTS (CMD_MAX_SIZE / sizeof(int32_t))
49
50 // extracts the command ID from a command buffer
51 #define CMD_ID(cmd) ((*(cmd) >> 24) & 0x3f)
52
53 // list of command IDs
54 #define CMD_ID_NO_OP 0x00
55 #define CMD_ID_FILL_TRIANGLE 0x08
56 #define CMD_ID_FILL_ZBUFFER_TRIANGLE 0x09
57 #define CMD_ID_TEXTURE_TRIANGLE 0x0a
58 #define CMD_ID_TEXTURE_ZBUFFER_TRIANGLE 0x0b
59 #define CMD_ID_SHADE_TRIANGLE 0x0c
60 #define CMD_ID_SHADE_ZBUFFER_TRIANGLE 0x0d
61 #define CMD_ID_SHADE_TEXTURE_TRIANGLE 0x0e
62 #define CMD_ID_SHADE_TEXTURE_Z_BUFFER_TRIANGLE 0x0f
63 #define CMD_ID_TEXTURE_RECTANGLE 0x24
64 #define CMD_ID_TEXTURE_RECTANGLE_FLIP 0x25
65 #define CMD_ID_SYNC_LOAD 0x26
66 #define CMD_ID_SYNC_PIPE 0x27
67 #define CMD_ID_SYNC_TILE 0x28
68 #define CMD_ID_SYNC_FULL 0x29
69 #define CMD_ID_SET_KEY_GB 0x2a
70 #define CMD_ID_SET_KEY_R 0x2b
71 #define CMD_ID_SET_CONVERT 0x2c
72 #define CMD_ID_SET_SCISSOR 0x2d
73 #define CMD_ID_SET_PRIM_DEPTH 0x2e
74 #define CMD_ID_SET_OTHER_MODES 0x2f
75 #define CMD_ID_LOAD_TLUT 0x30
76 #define CMD_ID_SET_TILE_SIZE 0x32
77 #define CMD_ID_LOAD_BLOCK 0x33
78 #define CMD_ID_LOAD_TILE 0x34
79 #define CMD_ID_SET_TILE 0x35
80 #define CMD_ID_FILL_RECTANGLE 0x36
81 #define CMD_ID_SET_FILL_COLOR 0x37
82 #define CMD_ID_SET_FOG_COLOR 0x38
83 #define CMD_ID_SET_BLEND_COLOR 0x39
84 #define CMD_ID_SET_PRIM_COLOR 0x3a
85 #define CMD_ID_SET_ENV_COLOR 0x3b
86 #define CMD_ID_SET_COMBINE 0x3c
87 #define CMD_ID_SET_TEXTURE_IMAGE 0x3d
88 #define CMD_ID_SET_MASK_IMAGE 0x3e
89 #define CMD_ID_SET_COLOR_IMAGE 0x3f
90
91 static struct n64video_config config;
92
93 static struct
94 {
95 bool fillmbitcrashes, vbusclock, nolerp;
96 } onetimewarnings;
97
98 static int rdp_pipeline_crashed = 0;
99
clamp(int32_t value,int32_t min,int32_t max)100 static STRICTINLINE int32_t clamp(int32_t value, int32_t min, int32_t max)
101 {
102 if (value < min)
103 return min;
104 else if (value > max)
105 return max;
106 return value;
107 }
108
irand(uint32_t * state)109 static STRICTINLINE uint32_t irand(uint32_t* state)
110 {
111 *state = *state * 0x343fd + 0x269ec3;
112 return ((*state >> 16) & 0x7fff);
113 }
114
115 #include "n64video/rdp.c"
116 #include "n64video/vi.c"
117
118 static uint32_t rdp_cmd_buf[CMD_BUFFER_SIZE][CMD_MAX_INTS];
119 static uint32_t rdp_cmd_buf_pos;
120
121 static uint32_t rdp_cmd_pos;
122 static uint32_t rdp_cmd_id;
123 static uint32_t rdp_cmd_len;
124
125 // table of commands that require thread synchronization in
126 // multithreaded mode
127 static bool rdp_cmd_sync[64];
128
cmd_run_buffered(uint32_t worker_id)129 static void cmd_run_buffered(uint32_t worker_id)
130 {
131 uint32_t pos;
132 for (pos = 0; pos < rdp_cmd_buf_pos; pos++)
133 rdp_cmd(worker_id, rdp_cmd_buf[pos]);
134 }
135
cmd_flush(void)136 static void cmd_flush(void)
137 {
138 // only run if there's something buffered
139 if (rdp_cmd_buf_pos) {
140 // let workers run all buffered commands in parallel
141 parallel_run(cmd_run_buffered);
142 // reset buffer by starting from the beginning
143 rdp_cmd_buf_pos = 0;
144 }
145 }
146
cmd_init(void)147 static void cmd_init(void)
148 {
149 rdp_cmd_pos = 0;
150 rdp_cmd_id = 0;
151 rdp_cmd_len = CMD_MAX_INTS;
152 }
153
n64video_config_init(struct n64video_config * config)154 void n64video_config_init(struct n64video_config* config)
155 {
156 memset(config, 0, sizeof(*config));
157
158 // config defaults that aren't false or 0
159 config->parallel = true;
160 config->vi.vsync = true;
161 config->dp.compat = DP_COMPAT_MEDIUM;
162 }
163
rdp_init_worker(uint32_t worker_id)164 void rdp_init_worker(uint32_t worker_id)
165 {
166 rdp_init(worker_id, parallel_num_workers());
167 }
168
169 #ifdef HAVE_RDP_DUMP
170 static bool rdp_dump_in_command_list;
171 #endif
172
n64video_init(struct n64video_config * _config)173 void n64video_init(struct n64video_config* _config)
174 {
175 if (_config)
176 config = *_config;
177
178 // initialize static lookup tables and RDP state, once is enough
179 static bool static_init;
180 if (!static_init)
181 {
182 blender_init_lut();
183 coverage_init_lut();
184 combiner_init_lut();
185 tex_init_lut();
186 z_init_lut();
187
188 fb_init(0);
189 combiner_init(0);
190 tex_init(0);
191 rasterizer_init(0);
192
193 static_init = true;
194 }
195
196 #ifdef HAVE_RDP_DUMP
197 const char *rdp_dump_path = getenv("RDP_DUMP");
198 if (rdp_dump_path)
199 {
200 rdp_dump_init(rdp_dump_path, config.gfx.rdram_size, sizeof(rdram_hidden));
201 // Force no MT when dumping for sanity.
202 config.parallel = false;
203 }
204 rdp_dump_in_command_list = false;
205 #endif
206
207 // enable sync switches depending on compatibility mode
208 memset(rdp_cmd_sync, 0, sizeof(rdp_cmd_sync));
209 switch (config.dp.compat) {
210 case DP_COMPAT_HIGH:
211 rdp_cmd_sync[CMD_ID_SET_TEXTURE_IMAGE] = true;
212 case DP_COMPAT_MEDIUM:
213 rdp_cmd_sync[CMD_ID_SET_MASK_IMAGE] = true;
214 rdp_cmd_sync[CMD_ID_SET_COLOR_IMAGE] = true;
215 case DP_COMPAT_LOW:
216 rdp_cmd_sync[CMD_ID_SYNC_FULL] = true;
217 }
218
219 // init internals
220 rdram_init();
221 vi_init();
222 cmd_init();
223
224 rdp_pipeline_crashed = 0;
225 memset(&onetimewarnings, 0, sizeof(onetimewarnings));
226
227 if (config.parallel)
228 {
229 uint32_t i;
230 // init worker system
231 parallel_alinit(config.num_workers);
232
233 // sync states from main worker
234 for (i = 1; i < parallel_num_workers(); i++)
235 memcpy(&state[i], &state[0], sizeof(struct rdp_state));
236
237 // init workers
238 parallel_run(rdp_init_worker);
239 }
240 else
241 rdp_init(0, 1);
242 }
243
n64video_process_list(void)244 void n64video_process_list(void)
245 {
246 uint32_t** dp_reg = config.gfx.dp_reg;
247 uint32_t dp_current_al = (*dp_reg[DP_CURRENT] & ~7) >> 2;
248 uint32_t dp_end_al = (*dp_reg[DP_END] & ~7) >> 2;
249
250 // don't do anything if the RDP has crashed or the registers are not set up correctly
251 if (rdp_pipeline_crashed || dp_end_al <= dp_current_al) {
252 return;
253 }
254
255 // while there's data in the command buffer...
256 while (dp_end_al - dp_current_al > 0) {
257 uint32_t i, toload;
258 bool xbus_dma = (*dp_reg[DP_STATUS] & DP_STATUS_XBUS_DMA) != 0;
259 uint32_t* dmem = (uint32_t*)config.gfx.dmem;
260 uint32_t* cmd_buf = rdp_cmd_buf[rdp_cmd_buf_pos];
261
262 // when reading the first int, extract the command ID and update the buffer length
263 if (rdp_cmd_pos == 0) {
264 if (xbus_dma) {
265 cmd_buf[rdp_cmd_pos++] = dmem[dp_current_al++ & 0x3ff];
266 } else {
267 cmd_buf[rdp_cmd_pos++] = rdram_read_idx32(dp_current_al++);
268 }
269
270 rdp_cmd_id = CMD_ID(cmd_buf);
271 rdp_cmd_len = rdp_commands[rdp_cmd_id].length >> 2;
272 }
273
274 // copy more data from the N64 to the local command buffer
275 toload = MIN(dp_end_al - dp_current_al, rdp_cmd_len - 1);
276
277 if (xbus_dma) {
278 for (i = 0; i < toload; i++) {
279 cmd_buf[rdp_cmd_pos++] = dmem[dp_current_al++ & 0x3ff];
280 }
281 } else {
282 for (i = 0; i < toload; i++) {
283 cmd_buf[rdp_cmd_pos++] = rdram_read_idx32(dp_current_al++);
284 }
285 }
286
287 // if there's enough data for the current command...
288 if (rdp_cmd_pos == rdp_cmd_len) {
289
290 #ifdef HAVE_RDP_DUMP
291 if (!rdp_dump_in_command_list)
292 {
293 rdp_dump_flush_dram(config.gfx.rdram, config.gfx.rdram_size);
294 rdp_dump_flush_hidden_dram(rdram_hidden, sizeof(rdram_hidden));
295 rdp_dump_in_command_list = true;
296 }
297
298 if (rdp_cmd_id == CMD_ID_SYNC_FULL)
299 {
300 rdp_dump_signal_complete();
301 rdp_dump_in_command_list = false;
302 }
303 else
304 {
305 rdp_dump_emit_command(rdp_cmd_id, cmd_buf, rdp_cmd_len);
306 }
307 #endif
308
309 // check if parallel processing is enabled
310 if (config.parallel) {
311 // special case: sync_full always needs to be run in main thread
312 if (rdp_cmd_id == CMD_ID_SYNC_FULL) {
313 // first, run all pending commands
314 cmd_flush();
315
316 // parameters are unused, so NULL is fine
317 rdp_sync_full(0, NULL);
318 } else {
319 // increment buffer position
320 rdp_cmd_buf_pos++;
321
322 // flush buffer when it is full or when the current command requires a sync
323 if (rdp_cmd_buf_pos >= CMD_BUFFER_SIZE || rdp_cmd_sync[rdp_cmd_id]) {
324 cmd_flush();
325 }
326 }
327 } else {
328 // run command directly
329 rdp_cmd(0, cmd_buf);
330 }
331
332 // send Z-buffer address to VI for "depth" output mode
333 if (rdp_cmd_id == CMD_ID_SET_MASK_IMAGE) {
334 vi_set_zbuffer_address(cmd_buf[1] & 0x0ffffff);
335 }
336
337 // reset current command buffer to prepare for the next one
338 cmd_init();
339 }
340 }
341
342 // update DP registers to indicate that all bytes have been read
343 *dp_reg[DP_START] = *dp_reg[DP_CURRENT] = *dp_reg[DP_END];
344 }
345
n64video_close(void)346 void n64video_close(void)
347 {
348 #ifdef HAVE_RDP_DUMP
349 if (rdp_dump_in_command_list)
350 rdp_dump_in_command_list = false;
351 rdp_dump_end();
352 #endif
353
354 vi_close();
355 parallel_close();
356 }
357