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