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