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