1 /* Copyright 2012 Guillaume Duhamel
2
3 This file is part of Yabause.
4
5 Yabause is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 Yabause is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Yabause; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "titan.h"
21 #include "../vidshared.h"
22 #include "../vidsoft.h"
23 #include "../threads.h"
24
25 #include <stdlib.h>
26
27 /* private */
28 typedef u32 (*TitanBlendFunc)(u32 top, u32 bottom);
29 typedef int FASTCALL (*TitanTransFunc)(u32 pixel);
30 void TitanRenderLines(pixel_t * dispbuffer, int start_line, int end_line);
31 extern int vdp2_interlace;
32
33 int vidsoft_num_priority_threads = 0;
34
35 struct PixelData
36 {
37 u32 pixel;
38 u8 priority;
39 u8 linescreen;
40 u8 shadow_type;
41 u8 shadow_enabled;
42 };
43
44 static struct TitanContext {
45 int inited;
46 struct PixelData * vdp2framebuffer[6];
47 u32 * linescreen[4];
48 int vdp2width;
49 int vdp2height;
50 TitanBlendFunc blend;
51 TitanTransFunc trans;
52 struct PixelData * backscreen;
53 int layer_priority[6];
54 } tt_context = {
55 0,
56 { NULL, NULL, NULL, NULL, NULL, NULL },
57 { NULL, NULL, NULL, NULL },
58 320,
59 224,
60 NULL,NULL,NULL
61 };
62
63 struct
64 {
65 volatile int need_draw[5];
66 volatile int draw_finished[5];
67 struct
68 {
69 volatile int start;
70 volatile int end;
71 }lines[5];
72
73 pixel_t * dispbuffer;
74 int use_simplified;
75 }priority_thread_context;
76
77 #if defined WORDS_BIGENDIAN
78 #ifdef USE_RGB_555
TitanFixAlpha(u32 pixel)79 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel >> 27) & 0x1F) | ((pixel >> 14) & 0x7C0) | (pixel >> 1) & 0xF8); }
80 #elif USE_RGB_565
TitanFixAlpha(u32 pixel)81 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel >> 27) & 0x1F) | ((pixel >> 13) & 0x7E0) | (pixel & 0xF8)); }
82 #else
TitanFixAlpha(u32 pixel)83 static INLINE u32 TitanFixAlpha(u32 pixel) { return ((((pixel & 0x3F) << 2) + 0x03) | (pixel & 0xFFFFFF00)); }
84 #endif
85
TitanGetAlpha(u32 pixel)86 static INLINE u8 TitanGetAlpha(u32 pixel) { return pixel & 0x3F; }
TitanGetRed(u32 pixel)87 static INLINE u8 TitanGetRed(u32 pixel) { return (pixel >> 8) & 0xFF; }
TitanGetGreen(u32 pixel)88 static INLINE u8 TitanGetGreen(u32 pixel) { return (pixel >> 16) & 0xFF; }
TitanGetBlue(u32 pixel)89 static INLINE u8 TitanGetBlue(u32 pixel) { return (pixel >> 24) & 0xFF; }
TitanCreatePixel(u8 alpha,u8 red,u8 green,u8 blue)90 static INLINE u32 TitanCreatePixel(u8 alpha, u8 red, u8 green, u8 blue) { return alpha | (red << 8) | (green << 16) | (blue << 24); }
91 #else
92 #ifdef USE_RGB_555
TitanFixAlpha(u32 pixel)93 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel << 7) & 0x7C00) | ((pixel >> 6) & 0x3C0) | ((pixel >> 19) & 0x1F)); }
94 #elif USE_RGB_565
TitanFixAlpha(u32 pixel)95 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel << 8) & 0xF800) | ((pixel >> 5) & 0x7C0) | ((pixel >> 19) & 0x1F)); }
96 #else
TitanFixAlpha(u32 pixel)97 static INLINE u32 TitanFixAlpha(u32 pixel) { return ((((pixel & 0x3F000000) << 2) + 0x03000000) | (pixel & 0x00FFFFFF)); }
98 #endif
99
TitanGetAlpha(u32 pixel)100 static INLINE u8 TitanGetAlpha(u32 pixel) { return (pixel >> 24) & 0x3F; }
TitanGetRed(u32 pixel)101 static INLINE u8 TitanGetRed(u32 pixel) { return (pixel >> 16) & 0xFF; }
TitanGetGreen(u32 pixel)102 static INLINE u8 TitanGetGreen(u32 pixel) { return (pixel >> 8) & 0xFF; }
TitanGetBlue(u32 pixel)103 static INLINE u8 TitanGetBlue(u32 pixel) { return pixel & 0xFF; }
TitanCreatePixel(u8 alpha,u8 red,u8 green,u8 blue)104 static INLINE u32 TitanCreatePixel(u8 alpha, u8 red, u8 green, u8 blue) { return (alpha << 24) | (red << 16) | (green << 8) | blue; }
105 #endif
106
107
set_layer_y(const int start_line,int * layer_y)108 void set_layer_y(const int start_line, int * layer_y)
109 {
110 if (vdp2_interlace)
111 *layer_y = start_line / 2;
112 else
113 *layer_y = start_line;
114 }
115
TitanRenderLinesSimplified(pixel_t * dispbuffer,int start_line,int end_line)116 void TitanRenderLinesSimplified(pixel_t * dispbuffer, int start_line, int end_line)
117 {
118 int x, y, i, layer, j, layer_y;
119 int line_increment, interlace_line;
120 int sorted_layers[8] = { 0 };
121 int num_layers = 0;
122
123 if (!tt_context.inited || (!tt_context.trans))
124 {
125 return;
126 }
127
128 Vdp2GetInterlaceInfo(&interlace_line, &line_increment);
129
130 //pre-sort the layers so it doesn't have to be done per-pixel
131 for (i = 7; i >= 0; i--)
132 {
133 for (layer = TITAN_RBG0; layer >= 0; layer--)
134 {
135 if (tt_context.layer_priority[layer] > 0 && tt_context.layer_priority[layer] == i)
136 sorted_layers[num_layers++] = layer;
137 }
138 }
139
140 //last layer is always the back screen
141 sorted_layers[num_layers++] = TITAN_BACK;
142
143 set_layer_y(start_line, &layer_y);
144
145 for (y = start_line + interlace_line; y < end_line; y += line_increment)
146 {
147 for (x = 0; x < tt_context.vdp2width; x++)
148 {
149 int layer_pos = (layer_y * tt_context.vdp2width) + x;
150 i = (y * tt_context.vdp2width) + x;
151
152 dispbuffer[i] = 0;
153
154 for (j = 0; j < num_layers; j++)
155 {
156 struct PixelData sprite = tt_context.vdp2framebuffer[TITAN_SPRITE][layer_pos];
157
158 int bg_layer = sorted_layers[j];
159
160 //if the top layer is the back screen
161 if (bg_layer == TITAN_BACK)
162 {
163 //use a sprite pixel if it is not transparent
164 if (sprite.pixel)
165 {
166 dispbuffer[i] = TitanFixAlpha(sprite.pixel);
167 break;
168 }
169 else
170 {
171 //otherwise use the back screen pixel
172 dispbuffer[i] = TitanFixAlpha(tt_context.backscreen[y].pixel);
173 break;
174 }
175 }
176 //if the top layer is a sprite pixel
177 else if (sprite.priority >= tt_context.layer_priority[bg_layer])
178 {
179 //use the sprite pixel if it is not transparent
180 if (sprite.pixel)
181 {
182 dispbuffer[i] = TitanFixAlpha(sprite.pixel);
183 break;
184 }
185 }
186 else
187 {
188 //use the bg layer if it is not covered with a sprite pixel and not transparent
189 if (tt_context.vdp2framebuffer[bg_layer][layer_pos].pixel)
190 {
191 dispbuffer[i] = TitanFixAlpha(tt_context.vdp2framebuffer[bg_layer][layer_pos].pixel);
192 break;
193 }
194 }
195 }
196 }
197 layer_y++;
198 }
199 }
200
TitanRenderSimplifiedCheck(pixel_t * buf,int start,int end,int can_use_simplified_rendering)201 void TitanRenderSimplifiedCheck(pixel_t * buf, int start, int end, int can_use_simplified_rendering)
202 {
203 if (can_use_simplified_rendering)
204 TitanRenderLinesSimplified(buf, start, end);
205 else
206 TitanRenderLines(buf, start, end);
207 }
208
209 #define DECLARE_PRIORITY_THREAD(FUNC_NAME, THREAD_NUMBER) \
210 void FUNC_NAME(void* data) \
211 { \
212 for (;;) \
213 { \
214 if (priority_thread_context.need_draw[THREAD_NUMBER]) \
215 { \
216 priority_thread_context.need_draw[THREAD_NUMBER] = 0; \
217 TitanRenderSimplifiedCheck(priority_thread_context.dispbuffer, priority_thread_context.lines[THREAD_NUMBER].start, priority_thread_context.lines[THREAD_NUMBER].end, priority_thread_context.use_simplified); \
218 priority_thread_context.draw_finished[THREAD_NUMBER] = 1; \
219 } \
220 YabThreadSleep(); \
221 } \
222 }
223
224 DECLARE_PRIORITY_THREAD(VidsoftPriorityThread0, 0);
225 DECLARE_PRIORITY_THREAD(VidsoftPriorityThread1, 1);
226 DECLARE_PRIORITY_THREAD(VidsoftPriorityThread2, 2);
227 DECLARE_PRIORITY_THREAD(VidsoftPriorityThread3, 3);
228 DECLARE_PRIORITY_THREAD(VidsoftPriorityThread4, 4);
229
TitanBlendPixelsTop(u32 top,u32 bottom)230 static u32 TitanBlendPixelsTop(u32 top, u32 bottom)
231 {
232 u8 alpha, ralpha, tr, tg, tb, br, bg, bb;
233
234 alpha = (TitanGetAlpha(top) << 2) + 3;
235 ralpha = 0xFF - alpha;
236
237 tr = (TitanGetRed(top) * alpha) / 0xFF;
238 tg = (TitanGetGreen(top) * alpha) / 0xFF;
239 tb = (TitanGetBlue(top) * alpha) / 0xFF;
240
241 br = (TitanGetRed(bottom) * ralpha) / 0xFF;
242 bg = (TitanGetGreen(bottom) * ralpha) / 0xFF;
243 bb = (TitanGetBlue(bottom) * ralpha) / 0xFF;
244
245 return TitanCreatePixel(0x3F, tr + br, tg + bg, tb + bb);
246 }
247
TitanBlendPixelsBottom(u32 top,u32 bottom)248 static u32 TitanBlendPixelsBottom(u32 top, u32 bottom)
249 {
250 u8 alpha, ralpha, tr, tg, tb, br, bg, bb;
251
252 if ((top & 0x80000000) == 0) return top;
253
254 alpha = (TitanGetAlpha(bottom) << 2) + 3;
255 ralpha = 0xFF - alpha;
256
257 tr = (TitanGetRed(top) * alpha) / 0xFF;
258 tg = (TitanGetGreen(top) * alpha) / 0xFF;
259 tb = (TitanGetBlue(top) * alpha) / 0xFF;
260
261 br = (TitanGetRed(bottom) * ralpha) / 0xFF;
262 bg = (TitanGetGreen(bottom) * ralpha) / 0xFF;
263 bb = (TitanGetBlue(bottom) * ralpha) / 0xFF;
264
265 return TitanCreatePixel(TitanGetAlpha(top), tr + br, tg + bg, tb + bb);
266 }
267
TitanBlendPixelsAdd(u32 top,u32 bottom)268 static u32 TitanBlendPixelsAdd(u32 top, u32 bottom)
269 {
270 u32 r, g, b;
271
272 r = TitanGetRed(top) + TitanGetRed(bottom);
273 if (r > 0xFF) r = 0xFF;
274
275 g = TitanGetGreen(top) + TitanGetGreen(bottom);
276 if (g > 0xFF) g = 0xFF;
277
278 b = TitanGetBlue(top) + TitanGetBlue(bottom);
279 if (b > 0xFF) b = 0xFF;
280
281 return TitanCreatePixel(0x3F, r, g, b);
282 }
283
TitanTransAlpha(u32 pixel)284 static INLINE int FASTCALL TitanTransAlpha(u32 pixel)
285 {
286 return TitanGetAlpha(pixel) < 0x3F;
287 }
288
TitanTransBit(u32 pixel)289 static INLINE int FASTCALL TitanTransBit(u32 pixel)
290 {
291 return pixel & 0x80000000;
292 }
293
TitanDigPixel(int pos,int y)294 static u32 TitanDigPixel(int pos, int y)
295 {
296 struct PixelData pixel_stack[2] = { 0 };
297
298 int pixel_stack_pos = 0;
299
300 int priority;
301
302 //sort the pixels from highest to lowest priority
303 for (priority = 7; priority > 0; priority--)
304 {
305 int which_layer;
306
307 for (which_layer = TITAN_SPRITE; which_layer >= 0; which_layer--)
308 {
309 if (tt_context.vdp2framebuffer[which_layer][pos].priority == priority)
310 {
311 pixel_stack[pixel_stack_pos] = tt_context.vdp2framebuffer[which_layer][pos];
312 pixel_stack_pos++;
313
314 if (pixel_stack_pos == 2)
315 goto finished;//backscreen is unnecessary in this case
316 }
317 }
318 }
319
320 pixel_stack[pixel_stack_pos] = tt_context.backscreen[pos];
321
322 finished:
323
324 if (pixel_stack[0].linescreen)
325 {
326 pixel_stack[0].pixel = tt_context.blend(pixel_stack[0].pixel, tt_context.linescreen[pixel_stack[0].linescreen][y]);
327 }
328
329 if ((pixel_stack[0].shadow_type == TITAN_MSB_SHADOW) && ((pixel_stack[0].pixel & 0xFFFFFF) == 0))
330 {
331 //transparent sprite shadow
332 if (pixel_stack[1].shadow_enabled)
333 {
334 pixel_stack[0].pixel = TitanBlendPixelsTop(0x20000000, pixel_stack[1].pixel);
335 }
336 else
337 {
338 pixel_stack[0].pixel = pixel_stack[1].pixel;
339 }
340 }
341 else if (pixel_stack[0].shadow_type == TITAN_MSB_SHADOW && ((pixel_stack[0].pixel & 0xFFFFFF) != 0))
342 {
343 if (tt_context.trans(pixel_stack[0].pixel))
344 {
345 u32 bottom = pixel_stack[1].pixel;
346 pixel_stack[0].pixel = tt_context.blend(pixel_stack[0].pixel, bottom);
347 }
348
349 //sprite self-shadowing, only if sprite window is not enabled
350 if (!(Vdp2Regs->SPCTL & 0x10))
351 pixel_stack[0].pixel = TitanBlendPixelsTop(0x20000000, pixel_stack[0].pixel);
352 }
353 else if (pixel_stack[0].shadow_type == TITAN_NORMAL_SHADOW)
354 {
355 if (pixel_stack[1].shadow_enabled)
356 {
357 pixel_stack[0].pixel = TitanBlendPixelsTop(0x20000000, pixel_stack[1].pixel);
358 }
359 else
360 {
361 pixel_stack[0].pixel = pixel_stack[1].pixel;
362 }
363 }
364 else
365 {
366 if (tt_context.trans(pixel_stack[0].pixel))
367 {
368 u32 bottom = pixel_stack[1].pixel;
369 pixel_stack[0].pixel = tt_context.blend(pixel_stack[0].pixel, bottom);
370 }
371 }
372
373 return pixel_stack[0].pixel;
374 }
375
376 /* public */
TitanInit()377 int TitanInit()
378 {
379 int i;
380
381 if (! tt_context.inited)
382 {
383 for(i = 0;i < 6;i++)
384 {
385 if ((tt_context.vdp2framebuffer[i] = (struct PixelData *)calloc(sizeof(struct PixelData), 704 * 256)) == NULL)
386 return -1;
387 }
388
389 /* linescreen 0 is not initialized as it's not used... */
390 for(i = 1;i < 4;i++)
391 {
392 if ((tt_context.linescreen[i] = (u32 *)calloc(sizeof(u32), 512)) == NULL)
393 return -1;
394 }
395
396 if ((tt_context.backscreen = (struct PixelData *)calloc(sizeof(struct PixelData), 704 * 512)) == NULL)
397 return -1;
398
399 for (i = 0; i < 5; i++)
400 {
401 priority_thread_context.draw_finished[i] = 1;
402 priority_thread_context.need_draw[i] = 0;
403 }
404
405 YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_0, VidsoftPriorityThread0, NULL);
406 YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_1, VidsoftPriorityThread1, NULL);
407 YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_2, VidsoftPriorityThread2, NULL);
408 YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_3, VidsoftPriorityThread3, NULL);
409 YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_4, VidsoftPriorityThread4, NULL);
410
411 tt_context.inited = 1;
412 }
413
414 for(i = 0;i < 6;i++)
415 memset(tt_context.vdp2framebuffer[i], 0, sizeof(u32) * 704 * 256);
416
417 for(i = 1;i < 4;i++)
418 memset(tt_context.linescreen[i], 0, sizeof(u32) * 512);
419
420 return 0;
421 }
422
TitanErase()423 void TitanErase()
424 {
425 int i = 0;
426
427 int height = tt_context.vdp2height;
428
429 if (vdp2_interlace)
430 height /= 2;
431
432 for (i = 0; i < 6; i++)
433 memset(tt_context.vdp2framebuffer[i], 0, sizeof(struct PixelData) * tt_context.vdp2width * height);
434 }
435
TitanDeInit()436 int TitanDeInit()
437 {
438 int i;
439
440 for(i = 0;i < 6;i++)
441 free(tt_context.vdp2framebuffer[i]);
442
443 for(i = 1;i < 4;i++)
444 free(tt_context.linescreen[i]);
445
446 return 0;
447 }
448
TitanSetResolution(int width,int height)449 void TitanSetResolution(int width, int height)
450 {
451 tt_context.vdp2width = width;
452 tt_context.vdp2height = height;
453 }
454
TitanGetResolution(int * width,int * height)455 void TitanGetResolution(int * width, int * height)
456 {
457 *width = tt_context.vdp2width;
458 *height = tt_context.vdp2height;
459 }
460
TitanSetBlendingMode(int blend_mode)461 void TitanSetBlendingMode(int blend_mode)
462 {
463 if (blend_mode == TITAN_BLEND_BOTTOM)
464 {
465 tt_context.blend = TitanBlendPixelsBottom;
466 tt_context.trans = TitanTransBit;
467 }
468 else if (blend_mode == TITAN_BLEND_ADD)
469 {
470 tt_context.blend = TitanBlendPixelsAdd;
471 tt_context.trans = TitanTransBit;
472 }
473 else
474 {
475 tt_context.blend = TitanBlendPixelsTop;
476 tt_context.trans = TitanTransAlpha;
477 }
478 }
479
TitanPutBackHLine(s32 y,u32 color)480 void TitanPutBackHLine(s32 y, u32 color)
481 {
482 struct PixelData* buffer = &tt_context.backscreen[(y * tt_context.vdp2width)];
483 int i;
484
485 for (i = 0; i < tt_context.vdp2width; i++)
486 buffer[i].pixel = color;
487 }
488
TitanPutLineHLine(int linescreen,s32 y,u32 color)489 void TitanPutLineHLine(int linescreen, s32 y, u32 color)
490 {
491 if (linescreen == 0) return;
492
493 {
494 u32 * buffer = tt_context.linescreen[linescreen] + y;
495 *buffer = color;
496 }
497 }
498
TitanPutPixel(int priority,s32 x,s32 y,u32 color,int linescreen,vdp2draw_struct * info)499 void TitanPutPixel(int priority, s32 x, s32 y, u32 color, int linescreen, vdp2draw_struct* info)
500 {
501 if (priority == 0) return;
502
503 {
504 int pos = (y * tt_context.vdp2width) + x;
505 tt_context.vdp2framebuffer[info->titan_which_layer][pos].pixel = color;
506 tt_context.vdp2framebuffer[info->titan_which_layer][pos].priority = priority;
507 tt_context.vdp2framebuffer[info->titan_which_layer][pos].linescreen = linescreen;
508 tt_context.vdp2framebuffer[info->titan_which_layer][pos].shadow_enabled = info->titan_shadow_enabled;
509 tt_context.vdp2framebuffer[info->titan_which_layer][pos].shadow_type = info->titan_shadow_type;
510 }
511 }
512
TitanPutHLine(int priority,s32 x,s32 y,s32 width,u32 color)513 void TitanPutHLine(int priority, s32 x, s32 y, s32 width, u32 color)
514 {
515 if (priority == 0) return;
516
517 {
518 struct PixelData * buffer = &tt_context.vdp2framebuffer[priority][ (y * tt_context.vdp2width) + x];
519 int i;
520
521 for (i = 0; i < width; i++)
522 buffer[i].pixel = color;
523 }
524 }
525
TitanRenderLines(pixel_t * dispbuffer,int start_line,int end_line)526 void TitanRenderLines(pixel_t * dispbuffer, int start_line, int end_line)
527 {
528 int x, y, layer_y;
529 u32 dot;
530 int line_increment, interlace_line;
531
532 if (!tt_context.inited || (!tt_context.trans))
533 {
534 return;
535 }
536
537 Vdp2GetInterlaceInfo(&interlace_line, &line_increment);
538
539 set_layer_y(start_line, &layer_y);
540
541 for (y = start_line + interlace_line; y < end_line; y += line_increment)
542 {
543 for (x = 0; x < tt_context.vdp2width; x++)
544 {
545 int i = (y * tt_context.vdp2width) + x;
546 int layer_pos = (layer_y * tt_context.vdp2width) + x;
547
548 dispbuffer[i] = 0;
549
550 dot = TitanDigPixel(layer_pos, y);
551
552 if (dot)
553 {
554 dispbuffer[i] = TitanFixAlpha(dot);
555 }
556 }
557
558 layer_y++;
559 }
560 }
561
562 //num + 1 needs to be an even number to avoid issues with interlace modes
VIDSoftSetNumPriorityThreads(int num)563 void VIDSoftSetNumPriorityThreads(int num)
564 {
565 vidsoft_num_priority_threads = num > 5 ? 5 : num;
566
567 if (num == 2)
568 vidsoft_num_priority_threads = 1;
569
570 if (num == 4)
571 vidsoft_num_priority_threads = 3;
572 }
573
TitanStartPriorityThread(int which)574 void TitanStartPriorityThread(int which)
575 {
576 priority_thread_context.need_draw[which] = 1;
577 priority_thread_context.draw_finished[which] = 0;
578 YabThreadWake(YAB_THREAD_VIDSOFT_PRIORITY_0 + which);
579 }
580
TitanWaitForPriorityThread(int which)581 void TitanWaitForPriorityThread(int which)
582 {
583 while (!priority_thread_context.draw_finished[which]){}
584 }
585
TitanRenderThreads(pixel_t * dispbuffer,int can_use_simplified)586 void TitanRenderThreads(pixel_t * dispbuffer, int can_use_simplified)
587 {
588 int i;
589 int total_jobs = vidsoft_num_priority_threads + 1;//main thread runs a job
590 int num_lines_per_job = tt_context.vdp2height / total_jobs;
591 int remainder = tt_context.vdp2height % total_jobs;
592 int starts[6] = { 0 };
593 int ends[6] = { 0 };
594
595 priority_thread_context.dispbuffer = dispbuffer;
596 priority_thread_context.use_simplified = can_use_simplified;
597
598 for (i = 0; i < total_jobs; i++)
599 {
600 starts[i] = num_lines_per_job * i;
601 ends[i] = ((i + 1) * num_lines_per_job);
602 }
603
604 for (i = 0; i < vidsoft_num_priority_threads; i++)
605 {
606 priority_thread_context.lines[i].start = starts[i+1];
607 priority_thread_context.lines[i].end = ends[i+1];
608 }
609
610 //put any remaining lines on the last thread
611 priority_thread_context.lines[vidsoft_num_priority_threads - 1].end += remainder;
612
613 for (i = 0; i < vidsoft_num_priority_threads; i++)
614 {
615 TitanStartPriorityThread(i);
616 }
617
618 TitanRenderSimplifiedCheck(dispbuffer, starts[0], ends[0], can_use_simplified);
619
620 for (i = 0; i < vidsoft_num_priority_threads; i++)
621 {
622 TitanWaitForPriorityThread(i);
623 }
624 }
625
TitanRender(pixel_t * dispbuffer)626 void TitanRender(pixel_t * dispbuffer)
627 {
628 int can_use_simplified_rendering = 1;
629
630 if (!tt_context.inited || (!tt_context.trans))
631 {
632 return;
633 }
634
635 //using color calculation
636 if ((Vdp2Regs->CCCTL & 0x807f) != 0)
637 can_use_simplified_rendering = 0;
638
639 //using special priority
640 if ((Vdp2Regs->SFPRMD & 0x3ff) != 0)
641 can_use_simplified_rendering = 0;
642
643 //using line screen
644 if ((Vdp2Regs->LNCLEN & 0x1f) != 0)
645 can_use_simplified_rendering = 0;
646
647 //using shadow
648 if ((Vdp2Regs->SDCTL & 0x13F) != 0)
649 can_use_simplified_rendering = 0;
650
651 tt_context.layer_priority[TITAN_NBG0] = Vdp2Regs->PRINA & 0x7;
652 tt_context.layer_priority[TITAN_NBG1] = ((Vdp2Regs->PRINA >> 8) & 0x7);
653 tt_context.layer_priority[TITAN_NBG2] = (Vdp2Regs->PRINB & 0x7);
654 tt_context.layer_priority[TITAN_NBG3] = ((Vdp2Regs->PRINB >> 8) & 0x7);
655 tt_context.layer_priority[TITAN_RBG0] = (Vdp2Regs->PRIR & 0x7);
656
657 if (vidsoft_num_priority_threads > 0)
658 {
659 TitanRenderThreads(dispbuffer, can_use_simplified_rendering);
660 }
661 else
662 {
663 TitanRenderSimplifiedCheck(dispbuffer, 0, tt_context.vdp2height, can_use_simplified_rendering);
664 }
665 }
666
667 #ifdef WORDS_BIGENDIAN
TitanWriteColor(pixel_t * dispbuffer,s32 bufwidth,s32 x,s32 y,u32 color)668 void TitanWriteColor(pixel_t * dispbuffer, s32 bufwidth, s32 x, s32 y, u32 color)
669 {
670 int pos = (y * bufwidth) + x;
671 pixel_t * buffer = dispbuffer + pos;
672 *buffer = ((color >> 24) & 0xFF) | ((color >> 8) & 0xFF00) | ((color & 0xFF00) << 8) | ((color & 0xFF) << 24);
673 }
674 #else
TitanWriteColor(pixel_t * dispbuffer,s32 bufwidth,s32 x,s32 y,u32 color)675 void TitanWriteColor(pixel_t * dispbuffer, s32 bufwidth, s32 x, s32 y, u32 color)
676 {
677 int pos = (y * bufwidth) + x;
678 pixel_t * buffer = dispbuffer + pos;
679 *buffer = color;
680 }
681 #endif
682