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