d3616bdad823f7821e0ed429cdb402f81fecbb46
[pcsx_rearmed.git] / plugins / gpu_neon / psx_gpu / psx_gpu_parse.c
1 /*
2  * Copyright (C) 2011 Gilead Kutnick "Exophase" <exophase@gmail.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include <stdio.h>
16
17 #include "common.h"
18
19 #ifndef command_lengths
20 const u8 command_lengths[256] =
21 {
22         0,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // 00
23         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // 10
24         3,  3,  3,  3,  6,  6,  6,  6,  4,  4,  4,  4,  8,  8,  8,  8,   // 20
25         5,  5,  5,  5,  8,  8,  8,  8,  7,  7,  7,  7,  11, 11, 11, 11,  // 30
26         2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,   // 40
27         3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  4,  4,   // 50
28         2,  2,  2,  2,  3,  3,  3,  3,  1,  1,  1,  1,  0,  0,  0,  0,   // 60
29         1,  1,  1,  1,  2,  2,  2,  2,  1,  1,  1,  1,  2,  2,  2,  2,   // 70
30         3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // 80
31         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // 90
32         2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // a0
33         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // b0
34         2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // c0
35         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // d0
36         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   // e0
37         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0    // f0
38 };
39 #endif
40
41 void update_texture_ptr(psx_gpu_struct *psx_gpu)
42 {
43   u8 *texture_base;
44   u8 *texture_ptr;
45
46   switch((psx_gpu->render_state_base >> 8) & 0x3)
47   {
48     default:
49     case TEXTURE_MODE_4BPP:
50       texture_base = psx_gpu->texture_4bpp_cache[psx_gpu->current_texture_page];
51
52       texture_ptr = texture_base;
53       texture_ptr += psx_gpu->texture_window_x & 0xF;
54       texture_ptr += (psx_gpu->texture_window_y & 0xF) << 4;
55       texture_ptr += (psx_gpu->texture_window_x >> 4) << 8;
56       texture_ptr += (psx_gpu->texture_window_y >> 4) << 12;
57       break;
58
59     case TEXTURE_MODE_8BPP:
60       if(psx_gpu->current_texture_page & 0x1)
61       {
62         texture_base =
63          psx_gpu->texture_8bpp_odd_cache[psx_gpu->current_texture_page >> 1];
64       }
65       else
66       {
67         texture_base =
68          psx_gpu->texture_8bpp_even_cache[psx_gpu->current_texture_page >> 1];
69       }
70       
71       texture_ptr = texture_base;
72       texture_ptr += psx_gpu->texture_window_x & 0xF;
73       texture_ptr += (psx_gpu->texture_window_y & 0xF) << 4;
74       texture_ptr += (psx_gpu->texture_window_x >> 4) << 8;
75       texture_ptr += (psx_gpu->texture_window_y >> 4) << 12;
76       break;
77
78     case TEXTURE_MODE_16BPP:
79       texture_base = (u8 *)(psx_gpu->vram_ptr);
80       texture_base += (psx_gpu->current_texture_page & 0xF) * 128;
81       texture_base += ((psx_gpu->current_texture_page >> 4) * 256) * 2048;
82
83       texture_ptr = texture_base;
84       texture_ptr += psx_gpu->texture_window_x * 2;
85       texture_ptr += (psx_gpu->texture_window_y) * 2048;
86       break;
87   }
88
89   psx_gpu->texture_page_base = texture_base;
90   psx_gpu->texture_page_ptr = texture_ptr;  
91 }
92
93 void set_texture(psx_gpu_struct *psx_gpu, u32 texture_settings)
94 {
95   if(psx_gpu->texture_settings != texture_settings)
96   {
97     u32 new_texture_page = texture_settings & 0x1F;
98     u32 texture_mode = (texture_settings >> 7) & 0x3;
99     u32 render_state_base = psx_gpu->render_state_base;
100
101     flush_render_block_buffer(psx_gpu);
102
103     render_state_base &= ~(0xF << 6);
104     render_state_base |= ((texture_settings >> 5) & 0xF) << 6;
105
106     psx_gpu->render_state_base = render_state_base;
107
108     psx_gpu->current_texture_mask = 0x1 << new_texture_page;
109
110     if(texture_mode == TEXTURE_MODE_8BPP)
111     {     
112       // In 8bpp mode 256x256 takes up two pages. If it's on the right edge it
113       // wraps back around to the left edge.
114       u32 adjacent_texture_page = ((texture_settings + 1) & 0xF) | (texture_settings & 0x10);
115       psx_gpu->current_texture_mask |= 0x1 << adjacent_texture_page;
116
117       if((psx_gpu->last_8bpp_texture_page ^ new_texture_page) & 0x1)
118       {
119         u32 dirty_textures_8bpp_alternate_mask =
120          psx_gpu->dirty_textures_8bpp_alternate_mask;
121         psx_gpu->dirty_textures_8bpp_alternate_mask =
122          psx_gpu->dirty_textures_8bpp_mask;
123         psx_gpu->dirty_textures_8bpp_mask = dirty_textures_8bpp_alternate_mask;
124       }
125
126       psx_gpu->last_8bpp_texture_page = new_texture_page;
127     }
128
129     psx_gpu->current_texture_page = new_texture_page;
130     psx_gpu->texture_settings = texture_settings;
131
132     update_texture_ptr(psx_gpu);
133   }
134 }
135
136 void set_clut(psx_gpu_struct *psx_gpu, u32 clut_settings)
137 {
138   if(psx_gpu->clut_settings != clut_settings)
139   {
140     flush_render_block_buffer(psx_gpu);
141     psx_gpu->clut_settings = clut_settings;
142     psx_gpu->clut_ptr = psx_gpu->vram_ptr + ((clut_settings & 0x7FFF) * 16);
143   }
144 }
145
146 void set_triangle_color(psx_gpu_struct *psx_gpu, u32 triangle_color)
147 {
148   if(psx_gpu->triangle_color != triangle_color)
149   {
150     flush_render_block_buffer(psx_gpu);
151     psx_gpu->triangle_color = triangle_color;
152   }
153 }
154
155 static void do_fill(psx_gpu_struct *psx_gpu, u32 x, u32 y,
156  u32 width, u32 height, u32 color)
157 {
158   x &= ~0xF;
159   width = ((width + 0xF) & ~0xF);
160
161   flush_render_block_buffer(psx_gpu);
162
163   if(unlikely((x + width) > 1024))
164   {
165     u32 width_a = 1024 - x;
166     u32 width_b = width - width_a;
167
168     if(unlikely((y + height) > 512))
169     {
170       u32 height_a = 512 - y;
171       u32 height_b = height - height_a;
172
173       render_block_fill(psx_gpu, color, x, y, width_a, height_a);
174       render_block_fill(psx_gpu, color, 0, y, width_b, height_a);
175       render_block_fill(psx_gpu, color, x, 0, width_a, height_b);
176       render_block_fill(psx_gpu, color, 0, 0, width_b, height_b);
177     }
178     else
179     {
180       render_block_fill(psx_gpu, color, x, y, width_a, height);
181       render_block_fill(psx_gpu, color, 0, y, width_b, height);
182     }
183   }
184   else
185   {
186     if(unlikely((y + height) > 512))
187     {
188       u32 height_a = 512 - y;
189       u32 height_b = height - height_a;
190
191       render_block_fill(psx_gpu, color, x, y, width, height_a);
192       render_block_fill(psx_gpu, color, x, 0, width, height_b);
193     }
194     else
195     {
196       render_block_fill(psx_gpu, color, x, y, width, height);
197     }
198   }
199 }
200
201 #define sign_extend_12bit(value)                                               \
202   (((s32)((value) << 20)) >> 20)                                               \
203
204 #define sign_extend_11bit(value)                                               \
205   (((s32)((value) << 21)) >> 21)                                               \
206
207 #define sign_extend_10bit(value)                                               \
208   (((s32)((value) << 22)) >> 22)                                               \
209
210
211 #define get_vertex_data_xy(vertex_number, offset16)                            \
212   vertexes[vertex_number].x =                                                  \
213    sign_extend_12bit(list_s16[offset16]) + psx_gpu->offset_x;                  \
214   vertexes[vertex_number].y =                                                  \
215    sign_extend_12bit(list_s16[(offset16) + 1]) + psx_gpu->offset_y;            \
216
217 #define get_vertex_data_uv(vertex_number, offset16)                            \
218   vertexes[vertex_number].u = list_s16[offset16] & 0xFF;                       \
219   vertexes[vertex_number].v = (list_s16[offset16] >> 8) & 0xFF                 \
220
221 #define get_vertex_data_rgb(vertex_number, offset32)                           \
222   vertexes[vertex_number].r = list[offset32] & 0xFF;                           \
223   vertexes[vertex_number].g = (list[offset32] >> 8) & 0xFF;                    \
224   vertexes[vertex_number].b = (list[offset32] >> 16) & 0xFF                    \
225
226 #define get_vertex_data_xy_uv(vertex_number, offset16)                         \
227   get_vertex_data_xy(vertex_number, offset16);                                 \
228   get_vertex_data_uv(vertex_number, (offset16) + 2)                            \
229
230 #define get_vertex_data_xy_rgb(vertex_number, offset16)                        \
231   get_vertex_data_rgb(vertex_number, (offset16) / 2);                          \
232   get_vertex_data_xy(vertex_number, (offset16) + 2);                           \
233
234 #define get_vertex_data_xy_uv_rgb(vertex_number, offset16)                     \
235   get_vertex_data_rgb(vertex_number, (offset16) / 2);                          \
236   get_vertex_data_xy(vertex_number, (offset16) + 2);                           \
237   get_vertex_data_uv(vertex_number, (offset16) + 4);                           \
238
239 #define set_vertex_color_constant(vertex_number, color)                        \
240   vertexes[vertex_number].r = color & 0xFF;                                    \
241   vertexes[vertex_number].g = (color >> 8) & 0xFF;                             \
242   vertexes[vertex_number].b = (color >> 16) & 0xFF                             \
243
244 #define get_vertex_data_xy_rgb_constant(vertex_number, offset16, color)        \
245   get_vertex_data_xy(vertex_number, offset16);                                 \
246   set_vertex_color_constant(vertex_number, color)                              \
247
248 #ifndef SET_Ex
249 #define SET_Ex(r, v)
250 #endif
251
252 vertex_struct vertexes[4] __attribute__((aligned(32)));
253
254 u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
255 {
256   u32 current_command = 0, command_length;
257
258   u32 *list_start = list;
259   u32 *list_end = list + (size / 4);
260
261   for(; list < list_end; list += 1 + command_length)
262   {
263         s16 *list_s16 = (void *)list;
264         current_command = *list >> 24;
265         command_length = command_lengths[current_command];
266         if (list + 1 + command_length > list_end) {
267           current_command = (u32)-1;
268           break;
269         }
270
271         switch(current_command)
272         {
273                 case 0x00:
274                         break;
275   
276                 case 0x02:
277       {
278         u32 x = list_s16[2] & 0x3FF;
279         u32 y = list_s16[3] & 0x1FF;
280         u32 width = list_s16[4] & 0x3FF;
281         u32 height = list_s16[5] & 0x1FF;
282         u32 color = list[0] & 0xFFFFFF;
283
284         do_fill(psx_gpu, x, y, width, height, color);
285                         break;
286       }
287   
288                 case 0x20 ... 0x23:
289       {
290         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
291   
292         get_vertex_data_xy(0, 2);
293         get_vertex_data_xy(1, 4);
294         get_vertex_data_xy(2, 6);
295           
296         render_triangle(psx_gpu, vertexes, current_command);
297                         break;
298       }
299   
300                 case 0x24 ... 0x27:
301       {
302         set_clut(psx_gpu, list_s16[5]);
303         set_texture(psx_gpu, list_s16[9]);
304         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
305   
306         get_vertex_data_xy_uv(0, 2);
307         get_vertex_data_xy_uv(1, 6);
308         get_vertex_data_xy_uv(2, 10);
309   
310         render_triangle(psx_gpu, vertexes, current_command);
311                         break;
312       }
313   
314                 case 0x28 ... 0x2B:
315       {
316         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
317   
318         get_vertex_data_xy(0, 2);
319         get_vertex_data_xy(1, 4);
320         get_vertex_data_xy(2, 6);
321         get_vertex_data_xy(3, 8);
322   
323         render_triangle(psx_gpu, vertexes, current_command);
324         render_triangle(psx_gpu, &(vertexes[1]), current_command);
325                         break;
326       }
327   
328                 case 0x2C ... 0x2F:
329       {
330         set_clut(psx_gpu, list_s16[5]);
331         set_texture(psx_gpu, list_s16[9]);
332         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
333   
334         get_vertex_data_xy_uv(0, 2);   
335         get_vertex_data_xy_uv(1, 6);   
336         get_vertex_data_xy_uv(2, 10);  
337         get_vertex_data_xy_uv(3, 14);
338   
339         render_triangle(psx_gpu, vertexes, current_command);
340         render_triangle(psx_gpu, &(vertexes[1]), current_command);
341                         break;
342       }
343   
344                 case 0x30 ... 0x33:
345       {
346         get_vertex_data_xy_rgb(0, 0);
347         get_vertex_data_xy_rgb(1, 4);
348         get_vertex_data_xy_rgb(2, 8);
349   
350         render_triangle(psx_gpu, vertexes, current_command);
351                         break;
352       }
353   
354                 case 0x34:
355                 case 0x35:
356                 case 0x36:
357                 case 0x37:
358       {
359         set_clut(psx_gpu, list_s16[5]);
360         set_texture(psx_gpu, list_s16[11]);
361   
362         get_vertex_data_xy_uv_rgb(0, 0);
363         get_vertex_data_xy_uv_rgb(1, 6);
364         get_vertex_data_xy_uv_rgb(2, 12);
365
366         render_triangle(psx_gpu, vertexes, current_command);
367                         break;
368       }
369   
370                 case 0x38:
371                 case 0x39:
372                 case 0x3A:
373                 case 0x3B:
374       {
375         get_vertex_data_xy_rgb(0, 0);
376         get_vertex_data_xy_rgb(1, 4);
377         get_vertex_data_xy_rgb(2, 8);
378         get_vertex_data_xy_rgb(3, 12);
379   
380         render_triangle(psx_gpu, vertexes, current_command);
381         render_triangle(psx_gpu, &(vertexes[1]), current_command);
382                         break;
383       }
384   
385                 case 0x3C:
386                 case 0x3D:
387                 case 0x3E:
388                 case 0x3F:
389       {
390         set_clut(psx_gpu, list_s16[5]);
391         set_texture(psx_gpu, list_s16[11]);
392   
393         get_vertex_data_xy_uv_rgb(0, 0);
394         get_vertex_data_xy_uv_rgb(1, 6);
395         get_vertex_data_xy_uv_rgb(2, 12);
396         get_vertex_data_xy_uv_rgb(3, 18);
397   
398         render_triangle(psx_gpu, vertexes, current_command);
399         render_triangle(psx_gpu, &(vertexes[1]), current_command);
400                         break;
401       }
402   
403                 case 0x40 ... 0x47:
404       {
405         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
406         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
407         vertexes[1].x = list_s16[4] + psx_gpu->offset_x;
408         vertexes[1].y = list_s16[5] + psx_gpu->offset_y;
409
410         render_line(psx_gpu, vertexes, current_command, list[0]);
411                         break;
412       }
413   
414                 case 0x48 ... 0x4F:
415       {
416         u32 num_vertexes = 1;
417         u32 *list_position = &(list[2]);
418         u32 xy = list[1];
419
420         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
421         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
422       
423         xy = *list_position;
424         while(1)
425         {
426           vertexes[0] = vertexes[1];
427
428           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
429           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
430
431           render_line(psx_gpu, vertexes, current_command, list[0]);
432
433           list_position++;
434           num_vertexes++;
435
436           if(list_position >= list_end)
437             break;
438
439           xy = *list_position;
440           if((xy & 0xF000F000) == 0x50005000)
441             break;
442         }
443
444         command_length += (num_vertexes - 2);
445         break;
446       }
447   
448                 case 0x50 ... 0x57:
449       {
450         vertexes[0].r = list[0] & 0xFF;
451         vertexes[0].g = (list[0] >> 8) & 0xFF;
452         vertexes[0].b = (list[0] >> 16) & 0xFF;
453         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
454         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
455
456         vertexes[1].r = list[2] & 0xFF;
457         vertexes[1].g = (list[2] >> 8) & 0xFF;
458         vertexes[1].b = (list[2] >> 16) & 0xFF;
459         vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
460         vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
461
462         render_line(psx_gpu, vertexes, current_command, 0);
463                         break;
464       }
465  
466       case 0x58 ... 0x5F:
467       {
468         u32 num_vertexes = 1;
469         u32 *list_position = &(list[2]);
470         u32 color = list[0];
471         u32 xy = list[1];
472
473         vertexes[1].r = color & 0xFF;
474         vertexes[1].g = (color >> 8) & 0xFF;
475         vertexes[1].b = (color >> 16) & 0xFF;
476         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
477         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
478       
479         color = list_position[0];
480         while(1)
481         {
482           xy = list_position[1];
483
484           vertexes[0] = vertexes[1];
485
486           vertexes[1].r = color & 0xFF;
487           vertexes[1].g = (color >> 8) & 0xFF;
488           vertexes[1].b = (color >> 16) & 0xFF;
489           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
490           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
491
492           render_line(psx_gpu, vertexes, current_command, 0);
493
494           list_position += 2;
495           num_vertexes++;
496
497           if(list_position >= list_end)
498             break;
499
500           color = list_position[0];
501           if((color & 0xF000F000) == 0x50005000)
502             break;
503         }
504
505         command_length += ((num_vertexes - 2) * 2);
506         break;
507       }
508   
509                 case 0x60 ... 0x63:
510       {        
511         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
512         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
513         u32 width = list_s16[4] & 0x3FF;
514         u32 height = list_s16[5] & 0x1FF;
515
516         render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]);
517                         break;
518       }
519   
520                 case 0x64 ... 0x67:
521       {        
522         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
523         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
524         u32 uv = list_s16[4];
525         u32 width = list_s16[6] & 0x3FF;
526         u32 height = list_s16[7] & 0x1FF;
527
528         set_clut(psx_gpu, list_s16[5]);
529
530         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, width, height,
531          current_command, list[0]);
532                         break;
533       }
534   
535                 case 0x68:
536                 case 0x69:
537                 case 0x6A:
538                 case 0x6B:
539       {
540         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
541         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
542
543         render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]);
544                         break;
545       }
546   
547                 case 0x70:
548                 case 0x71:
549                 case 0x72:
550                 case 0x73:
551       {        
552         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
553         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
554
555         render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]);
556                         break;
557       }
558   
559                 case 0x74:
560                 case 0x75:
561                 case 0x76:
562                 case 0x77:
563       {        
564         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
565         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
566         u32 uv = list_s16[4];
567
568         set_clut(psx_gpu, list_s16[5]);
569
570         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 8, 8,
571          current_command, list[0]);
572                         break;
573       }
574   
575                 case 0x78:
576                 case 0x79:
577                 case 0x7A:
578                 case 0x7B:
579       {        
580         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
581         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
582
583         render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]);
584                         break;
585       }
586   
587                 case 0x7C:
588                 case 0x7D:
589                 case 0x7E:
590                 case 0x7F:
591       {        
592         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
593         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
594         u32 uv = list_s16[4];
595
596         set_clut(psx_gpu, list_s16[5]);
597
598         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 16, 16,
599          current_command, list[0]);
600                         break;
601       }
602   
603                 case 0x80:          //  vid -> vid
604         render_block_move(psx_gpu, list_s16[2] & 0x3FF, list_s16[3] & 0x1FF,
605          list_s16[4] & 0x3FF, list_s16[5] & 0x1FF,
606          ((list_s16[6] - 1) & 0x3FF) + 1, ((list_s16[7] - 1) & 0x1FF) + 1);
607                         break;
608  
609 #ifdef PCSX
610                 case 0xA0:          //  sys -> vid
611                 case 0xC0:          //  vid -> sys
612                         goto breakloop;
613 #else
614                 case 0xA0:          //  sys -> vid
615       {
616         u32 load_x = list_s16[2] & 0x3FF;
617         u32 load_y = list_s16[3] & 0x1FF;
618         u32 load_width = list_s16[4] & 0x3FF;
619         u32 load_height = list_s16[5] & 0x1FF;
620         u32 load_size = load_width * load_height;
621   
622         command_length += load_size / 2;
623
624         if(load_size & 1)
625           command_length++;
626
627         render_block_copy(psx_gpu, (u16 *)&(list_s16[6]), load_x, load_y,
628          load_width, load_height, load_width);
629                         break;
630       }
631
632                 case 0xC0:          //  vid -> sys
633                         break;
634 #endif
635
636                 case 0xE1:
637         set_texture(psx_gpu, list[0] & 0x1FF);
638
639         if(list[0] & (1 << 9))
640           psx_gpu->render_state_base |= RENDER_STATE_DITHER;
641         else
642           psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
643
644         psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1;
645                         SET_Ex(1, list[0]);
646                         break;
647   
648                 case 0xE2:
649       {
650         // TODO: Clean
651         u32 texture_window_settings = list[0];
652         u32 tmp, x, y, w, h;
653
654         if(texture_window_settings != psx_gpu->texture_window_settings)
655         {
656           tmp = (texture_window_settings & 0x1F) | 0x20;
657           for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1);
658
659           tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20;
660           for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1);
661
662           tmp = 32 - (w >> 3);
663           x = ((texture_window_settings >> 10) & tmp) << 3;
664
665           tmp = 32 - (h >> 3);
666           y = ((texture_window_settings >> 15) & tmp) << 3;
667
668           flush_render_block_buffer(psx_gpu);
669           
670           psx_gpu->texture_window_settings = texture_window_settings;
671           psx_gpu->texture_window_x = x;
672           psx_gpu->texture_window_y = y;
673           psx_gpu->texture_mask_width = w - 1;
674           psx_gpu->texture_mask_height = h - 1;
675
676           update_texture_ptr(psx_gpu);
677         }
678         SET_Ex(2, list[0]);
679         break;
680                 }
681   
682                 case 0xE3:
683         psx_gpu->viewport_start_x = list[0] & 0x3FF;
684         psx_gpu->viewport_start_y = (list[0] >> 10) & 0x1FF;
685
686 #ifdef TEXTURE_CACHE_4BPP
687         psx_gpu->viewport_mask =
688          texture_region_mask(psx_gpu->viewport_start_x,
689          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
690          psx_gpu->viewport_end_y);
691 #endif
692                         SET_Ex(3, list[0]);
693                         break;
694   
695                 case 0xE4:
696         psx_gpu->viewport_end_x = list[0] & 0x3FF;
697         psx_gpu->viewport_end_y = (list[0] >> 10) & 0x1FF;
698
699 #ifdef TEXTURE_CACHE_4BPP
700         psx_gpu->viewport_mask =
701          texture_region_mask(psx_gpu->viewport_start_x,
702          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
703          psx_gpu->viewport_end_y);
704 #endif
705                         SET_Ex(4, list[0]);
706                         break;
707   
708                 case 0xE5:
709       {
710         s32 offset_x = list[0] << 21;
711         s32 offset_y = list[0] << 10;
712         psx_gpu->offset_x = offset_x >> 21;
713         psx_gpu->offset_y = offset_y >> 21; 
714   
715                         SET_Ex(5, list[0]);
716                         break;
717                 }
718
719                 case 0xE6:
720       {
721         u32 mask_settings = list[0];
722         u16 mask_msb = mask_settings << 15;
723
724         if(list[0] & 0x2)
725           psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE;
726         else
727           psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE;
728
729         if(mask_msb != psx_gpu->mask_msb)
730         {
731           flush_render_block_buffer(psx_gpu);
732           psx_gpu->mask_msb = mask_msb;
733         }
734
735                         SET_Ex(6, list[0]);
736                         break;
737       }
738   
739                 default:
740                         break;
741         }
742   }
743
744 #ifdef PCSX
745 breakloop:
746 #endif
747   if (last_command != NULL)
748     *last_command = current_command;
749   return list - list_start;
750 }
751
752 #define enhancement_disable() { \
753   psx_gpu->vram_out_ptr = psx_gpu->vram_ptr; \
754   psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x; \
755   psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y; \
756   psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x; \
757   psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y; \
758   psx_gpu->render_mode &= ~RENDER_DOUBLE_MODE; \
759 }
760
761 #define enhancement_enable() { \
762   psx_gpu->vram_out_ptr = psx_gpu->enhancement_buf_ptr; \
763   psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x * 2; \
764   psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y * 2; \
765   psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x * 2; \
766   psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y * 2; \
767   psx_gpu->render_mode |= RENDER_DOUBLE_MODE; \
768 }
769
770 #define shift_vertices3(v) { \
771   v[0]->x *= 2; \
772   v[0]->y *= 2; \
773   v[1]->x *= 2; \
774   v[1]->y *= 2; \
775   v[2]->x *= 2; \
776   v[2]->y *= 2; \
777 }
778
779 #define unshift_vertices3(v) { \
780   v[0]->x /= 2; \
781   v[0]->y /= 2; \
782   v[1]->x /= 2; \
783   v[1]->y /= 2; \
784   v[2]->x /= 2; \
785   v[2]->y /= 2; \
786 }
787
788 #define shift_triangle_area() \
789   psx_gpu->triangle_area *= 4
790
791 static int disable_main_render;
792
793 static void do_triangle_enhanced(psx_gpu_struct *psx_gpu,
794  vertex_struct *vertexes, u32 current_command)
795 {
796   vertex_struct *vertex_ptrs[3];
797
798   if (!prepare_triangle(psx_gpu, vertexes, vertex_ptrs))
799     return;
800
801   if (!disable_main_render)
802     render_triangle_p(psx_gpu, vertex_ptrs, current_command);
803
804   enhancement_enable();
805   shift_vertices3(vertex_ptrs);
806   shift_triangle_area();
807   render_triangle_p(psx_gpu, vertex_ptrs, current_command);
808 }
809
810 static void do_quad_enhanced(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
811  u32 current_command)
812 {
813   vertex_struct *vertex_ptrs[3];
814
815   if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
816     if (!disable_main_render)
817       render_triangle_p(psx_gpu, vertex_ptrs, current_command);
818
819     enhancement_enable();
820     shift_vertices3(vertex_ptrs);
821     shift_triangle_area();
822     render_triangle_p(psx_gpu, vertex_ptrs, current_command);
823     unshift_vertices3(vertex_ptrs);
824   }
825   enhancement_disable();
826   if (prepare_triangle(psx_gpu, &vertexes[1], vertex_ptrs)) {
827     if (!disable_main_render)
828       render_triangle_p(psx_gpu, vertex_ptrs, current_command);
829
830     enhancement_enable();
831     shift_vertices3(vertex_ptrs);
832     shift_triangle_area();
833     render_triangle_p(psx_gpu, vertex_ptrs, current_command);
834   }
835 }
836
837 u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
838 {
839   u32 current_command = 0, command_length;
840
841   u32 *list_start = list;
842   u32 *list_end = list + (size / 4);
843
844   psx_gpu->saved_viewport_start_x = psx_gpu->viewport_start_x;
845   psx_gpu->saved_viewport_start_y = psx_gpu->viewport_start_y;
846   psx_gpu->saved_viewport_end_x = psx_gpu->viewport_end_x;
847   psx_gpu->saved_viewport_end_y = psx_gpu->viewport_end_y;
848
849   for(; list < list_end; list += 1 + command_length)
850   {
851     s16 *list_s16 = (void *)list;
852     current_command = *list >> 24;
853     command_length = command_lengths[current_command];
854     if (list + 1 + command_length > list_end) {
855       current_command = (u32)-1;
856       break;
857     }
858
859     enhancement_disable();
860
861     switch(current_command)
862     {
863       case 0x00:
864         break;
865   
866       case 0x02:
867       {
868         u32 x = list_s16[2] & 0x3FF;
869         u32 y = list_s16[3] & 0x1FF;
870         u32 width = list_s16[4] & 0x3FF;
871         u32 height = list_s16[5] & 0x1FF;
872         u32 color = list[0] & 0xFFFFFF;
873
874         x &= ~0xF;
875         width = ((width + 0xF) & ~0xF);
876
877         do_fill(psx_gpu, x, y, width, height, color);
878
879         psx_gpu->vram_out_ptr = psx_gpu->enhancement_buf_ptr;
880         x *= 2;
881         y *= 2;
882         width *= 2;
883         height *= 2;
884         render_block_fill_enh(psx_gpu, color, x, y, width, height);
885         break;
886       }
887   
888       case 0x20 ... 0x23:
889       {
890         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
891   
892         get_vertex_data_xy(0, 2);
893         get_vertex_data_xy(1, 4);
894         get_vertex_data_xy(2, 6);
895
896         do_triangle_enhanced(psx_gpu, vertexes, current_command);
897         break;
898       }
899   
900       case 0x24 ... 0x27:
901       {
902         set_clut(psx_gpu, list_s16[5]);
903         set_texture(psx_gpu, list_s16[9]);
904         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
905   
906         get_vertex_data_xy_uv(0, 2);
907         get_vertex_data_xy_uv(1, 6);
908         get_vertex_data_xy_uv(2, 10);
909   
910         do_triangle_enhanced(psx_gpu, vertexes, current_command);
911         break;
912       }
913   
914       case 0x28 ... 0x2B:
915       {
916         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
917   
918         get_vertex_data_xy(0, 2);
919         get_vertex_data_xy(1, 4);
920         get_vertex_data_xy(2, 6);
921         get_vertex_data_xy(3, 8);
922
923         do_quad_enhanced(psx_gpu, vertexes, current_command);
924         break;
925       }
926   
927       case 0x2C ... 0x2F:
928       {
929         set_clut(psx_gpu, list_s16[5]);
930         set_texture(psx_gpu, list_s16[9]);
931         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
932   
933         get_vertex_data_xy_uv(0, 2);   
934         get_vertex_data_xy_uv(1, 6);   
935         get_vertex_data_xy_uv(2, 10);  
936         get_vertex_data_xy_uv(3, 14);
937   
938         do_quad_enhanced(psx_gpu, vertexes, current_command);
939         break;
940       }
941   
942       case 0x30 ... 0x33:
943       {
944         get_vertex_data_xy_rgb(0, 0);
945         get_vertex_data_xy_rgb(1, 4);
946         get_vertex_data_xy_rgb(2, 8);
947   
948         do_triangle_enhanced(psx_gpu, vertexes, current_command);
949         break;
950       }
951   
952       case 0x34:
953       case 0x35:
954       case 0x36:
955       case 0x37:
956       {
957         set_clut(psx_gpu, list_s16[5]);
958         set_texture(psx_gpu, list_s16[11]);
959   
960         get_vertex_data_xy_uv_rgb(0, 0);
961         get_vertex_data_xy_uv_rgb(1, 6);
962         get_vertex_data_xy_uv_rgb(2, 12);
963
964         do_triangle_enhanced(psx_gpu, vertexes, current_command);
965         break;
966       }
967   
968       case 0x38:
969       case 0x39:
970       case 0x3A:
971       case 0x3B:
972       {
973         get_vertex_data_xy_rgb(0, 0);
974         get_vertex_data_xy_rgb(1, 4);
975         get_vertex_data_xy_rgb(2, 8);
976         get_vertex_data_xy_rgb(3, 12);
977   
978         do_quad_enhanced(psx_gpu, vertexes, current_command);
979         break;
980       }
981   
982       case 0x3C:
983       case 0x3D:
984       case 0x3E:
985       case 0x3F:
986       {
987         set_clut(psx_gpu, list_s16[5]);
988         set_texture(psx_gpu, list_s16[11]);
989   
990         get_vertex_data_xy_uv_rgb(0, 0);
991         get_vertex_data_xy_uv_rgb(1, 6);
992         get_vertex_data_xy_uv_rgb(2, 12);
993         get_vertex_data_xy_uv_rgb(3, 18);
994
995         do_quad_enhanced(psx_gpu, vertexes, current_command);
996         break;
997       }
998   
999       case 0x40 ... 0x47:
1000       {
1001         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
1002         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
1003         vertexes[1].x = list_s16[4] + psx_gpu->offset_x;
1004         vertexes[1].y = list_s16[5] + psx_gpu->offset_y;
1005
1006         render_line(psx_gpu, vertexes, current_command, list[0]);
1007         break;
1008       }
1009   
1010       case 0x48 ... 0x4F:
1011       {
1012         u32 num_vertexes = 1;
1013         u32 *list_position = &(list[2]);
1014         u32 xy = list[1];
1015
1016         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1017         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1018       
1019         xy = *list_position;
1020         while(1)
1021         {
1022           vertexes[0] = vertexes[1];
1023
1024           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1025           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1026
1027           render_line(psx_gpu, vertexes, current_command, list[0]);
1028
1029           list_position++;
1030           num_vertexes++;
1031
1032           if(list_position >= list_end)
1033             break;
1034
1035           xy = *list_position;
1036           if((xy & 0xF000F000) == 0x50005000)
1037             break;
1038         }
1039
1040         command_length += (num_vertexes - 2);
1041         break;
1042       }
1043   
1044       case 0x50 ... 0x57:
1045       {
1046         vertexes[0].r = list[0] & 0xFF;
1047         vertexes[0].g = (list[0] >> 8) & 0xFF;
1048         vertexes[0].b = (list[0] >> 16) & 0xFF;
1049         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
1050         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
1051
1052         vertexes[1].r = list[2] & 0xFF;
1053         vertexes[1].g = (list[2] >> 8) & 0xFF;
1054         vertexes[1].b = (list[2] >> 16) & 0xFF;
1055         vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
1056         vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
1057
1058         render_line(psx_gpu, vertexes, current_command, 0);
1059         break;
1060       }
1061  
1062       case 0x58 ... 0x5F:
1063       {
1064         u32 num_vertexes = 1;
1065         u32 *list_position = &(list[2]);
1066         u32 color = list[0];
1067         u32 xy = list[1];
1068
1069         vertexes[1].r = color & 0xFF;
1070         vertexes[1].g = (color >> 8) & 0xFF;
1071         vertexes[1].b = (color >> 16) & 0xFF;
1072         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1073         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1074       
1075         color = list_position[0];
1076         while(1)
1077         {
1078           xy = list_position[1];
1079
1080           vertexes[0] = vertexes[1];
1081
1082           vertexes[1].r = color & 0xFF;
1083           vertexes[1].g = (color >> 8) & 0xFF;
1084           vertexes[1].b = (color >> 16) & 0xFF;
1085           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1086           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1087
1088           render_line(psx_gpu, vertexes, current_command, 0);
1089
1090           list_position += 2;
1091           num_vertexes++;
1092
1093           if(list_position >= list_end)
1094             break;
1095
1096           color = list_position[0];
1097           if((color & 0xF000F000) == 0x50005000)
1098             break;
1099         }
1100
1101         command_length += ((num_vertexes - 2) * 2);
1102         break;
1103       }
1104   
1105       case 0x60 ... 0x63:
1106       {        
1107         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1108         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1109         u32 width = list_s16[4] & 0x3FF;
1110         u32 height = list_s16[5] & 0x1FF;
1111
1112         render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]);
1113         break;
1114       }
1115   
1116       case 0x64 ... 0x67:
1117       {        
1118         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1119         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1120         u32 uv = list_s16[4];
1121         u32 width = list_s16[6] & 0x3FF;
1122         u32 height = list_s16[7] & 0x1FF;
1123
1124         set_clut(psx_gpu, list_s16[5]);
1125
1126         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, width, height,
1127          current_command, list[0]);
1128         break;
1129       }
1130   
1131       case 0x68:
1132       case 0x69:
1133       case 0x6A:
1134       case 0x6B:
1135       {
1136         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1137         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1138
1139         render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]);
1140         break;
1141       }
1142   
1143       case 0x70:
1144       case 0x71:
1145       case 0x72:
1146       case 0x73:
1147       {        
1148         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1149         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1150
1151         render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]);
1152         break;
1153       }
1154   
1155       case 0x74:
1156       case 0x75:
1157       case 0x76:
1158       case 0x77:
1159       {        
1160         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1161         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1162         u32 uv = list_s16[4];
1163
1164         set_clut(psx_gpu, list_s16[5]);
1165
1166         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 8, 8,
1167          current_command, list[0]);
1168         break;
1169       }
1170   
1171       case 0x78:
1172       case 0x79:
1173       case 0x7A:
1174       case 0x7B:
1175       {        
1176         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1177         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1178
1179         render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]);
1180         break;
1181       }
1182   
1183       case 0x7C:
1184       case 0x7D:
1185       case 0x7E:
1186       case 0x7F:
1187       {        
1188         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1189         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1190         u32 uv = list_s16[4];
1191
1192         set_clut(psx_gpu, list_s16[5]);
1193
1194         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 16, 16,
1195          current_command, list[0]);
1196         break;
1197       }
1198   
1199       case 0x80:          //  vid -> vid
1200         render_block_move(psx_gpu, list_s16[2] & 0x3FF, list_s16[3] & 0x1FF,
1201          list_s16[4] & 0x3FF, list_s16[5] & 0x1FF,
1202          ((list_s16[6] - 1) & 0x3FF) + 1, ((list_s16[7] - 1) & 0x1FF) + 1);
1203         break;
1204  
1205 #ifdef PCSX
1206       case 0xA0:          //  sys -> vid
1207       case 0xC0:          //  vid -> sys
1208         goto breakloop;
1209 #else
1210       case 0xA0:          //  sys -> vid
1211       {
1212         u32 load_x = list_s16[2] & 0x3FF;
1213         u32 load_y = list_s16[3] & 0x1FF;
1214         u32 load_width = list_s16[4] & 0x3FF;
1215         u32 load_height = list_s16[5] & 0x1FF;
1216         u32 load_size = load_width * load_height;
1217   
1218         command_length += load_size / 2;
1219
1220         if(load_size & 1)
1221           command_length++;
1222
1223         render_block_copy(psx_gpu, (u16 *)&(list_s16[6]), load_x, load_y,
1224          load_width, load_height, load_width);
1225         break;
1226       }
1227
1228       case 0xC0:          //  vid -> sys
1229         break;
1230 #endif
1231
1232       case 0xE1:
1233         set_texture(psx_gpu, list[0] & 0x1FF);
1234
1235         if(list[0] & (1 << 9))
1236           psx_gpu->render_state_base |= RENDER_STATE_DITHER;
1237         else
1238           psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
1239
1240         psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1;
1241         SET_Ex(1, list[0]);
1242         break;
1243   
1244       case 0xE2:
1245       {
1246         // TODO: Clean
1247         u32 texture_window_settings = list[0];
1248         u32 tmp, x, y, w, h;
1249
1250         if(texture_window_settings != psx_gpu->texture_window_settings)
1251         {
1252           tmp = (texture_window_settings & 0x1F) | 0x20;
1253           for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1);
1254
1255           tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20;
1256           for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1);
1257
1258           tmp = 32 - (w >> 3);
1259           x = ((texture_window_settings >> 10) & tmp) << 3;
1260
1261           tmp = 32 - (h >> 3);
1262           y = ((texture_window_settings >> 15) & tmp) << 3;
1263
1264           flush_render_block_buffer(psx_gpu);
1265           
1266           psx_gpu->texture_window_settings = texture_window_settings;
1267           psx_gpu->texture_window_x = x;
1268           psx_gpu->texture_window_y = y;
1269           psx_gpu->texture_mask_width = w - 1;
1270           psx_gpu->texture_mask_height = h - 1;
1271
1272           update_texture_ptr(psx_gpu);
1273         }
1274         SET_Ex(2, list[0]);
1275         break;
1276       }
1277   
1278       case 0xE3:
1279         psx_gpu->viewport_start_x = list[0] & 0x3FF;
1280         psx_gpu->viewport_start_y = (list[0] >> 10) & 0x1FF;
1281         psx_gpu->saved_viewport_start_x = psx_gpu->viewport_start_x;
1282         psx_gpu->saved_viewport_start_y = psx_gpu->viewport_start_y;
1283
1284 #ifdef TEXTURE_CACHE_4BPP
1285         psx_gpu->viewport_mask =
1286          texture_region_mask(psx_gpu->viewport_start_x,
1287          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
1288          psx_gpu->viewport_end_y);
1289 #endif
1290         SET_Ex(3, list[0]);
1291         break;
1292   
1293       case 0xE4:
1294         psx_gpu->viewport_end_x = list[0] & 0x3FF;
1295         psx_gpu->viewport_end_y = (list[0] >> 10) & 0x1FF;
1296         psx_gpu->saved_viewport_end_x = psx_gpu->viewport_end_x;
1297         psx_gpu->saved_viewport_end_y = psx_gpu->viewport_end_y;
1298
1299 #ifdef TEXTURE_CACHE_4BPP
1300         psx_gpu->viewport_mask =
1301          texture_region_mask(psx_gpu->viewport_start_x,
1302          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
1303          psx_gpu->viewport_end_y);
1304 #endif
1305         SET_Ex(4, list[0]);
1306         break;
1307   
1308       case 0xE5:
1309       {
1310         s32 offset_x = list[0] << 21;
1311         s32 offset_y = list[0] << 10;
1312         psx_gpu->offset_x = offset_x >> 21;
1313         psx_gpu->offset_y = offset_y >> 21; 
1314   
1315         SET_Ex(5, list[0]);
1316         break;
1317       }
1318
1319       case 0xE6:
1320       {
1321         u32 mask_settings = list[0];
1322         u16 mask_msb = mask_settings << 15;
1323
1324         if(list[0] & 0x2)
1325           psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE;
1326         else
1327           psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE;
1328
1329         if(mask_msb != psx_gpu->mask_msb)
1330         {
1331           flush_render_block_buffer(psx_gpu);
1332           psx_gpu->mask_msb = mask_msb;
1333         }
1334
1335         SET_Ex(6, list[0]);
1336         break;
1337       }
1338   
1339       default:
1340         break;
1341     }
1342   }
1343
1344 #ifdef PCSX
1345 breakloop:
1346 #endif
1347 enhancement_disable();
1348   if (last_command != NULL)
1349     *last_command = current_command;
1350   return list - list_start;
1351 }
1352
1353 // vim:shiftwidth=2:expandtab