gpu_neon: more complicated overflow check
[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     case TEXTURE_MODE_4BPP:
49       texture_base = psx_gpu->texture_4bpp_cache[psx_gpu->current_texture_page];
50
51       texture_ptr = texture_base;
52       texture_ptr += psx_gpu->texture_window_x & 0xF;
53       texture_ptr += (psx_gpu->texture_window_y & 0xF) << 4;
54       texture_ptr += (psx_gpu->texture_window_x >> 4) << 8;
55       texture_ptr += (psx_gpu->texture_window_y >> 4) << 12;
56       break;
57
58     case TEXTURE_MODE_8BPP:
59       if(psx_gpu->current_texture_page & 0x1)
60       {
61         texture_base =
62          psx_gpu->texture_8bpp_odd_cache[psx_gpu->current_texture_page >> 1];
63       }
64       else
65       {
66         texture_base =
67          psx_gpu->texture_8bpp_even_cache[psx_gpu->current_texture_page >> 1];
68       }
69       
70       texture_ptr = texture_base;
71       texture_ptr += psx_gpu->texture_window_x & 0xF;
72       texture_ptr += (psx_gpu->texture_window_y & 0xF) << 4;
73       texture_ptr += (psx_gpu->texture_window_x >> 4) << 8;
74       texture_ptr += (psx_gpu->texture_window_y >> 4) << 12;
75       break;
76
77     default:
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   texture_settings &= 0x1FF;
96   if(psx_gpu->texture_settings != texture_settings)
97   {
98     u32 new_texture_page = texture_settings & 0x1F;
99     u32 texture_mode = (texture_settings >> 7) & 0x3;
100     u32 render_state_base = psx_gpu->render_state_base;
101
102     flush_render_block_buffer(psx_gpu);
103
104     render_state_base &= ~(0xF << 6);
105     render_state_base |= ((texture_settings >> 5) & 0xF) << 6;
106
107     psx_gpu->render_state_base = render_state_base;
108
109     psx_gpu->current_texture_mask = 0x1 << new_texture_page;
110
111     if(texture_mode == TEXTURE_MODE_8BPP)
112     {     
113       // In 8bpp mode 256x256 takes up two pages. If it's on the right edge it
114       // wraps back around to the left edge.
115       u32 adjacent_texture_page = ((texture_settings + 1) & 0xF) | (texture_settings & 0x10);
116       psx_gpu->current_texture_mask |= 0x1 << adjacent_texture_page;
117
118       if((psx_gpu->last_8bpp_texture_page ^ new_texture_page) & 0x1)
119       {
120         u32 dirty_textures_8bpp_alternate_mask =
121          psx_gpu->dirty_textures_8bpp_alternate_mask;
122         psx_gpu->dirty_textures_8bpp_alternate_mask =
123          psx_gpu->dirty_textures_8bpp_mask;
124         psx_gpu->dirty_textures_8bpp_mask = dirty_textures_8bpp_alternate_mask;
125       }
126
127       psx_gpu->last_8bpp_texture_page = new_texture_page;
128     }
129
130     psx_gpu->current_texture_page = new_texture_page;
131     psx_gpu->texture_settings = texture_settings;
132
133     update_texture_ptr(psx_gpu);
134   }
135 }
136
137 void set_clut(psx_gpu_struct *psx_gpu, u32 clut_settings)
138 {
139   if(psx_gpu->clut_settings != clut_settings)
140   {
141     flush_render_block_buffer(psx_gpu);
142     psx_gpu->clut_settings = clut_settings;
143     psx_gpu->clut_ptr = psx_gpu->vram_ptr + ((clut_settings & 0x7FFF) * 16);
144   }
145 }
146
147 void set_triangle_color(psx_gpu_struct *psx_gpu, u32 triangle_color)
148 {
149   if(psx_gpu->triangle_color != triangle_color)
150   {
151     flush_render_block_buffer(psx_gpu);
152     psx_gpu->triangle_color = triangle_color;
153   }
154 }
155
156 static void do_fill(psx_gpu_struct *psx_gpu, u32 x, u32 y,
157  u32 width, u32 height, u32 color)
158 {
159   x &= ~0xF;
160   width = ((width + 0xF) & ~0xF);
161
162   flush_render_block_buffer(psx_gpu);
163
164   if(unlikely((x + width) > 1024))
165   {
166     u32 width_a = 1024 - x;
167     u32 width_b = width - width_a;
168
169     if(unlikely((y + height) > 512))
170     {
171       u32 height_a = 512 - y;
172       u32 height_b = height - height_a;
173
174       render_block_fill(psx_gpu, color, x, y, width_a, height_a);
175       render_block_fill(psx_gpu, color, 0, y, width_b, height_a);
176       render_block_fill(psx_gpu, color, x, 0, width_a, height_b);
177       render_block_fill(psx_gpu, color, 0, 0, width_b, height_b);
178     }
179     else
180     {
181       render_block_fill(psx_gpu, color, x, y, width_a, height);
182       render_block_fill(psx_gpu, color, 0, y, width_b, height);
183     }
184   }
185   else
186   {
187     if(unlikely((y + height) > 512))
188     {
189       u32 height_a = 512 - y;
190       u32 height_b = height - height_a;
191
192       render_block_fill(psx_gpu, color, x, y, width, height_a);
193       render_block_fill(psx_gpu, color, x, 0, width, height_b);
194     }
195     else
196     {
197       render_block_fill(psx_gpu, color, x, y, width, height);
198     }
199   }
200 }
201
202 #define sign_extend_12bit(value)                                               \
203   (((s32)((value) << 20)) >> 20)                                               \
204
205 #define sign_extend_11bit(value)                                               \
206   (((s32)((value) << 21)) >> 21)                                               \
207
208 #define sign_extend_10bit(value)                                               \
209   (((s32)((value) << 22)) >> 22)                                               \
210
211
212 #define get_vertex_data_xy(vertex_number, offset16)                            \
213   vertexes[vertex_number].x =                                                  \
214    sign_extend_12bit(list_s16[offset16]) + psx_gpu->offset_x;                  \
215   vertexes[vertex_number].y =                                                  \
216    sign_extend_12bit(list_s16[(offset16) + 1]) + psx_gpu->offset_y;            \
217
218 #define get_vertex_data_uv(vertex_number, offset16)                            \
219   vertexes[vertex_number].u = list_s16[offset16] & 0xFF;                       \
220   vertexes[vertex_number].v = (list_s16[offset16] >> 8) & 0xFF                 \
221
222 #define get_vertex_data_rgb(vertex_number, offset32)                           \
223   vertexes[vertex_number].r = list[offset32] & 0xFF;                           \
224   vertexes[vertex_number].g = (list[offset32] >> 8) & 0xFF;                    \
225   vertexes[vertex_number].b = (list[offset32] >> 16) & 0xFF                    \
226
227 #define get_vertex_data_xy_uv(vertex_number, offset16)                         \
228   get_vertex_data_xy(vertex_number, offset16);                                 \
229   get_vertex_data_uv(vertex_number, (offset16) + 2)                            \
230
231 #define get_vertex_data_xy_rgb(vertex_number, offset16)                        \
232   get_vertex_data_rgb(vertex_number, (offset16) / 2);                          \
233   get_vertex_data_xy(vertex_number, (offset16) + 2);                           \
234
235 #define get_vertex_data_xy_uv_rgb(vertex_number, offset16)                     \
236   get_vertex_data_rgb(vertex_number, (offset16) / 2);                          \
237   get_vertex_data_xy(vertex_number, (offset16) + 2);                           \
238   get_vertex_data_uv(vertex_number, (offset16) + 4);                           \
239
240 #define set_vertex_color_constant(vertex_number, color)                        \
241   vertexes[vertex_number].r = color & 0xFF;                                    \
242   vertexes[vertex_number].g = (color >> 8) & 0xFF;                             \
243   vertexes[vertex_number].b = (color >> 16) & 0xFF                             \
244
245 #define get_vertex_data_xy_rgb_constant(vertex_number, offset16, color)        \
246   get_vertex_data_xy(vertex_number, offset16);                                 \
247   set_vertex_color_constant(vertex_number, color)                              \
248
249 #ifndef SET_Ex
250 #define SET_Ex(r, v)
251 #endif
252
253 u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
254 {
255   vertex_struct vertexes[4] __attribute__((aligned(16))) = {};
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], 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], 0);
432
433           list_position++;
434           num_vertexes++;
435
436           if(list_position >= list_end)
437           {
438             current_command = (u32)-1;
439             goto breakloop;
440           }
441
442           xy = *list_position;
443           if((xy & 0xF000F000) == 0x50005000)
444             break;
445         }
446
447         command_length += (num_vertexes - 2);
448         break;
449       }
450   
451                 case 0x50 ... 0x57:
452       {
453         vertexes[0].r = list[0] & 0xFF;
454         vertexes[0].g = (list[0] >> 8) & 0xFF;
455         vertexes[0].b = (list[0] >> 16) & 0xFF;
456         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
457         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
458
459         vertexes[1].r = list[2] & 0xFF;
460         vertexes[1].g = (list[2] >> 8) & 0xFF;
461         vertexes[1].b = (list[2] >> 16) & 0xFF;
462         vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
463         vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
464
465         render_line(psx_gpu, vertexes, current_command, 0, 0);
466                         break;
467       }
468  
469       case 0x58 ... 0x5F:
470       {
471         u32 num_vertexes = 1;
472         u32 *list_position = &(list[2]);
473         u32 color = list[0];
474         u32 xy = list[1];
475
476         vertexes[1].r = color & 0xFF;
477         vertexes[1].g = (color >> 8) & 0xFF;
478         vertexes[1].b = (color >> 16) & 0xFF;
479         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
480         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
481       
482         color = list_position[0];
483         while(1)
484         {
485           xy = list_position[1];
486
487           vertexes[0] = vertexes[1];
488
489           vertexes[1].r = color & 0xFF;
490           vertexes[1].g = (color >> 8) & 0xFF;
491           vertexes[1].b = (color >> 16) & 0xFF;
492           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
493           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
494
495           render_line(psx_gpu, vertexes, current_command, 0, 0);
496
497           list_position += 2;
498           num_vertexes++;
499
500           if(list_position >= list_end)
501           {
502             current_command = (u32)-1;
503             goto breakloop;
504           }
505
506           color = list_position[0];
507           if((color & 0xF000F000) == 0x50005000)
508             break;
509         }
510
511         command_length += ((num_vertexes - 2) * 2);
512         break;
513       }
514   
515                 case 0x60 ... 0x63:
516       {        
517         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
518         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
519         u32 width = list_s16[4] & 0x3FF;
520         u32 height = list_s16[5] & 0x1FF;
521
522         render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]);
523                         break;
524       }
525   
526                 case 0x64 ... 0x67:
527       {        
528         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
529         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
530         u32 uv = list_s16[4];
531         u32 width = list_s16[6] & 0x3FF;
532         u32 height = list_s16[7] & 0x1FF;
533
534         set_clut(psx_gpu, list_s16[5]);
535
536         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, width, height,
537          current_command, list[0]);
538                         break;
539       }
540   
541                 case 0x68:
542                 case 0x69:
543                 case 0x6A:
544                 case 0x6B:
545       {
546         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
547         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
548
549         render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]);
550                         break;
551       }
552   
553                 case 0x70:
554                 case 0x71:
555                 case 0x72:
556                 case 0x73:
557       {        
558         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
559         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
560
561         render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]);
562                         break;
563       }
564   
565                 case 0x74:
566                 case 0x75:
567                 case 0x76:
568                 case 0x77:
569       {        
570         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
571         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
572         u32 uv = list_s16[4];
573
574         set_clut(psx_gpu, list_s16[5]);
575
576         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 8, 8,
577          current_command, list[0]);
578                         break;
579       }
580   
581                 case 0x78:
582                 case 0x79:
583                 case 0x7A:
584                 case 0x7B:
585       {        
586         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
587         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
588
589         render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]);
590                         break;
591       }
592   
593                 case 0x7C:
594                 case 0x7D:
595                 case 0x7E:
596                 case 0x7F:
597       {        
598         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
599         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
600         u32 uv = list_s16[4];
601
602         set_clut(psx_gpu, list_s16[5]);
603
604         render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 16, 16,
605          current_command, list[0]);
606                         break;
607       }
608   
609       case 0x80:          //  vid -> vid
610       {
611         u32 sx = list_s16[2] & 0x3FF;
612         u32 sy = list_s16[3] & 0x1FF;
613         u32 dx = list_s16[4] & 0x3FF;
614         u32 dy = list_s16[5] & 0x1FF;
615         u32 w = ((list_s16[6] - 1) & 0x3FF) + 1;
616         u32 h = ((list_s16[7] - 1) & 0x1FF) + 1;
617
618         if (sx == dx && sy == dy && psx_gpu->mask_msb == 0)
619           break;
620
621         render_block_move(psx_gpu, sx, sy, dx, dy, w, h);
622         break;
623       } 
624
625 #ifdef PCSX
626                 case 0xA0:          //  sys -> vid
627                 case 0xC0:          //  vid -> sys
628                         goto breakloop;
629 #else
630                 case 0xA0:          //  sys -> vid
631       {
632         u32 load_x = list_s16[2] & 0x3FF;
633         u32 load_y = list_s16[3] & 0x1FF;
634         u32 load_width = list_s16[4] & 0x3FF;
635         u32 load_height = list_s16[5] & 0x1FF;
636         u32 load_size = load_width * load_height;
637   
638         command_length += load_size / 2;
639
640         if(load_size & 1)
641           command_length++;
642
643         render_block_copy(psx_gpu, (u16 *)&(list_s16[6]), load_x, load_y,
644          load_width, load_height, load_width);
645                         break;
646       }
647
648                 case 0xC0:          //  vid -> sys
649                         break;
650 #endif
651
652                 case 0xE1:
653         set_texture(psx_gpu, list[0]);
654
655         if(list[0] & (1 << 9))
656           psx_gpu->render_state_base |= RENDER_STATE_DITHER;
657         else
658           psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
659
660         psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1;
661                         SET_Ex(1, list[0]);
662                         break;
663   
664                 case 0xE2:
665       {
666         // TODO: Clean
667         u32 texture_window_settings = list[0];
668         u32 tmp, x, y, w, h;
669
670         if(texture_window_settings != psx_gpu->texture_window_settings)
671         {
672           tmp = (texture_window_settings & 0x1F) | 0x20;
673           for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1);
674
675           tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20;
676           for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1);
677
678           tmp = 32 - (w >> 3);
679           x = ((texture_window_settings >> 10) & tmp) << 3;
680
681           tmp = 32 - (h >> 3);
682           y = ((texture_window_settings >> 15) & tmp) << 3;
683
684           flush_render_block_buffer(psx_gpu);
685           
686           psx_gpu->texture_window_settings = texture_window_settings;
687           psx_gpu->texture_window_x = x;
688           psx_gpu->texture_window_y = y;
689           psx_gpu->texture_mask_width = w - 1;
690           psx_gpu->texture_mask_height = h - 1;
691
692           update_texture_ptr(psx_gpu);
693         }
694         SET_Ex(2, list[0]);
695         break;
696       }
697
698       case 0xE3:
699       {
700         s16 viewport_start_x = list[0] & 0x3FF;
701         s16 viewport_start_y = (list[0] >> 10) & 0x1FF;
702
703         if(viewport_start_x == psx_gpu->viewport_start_x &&
704          viewport_start_y == psx_gpu->viewport_start_y)
705         {
706           break;
707         }
708   
709         psx_gpu->viewport_start_x = viewport_start_x;
710         psx_gpu->viewport_start_y = viewport_start_y;
711
712 #ifdef TEXTURE_CACHE_4BPP
713         psx_gpu->viewport_mask =
714          texture_region_mask(psx_gpu->viewport_start_x,
715          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
716          psx_gpu->viewport_end_y);
717 #endif
718         SET_Ex(3, list[0]);
719         break;
720       }
721
722       case 0xE4:
723       {
724         s16 viewport_end_x = list[0] & 0x3FF;
725         s16 viewport_end_y = (list[0] >> 10) & 0x1FF;
726
727         if(viewport_end_x == psx_gpu->viewport_end_x &&
728          viewport_end_y == psx_gpu->viewport_end_y)
729         {
730           break;
731         }
732
733         psx_gpu->viewport_end_x = viewport_end_x;
734         psx_gpu->viewport_end_y = viewport_end_y;
735
736 #ifdef TEXTURE_CACHE_4BPP
737         psx_gpu->viewport_mask =
738          texture_region_mask(psx_gpu->viewport_start_x,
739          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
740          psx_gpu->viewport_end_y);
741 #endif
742         SET_Ex(4, list[0]);
743         break;
744       }
745   
746       case 0xE5:
747       {
748         s32 offset_x = list[0] << 21;
749         s32 offset_y = list[0] << 10;
750         psx_gpu->offset_x = offset_x >> 21;
751         psx_gpu->offset_y = offset_y >> 21; 
752   
753                         SET_Ex(5, list[0]);
754                         break;
755                 }
756
757                 case 0xE6:
758       {
759         u32 mask_settings = list[0];
760         u16 mask_msb = mask_settings << 15;
761
762         if(list[0] & 0x2)
763           psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE;
764         else
765           psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE;
766
767         if(mask_msb != psx_gpu->mask_msb)
768         {
769           flush_render_block_buffer(psx_gpu);
770           psx_gpu->mask_msb = mask_msb;
771         }
772
773                         SET_Ex(6, list[0]);
774                         break;
775       }
776   
777                 default:
778                         break;
779         }
780   }
781
782 breakloop:
783   if (last_command != NULL)
784     *last_command = current_command;
785   return list - list_start;
786 }
787
788 #ifdef PCSX
789
790 #define ENH_BUF_TABLE_STEP (1024 / sizeof(psx_gpu->enhancement_buf_by_x16))
791
792 static int is_new_scanout(psx_gpu_struct *psx_gpu, int x)
793 {
794   int i, scanout_x;
795   for (i = 0; i < ARRAY_SIZE(psx_gpu->enhancement_scanout_x); i++)
796   {
797     scanout_x = psx_gpu->enhancement_scanout_x[i];
798     if (x <= scanout_x && scanout_x < x + ENH_BUF_TABLE_STEP)
799     {
800       if (x != scanout_x)
801         log_anomaly("unaligned scanout x: %d,%d\n", scanout_x, x);
802       return 1;
803     }
804   }
805   return 0;
806 }
807
808 static void update_enhancement_buf_table_from_hres(psx_gpu_struct *psx_gpu)
809 {
810   u32 b, x;
811
812   b = 0;
813   psx_gpu->enhancement_buf_by_x16[0] = b;
814   psx_gpu->enhancement_buf_start[0] = 0;
815   for (x = 1; x < sizeof(psx_gpu->enhancement_buf_by_x16); x++)
816   {
817     if (b < 3 && is_new_scanout(psx_gpu, x * ENH_BUF_TABLE_STEP)) {
818       b++;
819       psx_gpu->enhancement_buf_start[b] = x * ENH_BUF_TABLE_STEP;
820     }
821
822     psx_gpu->enhancement_buf_by_x16[x] = b;
823   }
824 #if 0
825   printf("buf_by_x16:\n");
826   for (b = 0; b < 3; b++) {
827     int first = -1, count = 0;
828     for (x = 0; x < sizeof(psx_gpu->enhancement_buf_by_x16); x++) {
829       if (psx_gpu->enhancement_buf_by_x16[x] == b) {
830         if (first < 0) first = x;
831         count++;
832       }
833     }
834     if (count) {
835       assert(first * ENH_BUF_TABLE_STEP == psx_gpu->enhancement_buf_start[b]);
836       printf("%d: %3zd-%zd\n", b, first * ENH_BUF_TABLE_STEP,
837           (first + count) * ENH_BUF_TABLE_STEP);
838     }
839   }
840 #endif
841 }
842
843 static void update_enhancement_buf_table_from_x(psx_gpu_struct *psx_gpu,
844  u32 x0, u32 len)
845 {
846 #if 0
847   u32 x, b;
848
849   for (x = x0, b = 0; x >= len; b++)
850     x -= len;
851   if (b > 3)
852     b = 3;
853
854   memset(psx_gpu->enhancement_buf_by_x16 + x0 / ENH_BUF_TABLE_STEP,
855    b, (len + ENH_BUF_TABLE_STEP - 1) / ENH_BUF_TABLE_STEP);
856 #endif
857 }
858
859 #define select_enhancement_buf(psx_gpu) \
860   psx_gpu->enhancement_current_buf_ptr = \
861     select_enhancement_buf_ptr(psx_gpu, psx_gpu->saved_viewport_start_x)
862
863 #define enhancement_disable() { \
864   psx_gpu->vram_out_ptr = psx_gpu->vram_ptr; \
865   psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x; \
866   psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y; \
867   psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x; \
868   psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y; \
869   psx_gpu->uvrgb_phase = 0x8000; \
870 }
871
872 #define enhancement_enable() { \
873   psx_gpu->vram_out_ptr = psx_gpu->enhancement_current_buf_ptr; \
874   psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x * 2; \
875   psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y * 2; \
876   psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x * 2 + 1; \
877   psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y * 2 + 1; \
878   psx_gpu->uvrgb_phase = 0x7fff; \
879 }
880
881 #define shift_vertices3(v) { \
882   v[0]->x <<= 1; \
883   v[0]->y <<= 1; \
884   v[1]->x <<= 1; \
885   v[1]->y <<= 1; \
886   v[2]->x <<= 1; \
887   v[2]->y <<= 1; \
888 }
889
890 #define unshift_vertices3(v) { \
891   v[0]->x >>= 1; \
892   v[0]->y >>= 1; \
893   v[1]->x >>= 1; \
894   v[1]->y >>= 1; \
895   v[2]->x >>= 1; \
896   v[2]->y >>= 1; \
897 }
898
899 #define shift_triangle_area() \
900   psx_gpu->triangle_area *= 4
901
902 #ifndef NEON_BUILD
903 void scale2x_tiles8(void *dst, const void *src, int w8, int h)
904 {
905   uint16_t* d = (uint16_t*)dst;
906   const uint16_t* s = (const uint16_t*)src;
907
908   while ( h-- )
909   {
910     uint16_t* d_save = d;
911     const uint16_t* s_save = s;
912     int w = w8;
913
914     while ( w-- )
915     {
916       d[    0 ] = *s;
917       d[    1 ] = *s;
918       d[ 1024 ] = *s;
919       d[ 1025 ] = *s;
920       d += 2; s++;
921
922       d[    0 ] = *s;
923       d[    1 ] = *s;
924       d[ 1024 ] = *s;
925       d[ 1025 ] = *s;
926       d += 2; s++;
927
928       d[    0 ] = *s;
929       d[    1 ] = *s;
930       d[ 1024 ] = *s;
931       d[ 1025 ] = *s;
932       d += 2; s++;
933
934       d[    0 ] = *s;
935       d[    1 ] = *s;
936       d[ 1024 ] = *s;
937       d[ 1025 ] = *s;
938       d += 2; s++;
939
940       d[    0 ] = *s;
941       d[    1 ] = *s;
942       d[ 1024 ] = *s;
943       d[ 1025 ] = *s;
944       d += 2; s++;
945
946       d[    0 ] = *s;
947       d[    1 ] = *s;
948       d[ 1024 ] = *s;
949       d[ 1025 ] = *s;
950       d += 2; s++;
951
952       d[    0 ] = *s;
953       d[    1 ] = *s;
954       d[ 1024 ] = *s;
955       d[ 1025 ] = *s;
956       d += 2; s++;
957
958       d[    0 ] = *s;
959       d[    1 ] = *s;
960       d[ 1024 ] = *s;
961       d[ 1025 ] = *s;
962       d += 2; s++;
963     }
964
965     d = d_save + 2048;
966     s = s_save + 1024; /* or 512? */
967   }
968 }
969 #endif
970
971 static int disable_main_render;
972
973 static int check_enhanced_range(psx_gpu_struct *psx_gpu, int x, int x_end)
974 {
975   // reject to avoid oveflowing the 1024 width
976   // (assume some offscreen render-to-texture thing)
977   int fb_index;
978   if (x < 0)
979     return 1;
980   fb_index = select_enhancement_buf_index(psx_gpu, x);
981   if (x >= psx_gpu->enhancement_buf_start[fb_index] + 512)
982     return 0;
983
984   return 1;
985 }
986
987 static int is_in_array(int val, int array[], int len)
988 {
989   int i;
990   for (i = 0; i < len; i++)
991     if (array[i] == val)
992       return 1;
993   return 0;
994 }
995
996 static int make_members_unique(int array[], int len)
997 {
998   int i, j;
999   for (i = j = 1; i < len; i++)
1000     if (!is_in_array(array[i], array, j))
1001       array[j++] = array[i];
1002
1003   if (array[0] > array[1]) {
1004     i = array[0]; array[0] = array[1]; array[1] = i;
1005   }
1006   return j;
1007 }
1008
1009 static void patch_u(vertex_struct *vertex_ptrs, int count, int old, int new)
1010 {
1011   int i;
1012   for (i = 0; i < count; i++)
1013     if (vertex_ptrs[i].u == old)
1014       vertex_ptrs[i].u = new;
1015 }
1016
1017 static void patch_v(vertex_struct *vertex_ptrs, int count, int old, int new)
1018 {
1019   int i;
1020   for (i = 0; i < count; i++)
1021     if (vertex_ptrs[i].v == old)
1022       vertex_ptrs[i].v = new;
1023 }
1024
1025 static void uv_hack(vertex_struct *vertex_ptrs, int vertex_count)
1026 {
1027   int i, u[4], v[4];
1028
1029   for (i = 0; i < vertex_count; i++) {
1030     u[i] = vertex_ptrs[i].u;
1031     v[i] = vertex_ptrs[i].v;
1032   }
1033   if (make_members_unique(u, vertex_count) == 2 && u[1] - u[0] >= 8) {
1034     if ((u[0] & 7) == 7) {
1035       patch_u(vertex_ptrs, vertex_count, u[0], u[0] + 1);
1036       //printf("u hack: %3u-%3u -> %3u-%3u\n", u[0], u[1], u[0]+1, u[1]);
1037     }
1038     else if ((u[1] & 7) == 0 || u[1] - u[0] > 128) {
1039       patch_u(vertex_ptrs, vertex_count, u[1], u[1] - 1);
1040       //printf("u hack: %3u-%3u -> %3u-%3u\n", u[0], u[1], u[0], u[1]-1);
1041     }
1042   }
1043   if (make_members_unique(v, vertex_count) == 2 && ((v[0] - v[1]) & 7) == 0) {
1044     if ((v[0] & 7) == 7) {
1045       patch_v(vertex_ptrs, vertex_count, v[0], v[0] + 1);
1046       //printf("v hack: %3u-%3u -> %3u-%3u\n", v[0], v[1], v[0]+1, v[1]);
1047     }
1048     else if ((v[1] & 7) == 0) {
1049       patch_v(vertex_ptrs, vertex_count, v[1], v[1] - 1);
1050       //printf("v hack: %3u-%3u -> %3u-%3u\n", v[0], v[1], v[0], v[1]-1);
1051     }
1052   }
1053 }
1054
1055 static void do_triangle_enhanced(psx_gpu_struct *psx_gpu,
1056  vertex_struct *vertexes, u32 current_command)
1057 {
1058   vertex_struct *vertex_ptrs[3];
1059
1060   if (!prepare_triangle(psx_gpu, vertexes, vertex_ptrs))
1061     return;
1062
1063   if (!disable_main_render)
1064     render_triangle_p(psx_gpu, vertex_ptrs, current_command);
1065
1066   if (!check_enhanced_range(psx_gpu, vertex_ptrs[0]->x, vertex_ptrs[2]->x))
1067     return;
1068
1069   enhancement_enable();
1070   shift_vertices3(vertex_ptrs);
1071   shift_triangle_area();
1072   render_triangle_p(psx_gpu, vertex_ptrs, current_command);
1073   unshift_vertices3(vertex_ptrs);
1074 }
1075
1076 static void do_quad_enhanced(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
1077  u32 current_command)
1078 {
1079   do_triangle_enhanced(psx_gpu, vertexes, current_command);
1080   enhancement_disable();
1081   do_triangle_enhanced(psx_gpu, &vertexes[1], current_command);
1082 }
1083
1084 #if 0
1085
1086 #define fill_vertex(i, x_, y_, u_, v_, rgb_) \
1087   vertexes[i].x = x_; \
1088   vertexes[i].y = y_; \
1089   vertexes[i].u = u_; \
1090   vertexes[i].v = v_; \
1091   vertexes[i].r = rgb_; \
1092   vertexes[i].g = (rgb_) >> 8; \
1093   vertexes[i].b = (rgb_) >> 16
1094
1095 static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y,
1096  u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb)
1097 {
1098   vertex_struct *vertex_ptrs[3];
1099   u32 flags = (cmd_rgb >> 24);
1100   u32 color = cmd_rgb & 0xffffff;
1101   u32 render_state_base_saved = psx_gpu->render_state_base;
1102   int x1, y1;
1103   u8 u1, v1;
1104
1105   flags &=
1106    (RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND |
1107    RENDER_FLAGS_TEXTURE_MAP);
1108
1109   set_triangle_color(psx_gpu, color);
1110   if(color == 0x808080)
1111     flags |= RENDER_FLAGS_MODULATE_TEXELS;
1112
1113   psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
1114   enhancement_enable();
1115
1116   x1 = x + w;
1117   y1 = y + h;
1118   u1 = u + w;
1119   v1 = v + h;
1120   // FIXME..
1121   if (u1 < u) u1 = 0xff;
1122   if (v1 < v) v1 = 0xff;
1123
1124   // 0-2
1125   // |/
1126   // 1
1127   fill_vertex(0, x,  y,  u,  v,  color);
1128   fill_vertex(1, x,  y1, u,  v1, color);
1129   fill_vertex(2, x1, y,  u1, v,  color);
1130   if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
1131     shift_vertices3(vertex_ptrs);
1132     shift_triangle_area();
1133     render_triangle_p(psx_gpu, vertex_ptrs, flags);
1134   }
1135
1136   //   0
1137   //  /|
1138   // 1-2
1139   fill_vertex(0, x1, y,  u1, v,  color);
1140   fill_vertex(1, x,  y1, u,  v1, color);
1141   fill_vertex(2, x1, y1, u1, v1, color);
1142   if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
1143     shift_vertices3(vertex_ptrs);
1144     shift_triangle_area();
1145     render_triangle_p(psx_gpu, vertex_ptrs, flags);
1146   }
1147
1148   psx_gpu->render_state_base = render_state_base_saved;
1149 }
1150 #else
1151 static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y,
1152  u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb)
1153 {
1154   u32 flags = (cmd_rgb >> 24);
1155   u32 color = cmd_rgb & 0xffffff;
1156
1157   render_sprite_4x(psx_gpu, x, y, u, v, w, h, flags, color);
1158 }
1159 #endif
1160
1161 u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size,
1162  u32 *last_command)
1163 {
1164   vertex_struct vertexes[4] __attribute__((aligned(16))) = {};
1165   u32 current_command = 0, command_length;
1166
1167   u32 *list_start = list;
1168   u32 *list_end = list + (size / 4);
1169
1170   psx_gpu->saved_viewport_start_x = psx_gpu->viewport_start_x;
1171   psx_gpu->saved_viewport_start_y = psx_gpu->viewport_start_y;
1172   psx_gpu->saved_viewport_end_x = psx_gpu->viewport_end_x;
1173   psx_gpu->saved_viewport_end_y = psx_gpu->viewport_end_y;
1174   select_enhancement_buf(psx_gpu);
1175
1176   for(; list < list_end; list += 1 + command_length)
1177   {
1178     s16 *list_s16 = (void *)list;
1179     current_command = *list >> 24;
1180     command_length = command_lengths[current_command];
1181     if (list + 1 + command_length > list_end) {
1182       current_command = (u32)-1;
1183       break;
1184     }
1185
1186     enhancement_disable();
1187
1188     switch(current_command)
1189     {
1190       case 0x00:
1191         break;
1192   
1193       case 0x02:
1194       {
1195         u32 x = list_s16[2] & 0x3FF;
1196         u32 y = list_s16[3] & 0x1FF;
1197         u32 width = list_s16[4] & 0x3FF;
1198         u32 height = list_s16[5] & 0x1FF;
1199         u32 color = list[0] & 0xFFFFFF;
1200         u32 i1, i2;
1201
1202         x &= ~0xF;
1203         width = ((width + 0xF) & ~0xF);
1204         if (width == 0 || height == 0)
1205           break;
1206
1207         do_fill(psx_gpu, x, y, width, height, color);
1208
1209         i1 = select_enhancement_buf_index(psx_gpu, x);
1210         i2 = select_enhancement_buf_index(psx_gpu, x + width - 1);
1211         if (i1 != i2) {
1212           sync_enhancement_buffers(x, y, width, height);
1213           break;
1214         }
1215         if (x >= psx_gpu->enhancement_buf_start[i1] + psx_gpu->saved_hres)
1216           break;
1217
1218         psx_gpu->vram_out_ptr = select_enhancement_buf_ptr(psx_gpu, x);
1219         x *= 2;
1220         y *= 2;
1221         width *= 2;
1222         height *= 2;
1223         render_block_fill_enh(psx_gpu, color, x, y, width, height);
1224         break;
1225       }
1226   
1227       case 0x20 ... 0x23:
1228       {
1229         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1230   
1231         get_vertex_data_xy(0, 2);
1232         get_vertex_data_xy(1, 4);
1233         get_vertex_data_xy(2, 6);
1234
1235         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1236         break;
1237       }
1238   
1239       case 0x24 ... 0x27:
1240       {
1241         set_clut(psx_gpu, list_s16[5]);
1242         set_texture(psx_gpu, list_s16[9]);
1243         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1244   
1245         get_vertex_data_xy_uv(0, 2);
1246         get_vertex_data_xy_uv(1, 6);
1247         get_vertex_data_xy_uv(2, 10);
1248   
1249         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1250         break;
1251       }
1252   
1253       case 0x28 ... 0x2B:
1254       {
1255         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1256   
1257         get_vertex_data_xy(0, 2);
1258         get_vertex_data_xy(1, 4);
1259         get_vertex_data_xy(2, 6);
1260         get_vertex_data_xy(3, 8);
1261
1262         do_quad_enhanced(psx_gpu, vertexes, current_command);
1263         break;
1264       }
1265   
1266       case 0x2C ... 0x2F:
1267       {
1268         set_clut(psx_gpu, list_s16[5]);
1269         set_texture(psx_gpu, list_s16[9]);
1270         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1271   
1272         get_vertex_data_xy_uv(0, 2);   
1273         get_vertex_data_xy_uv(1, 6);   
1274         get_vertex_data_xy_uv(2, 10);  
1275         get_vertex_data_xy_uv(3, 14);
1276   
1277         uv_hack(vertexes, 4);
1278         do_quad_enhanced(psx_gpu, vertexes, current_command);
1279         break;
1280       }
1281   
1282       case 0x30 ... 0x33:
1283       {
1284         get_vertex_data_xy_rgb(0, 0);
1285         get_vertex_data_xy_rgb(1, 4);
1286         get_vertex_data_xy_rgb(2, 8);
1287   
1288         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1289         break;
1290       }
1291   
1292       case 0x34:
1293       case 0x35:
1294       case 0x36:
1295       case 0x37:
1296       {
1297         set_clut(psx_gpu, list_s16[5]);
1298         set_texture(psx_gpu, list_s16[11]);
1299   
1300         get_vertex_data_xy_uv_rgb(0, 0);
1301         get_vertex_data_xy_uv_rgb(1, 6);
1302         get_vertex_data_xy_uv_rgb(2, 12);
1303
1304         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1305         break;
1306       }
1307   
1308       case 0x38:
1309       case 0x39:
1310       case 0x3A:
1311       case 0x3B:
1312       {
1313         get_vertex_data_xy_rgb(0, 0);
1314         get_vertex_data_xy_rgb(1, 4);
1315         get_vertex_data_xy_rgb(2, 8);
1316         get_vertex_data_xy_rgb(3, 12);
1317   
1318         do_quad_enhanced(psx_gpu, vertexes, current_command);
1319         break;
1320       }
1321   
1322       case 0x3C:
1323       case 0x3D:
1324       case 0x3E:
1325       case 0x3F:
1326       {
1327         set_clut(psx_gpu, list_s16[5]);
1328         set_texture(psx_gpu, list_s16[11]);
1329   
1330         get_vertex_data_xy_uv_rgb(0, 0);
1331         get_vertex_data_xy_uv_rgb(1, 6);
1332         get_vertex_data_xy_uv_rgb(2, 12);
1333         get_vertex_data_xy_uv_rgb(3, 18);
1334
1335         uv_hack(vertexes, 4);
1336         do_quad_enhanced(psx_gpu, vertexes, current_command);
1337         break;
1338       }
1339   
1340       case 0x40 ... 0x47:
1341       {
1342         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
1343         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
1344         vertexes[1].x = list_s16[4] + psx_gpu->offset_x;
1345         vertexes[1].y = list_s16[5] + psx_gpu->offset_y;
1346
1347         render_line(psx_gpu, vertexes, current_command, list[0], 0);
1348         enhancement_enable();
1349         render_line(psx_gpu, vertexes, current_command, list[0], 1);
1350         break;
1351       }
1352   
1353       case 0x48 ... 0x4F:
1354       {
1355         u32 num_vertexes = 1;
1356         u32 *list_position = &(list[2]);
1357         u32 xy = list[1];
1358
1359         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1360         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1361       
1362         xy = *list_position;
1363         while(1)
1364         {
1365           vertexes[0] = vertexes[1];
1366
1367           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1368           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1369
1370           enhancement_disable();
1371           render_line(psx_gpu, vertexes, current_command, list[0], 0);
1372           enhancement_enable();
1373           render_line(psx_gpu, vertexes, current_command, list[0], 1);
1374
1375           list_position++;
1376           num_vertexes++;
1377
1378           if(list_position >= list_end)
1379           {
1380             current_command = (u32)-1;
1381             goto breakloop;
1382           }
1383
1384           xy = *list_position;
1385           if((xy & 0xF000F000) == 0x50005000)
1386             break;
1387         }
1388
1389         command_length += (num_vertexes - 2);
1390         break;
1391       }
1392   
1393       case 0x50 ... 0x57:
1394       {
1395         vertexes[0].r = list[0] & 0xFF;
1396         vertexes[0].g = (list[0] >> 8) & 0xFF;
1397         vertexes[0].b = (list[0] >> 16) & 0xFF;
1398         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
1399         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
1400
1401         vertexes[1].r = list[2] & 0xFF;
1402         vertexes[1].g = (list[2] >> 8) & 0xFF;
1403         vertexes[1].b = (list[2] >> 16) & 0xFF;
1404         vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
1405         vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
1406
1407         render_line(psx_gpu, vertexes, current_command, 0, 0);
1408         enhancement_enable();
1409         render_line(psx_gpu, vertexes, current_command, 0, 1);
1410         break;
1411       }
1412  
1413       case 0x58 ... 0x5F:
1414       {
1415         u32 num_vertexes = 1;
1416         u32 *list_position = &(list[2]);
1417         u32 color = list[0];
1418         u32 xy = list[1];
1419
1420         vertexes[1].r = color & 0xFF;
1421         vertexes[1].g = (color >> 8) & 0xFF;
1422         vertexes[1].b = (color >> 16) & 0xFF;
1423         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1424         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1425       
1426         color = list_position[0];
1427         while(1)
1428         {
1429           xy = list_position[1];
1430
1431           vertexes[0] = vertexes[1];
1432
1433           vertexes[1].r = color & 0xFF;
1434           vertexes[1].g = (color >> 8) & 0xFF;
1435           vertexes[1].b = (color >> 16) & 0xFF;
1436           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1437           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1438
1439           enhancement_disable();
1440           render_line(psx_gpu, vertexes, current_command, 0, 0);
1441           enhancement_enable();
1442           render_line(psx_gpu, vertexes, current_command, 0, 1);
1443
1444           list_position += 2;
1445           num_vertexes++;
1446
1447           if(list_position >= list_end)
1448           {
1449             current_command = (u32)-1;
1450             goto breakloop;
1451           }
1452
1453           color = list_position[0];
1454           if((color & 0xF000F000) == 0x50005000)
1455             break;
1456         }
1457
1458         command_length += ((num_vertexes - 2) * 2);
1459         break;
1460       }
1461   
1462       case 0x60 ... 0x63:
1463       {        
1464         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1465         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1466         u32 width = list_s16[4] & 0x3FF;
1467         u32 height = list_s16[5] & 0x1FF;
1468
1469         render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]);
1470
1471         if (check_enhanced_range(psx_gpu, x, x + width))
1472           do_sprite_enhanced(psx_gpu, x, y, 0, 0, width, height, list[0]);
1473         break;
1474       }
1475   
1476       case 0x64 ... 0x67:
1477       {        
1478         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1479         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1480         u8 u = list_s16[4];
1481         u8 v = list_s16[4] >> 8;
1482         u32 width = list_s16[6] & 0x3FF;
1483         u32 height = list_s16[7] & 0x1FF;
1484
1485         set_clut(psx_gpu, list_s16[5]);
1486
1487         render_sprite(psx_gpu, x, y, u, v, width, height,
1488          current_command, list[0]);
1489
1490         if (check_enhanced_range(psx_gpu, x, x + width))
1491           do_sprite_enhanced(psx_gpu, x, y, u, v, width, height, list[0]);
1492         break;
1493       }
1494   
1495       case 0x68:
1496       case 0x69:
1497       case 0x6A:
1498       case 0x6B:
1499       {
1500         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1501         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1502
1503         render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]);
1504
1505         if (check_enhanced_range(psx_gpu, x, x + 1))
1506           do_sprite_enhanced(psx_gpu, x, y, 0, 0, 1, 1, list[0]);
1507         break;
1508       }
1509   
1510       case 0x70:
1511       case 0x71:
1512       case 0x72:
1513       case 0x73:
1514       {        
1515         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1516         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1517
1518         render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]);
1519
1520         if (check_enhanced_range(psx_gpu, x, x + 8))
1521           do_sprite_enhanced(psx_gpu, x, y, 0, 0, 8, 8, list[0]);
1522         break;
1523       }
1524   
1525       case 0x74:
1526       case 0x75:
1527       case 0x76:
1528       case 0x77:
1529       {        
1530         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1531         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1532         u8 u = list_s16[4];
1533         u8 v = list_s16[4] >> 8;
1534
1535         set_clut(psx_gpu, list_s16[5]);
1536
1537         render_sprite(psx_gpu, x, y, u, v, 8, 8,
1538          current_command, list[0]);
1539
1540         if (check_enhanced_range(psx_gpu, x, x + 8))
1541           do_sprite_enhanced(psx_gpu, x, y, u, v, 8, 8, list[0]);
1542         break;
1543       }
1544   
1545       case 0x78:
1546       case 0x79:
1547       case 0x7A:
1548       case 0x7B:
1549       {        
1550         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1551         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1552
1553         render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]);
1554
1555         if (check_enhanced_range(psx_gpu, x, x + 16))
1556           do_sprite_enhanced(psx_gpu, x, y, 0, 0, 16, 16, list[0]);
1557         break;
1558       }
1559   
1560       case 0x7C:
1561       case 0x7D:
1562       case 0x7E:
1563       case 0x7F:
1564       {        
1565         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1566         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1567         u8 u = list_s16[4];
1568         u8 v = list_s16[4] >> 8;
1569
1570         set_clut(psx_gpu, list_s16[5]);
1571
1572         render_sprite(psx_gpu, x, y, u, v, 16, 16, current_command, list[0]);
1573
1574         if (check_enhanced_range(psx_gpu, x, x + 16))
1575           do_sprite_enhanced(psx_gpu, x, y, u, v, 16, 16, list[0]);
1576         break;
1577       }
1578   
1579       case 0x80:          //  vid -> vid
1580       {
1581         u32 sx = list_s16[2] & 0x3FF;
1582         u32 sy = list_s16[3] & 0x1FF;
1583         u32 dx = list_s16[4] & 0x3FF;
1584         u32 dy = list_s16[5] & 0x1FF;
1585         u32 w = ((list_s16[6] - 1) & 0x3FF) + 1;
1586         u32 h = ((list_s16[7] - 1) & 0x1FF) + 1;
1587
1588         if (sx == dx && sy == dy && psx_gpu->mask_msb == 0)
1589           break;
1590
1591         render_block_move(psx_gpu, sx, sy, dx, dy, w, h);
1592         sync_enhancement_buffers(dx, dy, w, h);
1593         break;
1594       }
1595  
1596       case 0xA0:          //  sys -> vid
1597       case 0xC0:          //  vid -> sys
1598         goto breakloop;
1599
1600       case 0xE1:
1601         set_texture(psx_gpu, list[0]);
1602
1603         if(list[0] & (1 << 9))
1604           psx_gpu->render_state_base |= RENDER_STATE_DITHER;
1605         else
1606           psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
1607
1608         psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1;
1609         SET_Ex(1, list[0]);
1610         break;
1611   
1612       case 0xE2:
1613       {
1614         // TODO: Clean
1615         u32 texture_window_settings = list[0];
1616         u32 tmp, x, y, w, h;
1617
1618         if(texture_window_settings != psx_gpu->texture_window_settings)
1619         {
1620           tmp = (texture_window_settings & 0x1F) | 0x20;
1621           for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1);
1622
1623           tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20;
1624           for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1);
1625
1626           tmp = 32 - (w >> 3);
1627           x = ((texture_window_settings >> 10) & tmp) << 3;
1628
1629           tmp = 32 - (h >> 3);
1630           y = ((texture_window_settings >> 15) & tmp) << 3;
1631
1632           flush_render_block_buffer(psx_gpu);
1633           
1634           psx_gpu->texture_window_settings = texture_window_settings;
1635           psx_gpu->texture_window_x = x;
1636           psx_gpu->texture_window_y = y;
1637           psx_gpu->texture_mask_width = w - 1;
1638           psx_gpu->texture_mask_height = h - 1;
1639
1640           update_texture_ptr(psx_gpu);
1641         }
1642         SET_Ex(2, list[0]);
1643         break;
1644       }
1645   
1646       case 0xE3:
1647       {
1648         s16 viewport_start_x = list[0] & 0x3FF;
1649         s16 viewport_start_y = (list[0] >> 10) & 0x1FF;
1650         u32 w;
1651         s32 d;
1652
1653         if(viewport_start_x == psx_gpu->viewport_start_x &&
1654          viewport_start_y == psx_gpu->viewport_start_y)
1655         {
1656           break;
1657         }
1658         psx_gpu->viewport_start_x = viewport_start_x;
1659         psx_gpu->viewport_start_y = viewport_start_y;
1660         psx_gpu->saved_viewport_start_x = viewport_start_x;
1661         psx_gpu->saved_viewport_start_y = viewport_start_y;
1662
1663         w = (u32)psx_gpu->viewport_end_x - (u32)viewport_start_x + 1;
1664         d = psx_gpu->saved_hres - w;
1665         if(-16 <= d && d <= 16)
1666         {
1667           update_enhancement_buf_table_from_x(psx_gpu,
1668            viewport_start_x, w);
1669         }
1670         select_enhancement_buf(psx_gpu);
1671
1672 #ifdef TEXTURE_CACHE_4BPP
1673         psx_gpu->viewport_mask =
1674          texture_region_mask(psx_gpu->viewport_start_x,
1675          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
1676          psx_gpu->viewport_end_y);
1677 #endif
1678         SET_Ex(3, list[0]);
1679         break;
1680       }
1681
1682       case 0xE4:
1683       {
1684         s16 viewport_end_x = list[0] & 0x3FF;
1685         s16 viewport_end_y = (list[0] >> 10) & 0x1FF;
1686         u32 w;
1687         s32 d;
1688
1689         if(viewport_end_x == psx_gpu->viewport_end_x &&
1690          viewport_end_y == psx_gpu->viewport_end_y)
1691         {
1692           break;
1693         }
1694
1695         psx_gpu->viewport_end_x = viewport_end_x;
1696         psx_gpu->viewport_end_y = viewport_end_y;
1697         psx_gpu->saved_viewport_end_x = viewport_end_x;
1698         psx_gpu->saved_viewport_end_y = viewport_end_y;
1699
1700         w = (u32)viewport_end_x - (u32)psx_gpu->viewport_start_x + 1;
1701         d = psx_gpu->saved_hres - w;
1702         if(-16 <= d && d <= 16)
1703         {
1704           update_enhancement_buf_table_from_x(psx_gpu,
1705            psx_gpu->viewport_start_x, w);
1706         }
1707         select_enhancement_buf(psx_gpu);
1708
1709 #ifdef TEXTURE_CACHE_4BPP
1710         psx_gpu->viewport_mask =
1711          texture_region_mask(psx_gpu->viewport_start_x,
1712          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
1713          psx_gpu->viewport_end_y);
1714 #endif
1715         SET_Ex(4, list[0]);
1716         break;
1717       }
1718   
1719       case 0xE5:
1720       {
1721         s32 offset_x = list[0] << 21;
1722         s32 offset_y = list[0] << 10;
1723         psx_gpu->offset_x = offset_x >> 21;
1724         psx_gpu->offset_y = offset_y >> 21; 
1725   
1726         SET_Ex(5, list[0]);
1727         break;
1728       }
1729
1730       case 0xE6:
1731       {
1732         u32 mask_settings = list[0];
1733         u16 mask_msb = mask_settings << 15;
1734
1735         if(list[0] & 0x2)
1736           psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE;
1737         else
1738           psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE;
1739
1740         if(mask_msb != psx_gpu->mask_msb)
1741         {
1742           flush_render_block_buffer(psx_gpu);
1743           psx_gpu->mask_msb = mask_msb;
1744         }
1745
1746         SET_Ex(6, list[0]);
1747         break;
1748       }
1749   
1750       default:
1751         break;
1752     }
1753   }
1754
1755   enhancement_disable();
1756
1757 breakloop:
1758   if (last_command != NULL)
1759     *last_command = current_command;
1760   return list - list_start;
1761 }
1762
1763 #endif /* PCSX */
1764
1765 // vim:ts=2:shiftwidth=2:expandtab