gpu_neon: rework buffer selection
[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 = 0x1000; \
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 void do_triangle_enhanced(psx_gpu_struct *psx_gpu,
984  vertex_struct *vertexes, u32 current_command)
985 {
986   vertex_struct *vertex_ptrs[3];
987
988   if (!prepare_triangle(psx_gpu, vertexes, vertex_ptrs))
989     return;
990
991   if (!disable_main_render)
992     render_triangle_p(psx_gpu, vertex_ptrs, current_command);
993
994   if (!check_enhanced_range(psx_gpu, vertex_ptrs[0]->x, vertex_ptrs[2]->x))
995     return;
996
997   enhancement_enable();
998   shift_vertices3(vertex_ptrs);
999   shift_triangle_area();
1000   render_triangle_p(psx_gpu, vertex_ptrs, current_command);
1001   unshift_vertices3(vertex_ptrs);
1002 }
1003
1004 static void do_quad_enhanced(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
1005  u32 current_command)
1006 {
1007   do_triangle_enhanced(psx_gpu, vertexes, current_command);
1008   enhancement_disable();
1009   do_triangle_enhanced(psx_gpu, &vertexes[1], current_command);
1010 }
1011
1012 #if 0
1013
1014 #define fill_vertex(i, x_, y_, u_, v_, rgb_) \
1015   vertexes[i].x = x_; \
1016   vertexes[i].y = y_; \
1017   vertexes[i].u = u_; \
1018   vertexes[i].v = v_; \
1019   vertexes[i].r = rgb_; \
1020   vertexes[i].g = (rgb_) >> 8; \
1021   vertexes[i].b = (rgb_) >> 16
1022
1023 static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y,
1024  u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb)
1025 {
1026   vertex_struct *vertex_ptrs[3];
1027   u32 flags = (cmd_rgb >> 24);
1028   u32 color = cmd_rgb & 0xffffff;
1029   u32 render_state_base_saved = psx_gpu->render_state_base;
1030   int x1, y1;
1031   u8 u1, v1;
1032
1033   flags &=
1034    (RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND |
1035    RENDER_FLAGS_TEXTURE_MAP);
1036
1037   set_triangle_color(psx_gpu, color);
1038   if(color == 0x808080)
1039     flags |= RENDER_FLAGS_MODULATE_TEXELS;
1040
1041   psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
1042   enhancement_enable();
1043
1044   x1 = x + w;
1045   y1 = y + h;
1046   u1 = u + w;
1047   v1 = v + h;
1048   // FIXME..
1049   if (u1 < u) u1 = 0xff;
1050   if (v1 < v) v1 = 0xff;
1051
1052   // 0-2
1053   // |/
1054   // 1
1055   fill_vertex(0, x,  y,  u,  v,  color);
1056   fill_vertex(1, x,  y1, u,  v1, color);
1057   fill_vertex(2, x1, y,  u1, v,  color);
1058   if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
1059     shift_vertices3(vertex_ptrs);
1060     shift_triangle_area();
1061     render_triangle_p(psx_gpu, vertex_ptrs, flags);
1062   }
1063
1064   //   0
1065   //  /|
1066   // 1-2
1067   fill_vertex(0, x1, y,  u1, v,  color);
1068   fill_vertex(1, x,  y1, u,  v1, color);
1069   fill_vertex(2, x1, y1, u1, v1, color);
1070   if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) {
1071     shift_vertices3(vertex_ptrs);
1072     shift_triangle_area();
1073     render_triangle_p(psx_gpu, vertex_ptrs, flags);
1074   }
1075
1076   psx_gpu->render_state_base = render_state_base_saved;
1077 }
1078 #else
1079 static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y,
1080  u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb)
1081 {
1082   u32 flags = (cmd_rgb >> 24);
1083   u32 color = cmd_rgb & 0xffffff;
1084
1085   render_sprite_4x(psx_gpu, x, y, u, v, w, h, flags, color);
1086 }
1087 #endif
1088
1089 u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size,
1090  u32 *last_command)
1091 {
1092   vertex_struct vertexes[4] __attribute__((aligned(16))) = {};
1093   u32 current_command = 0, command_length;
1094
1095   u32 *list_start = list;
1096   u32 *list_end = list + (size / 4);
1097
1098   psx_gpu->saved_viewport_start_x = psx_gpu->viewport_start_x;
1099   psx_gpu->saved_viewport_start_y = psx_gpu->viewport_start_y;
1100   psx_gpu->saved_viewport_end_x = psx_gpu->viewport_end_x;
1101   psx_gpu->saved_viewport_end_y = psx_gpu->viewport_end_y;
1102   select_enhancement_buf(psx_gpu);
1103
1104   for(; list < list_end; list += 1 + command_length)
1105   {
1106     s16 *list_s16 = (void *)list;
1107     current_command = *list >> 24;
1108     command_length = command_lengths[current_command];
1109     if (list + 1 + command_length > list_end) {
1110       current_command = (u32)-1;
1111       break;
1112     }
1113
1114     enhancement_disable();
1115
1116     switch(current_command)
1117     {
1118       case 0x00:
1119         break;
1120   
1121       case 0x02:
1122       {
1123         u32 x = list_s16[2] & 0x3FF;
1124         u32 y = list_s16[3] & 0x1FF;
1125         u32 width = list_s16[4] & 0x3FF;
1126         u32 height = list_s16[5] & 0x1FF;
1127         u32 color = list[0] & 0xFFFFFF;
1128         u32 i1, i2;
1129
1130         x &= ~0xF;
1131         width = ((width + 0xF) & ~0xF);
1132         if (width == 0 || height == 0)
1133           break;
1134
1135         do_fill(psx_gpu, x, y, width, height, color);
1136
1137         i1 = select_enhancement_buf_index(psx_gpu, x);
1138         i2 = select_enhancement_buf_index(psx_gpu, x + width - 1);
1139         if (i1 != i2) {
1140           sync_enhancement_buffers(x, y, width, height);
1141           break;
1142         }
1143         if (x >= psx_gpu->enhancement_buf_start[i1] + psx_gpu->saved_hres)
1144           break;
1145
1146         psx_gpu->vram_out_ptr = select_enhancement_buf_ptr(psx_gpu, x);
1147         x *= 2;
1148         y *= 2;
1149         width *= 2;
1150         height *= 2;
1151         render_block_fill_enh(psx_gpu, color, x, y, width, height);
1152         break;
1153       }
1154   
1155       case 0x20 ... 0x23:
1156       {
1157         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1158   
1159         get_vertex_data_xy(0, 2);
1160         get_vertex_data_xy(1, 4);
1161         get_vertex_data_xy(2, 6);
1162
1163         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1164         break;
1165       }
1166   
1167       case 0x24 ... 0x27:
1168       {
1169         set_clut(psx_gpu, list_s16[5]);
1170         set_texture(psx_gpu, list_s16[9]);
1171         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1172   
1173         get_vertex_data_xy_uv(0, 2);
1174         get_vertex_data_xy_uv(1, 6);
1175         get_vertex_data_xy_uv(2, 10);
1176   
1177         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1178         break;
1179       }
1180   
1181       case 0x28 ... 0x2B:
1182       {
1183         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1184   
1185         get_vertex_data_xy(0, 2);
1186         get_vertex_data_xy(1, 4);
1187         get_vertex_data_xy(2, 6);
1188         get_vertex_data_xy(3, 8);
1189
1190         do_quad_enhanced(psx_gpu, vertexes, current_command);
1191         break;
1192       }
1193   
1194       case 0x2C ... 0x2F:
1195       {
1196         set_clut(psx_gpu, list_s16[5]);
1197         set_texture(psx_gpu, list_s16[9]);
1198         set_triangle_color(psx_gpu, list[0] & 0xFFFFFF);
1199   
1200         get_vertex_data_xy_uv(0, 2);   
1201         get_vertex_data_xy_uv(1, 6);   
1202         get_vertex_data_xy_uv(2, 10);  
1203         get_vertex_data_xy_uv(3, 14);
1204   
1205         do_quad_enhanced(psx_gpu, vertexes, current_command);
1206         break;
1207       }
1208   
1209       case 0x30 ... 0x33:
1210       {
1211         get_vertex_data_xy_rgb(0, 0);
1212         get_vertex_data_xy_rgb(1, 4);
1213         get_vertex_data_xy_rgb(2, 8);
1214   
1215         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1216         break;
1217       }
1218   
1219       case 0x34:
1220       case 0x35:
1221       case 0x36:
1222       case 0x37:
1223       {
1224         set_clut(psx_gpu, list_s16[5]);
1225         set_texture(psx_gpu, list_s16[11]);
1226   
1227         get_vertex_data_xy_uv_rgb(0, 0);
1228         get_vertex_data_xy_uv_rgb(1, 6);
1229         get_vertex_data_xy_uv_rgb(2, 12);
1230
1231         do_triangle_enhanced(psx_gpu, vertexes, current_command);
1232         break;
1233       }
1234   
1235       case 0x38:
1236       case 0x39:
1237       case 0x3A:
1238       case 0x3B:
1239       {
1240         get_vertex_data_xy_rgb(0, 0);
1241         get_vertex_data_xy_rgb(1, 4);
1242         get_vertex_data_xy_rgb(2, 8);
1243         get_vertex_data_xy_rgb(3, 12);
1244   
1245         do_quad_enhanced(psx_gpu, vertexes, current_command);
1246         break;
1247       }
1248   
1249       case 0x3C:
1250       case 0x3D:
1251       case 0x3E:
1252       case 0x3F:
1253       {
1254         set_clut(psx_gpu, list_s16[5]);
1255         set_texture(psx_gpu, list_s16[11]);
1256   
1257         get_vertex_data_xy_uv_rgb(0, 0);
1258         get_vertex_data_xy_uv_rgb(1, 6);
1259         get_vertex_data_xy_uv_rgb(2, 12);
1260         get_vertex_data_xy_uv_rgb(3, 18);
1261
1262         do_quad_enhanced(psx_gpu, vertexes, current_command);
1263         break;
1264       }
1265   
1266       case 0x40 ... 0x47:
1267       {
1268         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
1269         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
1270         vertexes[1].x = list_s16[4] + psx_gpu->offset_x;
1271         vertexes[1].y = list_s16[5] + psx_gpu->offset_y;
1272
1273         render_line(psx_gpu, vertexes, current_command, list[0], 0);
1274         enhancement_enable();
1275         render_line(psx_gpu, vertexes, current_command, list[0], 1);
1276         break;
1277       }
1278   
1279       case 0x48 ... 0x4F:
1280       {
1281         u32 num_vertexes = 1;
1282         u32 *list_position = &(list[2]);
1283         u32 xy = list[1];
1284
1285         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1286         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1287       
1288         xy = *list_position;
1289         while(1)
1290         {
1291           vertexes[0] = vertexes[1];
1292
1293           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1294           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1295
1296           enhancement_disable();
1297           render_line(psx_gpu, vertexes, current_command, list[0], 0);
1298           enhancement_enable();
1299           render_line(psx_gpu, vertexes, current_command, list[0], 1);
1300
1301           list_position++;
1302           num_vertexes++;
1303
1304           if(list_position >= list_end)
1305           {
1306             current_command = (u32)-1;
1307             goto breakloop;
1308           }
1309
1310           xy = *list_position;
1311           if((xy & 0xF000F000) == 0x50005000)
1312             break;
1313         }
1314
1315         command_length += (num_vertexes - 2);
1316         break;
1317       }
1318   
1319       case 0x50 ... 0x57:
1320       {
1321         vertexes[0].r = list[0] & 0xFF;
1322         vertexes[0].g = (list[0] >> 8) & 0xFF;
1323         vertexes[0].b = (list[0] >> 16) & 0xFF;
1324         vertexes[0].x = list_s16[2] + psx_gpu->offset_x;
1325         vertexes[0].y = list_s16[3] + psx_gpu->offset_y;
1326
1327         vertexes[1].r = list[2] & 0xFF;
1328         vertexes[1].g = (list[2] >> 8) & 0xFF;
1329         vertexes[1].b = (list[2] >> 16) & 0xFF;
1330         vertexes[1].x = list_s16[6] + psx_gpu->offset_x;
1331         vertexes[1].y = list_s16[7] + psx_gpu->offset_y;
1332
1333         render_line(psx_gpu, vertexes, current_command, 0, 0);
1334         enhancement_enable();
1335         render_line(psx_gpu, vertexes, current_command, 0, 1);
1336         break;
1337       }
1338  
1339       case 0x58 ... 0x5F:
1340       {
1341         u32 num_vertexes = 1;
1342         u32 *list_position = &(list[2]);
1343         u32 color = list[0];
1344         u32 xy = list[1];
1345
1346         vertexes[1].r = color & 0xFF;
1347         vertexes[1].g = (color >> 8) & 0xFF;
1348         vertexes[1].b = (color >> 16) & 0xFF;
1349         vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1350         vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1351       
1352         color = list_position[0];
1353         while(1)
1354         {
1355           xy = list_position[1];
1356
1357           vertexes[0] = vertexes[1];
1358
1359           vertexes[1].r = color & 0xFF;
1360           vertexes[1].g = (color >> 8) & 0xFF;
1361           vertexes[1].b = (color >> 16) & 0xFF;
1362           vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x;
1363           vertexes[1].y = (xy >> 16) + psx_gpu->offset_y;
1364
1365           enhancement_disable();
1366           render_line(psx_gpu, vertexes, current_command, 0, 0);
1367           enhancement_enable();
1368           render_line(psx_gpu, vertexes, current_command, 0, 1);
1369
1370           list_position += 2;
1371           num_vertexes++;
1372
1373           if(list_position >= list_end)
1374           {
1375             current_command = (u32)-1;
1376             goto breakloop;
1377           }
1378
1379           color = list_position[0];
1380           if((color & 0xF000F000) == 0x50005000)
1381             break;
1382         }
1383
1384         command_length += ((num_vertexes - 2) * 2);
1385         break;
1386       }
1387   
1388       case 0x60 ... 0x63:
1389       {        
1390         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1391         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1392         u32 width = list_s16[4] & 0x3FF;
1393         u32 height = list_s16[5] & 0x1FF;
1394
1395         render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]);
1396
1397         if (check_enhanced_range(psx_gpu, x, x + width))
1398           do_sprite_enhanced(psx_gpu, x, y, 0, 0, width, height, list[0]);
1399         break;
1400       }
1401   
1402       case 0x64 ... 0x67:
1403       {        
1404         u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1405         u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1406         u8 u = list_s16[4];
1407         u8 v = list_s16[4] >> 8;
1408         u32 width = list_s16[6] & 0x3FF;
1409         u32 height = list_s16[7] & 0x1FF;
1410
1411         set_clut(psx_gpu, list_s16[5]);
1412
1413         render_sprite(psx_gpu, x, y, u, v, width, height,
1414          current_command, list[0]);
1415
1416         if (check_enhanced_range(psx_gpu, x, x + width))
1417           do_sprite_enhanced(psx_gpu, x, y, u, v, width, height, list[0]);
1418         break;
1419       }
1420   
1421       case 0x68:
1422       case 0x69:
1423       case 0x6A:
1424       case 0x6B:
1425       {
1426         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1427         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1428
1429         render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]);
1430
1431         if (check_enhanced_range(psx_gpu, x, x + 1))
1432           do_sprite_enhanced(psx_gpu, x, y, 0, 0, 1, 1, list[0]);
1433         break;
1434       }
1435   
1436       case 0x70:
1437       case 0x71:
1438       case 0x72:
1439       case 0x73:
1440       {        
1441         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1442         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1443
1444         render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]);
1445
1446         if (check_enhanced_range(psx_gpu, x, x + 8))
1447           do_sprite_enhanced(psx_gpu, x, y, 0, 0, 8, 8, list[0]);
1448         break;
1449       }
1450   
1451       case 0x74:
1452       case 0x75:
1453       case 0x76:
1454       case 0x77:
1455       {        
1456         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1457         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1458         u8 u = list_s16[4];
1459         u8 v = list_s16[4] >> 8;
1460
1461         set_clut(psx_gpu, list_s16[5]);
1462
1463         render_sprite(psx_gpu, x, y, u, v, 8, 8,
1464          current_command, list[0]);
1465
1466         if (check_enhanced_range(psx_gpu, x, x + 8))
1467           do_sprite_enhanced(psx_gpu, x, y, u, v, 8, 8, list[0]);
1468         break;
1469       }
1470   
1471       case 0x78:
1472       case 0x79:
1473       case 0x7A:
1474       case 0x7B:
1475       {        
1476         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1477         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1478
1479         render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]);
1480
1481         if (check_enhanced_range(psx_gpu, x, x + 16))
1482           do_sprite_enhanced(psx_gpu, x, y, 0, 0, 16, 16, list[0]);
1483         break;
1484       }
1485   
1486       case 0x7C:
1487       case 0x7D:
1488       case 0x7E:
1489       case 0x7F:
1490       {        
1491         s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x);
1492         s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y);
1493         u8 u = list_s16[4];
1494         u8 v = list_s16[4] >> 8;
1495
1496         set_clut(psx_gpu, list_s16[5]);
1497
1498         render_sprite(psx_gpu, x, y, u, v, 16, 16, current_command, list[0]);
1499
1500         if (check_enhanced_range(psx_gpu, x, x + 16))
1501           do_sprite_enhanced(psx_gpu, x, y, u, v, 16, 16, list[0]);
1502         break;
1503       }
1504   
1505       case 0x80:          //  vid -> vid
1506       {
1507         u32 sx = list_s16[2] & 0x3FF;
1508         u32 sy = list_s16[3] & 0x1FF;
1509         u32 dx = list_s16[4] & 0x3FF;
1510         u32 dy = list_s16[5] & 0x1FF;
1511         u32 w = ((list_s16[6] - 1) & 0x3FF) + 1;
1512         u32 h = ((list_s16[7] - 1) & 0x1FF) + 1;
1513
1514         if (sx == dx && sy == dy && psx_gpu->mask_msb == 0)
1515           break;
1516
1517         render_block_move(psx_gpu, sx, sy, dx, dy, w, h);
1518         sync_enhancement_buffers(dx, dy, w, h);
1519         break;
1520       }
1521  
1522       case 0xA0:          //  sys -> vid
1523       case 0xC0:          //  vid -> sys
1524         goto breakloop;
1525
1526       case 0xE1:
1527         set_texture(psx_gpu, list[0]);
1528
1529         if(list[0] & (1 << 9))
1530           psx_gpu->render_state_base |= RENDER_STATE_DITHER;
1531         else
1532           psx_gpu->render_state_base &= ~RENDER_STATE_DITHER;
1533
1534         psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1;
1535         SET_Ex(1, list[0]);
1536         break;
1537   
1538       case 0xE2:
1539       {
1540         // TODO: Clean
1541         u32 texture_window_settings = list[0];
1542         u32 tmp, x, y, w, h;
1543
1544         if(texture_window_settings != psx_gpu->texture_window_settings)
1545         {
1546           tmp = (texture_window_settings & 0x1F) | 0x20;
1547           for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1);
1548
1549           tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20;
1550           for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1);
1551
1552           tmp = 32 - (w >> 3);
1553           x = ((texture_window_settings >> 10) & tmp) << 3;
1554
1555           tmp = 32 - (h >> 3);
1556           y = ((texture_window_settings >> 15) & tmp) << 3;
1557
1558           flush_render_block_buffer(psx_gpu);
1559           
1560           psx_gpu->texture_window_settings = texture_window_settings;
1561           psx_gpu->texture_window_x = x;
1562           psx_gpu->texture_window_y = y;
1563           psx_gpu->texture_mask_width = w - 1;
1564           psx_gpu->texture_mask_height = h - 1;
1565
1566           update_texture_ptr(psx_gpu);
1567         }
1568         SET_Ex(2, list[0]);
1569         break;
1570       }
1571   
1572       case 0xE3:
1573       {
1574         s16 viewport_start_x = list[0] & 0x3FF;
1575         s16 viewport_start_y = (list[0] >> 10) & 0x1FF;
1576         u32 w;
1577         s32 d;
1578
1579         if(viewport_start_x == psx_gpu->viewport_start_x &&
1580          viewport_start_y == psx_gpu->viewport_start_y)
1581         {
1582           break;
1583         }
1584         psx_gpu->viewport_start_x = viewport_start_x;
1585         psx_gpu->viewport_start_y = viewport_start_y;
1586         psx_gpu->saved_viewport_start_x = viewport_start_x;
1587         psx_gpu->saved_viewport_start_y = viewport_start_y;
1588
1589         w = (u32)psx_gpu->viewport_end_x - (u32)viewport_start_x + 1;
1590         d = psx_gpu->saved_hres - w;
1591         if(-16 <= d && d <= 16)
1592         {
1593           update_enhancement_buf_table_from_x(psx_gpu,
1594            viewport_start_x, w);
1595         }
1596         select_enhancement_buf(psx_gpu);
1597
1598 #ifdef TEXTURE_CACHE_4BPP
1599         psx_gpu->viewport_mask =
1600          texture_region_mask(psx_gpu->viewport_start_x,
1601          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
1602          psx_gpu->viewport_end_y);
1603 #endif
1604         SET_Ex(3, list[0]);
1605         break;
1606       }
1607
1608       case 0xE4:
1609       {
1610         s16 viewport_end_x = list[0] & 0x3FF;
1611         s16 viewport_end_y = (list[0] >> 10) & 0x1FF;
1612         u32 w;
1613         s32 d;
1614
1615         if(viewport_end_x == psx_gpu->viewport_end_x &&
1616          viewport_end_y == psx_gpu->viewport_end_y)
1617         {
1618           break;
1619         }
1620
1621         psx_gpu->viewport_end_x = viewport_end_x;
1622         psx_gpu->viewport_end_y = viewport_end_y;
1623         psx_gpu->saved_viewport_end_x = viewport_end_x;
1624         psx_gpu->saved_viewport_end_y = viewport_end_y;
1625
1626         w = (u32)viewport_end_x - (u32)psx_gpu->viewport_start_x + 1;
1627         d = psx_gpu->saved_hres - w;
1628         if(-16 <= d && d <= 16)
1629         {
1630           update_enhancement_buf_table_from_x(psx_gpu,
1631            psx_gpu->viewport_start_x, w);
1632         }
1633         select_enhancement_buf(psx_gpu);
1634
1635 #ifdef TEXTURE_CACHE_4BPP
1636         psx_gpu->viewport_mask =
1637          texture_region_mask(psx_gpu->viewport_start_x,
1638          psx_gpu->viewport_start_y, psx_gpu->viewport_end_x,
1639          psx_gpu->viewport_end_y);
1640 #endif
1641         SET_Ex(4, list[0]);
1642         break;
1643       }
1644   
1645       case 0xE5:
1646       {
1647         s32 offset_x = list[0] << 21;
1648         s32 offset_y = list[0] << 10;
1649         psx_gpu->offset_x = offset_x >> 21;
1650         psx_gpu->offset_y = offset_y >> 21; 
1651   
1652         SET_Ex(5, list[0]);
1653         break;
1654       }
1655
1656       case 0xE6:
1657       {
1658         u32 mask_settings = list[0];
1659         u16 mask_msb = mask_settings << 15;
1660
1661         if(list[0] & 0x2)
1662           psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE;
1663         else
1664           psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE;
1665
1666         if(mask_msb != psx_gpu->mask_msb)
1667         {
1668           flush_render_block_buffer(psx_gpu);
1669           psx_gpu->mask_msb = mask_msb;
1670         }
1671
1672         SET_Ex(6, list[0]);
1673         break;
1674       }
1675   
1676       default:
1677         break;
1678     }
1679   }
1680
1681   enhancement_disable();
1682
1683 breakloop:
1684   if (last_command != NULL)
1685     *last_command = current_command;
1686   return list - list_start;
1687 }
1688
1689 #endif /* PCSX */
1690
1691 // vim:ts=2:shiftwidth=2:expandtab