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