aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx/alpha_mvi_crossblit.c
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/gfx/alpha_mvi_crossblit.c')
-rw-r--r--engines/sci/gfx/alpha_mvi_crossblit.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/engines/sci/gfx/alpha_mvi_crossblit.c b/engines/sci/gfx/alpha_mvi_crossblit.c
new file mode 100644
index 0000000000..6a1e238c2b
--- /dev/null
+++ b/engines/sci/gfx/alpha_mvi_crossblit.c
@@ -0,0 +1,360 @@
+/***************************************************************************
+ alpha_mvi_crossblit.c Copyright (C) 2001 Christoph Reichenbach
+
+
+ This program may be modified and copied freely according to the terms of
+ the GNU general public license (GPL), as long as the above copyright
+ notice and the licensing information contained herein are preserved.
+
+ Please refer to www.gnu.org for licensing details.
+
+ This work is provided AS IS, without warranty of any kind, expressed or
+ implied, including but not limited to the warranties of merchantibility,
+ noninfringement, and fitness for a specific purpose. The author will not
+ be held liable for any damage caused by this work or derivatives of it.
+
+ By using this source code, you agree to the licensing terms as stated
+ above.
+
+
+ Please contact the maintainer for bug reports or inquiries.
+
+ Current Maintainer:
+
+ Christoph Reichenbach (CR) <jameson@linuxgames.com>
+
+***************************************************************************/
+
+/** MUST be compiled with -mcpu=cv6! */
+
+#include <gfx_tools.h>
+
+
+#ifdef HAVE_ALPHA_EV6_SUPPORT
+
+#ifdef __DECC
+# include "c_asm.h"
+# define USE_C_CODE
+#else /* GNU C */
+# undef USE_C_CODE
+#endif
+
+void
+FUNCT_NAME(byte *dest, byte *src, int bytes_per_dest_line, int bytes_per_src_line,
+ int xl, int yl, byte *alpha, int bytes_per_alpha_line, int bytes_per_alpha_pixel,
+ unsigned int alpha_test_mask, int alpha_shift
+#ifdef PRIORITY
+ ,byte *priority_pos ,int bytes_per_priority_line, int bytes_per_priority_pixel, int priority
+#endif
+ )
+{
+#ifdef USE_C_CODE
+#ifdef PRIORITY
+ int left_mask = (255 << (((unsigned long) dest) & 7)) & 255;
+ int right_mask = (255 >> (((unsigned long) dest + bytes_per_dest_line) & 7));
+#endif
+ unsigned long data;
+
+ assert(!(bytes_per_alpha_line & 7));
+ assert(!(((unsigned long) src) & 3));
+ assert(!(((unsigned long) dest) & 3));
+ assert(bytes_per_alpha_pixel < 2);
+
+ yl++;
+ while (--yl) {
+ int x;
+ byte *dest_next = dest + bytes_per_dest_line;
+ byte *src_next = src + bytes_per_src_line;
+#ifdef PRIORITY
+ byte *pri_next = priority_pos + bytes_per_priority_line;
+#endif
+ asm ("ldl $31, 0($31)\n\t"
+ "ldl $31, 0($31)\n\t"); /* Prefetch memory for next line */
+
+ if (((unsigned long)src) & 4)
+ data = *((unsigned int *) src);
+
+ for (x = xl; x > 0; x--) {
+ unsigned long alpha;
+
+ if (!(((unsigned long)src) & 4))
+ data = *((unsigned long *) src);
+ alpha = (data & alpha_test_mask) >> alpha_shift;
+
+ if (
+#ifdef PRIORITY
+ (*priority_pos <= priority) &&
+#endif
+ alpha != 255) {
+ unsigned long result;
+ unsigned long orig;
+ unsigned long unpkdata;
+
+ unpkdata = asm("unpkbw %0, %v0\n\t", data);
+
+ result = unpkdata * (255 - alpha);
+
+ orig = *((unsigned int *) dest);
+
+ orig = asm("unpkbw %0, %v0\n\t", orig);
+
+ result += orig * alpha;
+ src += 4;
+
+ result >>= 8;
+
+ result = asm("pkwb %0, %v0\n\t", result);
+
+ data >>= 32;
+ *((unsigned int *) dest) = result;
+#ifdef PRIORITY
+ *priority_pos = priority;
+#endif
+ dest += 4;
+ } else {
+ data >>= 32;
+ src += 4;
+ dest += 4;
+ }
+
+#ifdef PRIORITY
+ priority_pos++;
+#endif
+ }
+
+ dest = dest_next;
+ src = src_next;
+#ifdef PRIORITY
+ priority_pos = pri_next;
+#endif
+ }
+#else
+ unsigned long real_alpha_shift = alpha_shift;
+#ifdef PRIORITY
+ assert(!(bytes_per_alpha_line & 7));
+ assert(bytes_per_alpha_pixel < 2);
+ real_alpha_shift |= (unsigned long) (priority << 16) | ((unsigned long) bytes_per_priority_pixel << 32);
+ /* Work around gcc design bug allowing only 10 asm parameters */
+#endif
+ __asm__ __volatile__ (
+#ifdef PRIORITY
+ /*
+ ** dest: $16
+ ** src: $17
+ ** bytes_per_dest_line: $18
+ ** bytes_per_src_line: $19
+ ** xl : $20
+ ** yl : $21
+ ** alpha_test_mask: $24
+ ** alpha_shift: $25
+ ** 255: $8
+ **
+ ** bytes_per_priority_line: $9
+ ** priority_pos: $10
+ ** priority extended to 8 bytes: $7
+ ** bytes_per_priority_pixel: $6
+ **
+ ** temp_priority_collection: $11
+ ** priority_pos backup: $12
+ ** left border mask: $13
+ ** right border mask: $28
+ ** priority test bit: $15
+ ** ldq4priority result: $26
+ */
+
+ "lda $30, -88($30) \n\t"
+ "stq $9, 0($30) \n\t"
+ "stq $10, 8($30) \n\t"
+ "stq $11, 16($30) \n\t"
+ "stq $12, 24($30) \n\t"
+ "stq $13, 32($30) \n\t"
+ "stq $15, 40($30) \n\t"
+ "stq $26, 48($30) \n\t"
+ "stq %8, 56($30) \n\t"
+ "stq %9, 64($30) \n\t"
+ "stq $7, 72($30) \n\t"
+ "stq $6, 80($30) \n\t"
+
+ "mov %8, $9 \n\t"
+ "mov %9, $10 \n\t"
+#endif
+ "mov %6, $24 \n\t"
+ "mov %7, $25 \n\t"
+ "mov 255, $8 \n\t"
+ "subl $21, 1, $21 \n\t"
+#ifdef PRIORITY
+
+ /* Defrobnicate real_alpha_shift data */
+ "srl $25, 32, $6 \n\t"
+ "srl $25, 16, $7 \n\t"
+ "and $7, $8, $7 \n\t"
+
+ /* Load first priority data quad */
+ "andnot $10, 7, $0 \n\t"
+ "ldq $26, 0($0) \n\t" /* Load priority */
+ "and $10, 7, $13 \n\t"
+ "sll $13, 3, $0 \n\t"
+
+ /* Calculate right border mask */
+ "addl $13, $20, $28\n\t"
+ "and $28, 7, $28 \n\t"
+ "beq $28, 7f \n\t"
+ "mov 8, $0 \n\t"
+ "subl $0, $28, $28 \n"
+ "7:\n\t"
+ "srl $8, $28, $28 \n\t"
+ /* Left border mask */
+ "sll $8, $13, $13 \n\t"
+ "and $13, $8, $13 \n\t"
+
+ "mov $10, $12 \n\t"
+
+ "sll $7, 8, $0 \n\t"
+ "or $7, $0, $7 \n\t"
+ "sll $7, 16, $0 \n\t"
+ "or $7, $0, $7 \n\t"
+ "sll $7, 32, $0 \n\t"
+ "or $7, $0, $7 \n\t"
+ "cmpbge $7, $26, $3 \n\t"
+
+ "and $10, 7, $0 \n\t" /* Init priority bitptr */
+ "mov 1, $15 \n\t" /* .. */
+ "sll $15, $0, $15 \n\t" /* .. */
+
+ /* -> Priority buffer */
+ "and $3, $13, $11 \n\t"
+ "cmplt $20, 8, $0 \n\t"
+ "beq $0, 6f \n\t"
+ "and $11, $28, $11 \n\t"
+ "6:\n\t"
+#endif
+ "and $25, $8, $25 \n\t"
+
+ /***/
+ /*** Variable settings apply NOW ***/
+ /***/
+
+ "mov $20, $1 \n\t"
+ "mov $16, $2 \n\t"
+ "mov $17, $3 \n"
+ "8:\n\t"
+ "addq $2, $18, $2 \n\t"
+ "ldl $31, 0($2) \n\t" /* Prefetch dest */
+ "addq $3, $19, $3 \n\t"
+ "ldl $31, 0($3) \n" /* Prefetch src */
+ "1:\n\t"
+ "addq $17, 4, $17 \n\t"
+ "beq $20, 3f \n\t"
+ "subl $20, 1, $20 \n\t"
+#ifdef PRIORITY
+ "5:\n\t"
+ "addq $10, 1, $10 \n\t"
+ "and $11, $15, $0 \n\t" /* Other priority beat our priority? */
+ "beq $0, 2f \n\t"
+#endif
+ "ldl $0, -4($17) \n\t"
+ "unpkbw $0, $5 \n\t"
+ "and $0, $24, $0 \n\t"
+
+ "xor $0, $24, $4 \n\t"
+ "beq $4, 2f \n\t"
+
+ "ldl $4, 0($16) \n\t"
+ "unpkbw $4, $4 \n\t"
+ "srl $0, $25, $0 \n\t"
+ "mulq $4, $0, $4 \n\t"
+ "subl $8, $0, $0 \n\t"
+ "mulq $5, $0, $5 \n\t"
+ "addq $4, $5, $4 \n\t"
+ "srl $4, 8, $4 \n\t"
+ "pkwb $4, $0 \n\t"
+ "stl $0, 0($16) \n\t"
+ "br 9f \n\t"
+ "2:\n"
+ "andnot $11, $15, $11 \n\t" /* Don't draw priority if we're fully transparent */
+ "9:\n\t"
+ "addq $16, 4, $16 \n\t"
+#ifdef PRIORITY
+ "sll $15, 1, $15 \n\t"
+
+ "and $10, 7, $0 \n\t" /* Do we need to re-load priority mask? */
+/**/ "bne $0, 1b \n\t"
+
+ /* Write back to priority buffer */
+ "zap $26, $11, $26 \n\t"
+ "zapnot $7, $11, $0 \n\t"
+ "or $0, $26, $0 \n\t"
+ "stq $0, -8($10) \n\t"
+
+ "ldq $26, 0($10) \n\t" /* Load priority */
+ "cmpbge $7, $26, $11\n\t"
+
+ "mov 1, $15 \n\t" /* Init bitcmpmask */
+
+ "cmplt $20, 8, $0 \n\t"
+/**/ "beq $0, 1b \n\t"
+ "and $11, $28, $11 \n\t"
+#endif
+ "br 1b \n"
+ "3:\n\t"
+#ifdef PRIORITY
+ "and $10, 7, $16 \n\t"
+ "beq $16, 7f \n\t"
+ "and $11, $28, $11 \n\t"
+ "zap $26, $11, $26 \n\t"
+ "zapnot $7, $11, $0 \n\t"
+ "or $0, $26, $0 \n\t"
+ "andnot $10, 7, $16 \n\t"
+ "stq $0, 0($16) \n" /* Write back */
+ "7:\n\t"
+
+ "addq $9, $12, $12 \n\t"
+ "mov $12, $10 \n\t"
+ "andnot $10, 7, $0 \n\t"
+ "ldq $26, 0($0) \n\t"
+
+ "and $10, 7, $0 \n\t"
+ "mov 1, $15 \n\t"
+ "sll $15, $0, $15 \n\t" /* Store priority-induced write-enable mask */
+
+ "cmpbge $7, $26, $16 \n\t"
+ /* -> Priority buffer */
+ "and $16, $13, $11 \n\t"
+#endif
+ "beq $21, 4f \n\t"
+ "subl $21, 1, $21 \n\t"
+ "mov $1, $20 \n\t"
+ "mov $2, $16 \n\t" /* Set line numbers for next line */
+ "mov $3, $17 \n\t"
+ "br 8b \n"
+ "4:\n\t"
+#ifdef PRIORITY
+ "ldq $9, 0($30) \n\t"
+ "ldq $10, 8($30) \n\t"
+ "ldq $11, 16($30) \n\t"
+ "ldq $12, 24($30) \n\t"
+ "ldq $13, 32($30) \n\t"
+ "ldq $15, 40($30) \n\t"
+ "ldq $26, 48($30) \n\t"
+ "ldq %8, 56($30) \n\t"
+ "ldq %9, 64($30) \n\t"
+ "ldq $7, 72($30) \n\t"
+ "ldq $6, 80($30) \n\t"
+ "lda $30, 88($30) \n\t"
+#endif
+ :
+ :
+ "r"(dest), "r"(src), "r"(bytes_per_dest_line),
+ /*3*/ "r"(bytes_per_src_line), "r"(xl), "r"(yl),
+ /*6*/ "r"((unsigned long) alpha_test_mask), "r"(real_alpha_shift)
+#ifdef PRIORITY
+ , "r"(bytes_per_priority_line), "r"(priority_pos)
+#endif
+ : "%0", "%1", "%2", "%3", "%4", "%5", "%6",
+ "%7", "$16", "$17", "$18", "$19", "$20", "$21", "$24", "$25",
+ "$8", "memory"
+ );
+#endif
+}
+
+#endif /* __alpha__ */