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