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