OSDN Git Service

[VM][FMTOWNS][VRAM][WIP] Implementing.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / towns_vram.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Kyuma Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2016.12.28 -
6
7         [ FM-Towns VRAM ]
8         History: 2017.01.16 Initial.
9 */
10
11 #include "common.h"
12 #include "./towns_vram.h"
13
14 #define CLEAR_COLOR RGBA_COLOR(0,0,0,0)
15
16 #if defined(_RGB888)
17 #define _USE_ALPHA_CHANNEL
18 #endif
19
20 namespace FMTOWNS {
21
22 void TOWNS_VRAM::initialize()
23 {
24         for(int i = 0; i < 32768; i++) {
25                 uint8_t g = (i / (32 * 32)) & 0x1f;
26                 uint8_t r = (i / 32) & 0x1f;
27                 uint8_t b = i & 0x1f;
28                 table_32768c[i] = RGBA_COLOR(r << 3, g << 3, b << 3, 0xff);
29                 table_32768c[i + 32768] = table_32768c[i];
30                 alpha_32768c[i] = RGBA_COLOR(255, 255, 255, 255);
31                 alpha_32768c[i + 32768] = RGBA_COLOR(0, 0, 0, 0);
32                 mask_32768c[i] = 0xffff;
33                 mask_32768c[i + 32768] = 0x0000;
34         }
35         for(int i = 0; i < 256; i++) {
36                 int chigh = i & 0xf0;
37                 int clow  = i & 0x0f;
38                 uint8_t alpha;
39                 alpha_16c[ i << 2     ] = (chigh == 0) ? RGBA_COLOR(0, 0, 0, 0) : RGBA_COLOR(255, 255, 255, 255);
40                 alpha_16c[(i << 2) + 1] = (clow  == 0) ? RGBA_COLOR(0, 0, 0, 0) : RGBA_COLOR(255, 255, 255, 255);
41                 mask_16c[i] = ((chigh == 0) ? 0x00: 0xf0) | ((clow == 0) ? 0x00 : 0x0f);
42         }
43         for(int i = 0; i < TOWNS_CRTC_MAX_LINES; i++) {
44                 line_rendered[0][i] = false;
45                 line_rendered[1][i] = false;
46         }
47
48 }
49 uint32_t TOWNS_VRAM::read_data8(uint32_t addr)
50 {
51         // ToDo:Offset.
52         // ToDo: Wait.
53 #ifdef __LITTLE_ENDIAN__
54         uint8_t*p = (uint8_t*)vram;
55         return (uint32_t)(p[addr & 0x7ffff]);
56 #else
57         pair16_t d;
58         d.w= vram[(addr & 0x7ffff) >> 1];
59         if((addr & 0x01) == 0) { // Hi
60                 return (uint32_t)(d.b.h);
61         } else { // Lo
62                 return (uint32_t)(d.b.l);
63         }
64 #endif  
65 }
66
67
68
69 uint32_t TOWNS_VRAM::read_data16(uint32_t addr)
70 {
71         // ToDo:Offset.
72         // ToDo: Wait.
73         // Host: Little endian
74         // ToDo: Mask Register.
75         uint32_t naddr = (addr & 0x7fffe) >> 1;
76 #ifdef __LITTLE_ENDIAN__
77         uint16_t w = vram[naddr];
78         return (uint32_t)w;
79 #else // __BIG_ENDIAN__ 
80         pair16_t nw;
81         nw.w = vram[naddr];
82         return (uint32_t)(nw.w);
83 #endif
84 }
85
86 uint32_t TOWNS_VRAM::read_data32(uint32_t addr)
87 {
88         // ToDo: Wait.
89         // ToDo: Mask Register.
90 #ifdef __LITTLE_ENDIAN__
91         uint32_t*p = (uint32_t*)vram;
92         uint32_t naddr = (addr & 0x7ffff) >> 2;
93         uint32_t w = p[naddr];
94         return w;
95 #else // __BIG_ENDIAN__ 
96         pair32_t nd;
97         uint32_t naddr = (addr & 0x7ffff) >> 1;
98         nd.w.l = vram[naddr];
99         nd.w.h = vram[naddr + 1];;
100         return nd.d;
101 #endif
102 }
103
104 void TOWNS_VRAM::write_data8(uint32_t addr, uint32_t data)
105 {
106         // ToDo:Offset.
107         // ToDo: Wait.
108         // ToDo: Mask Register.
109         bool dirty;
110         uint32_t naddr = addr & 0x7ffff;
111         
112 #ifdef __LITTLE_ENDIAN__
113         uint8_t* p = (uint8_t*)vram;
114         n = p[naddr];
115 #else
116         pair16_t d;
117         // ToDo: Mask register
118         d.w = vram[naddr >> 1];
119         if((addr & 0x01) != 0) { // Hi
120                 n = d.b.h;
121                 d.b.h = data;
122         } else { // Lo
123                 n = d.b.l;
124                 d.b.l = data;
125         }
126 #endif
127         // ToDo: Mask register
128         
129         dirty = ((uint8_t)data != n) ? true : false;
130
131         if(dirty) {
132                 dirty_flag[naddr >> 3] = true;
133         // ToDo: Mask register
134 #ifdef __LITTLE_ENDIAN__
135                 p[naddr] = data;
136 #else
137                 vram[naddr >> 1] = d.w; 
138 #endif
139         }
140 }
141
142 void TOWNS_VRAM::write_data16(uint32_t addr, uint32_t data)
143 {
144         // ToDo:Offset.
145         // ToDo: Wait.
146         bool dirty;
147         uint32_t naddr = (addr & 0x7fffe) >> 1;
148         uint16_t d;
149         // ToDo: Mask register
150         d = vram[naddr];
151     dirty = ((uint16_t)data != d) ? true : false;
152
153         if(dirty) {
154                 dirty_flag[naddr >> 3] = true;
155                 // ToDo: Mask register
156                 vram[naddr] = data; 
157         }
158 }
159
160 void TOWNS_VRAM::write_data32(uint32_t addr, uint32_t data)
161 {
162         // ToDo:Offset.
163         // ToDo: Wait.
164         bool dirty;
165         uint32_t naddr = (addr & 0x7fffc) >> 1;
166         uint32_t *p = (uint32_t*)vram; 
167         pair32_t nw;
168
169         // ToDo: Mask register
170 #ifdef __LITTLE_ENDIAN__
171         nw.d = p[naddr >> 1];
172 #else
173         nw.w.l = vram[naddr + 0];
174         nw.w.h = vram[naddr + 1];
175 #endif
176         // ToDo: Mask register
177     dirty = (data != nw.d) ? true : false;
178
179         if(dirty) {
180                 // ToDo: Mask register
181                 dirty_flag[naddr >> 3] = true;
182
183 #ifdef __LITTLE_ENDIAN__
184                 p[naddr >> 1] = data;
185 #else
186                 nw.d = data;
187                 vram[naddr + 0] = nw.w.l;
188                 vram[naddr + 1] = nw.w.h;
189 #endif
190         }       
191 }
192
193 // Check dirty and calc alpha by 8 bytes.
194 bool TOWNS_VRAM::check_dirty_and_calc_alpha(uint32_t addr)
195 {
196         __DECL_ALIGNED(16) uint16_t pix_cache_16[4];
197         __DECL_ALIGNED(16)  uint8_t pix_cache_8[8];
198         __DECL_ALIGNED(16)  uint8_t pix_cache_4[16];
199         
200         __DECL_ALIGNED(4 * sizeof(scrntype_t)) scrntype_t alpha_cache_16[4];
201         __DECL_ALIGNED(16) uint16_t mask_cache_16[4];
202         __DECL_ALIGNED(16) uint16_t mask_cache_16_neg[4];
203         __DECL_ALIGNED(16) uint8_t mask_cache_4[8];
204         __DECL_ALIGNED(16) uint8_t mask_cache_4_neg[8];
205         __DECL_ALIGNED(16) scrntype_t alpha_cache_4[16];
206         bool dirty = dirty_flag[addr >> 3];
207         // If Not dirty, alpha/mask already calced.
208         if(dirty) {
209                 uint32_t layer = (addr >= 0x40000) ? 1 : 0;
210                 uint32_t naddr = addr & 0x3ffff;
211                 // alpha32768
212                 uint16_t *vptr = vram_ptr[layer];
213                 uint16_t *vptr8 = (uint8_t*)vptr;
214                 for(int i = 0; i < 4; i++) {
215                         pix_cache_16[i] = vptr[naddr >> 1];
216                 }
217                 for(int i = 0; i < 4; i++) {
218                         alpha_cache_16[i] = alpha_32768c[pix_cache_16[i]];
219                         mask_cache_16[i] =  mask_32768c[pix_cache_16[i]];
220                         mask_cache_16_neg[i] = ~mask_cache_16[i];
221                 }
222                 scrntype_t* palpha = &(alpha_buffer_32768[addr >> 1]);
223                 uint16_t* pmask16 = &(mask_buffer_32768[addr >> 1]);
224                 uint16_t* pmask16_neg = &(mask_buffer_32768_neg[addr >> 1]);
225                 for(int i = 0; i < 4; i++) {
226                         palpha[i]      = alpha_cache_16[i];
227                         pmask16[i]     = mask_cache_16[i];
228                         pmask16_neg[i] = mask_cache_16_neg[i];
229                 }
230                 
231                 for(int i = 0; i < 8; i++) {
232                         pix_cache_8[i] = vptr8[naddr];
233                 }
234                 // Alpha8
235                 
236                 for(int i = 0; i < 8; i++) {
237                         alpha_cache_4[i << 1]       = alpha_16c[pix_cache_8[i] << 1];
238                         alpha_cache_4[(i << 1) + 1] = alpha_16c[(pix_cache_8[i] << 1) + 1];
239                 }
240                 for(int i = 0; i < 8; i++) {
241                         mask_cache_4[i] = mask_16c[pix_cache_8[i]];
242                         mask_cache_4_neg[i] = ~mask_cache_4[i];
243                 }
244                 palpha = &(alpha_buffer_16[addr << 1]);
245                 uint16_t* pmask4 = &(mask_buffer_16[addr]);
246                 uint16_t* pmask4_neg = &(mask_buffer_16_neg[addr]);
247                 for(int i = 0; i < 16; i++) {
248                         palpha[i]     = alpha_cache_4[i];
249                 }
250                 for(int i = 0; i < 8; i++) {
251                         pmask4[i]     = mask_cache_4[i];
252                         pmask4_neg[i] = mask_cache_4_neg[i];
253                 }
254         }
255         return dirty;
256 }
257                         
258                 
259 uint32_t TOWNS_VRAM::read_plane_data8(uint32_t addr)
260 {
261         // Plane Access
262         pair_t data_p;
263         uint32_t x_addr = 0;
264         uint8_t *p = (uint8_t*)vram;
265         uint32_t mod_pos;
266
267         // ToDo: Writing plane.
268         if(access_page1) x_addr = 0x40000; //?
269         addr = (addr & 0x7fff) << 3;
270         p = &(p[x_addr + addr]); 
271         
272         // 8bit -> 32bit
273         uint32_t *pp = (uint32_t *)p;
274         uint8_t tmp = 0;
275         uint32_t tmp_d = *pp;
276         
277 #ifdef __LITTLE_ENDIAN__
278         uint32_t tmp_m1 = 0x000000f0;
279         uint32_t tmp_m2 = 0x0000000f;
280 #else
281         uint32_t tmp_m1 = 0xf0000000;
282         uint32_t tmp_m2 = 0x0f000000;
283 #endif  
284         uint32_t tmp_r;
285         tmp_d = tmp_d & write_plane_mask;
286         
287         for(int i = 0; i < 4; i++) {
288                 tmp <<= 2;
289                 tmp = tmp | (((tmp_d & tmp_m1) != 0) ? 0x02 : 0x00);
290                 tmp = tmp | (((tmp_d & tmp_m2) != 0) ? 0x01 : 0x00);
291                 
292 #ifdef __LITTLE_ENDIAN__
293                 tmp_d <<= 8;
294 #else
295                 tmp_d >>= 8;
296 #endif          
297         }
298         return tmp;
299 }
300
301 uint32_t TOWNS_VRAM::read_plane_data16(uint32_t addr)
302 {
303         pair16_t d;
304         d.b.l = (uint8_t)(read_plane_data8(addr + 0));
305         d.b.h = (uint8_t)(read_plane_data8(addr + 1));
306         return (uint32_t)(d.w);
307 }
308
309 uint32_t TOWNS_VRAM::read_plane_data32(uint32_t addr)
310 {
311         pair32_t d;
312         d.b.l  = (uint8_t)(read_plane_data8(addr + 0));
313         d.b.h  = (uint8_t)(read_plane_data8(addr + 1));
314         d.b.h2 = (uint8_t)(read_plane_data8(addr + 2));
315         d.b.h3 = (uint8_t)(read_plane_data8(addr + 3));
316         return d.d;
317 }
318
319 void TOWNS_VRAM::write_plane_data8(uint32_t addr, uint32_t data)
320 {
321         // Plane Access
322         pair_t data_p;
323         uint32_t x_addr = 0;
324         uint8_t *p = (uint8_t*)vram;
325         uint32_t mod_pos;
326
327         // ToDo: Writing plane.
328         if(access_page1) x_addr = 0x40000; //?
329         addr = (addr & 0x7fff) << 3;
330         x_addr = x_addr + addr;
331         p = &(p[x_addr]); 
332         
333         // 8bit -> 32bit
334         uint32_t *pp = (uint32_t *)p;
335         uint32_t tmp = 0;
336         uint32_t tmp_d = data & 0xff;
337 #ifdef __LITTLE_ENDIAN__
338         uint32_t tmp_m1 = 0xf0000000 & write_plane_mask;
339         uint32_t tmp_m2 = 0x0f000000 & write_plane_mask;
340 #else
341         uint32_t tmp_m1 = 0x000000f0 & write_plane_mask;
342         uint32_t tmp_m2 = 0x0000000f & write_plane_mask;
343 #endif  
344         uint32_t tmp_r1;
345         uint32_t tmp_r2;
346
347         for(int i = 0; i < 4; i++) {
348 #ifdef __LITTLE_ENDIAN__
349                 tmp = tmp >> 8;
350 #else
351                 tmp = tmp << 8;
352 #endif
353                 tmp = tmp | (((tmp_d & 0x02) != 0) ? tmp_m1 : 0x00);
354                 tmp = tmp | (((tmp_d & 0x01) != 0) ? tmp_m2 : 0x00);
355                 tmp_d >>= 2;
356         }
357         tmp_r1 = *pp;
358         tmp_r2 = tmp_r1;
359         tmp_r1 = tmp_r1 & ~write_plane_mask;
360         tmp_r1 = tmp_d | tmp_r1;
361         if(tmp_r2 != tmp_r1) {
362                 *pp = tmp_r1;
363                 dirty_flag[x_addr >> 3] = true;
364         }
365 }
366
367 void TOWNS_VRAM::write_plane_data16(uint32_t addr, uint32_t data)
368 {
369         pair16_t d;
370         d.w = (uint16_t)data;
371         write_plane_data8(addr + 0, d.b.l);
372         write_plane_data8(addr + 1, d.b.h);
373 }
374
375
376 void TOWNS_VRAM::write_plane_data32(uint32_t addr, uint32_t data)
377 {
378         pair32_t d;
379         d.d = data;
380         write_plane_data8(addr + 0, d.b.l);
381         write_plane_data8(addr + 1, d.b.h);
382         write_plane_data8(addr + 2, d.b.h2);
383         write_plane_data8(addr + 3, d.b.h3);
384 }
385
386
387 // I/Os
388 // Palette.
389 void TOWNS_CRTC::calc_apalette16(int layer, int index)
390 {
391         if(index < 0) return;
392         if(index > 15) return;
393         apalette_16_rgb[layer][index] =
394                 ((uint16_t)(apalette_b & 0x0f)) |
395                 ((uint16_t)(apalette_r & 0x0f) << 4) |
396                 ((uint16_t)(apalette_g & 0x0f) << 8);
397         if(index == 0) {
398                 apalette_16_pixel[layer][index] = _CLEAR_COLOR; // ??
399         } else {
400                 apalette_16_pixel[layer][index] = RGBA_COLOR((apalette_r & 0x0f) << 4, (apalette_g & 0x0f) << 4, (apalette_b & 0x0f) << 4, 0xff);
401         }
402 }
403
404 void TOWNS_CRTC::calc_apalette256(int index)
405 {
406         if(index < 0) return;
407         if(index > 255) return;
408         apalette_256_rgb[layer][index] =
409                 ((uint32_t)apalette_b) |
410                 ((uint32_t)apalette_r << 8) |
411                 ((uint32_t)apalette_g << 16);
412         if(index == 0) {
413                 apalette_256_pixel[index] = _CLEAR_COLOR; // ??
414         } else {
415                 apalette_256_pixel[index] = RGBA_COLOR(apalette_r, apalette_g, apalette_b, 0xff);
416         }
417 }
418
419 void TOWNS_CRTC::set_apalette_r(int layer, uint8_t val)
420 {
421         apalette_r = val;
422         if(apalette_code < 16) {
423                 calc_apalette16(layer, (int)apalette_code);
424         }
425         // if layer == 0 ?
426         calc_apalette256((int)apalette_code % 256);
427 }
428
429 void TOWNS_CRTC::set_apalette_g(int layer, uint8_t val)
430 {
431         apalette_g = val;
432         if(apalette_code < 16) {
433                 calc_apalette16(layer, (int)apalette_code);
434         }
435         // if layer == 0 ?
436         calc_apalette256((int)apalette_code % 256);
437 }
438
439 void TOWNS_CRTC::set_apalette_b(int layer, uint8_t val)
440 {
441         apalette_b = val;
442         if(apalette_code < 16) {
443                 calc_apalette16(layer, (int)apalette_code);
444         }
445         // if layer == 0 ?
446         calc_apalette256((int)apalette_code % 256);
447 }
448
449 void TOWNS_CRTC::set_apalette_num(int layer, uint8_t val)
450 {
451         apalette_code = ((int)val) % 256;
452 }
453
454 // Renderers
455 void TOWNS_CRTC::render_line_16_boundary(int layer, scrntype_t *framebuffer, uint8_t *vramptr, uint32_t startaddr, uint32_t words)
456 {
457         // Simplify render: Must set 16pixels
458         uint32_t wordptr = 0;
459         int nwords = (int)words / 16;
460         int ip;
461         uint32_t src;
462         uint32_t src1, src2;
463         __DECL_ALIGNED(8) uint8_t  srcdat[8];
464         __DECL_ALIGNED(sizeof(scrntype_t) * 16) scrntype_t data_cache_16[16];
465         
466         scrntype_t *pdst = framebuffer;
467         uint8_t *pp = (uint8_t *)vramptr;
468         if(framebuffer == NULL) return;
469         if(vramptr == NULL) return;
470
471         uintptr_t offset_base = (uintptr_t)startaddr;
472         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
473         uintptr_t offset;
474         // offet_base = (offset_base + [value_of_offset_register]) & mask.
475         offset_base = (offet_base & 0x3ffff) + base;
476         pp = &(pp[offset_base]);
477         
478         for(ip = 0; ip < nwords; ip++) {
479                 if(!check_dirty_and_calc_alpha(offset_base)) {
480                         pdst += 16;
481                         pp += 8;
482                         offset_base += 8;
483                         continue;
484                 }
485                 dirty_flag[(offset_base >> 3)] = false;
486                 for(int ii = 0; ii < 8; ii++) {
487                         srcdat[ii << 1]       =  pp[ii];
488                         srcdat[(ii << 1) + 1] =  srcdat[ii << 1] & 0x0f;
489                         srcdat[ii << 1]       = (srcdat[ii << 1] & 0x0f) >> 4;
490                 }
491                 scrntype_t* aptr = alpha_buffer_16[offset_base << 1];
492                 for(int ii = 0; ii < 16; ii++) {
493                         data_cache_16[ii] = apalette_16[layer][srcdat1[ii]];
494                 }
495                 // ToDo: For hadrdware that does not support alpha blending(not RGBA32).
496                 for(int ii = 0; ii < 16; ii++) {
497                         pdst[ii] = data_cache_16[ii];
498                 }
499                 pdst += 16;
500                 pp += 8;
501                 offset_base += 8;
502         }
503 }
504
505 void TOWNS_CRTC::render_line_16_not_boundary(int layer, scrntype_t *framebuffer, uint8_t *vramptr, uint32_t startaddr, uint32_t words)
506 {
507         // Simplify render: Must set 32pixels
508         uint32_t wordptr = 0;
509         int ip;
510         uint32_t src;
511         uint32_t src1, src2;
512         scrntype_t *pdst = framebuffer;
513         uint8_t *pp = (uint8_t *)vramptr;
514         if(framebuffer == NULL) return;
515         if(vramptr == NULL) return;
516
517         uintptr_t offset_base = (uintptr_t)startaddr;
518         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
519         uintptr_t offset;
520         // offet_base = (offset_base + [value_of_offset_register]) & mask.
521         offset_base = (offet_base & 0x3ffff) + base;
522         pp = &(pp[offset_base]);
523         
524         if(check_dirty_and_calc_alpha(offset_base)) {
525                 //dirty_flag[(offset_base >> 3)] = false; // OK?
526                 for(ip = 0; ip < words; ip++) {
527                         uint8_t sdat = pp[ip];
528                         scrntype_t pdat = apalette_16[layer][sdat];
529                         pdst[ii] = pdat;
530                 }
531         }
532 }
533
534 void TOWNS_CRTC::render_line_256_boundary(int layer, scrntype_t *framebuffer, uint8_t *vramptr, uint32_t startaddr, uint32_t words)
535 {
536         uint32_t wordptr = 0;
537         int nwords = (int)words / 8;
538         int ip;
539         __DECL_ALIGNED(16) uint8_t src[8];
540         scrntype_t *pdst  = __builtin_assume_aligned(framebuffer, sizeof(scrntype_t));
541         uint8_t *pp = (uint8_t *)vramptr;
542         
543         if(framebuffer == NULL) return;
544         if(vramptr == NULL) return;
545
546         uintptr_t offset_base = (uintptr_t)startaddr;
547         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
548         // offet_base = (offset_base + [value_of_offset_register]) & mask.
549         offset_base = (offet_base & 0x3ffff) + base;
550         pp = &(pp[offset_base >> 2]);
551         
552         for(ip = 0; ip < nwords; ip++) {
553                 if(check_dirty_and_calc_alpha(offset_base)) {
554                         dirty_flag[offset_base >> 3] = false;
555                         for(int i = 0; i < 8; i++) {
556                                 src[i] = pp[i];
557                         }
558                         // ToDo: Super Impose.
559                         for(int i = 0; i < 8; i++) {
560                                 pdst[i] = apalette_256_pixel[src[i]];
561                         }
562                 }
563                 offset_base += 8;
564                 pp += 8;
565                 pdst += 8;
566         }
567 }
568
569 void TOWNS_CRTC::render_line_256_not_boundary(int layer, scrntype_t *framebuffer, uint8_t *vramptr, uint32_t startaddr, uint32_t words)
570 {
571         uint32_t wordptr = 0;
572         int nwords = (int)words / 8;
573         int ip;
574         uint8_t *pp = (uint8_t *)vramptr;
575         uint8_t src;
576         if(framebuffer == NULL) return;
577         if(vramptr == NULL) return;
578
579         uintptr_t offset_base = (uintptr_t)startaddr;
580         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
581         // offet_base = (offset_base + [value_of_offset_register]) & mask.
582         offset_base = (offet_base & 0x3ffff) + base;
583         pp = &(pp[offset_base >> 2]);
584         
585         for(ip = 0; ip < nwords; ip++) {
586                 if(check_dirty_and_calc_alpha(offset_base + ip)) {
587                         // Keep dirty?
588                         src = pp[ip];
589                         // ToDo: Super Impose.
590                         pdst[ip] = apalette_256_pixel[src];
591                 }
592         }
593 }
594
595
596 // To be used table??
597 void TOWNS_CRTC::render_line_32768_boundary(int layer, scrntype_t *pixcache, uint16_t *vramptr, uint32_t words)
598 {
599         uint32_t wordptr = 0;
600         int nwords = (int)words / 4;
601         int ip;
602         uint16_t src16;
603         scrntype_t *pdst = pixcache;
604         uint16_t *pp = (uint16_t *)vramptr;
605         uint16_t *cachep = (uint16_t *)srcdat;
606         __DECL_ALIGNED(16) uint16_t rgb[4];
607         __DECL_ALIGNED(sizeof(scrntype_t) * 4) scrntype_t dcache[4];
608         int i = 0;
609         
610         if(framebuffer == NULL) return;
611         if(vramptr == NULL) return;
612
613         uintptr_t offset_base = (uintptr_t)startaddr;
614         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
615         // offet_base = (offset_base + [value_of_offset_register]) & mask.
616         offset_base = (offet_base & 0x3ffff) + base;
617         pp = &(pp[offset_base >> 1]);
618
619         for(ip = 0; ip < nwords; ip++) {
620                 if(check_dirty_and_calc_alpha(offset_base)) {
621                         dirty_flag[(offset_base >> 3)] = false;
622                         for(int i = 0; i < 4; i++) {
623                                 rgb[i] = pp[i];
624                         }
625                         for(int ii = 0; ii < 4; ii++) {
626                                 dcache[ii] = table_32768c[rgb[ii]];
627                         }
628                         for(int ii = 0; ii < 4; ii++) {
629                                 pdst[ii] = dcache[ii];
630                         }
631                 }
632                 offset_base += 8;
633                 pdst += 4;
634                 pp += 4;
635         }
636 }
637
638 void TOWNS_CRTC::render_line_32768_not_boundary(int layer, scrntype_t *pixcache, uint16_t *vramptr, uint32_t words)
639 {
640         uint32_t wordptr = 0;
641         int nwords = (int)words / 4;
642         int ip;
643         uint16_t src16;
644         scrntype_t *pdst = pixcache;
645         uint16_t *pp = (uint16_t *)vramptr;
646         uint16_t *cachep = (uint16_t *)srcdat;
647         int i = 0;
648         
649         if(framebuffer == NULL) return;
650         if(vramptr == NULL) return;
651
652         uintptr_t offset_base = (uintptr_t)startaddr;
653         uintptr_t base = ((layer == 0) ? 0x00000 : 0x40000);
654         // offet_base = (offset_base + [value_of_offset_register]) & mask.
655         offset_base = (offet_base & 0x3ffff) + base;
656         pp = &(pp[offset_base >> 1]);
657
658         for(ip = 0; ip < words; ip++) {
659                 if(check_dirty_and_calc_alpha(offset_base)) {
660                         // Keep dirty?
661                         pdst[ip] = table_32768c[pp[ip]];
662                 }
663                 offset_base++;
664         }
665 }
666 // ToDo: Super impose.
667 void TOWNS_CRTC::mix_layers(scrntype* dst, scrntype_t* upper, scrntype_t *upper_alpha, scrntype_t* lower, int width)
668 {
669         scrntype_t* src1 = upper;
670         scrntype_t* src2 = lower;
671         
672         __DECL_ALIGNED(sizeof(scrntype_t) * 8) scrntype_t dcache1[8];
673         __DECL_ALIGNED(sizeof(scrntype_t) * 8) scrntype_t dcache2[8];
674         __DECL_ALIGNED(sizeof(scrntype_t) * 8) scrntype_t dcache3[8];
675         __DECL_ALIGNED(sizeof(scrntype_t) * 8) scrntype_t acache1[8];
676         __DECL_ALIGNED(sizeof(scrntype_t) * 8) scrntype_t acache2[8];
677         if(src1 == NULL) {
678                 if(src2 == NULL) {
679                         for(int i = 0; i < width; i++) {
680                                 dst[i] = RGBA_COLOR(0, 0, 0, 255);
681                         }
682                 } else {
683                         // Upper don't display, lower displayed.
684                         int iwidth = width / 8;
685                         for(int i = 0; i < iwidth; i++) {
686                                 for(int ii = 0; ii < 8; ii++) {
687                                         dcache2[ii] = src2[ii];
688                                 }
689                                 for(int ii = 0; ii < 8; ii++) {
690                                         dst[ii] = dcache2[ii];
691                                 }
692                                 src2 += 8;
693                                 dst += 8;
694                         }
695                         width = width - (iwidth * 8);
696                         if(width > 0) {
697                                 for(int i = 0; i < width; i++) {
698                                         sdt[i] = src2[i];
699                                 }
700                         }
701                 }
702         } else { 
703                 if(src2 == NULL) { // upper only
704                         int iwidth = width / 8;
705                         for(int i = 0; i < iwidth; i++) {
706                                 for(int ii = 0; ii < 8; ii++) {
707                                         dcache1[ii] = src1[ii];
708                                 }
709                                 for(int ii = 0; ii < 8; ii++) {
710                                         dst[ii] = dcache1[ii];
711                                 }
712                                 src1 += 8;
713                                 dst += 8;
714                         }
715                         width = width - (iwidth * 8);
716                         if(width > 0) {
717                                 for(int i = 0; i < width; i++) {
718                                         sdt[i] = src2[i];
719                                 }
720                         }
721                 } else { // Both lives
722                         if(upper_alpha == NULL) {
723                                 for(int i = 0; i < 8; i++) {
724                                         acache1[i] = RGBA_COLOR(255, 255, 255, 255);
725                                 }
726                         }
727                         int iwidth = width / 8;
728                         for(int i = 0; i < iwidth; i++) {
729                                 if(upper_alpha != NULL) {
730                                         for(int ii = 0; ii < 8; i++) {
731                                                 acache1[ii] = upper_alpha[ii];
732                                         }
733                                         upper_alpha += 8;
734                                 }
735                                 for(int ii = 0; ii < 8; i++) {
736                                         acache2[ii] = ~acache1[ii];
737                                 }
738                                 for(int ii = 0; ii < 8; ii++) {
739                                         dcache1[ii] = src1[ii];
740                                         dcache2[ii] = src2[ii];
741                                 }
742                                 for(int ii = 0; ii < 8; ii++) {
743                                         dcache2[ii] = dcache2[ii] * acache1[ii]; // Mask Upper
744                                         //dcache3[ii] = (dcache2[ii] == RGBA_COLOR(0, 0, 0, 0)) ? dcache1[ii] : dcache2[ii];
745                                         dcache1[ii] = dcache1[ii] * acache2[ii]; // Mask Lower.
746                                         dcache3[ii] = dcache1[ii] | dcache2[ii];
747                                 }
748                                 for(int ii = 0; ii < 8; ii++) {
749                                         dst[ii] = dcache3[ii];
750                                 }
751                                 src1 += 8;
752                                 src2 += 8;
753                                 dst += 8;
754                         }
755                         width = width - (iwidth * 8) ;
756                         scrntype_t d1, d2, a1, a2;
757                         for(int i = 0; i < width; i++) {
758                                 if(upper_alpha != NULL) {
759                                         a1 = upper_alpha[i];
760                                 } else {
761                                         a1 = RGBA_COLOR(255, 255, 255, 255);
762                                 }
763                                 a2 = ~a1;
764                                 d1 = src1[i];
765                                 d2 = src2[i];
766                                 d2 = d2 * a1;
767                                 d1 = d1 * a2;
768                                 dst[i] = d1 | d2;
769                         }
770                 }
771         }
772 }
773
774 void TOWNS_CRTC::vzoom_pixel(scrntype_t*src, int width, int srclines, scrntype_t* dst, int stride, int dstlines, float vzoom)
775 {
776         if(src == dst) return;
777         if(vzoom <= 0.0f) return;
778         if((src == NULL) || (dst == NULL)) return;
779         if(width <= 0) return;
780         if(srclines <= 0) return;
781         if(dstlines <= 0) return;
782
783         scrntype_t *psrc = src;
784         scrntype_t *pdst = dst;
785
786         float vzoom_int = floor(vzoom);
787         float vzoom_mod = vzoom - vzoom_int;
788         float nmod = 0.0f;
789         int nint = (int)vzoom_int;
790         int srcline = 0;
791         int linecount = 0;
792         for(srcline = 0; srcline < srclines; srcline++) {
793                 int ifactor = nint;
794                 if(nmod >= 1.0f) {
795                         nmod = nmod - 1.0f;
796                         ifactor++;
797                 }
798                 for(int ii = 0; ii < ifactor; ii++) {
799                         // ToDo: Mask, blend.
800                         memcpy(pdst, psrc, width * sizeof(scrntype_t));
801                         linecount++;
802                         if(linecount >= dstlines) goto _exit0;;
803                         pdst += stride;
804                 }
805                 psrc += stride;
806                 nmod = nmod + vzoom_mod;
807         }
808 _exit0: 
809         return;
810 }
811                 
812 void TOWNS_CRTC::hzoom_pixel(scrntype_t* src, int width, scrntype_t* dst, int dst_width, float hzoom)
813 {
814         if(src == dst) return;
815         if(hzoom <= 0.0f) return;
816         if((src == NULL) || (dst == NULL)) return;
817         if(width <= 0) return;
818         if(dst_width <= 0) return;
819
820         scrntype_t* pdst = dst;
821         float hzoom_int = floor(hzoom);
822         float hzoom_mod = hzoom - hzoom_int;
823         float nmod = 0.0f;
824         int nint = (int)hzoom_int;
825         if((nint == 1) && (hzoom_mod <= 0.0f)) {
826                 // x1.0
827                 scrntype_t *sp = src;
828                 scrntype_t pcache[4];
829                 int nw = width / 4;
830                 int dx = 0;
831                 int ycount = 0;
832                 for(int ii = 0; ii < nw; ii++) {
833                         if((dx + 3) >= dst_width) break;
834                         for(int j = 0; j < 4; j++) {
835                                 pcache[j] = sp[j];
836                         }
837                         // ToDo: Mask/Alpha
838                         for(int j = 0; j < 4; j++) {
839                                 pdst[j] = pcache[j];
840                         }
841                         dx += 4;
842                         pdst += 4;
843                         sp += 4;
844                 }
845                 nw = width - dx;
846                 if(dx >= dst_width) return;
847                 for(int ii = 0; ii < nw; ii++) {
848                         if(dx >= dst_width) goto __exit_0;
849                         // ToDo: Mask/Alpha
850                         pcache[ii] = sp[ii];
851                         pdst[ii] = pcache[ii];
852                         dx++;
853                 }
854         } else {
855                 scrntype_t *sp = src;
856                 int dx = 0;
857                 int xcount = 0;
858                 for(int i = 0; i < width; i++) {
859                         // ToDo : Storage via SIMD.
860                         if(dx >= dst_width) goto __exit_0;
861                         
862                         int ifactor = nint;
863                         if(nmod >= 1.0f) {
864                                 ifactor++;
865                                 nmod = nmod - 1.0f;
866                         }
867                         scrntype_t pix = *sp++;
868                         scrntype_t pcache[4];
869                         // ToDo: MASK/ALPHA
870                 
871                         int jfactor = ifactor / 4;
872                         xcount = 0;
873                         for(int k = 0; k < 4; k++) {
874                                 pcache[k] = pix;
875                         }
876                         for(int j = 0; j < jfactor; j++) {
877                                 if((dx + 3) >= dst_width) break; 
878                                 for(int k = 0; k < 4; k++) {
879                                         pdst[k] = pcache[k];
880                                 }
881                                 xcount += 4;
882                                 pdst += 4;
883                                 dx += 4;
884                         }
885                         ifactor = ifactor - xcount;
886                         if(ifactor < 0) ifactor = 0;
887                         for(int k = 0; k < ifactor; k++) {
888                                 if(dx >= dst_width) goto __exit_0;
889                                 pdst[k] = pcache[k];
890                                 dx++;
891                         }
892                         nmod = nmod + hzoom_mod;
893                         
894                         pdst += ifactor;
895                 }               
896         }
897 __exit_0:
898         return;
899 }
900
901 void TOWNS_VRAM::draw_screen()
902 {
903         // Note: This renderer will contain three types (at least:)
904         // 1. Software Zoom, Hardware stack (Using GPU for stack, Using CPU for zoom)
905         // 2. Softare Zoom,  Software stack (Using only host-CPU).
906         // 3. Hardware Zoom, Hardware stack (Using GPU and compute shader?).
907         // To implement 1., Zooming all screen don't wish to use CPU, per raster Zooming wish to use GPU.
908         // At first, will implement 2.As of CSP platform implement only single frame buffer area.
909         //
910         // Answer values(excepts 2.):
911         //  Note: Upper layer = layer1, lower layer = layer2.
912         // a. Pixel Layers of 1/2.
913         // b. Alpha Layers of 1.
914         // c. Layer using flags both layer1, layer2.
915         // d. Data of Layers (1/2).
916         // e. Source screen width and height per layer.
917         // f. Offset sourcfe-pixel-address per raster.
918         // g. Source raster width per layer and scanline.
919         // h. Offset dst-pixel-position in raster per layer.
920         // - 20190110 K.Ohta.
921 }
922
923
924 }
925 #undef _CLEAR_COLOR
926