From 9489cb6df727d2bbb32b4ebf98b14be2ada47924 Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Mon, 2 Dec 2019 16:18:50 +0100 Subject: [PATCH 001/107] added amiga files --- CMake/amiga/Configure.readme | 1 + CMake/amiga/m68k-amigaos.cmake | 63 ++++ SourceX/platform/amiga/render68k.s | 568 +++++++++++++++++++++++++++++ 3 files changed, 632 insertions(+) create mode 100644 CMake/amiga/Configure.readme create mode 100755 CMake/amiga/m68k-amigaos.cmake create mode 100755 SourceX/platform/amiga/render68k.s diff --git a/CMake/amiga/Configure.readme b/CMake/amiga/Configure.readme new file mode 100644 index 00000000000..09cd03042b6 --- /dev/null +++ b/CMake/amiga/Configure.readme @@ -0,0 +1 @@ +cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../m68k-amigaos.cmake -DM68K_TOOLCHAIN_PATH=/opt/amiga -DM68K_CPU=68060 -DM68K_FPU=hard .. diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake new file mode 100755 index 00000000000..d95c6edaf34 --- /dev/null +++ b/CMake/amiga/m68k-amigaos.cmake @@ -0,0 +1,63 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR m68k) + +# CPU +set(M68K_CPU_TYPES "68000" "68010" "68020" "68040" "68060") +set(M68K_CPU "68000" CACHE STRING "Target CPU model") +set_property(CACHE M68K_CPU PROPERTY STRINGS ${M68K_CPU_TYPES}) + +# FPU +set(M68K_FPU_TYPES "soft" "hard") +set(M68K_FPU "soft" CACHE STRING "FPU type") +set_property(CACHE M68K_FPU PROPERTY STRINGS ${M68K_FPU_TYPES}) + +if(NOT M68K_TOOLCHAIN_PATH) + set(M68K_TOOLCHAIN_PATH /d/amiga-gcc2) +endif() +set(CMAKE_SYSROOT ${M68K_TOOLCHAIN_PATH}) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(AMIGA 1) +set(AMIGAOS3 1) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + +set(CMAKE_C_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/m68k-amigaos-gcc) +set(CMAKE_CXX_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/m68k-amigaos-g++) +set(CMAKE_CPP_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/m68k-amigaos-cpp) +set(CMAKE_ASM_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/vasmm68k_mot) +set(CMAKE_PREFIX_PATH ${M68K_TOOLCHAIN_PATH}) +if(WIN32) + set(CMAKE_C_COMPILER ${CMAKE_C_COMPILER}.exe) + set(CMAKE_CXX_COMPILER ${CMAKE_CXX_COMPILER}.exe) + set(CMAKE_CPP_COMPILER ${CMAKE_CPP_COMPILER}.exe) + set(CMAKE_ASM_COMPILER ${CMAKE_ASM_COMPILER}.exe) +endif() + +# Compiler flags +set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -fbbb=abcdefghi -O3 -ffast-math -m68080 -w -fpermissive -fomit-frame-pointer -s -noixemul") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -Fhunk -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include") +set(CMAKE_ASM_COMPILE_OBJECT " -o ") +set(BUILD_SHARED_LIBS OFF) +unset(FLAGS_COMMON) + +# Linker configuration +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -Wl,--no-whole-archive -lft2 -lz -noixemul -s -Xlinker --allow-multiple-definition ") + +set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") +# user +set(FREETYPE_INCLUDE_DIRS ${M68K_TOOLCHAIN_PATH}/m68k-amigaos/include) +set(LIBMAD_INCLUDE_DIRS ${M68K_TOOLCHAIN_PATH}/m68k-amigaos/include) + +set(ASAN OFF) +set(UBSAN OFF) +set(NONET ON) +set(DEBUG OFF) +set(USE_SDL1 "Use SDL1.2 instead of SDL2" ON) +add_definitions(-D_POSIX_C_SOURCE=200809L) \ No newline at end of file diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s new file mode 100755 index 00000000000..3e70058d986 --- /dev/null +++ b/SourceX/platform/amiga/render68k.s @@ -0,0 +1,568 @@ +* ---------------------------------------------------------------------------------------------- +* diablo.s -- replacement of C code by hand-written asm code by S.Devulder +* ---------------------------------------------------------------------------------------------- + section .text + +BUFFER_WIDTH set 768 ; FIXME: set the correct value here + + XDEF _RenderTile_RT_SQUARE + XDEF _RenderTile_RT_TRANSPARENT + XDEF _RenderTile_RT_LTRIANGLE + XDEF _RenderTile_RT_RTRIANGLE + XDEF _RenderTile_RT_LTRAPEZOID + XDEF _RenderTile_RT_RTRAPEZOID + + XDEF _RenderLine0 + XDEF _RenderLine1 + XDEF _RenderLine2 + + XREF __ZN3dvl10gpBufStartE + XREF __ZN3dvl8gpBufEndE + + cnop 0,4 + +* ---------------------------------------------------------------------------------------------- + +* inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD mask) +* a0 = *dst +* a1 = *src +* d0 = n (1..32) +* a2 = tbl +* d1 = *mask +* d2 = scratch +* d3 = scratch +* CC sets according to d1 value + +inc_a0 macro + addq.l #1,a0 + endm + +inc_a0_a1 macro +* cmp.b (a1)+,(a0)+ + addq.l #1,a1 + addq.l #1,a0 + endm + +unroll macro + btst #5,d0 + beq \1_4 + \1 + \1 + \1 + \1 + \1 + \1 + \1 + \1 +\1_4 + btst #4,d0 + beq \1_2 + \1 + \1 + \1 + \1 +\1_2 + btst #3,d0 + beq \1_1 + \1 + \1 +\1_1 + btst #2,d0 + beq \2_1 + \1 +\2_1 + btst #1,d0 + beq \3_1 + \2 +\3_1 + btst #0,d0 + beq \3_2 + \3 +\3_2 + rts + endm + +loop macro +\1__1 + add.l d1,d1 + bcs \1__2 + \1 + subq.w #1,d0 + bne \1__1 + rts +\1__2 + \2 + subq.w #1,d0 + bne \1__1 + rts + endm + +* case light_table_index == 0 +_RenderLine0_ + add.w d0,a1 + add.w d0,a0 + rts +_RenderLine0 + move.l -(a3),d1 + beq.b _RenderLine0_ + cmp.l a5,a0 + bcs.b _RenderLine0_ + cmp.l a6,a0 + bhi.b _RenderLine0_ + + not.l d1 + bne .l1 +.m4 macro + move.l (a1)+,(a0)+ + endm +.m2 macro + move.w (a1)+,(a0)+ + endm +.m1 macro + move.b (a1)+,(a0)+ + endm + unroll .m4,.m2,.m1 + +.l1 + cmp.l #$AAAAAAAA,d1 ; bg / fg / bg fg + bne .l2 +.p4 macro + ifeq 1 + move.b 1(a1),1(a0) ; 2 + move.b 3(a1),3(a0) ; 2 + addq.l #4,a1 ; .5 + addq.l #4,a0 ; .5 ==> 5 cycles + else + move.l (a1)+,d1 ; \ + and.l #$00FF00FF,d1 ; / 1 cycle (fused) ? + move.l (a0),d2 ; \ + and.l #$FF00FF00,d2 ; / 1 cycle (fused) ? + or.l d2,d1 ; 1 + move.l d1,(a0)+ ; 1 ==> 4 cycles + endc + endm +.p2 macro + move.b 1(a1),1(a0) + addq.l #2,a1 + addq.l #2,a0 + endm +.p1 macro + addq.l #1,a1 + addq.l #1,a0 + endm + unroll .p4,.p2,.p1 + +.l2 + cmp.l #$55555555,d1 ; fg / bg /fg / bg + bne .l3 + +.q4 macro + ifeq 1 + move.b (a1),(a0) ; 2 + move.b 2(a1),2(a0) ; 2 + addq.l #4,a1 ; .5 + addq.l #4,a0 ; .5 ==> 5 cycles + else + move.l #$FF00FF00,d1 + and.l (a1)+,d1 + move.l #$00FF00FF,d2 + and.l (a0),d2 + or.l d2,d1 + move.l d1,(a0)+ + endc + endm +.q2 macro + ifeq 0 + move.b (a1),(a0) + addq.l #2,a1 + addq.l #2,a0 + else + move.w #$FF00,d1 + and.w (a1)+,d1 + move.w #$00FF,d2 + and.w (a0),d2 + or.w d2,d1 + move.w d1,(a0)+ + endc + endm +.q1 macro + move.b (a1)+,(a0)+ + endm + unroll .q4,.q2,.q1 + +.l3 + loop .m1,inc_a0_a1 + + +* case light_table_index == lightmax +_RenderLine1_ + add.w d0,a0 + rts +_RenderLine1 + move.l -(a3),d1 + add.w d0,a1 + beq.b _RenderLine1_ + cmp.l a5,a0 + bcs.b _RenderLine1_ + cmp.l a6,a0 + bhi.b _RenderLine1_ + + not.l d1 + bne .l1 + +.m4 macro + clr.l (a0)+ + endm +.m2 macro + clr.w (a0)+ + endm +.m1 macro + clr.b (a0)+ + endm + unroll .m4,.m2,.m1 +.l1 + cmp.l #$AAAAAAAA,d1 + bne .l2 + move.l #$FF00FF00,d2 +.p4 macro + and.l d2,(a0)+ + endm +.p2 macro + and.w d2,(a0)+ + endm +.p1 macro + addq.l #1,a0 + endm + unroll .p4,.p2,.p1 + +.l2 + cmp.l #$55555555,d1 + bne .l3 + move.l #$00FF00FF,d2 +.q4 macro + and.l d2,(a0)+ + endm +.q2 macro + and.w d2,(a0)+ + endm +.q1 macro + clr.b (a0)+ + endm + unroll .q4,.q2,.q1 +.l3 + loop .m1,inc_a0 + +* other cases +_RenderLine2_ + add.w d0,a1 + add.w d0,a0 + rts +_RenderLine2 + move.l -(a3),d1 + beq _RenderLine2_ + cmp.l a5,a0 + bcs.b _RenderLine2_ + cmp.l a6,a0 + bhi.b _RenderLine2_ + + moveq #0,d2 + moveq #0,d3 + + + not.l d1 + bne .l1 +.m4 macro + move.b (a1)+,d2 ; \ merged ? + move.b (a1)+,d3 ; / + move.w (a2,d2.w),d1 + move.b (a2,d3.w),d1 + swap d1 + move.b (a1)+,d2 ; \ + move.b (a1)+,d3 ; / + move.w (a2,d2.w),d1 + move.b (a2,d3.w),d1 + move.l d1,(a0)+ + endm +.m2 macro + move.b (a1)+,d2 ; \ + move.b (a1)+,d3 ; / + move.w (a2,d2.w),d1 + move.b (a2,d3.w),d1 + move.w d1,(a0)+ + endm +.m1 macro + move.b (a1)+,d2 + move.b (a2,d2.w),(a0)+ + endm + unroll .m4,.m2,.m1 + +.l1 + cmp.l #$AAAAAAAA,d1 + bne .l2 +.p4 macro + move.b 1(a1),d2 + move.b 3(a1),d3 + move.b (a2,d2.w),1(a0) + move.b (a2,d3.w),3(a0) + addq.l #4,a1 + addq.l #4,a0 + endm +.p2 macro + move.b 1(a1),d2 + move.b (a2,d2.w),1(a0) + addq.l #2,a1 + addq.l #2,a0 + endm +.p1 macro + inc_a0_a1 + endm + unroll .p4,.p2,.p1 + +.l2 + cmp.l #$55555555,d1 + bne .l3 +.q4 macro + move.b (a1),d2 + move.b 2(a1),d3 + move.b (a2,d2.w),(a0) + move.b (a2,d3.w),2(a0) + addq.l #4,a1 + addq.l #4,a0 + endm +.q2 macro + move.b (a1),d2 + move.b (a2,d2.l),(a0) + addq.l #2,a1 + addq.l #2,a0 + endm +.q1 macro + move.b (a1)+,d2 + move.b (a2,d2.l),(a0)+ + endm + unroll .q4,.q2,.q1 + +.l3 + loop .m1,inc_a0_a1 + +*---------------------------------------------------------------------------------------- +setup macro +* get params from stack +* movem.l (4*(1+\1),sp),a0/a1/a2/a3 + move.l (4*(1+\1),sp),a0 ; \ + move.l (4*(2+\1),sp),a1 ; / fused + + move.l (4*(3+\1),sp),a2 ; \ fused + move.l (4*(4+\1),sp),a3 ; / + +* determine renderFcn + lea _RenderLine0(pc),a4 + move.l __ZN3dvl17light_table_indexE,d2 + beq .L0 + sub.b __ZN3dvl8lightmaxE,d2 + lea _RenderLine2(pc),a4 + bne.b .L0 + lea _RenderLine1(pc),a4 +* factorize constants in regs +.L0 + move.l __ZN3dvl10gpBufStartE,a5 + addq.l #4,a3 + move.l __ZN3dvl8gpBufEndE,a6 + endm + +prologue_7 macro +* movem.l d2-d3/a2-a6,-(sp) + sub.w #4*7,sp + move.l d2,4*0(sp) ; \ + move.l d3,4*1(sp) ; / fused + + move.l a2,4*2(sp) ; \ + move.l a3,4*3(sp) ; / fused + + move.l a4,4*4(sp) ; \ + move.l a5,4*5(sp) ; / fused + + move.l a6,4*6(sp) + setup 7 + endm + +epilogue_7 macro +* movem.l (sp)+,d2-d3/a2-a3/a4-a6 + move.l (sp)+,d2 ; \ fused + move.l (sp)+,d3 ; / + move.l (sp)+,a2 ; \ fused + move.l (sp)+,a3 ; / + move.l (sp)+,a4 ; \ fused + move.l (sp)+,a5 ; / + move.l (sp)+,a6 ; \ fused?? + rts ; / + endm + +prologue_11 macro +* movem.l d2-d7/a2-a6,-(sp) + sub.w #4*11,sp + move.l d2,4*0(sp) ; \ + move.l d3,4*1(sp) ; / fused + + move.l d4,4*2(sp) ; \ + move.l d5,4*3(sp) ; / fused + + move.l d6,4*4(sp) ; \ + move.l d7,4*5(sp) ; / fused + + move.l a2,4*6(sp) ; \ + move.l a3,4*7(sp) ; / fused + + move.l a4,4*8(sp) ; \ + move.l a5,4*9(sp) ; / fused + + move.l a6,4*10(sp) + + setup 11 + endm + +epilogue_11 macro +* movem.l (sp)+,d2-d7/a2-a6 + move.l (sp)+,d2 ; \ fused + move.l (sp)+,d3 ; / + move.l (sp)+,d4 ; \ fused + move.l (sp)+,d5 ; / + move.l (sp)+,d6 ; \ fused + move.l (sp)+,d7 ; / + move.l (sp)+,a2 ; \ fused + move.l (sp)+,a3 ; / + move.l (sp)+,a4 ; \ fused + move.l (sp)+,a5 ; / + move.l (sp)+,a6 ; \ fused?? + rts ; / + endm + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_TRANSPARENT(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_TRANSPARENT + prologue_11 + addq.l #2,a4 ; skip over load mask + moveq #31,d7 +.L1 + move.l -(a3),d6 ; m = *mask; mask-- + moveq #32,d4 +.L2 + move.b (a1)+,d5 ; v = *src++; + ext.w d5 + bgt.b .L3 + suba.w d5,a0 ; dst += (-v) + neg.w d5 ; v =-v (parallel!) + bra.b .L4 +.L3 + move.w d5,d0 + move.l d6,d1 + jsr (a4) +.L4 + lsl.l d5,d6 ; m <<= v + sub.w d5,d4 ; j -= v + bne.b .L2 + sub.w #BUFFER_WIDTH+32,a0 + dbra d7,.L1 + epilogue_11 + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_SQUARE + prologue_7 + bsr block16 + bsr block16 + epilogue_7 + +*---------------------------------------------------------------------------------------- + + XDEF block16 +block16 + REPT 16 + moveq #32,d0 + jsr (a4) + sub.w #BUFFER_WIDTH+32,a0 + ENDR + rts + +triangL +.i set 30 + add.w #.i,a0 + REPT 16 + IFNE .i&2 + addq.w #2,a1 + ENDC + moveq #32-.i,d0 + jsr (a4) + IFNE .i +.i set .i-2 + ENDC + sub.w #BUFFER_WIDTH+32-.i,a0 + ENDR + rts + +triangR +.i set 30 + REPT 16 + moveq #32-.i,d0 + jsr (a4) + IFNE .i&2 + addq.w #2,a1 + ENDC + sub.w #BUFFER_WIDTH+32-.i,a0 +.i set .i-2 + ENDR + rts + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_LTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_LTRIANGLE + prologue_7 + bsr triangL +.i set 2 + addq.l #.i,a0 + REPT 15 + IFNE .i&2 + addq.w #2,a1 + ENDC + moveq #32-.i,d0 + jsr (a4) + IFNE .i-30 +.i set .i+2 + sub.w #BUFFER_WIDTH+32-.i,a0 + ENDC + ENDR + epilogue_7 + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_RTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_RTRIANGLE + prologue_7 + bsr triangR +.i set 2 + REPT 15 + moveq #32-.i,d0 + jsr (a4) + IFNE .i&2 + addq.w #2,a1 + ENDC + sub.w #BUFFER_WIDTH+32-.i,a0 +.i set .i+2 + ENDR + epilogue_7 + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_LTRAPEZOID + prologue_7 + bsr triangL + bsr block16 + epilogue_7 + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_RTRAPEZOID + prologue_7 + bsr triangR + bsr block16 + epilogue_7 + +* end of file \ No newline at end of file From 286e3087eaf9f6470d099e671704a2b4007fe76f Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Mon, 2 Dec 2019 16:25:12 +0100 Subject: [PATCH 002/107] fixed Configure.readme script --- CMake/amiga/Configure.readme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/amiga/Configure.readme b/CMake/amiga/Configure.readme index 09cd03042b6..554ef7e88c9 100644 --- a/CMake/amiga/Configure.readme +++ b/CMake/amiga/Configure.readme @@ -1 +1 @@ -cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../m68k-amigaos.cmake -DM68K_TOOLCHAIN_PATH=/opt/amiga -DM68K_CPU=68060 -DM68K_FPU=hard .. +cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../CMake/amiga/m68k-amigaos.cmake -DM68K_TOOLCHAIN_PATH=/opt/amiga -DM68K_CPU=68080 -DM68K_FPU=hard .. From a3aafa77a1ad38046134a0d62693845ac667af0f Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Mon, 2 Dec 2019 17:15:13 +0100 Subject: [PATCH 003/107] 1st successfull compilation --- CMake/amiga/Configure.readme | 2 ++ CMake/amiga/m68k-amigaos.cmake | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CMake/amiga/Configure.readme b/CMake/amiga/Configure.readme index 554ef7e88c9..be12be308fc 100644 --- a/CMake/amiga/Configure.readme +++ b/CMake/amiga/Configure.readme @@ -1 +1,3 @@ +export SDLDIR=/opt/amiga/m68k-amigaos/ + cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../CMake/amiga/m68k-amigaos.cmake -DM68K_TOOLCHAIN_PATH=/opt/amiga -DM68K_CPU=68080 -DM68K_FPU=hard .. diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index d95c6edaf34..2a276766afe 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -39,7 +39,10 @@ if(WIN32) endif() # Compiler flags -set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -fbbb=abcdefghi -O3 -ffast-math -m68080 -w -fpermissive -fomit-frame-pointer -s -noixemul") +set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage \ + -fsched-pressure -fsched-spec-load \ + -fsched-verbose=2 \ + -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -Fhunk -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include") @@ -48,7 +51,7 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -Wl,--no-whole-archive -lft2 -lz -noixemul -s -Xlinker --allow-multiple-definition ") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") # user From b34601ab37cff404481dd45cf2fab2effb760b3d Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Mon, 2 Dec 2019 23:27:50 +0100 Subject: [PATCH 004/107] fixed palette + intro-movie --- SourceS/sdl_compat.h | 6 ++++++ SourceX/storm/storm.cpp | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index f9213b89c92..dd3ff9cd171 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -94,6 +94,12 @@ inline int SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *pa } if (colors != (palette->colors + firstcolor)) SDL_memcpy(palette->colors + firstcolor, colors, ncolors * sizeof(*colors)); + + #if SDL1_VIDEO_MODE_BPP == 8 + // In SDL1, if the Video Surface is 8bit, you need to set this as well to match, + // otherwise colors will be wrong! + SDL_SetColors(SDL_GetVideoSurface(), colors, firstcolor, ncolors); + #endif // In SDL1, the surface always has its own distinct palette, so we need to // update it as well. return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) - 1; diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 8c6530d2e82..03591c5bfd1 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -703,7 +703,9 @@ BOOL SVidPlayContinue(void) Uint32 format = SDL_GetWindowPixelFormat(window); SDL_Surface *tmp = SDL_ConvertSurfaceFormat(SVidSurface, format, 0); #endif - ScaleOutputRect(&pal_surface_offset); +#ifndef __AMIGA__ + ScaleOutputRect(&pal_surface_offset); // somehow this lead to pb with amiga's SDL +#endif if (SDL_BlitScaled(tmp, NULL, GetOutputSurface(), &pal_surface_offset) <= -1) { SDL_Log(SDL_GetError()); return false; From cffcdbc52cc88362cbffb1b3a0d38df5429c8d44 Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Mon, 2 Dec 2019 23:29:28 +0100 Subject: [PATCH 005/107] moved fps to the right in case screen truncate left column --- Source/scrollrt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 5ff42a45ffd..da74679ae20 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1061,7 +1061,7 @@ static void DrawFPS() frameend = 0; } wsprintf(String, "%d FPS", framerate); - PrintGameStr(8, 65, String, COL_RED); + PrintGameStr(8+8, 65, String, COL_RED); } } From 4b5d0640fc1b4983e17b76f0fcf144131fabcb85 Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Tue, 3 Dec 2019 00:27:16 +0100 Subject: [PATCH 006/107] added asm version of render --- CMake/amiga/m68k-amigaos.cmake | 9 +++----- CMakeLists.txt | 7 +++++- Source/render.cpp | 35 ++++++++++++++++++++++++++++++ SourceX/platform/amiga/render68k.s | 4 +++- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 2a276766afe..287d1a05abd 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -39,14 +39,11 @@ if(WIN32) endif() # Compiler flags -set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage \ - -fsched-pressure -fsched-spec-load \ - -fsched-verbose=2 \ - -w -fpermissive -fomit-frame-pointer -g -noixemul") +set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -Fhunk -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include") -set(CMAKE_ASM_COMPILE_OBJECT " -o ") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include") +set(CMAKE_ASM_COMPILE_OBJECT " ${CMAKE_ASM_FLAGS} -o ") set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71f7115f3e3..eda76ba5951 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ endif() project(DevilutionX VERSION ${GIT_TAG} - LANGUAGES C CXX) + LANGUAGES C CXX ASM) if(BINARY_RELEASE) set(CMAKE_BUILD_TYPE "Release") @@ -311,6 +311,11 @@ if(SWITCH) set(BIN_TARGET devilutionx.elf) endif() +if(AMIGA) + list(APPEND devilutionx_SRCS + SourceX/platform/amiga/render68k.s) +endif() + add_executable(${BIN_TARGET} MACOSX_BUNDLE ${devilutionx_SRCS}) configure_file(SourceS/config.h.in config.h @ONLY) diff --git a/Source/render.cpp b/Source/render.cpp index 3cd7cd7479d..5338db03fc4 100644 --- a/Source/render.cpp +++ b/Source/render.cpp @@ -139,6 +139,17 @@ inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD ma } } +#ifdef __AMIGA__ +extern "C" { + void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask); + void RenderTile_RT_TRANSPARENT(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask); + void RenderTile_RT_LTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask); + void RenderTile_RT_RTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask); + void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask); + void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask); +} +#endif + #if defined(__clang__) || defined(__GNUC__) __attribute__((no_sanitize("shift-base"))) #endif @@ -185,11 +196,18 @@ RenderTile(BYTE *pBuff) switch (tile) { case RT_SQUARE: +#if defined(__AMIGA__) + RenderTile_RT_SQUARE(dst,src,tbl,mask); +#else for (i = 32; i != 0; i--, dst -= BUFFER_WIDTH + 32, mask--) { RenderLine(&dst, &src, 32, tbl, *mask); } +#endif break; case RT_TRANSPARENT: +#if defined(__AMIGA__) + RenderTile_RT_TRANSPARENT(dst,src,tbl,mask); +#else for (i = 32; i != 0; i--, dst -= BUFFER_WIDTH + 32, mask--) { m = *mask; for (j = 32; j != 0; j -= v, v == 32 ? m = 0 : m <<= v) { @@ -202,8 +220,12 @@ RenderTile(BYTE *pBuff) } } } +#endif break; case RT_LTRIANGLE: +#if defined(__AMIGA__) + RenderTile_RT_LTRIANGLE(dst,src,tbl,mask); +#else for (i = 30; i >= 0; i -= 2, dst -= BUFFER_WIDTH + 32, mask--) { src += i & 2; dst += i; @@ -214,8 +236,12 @@ RenderTile(BYTE *pBuff) dst += i; RenderLine(&dst, &src, 32 - i, tbl, *mask); } +#endif break; case RT_RTRIANGLE: +#if defined(__AMIGA__) + RenderTile_RT_RTRIANGLE(dst,src,tbl,mask); +#else for (i = 30; i >= 0; i -= 2, dst -= BUFFER_WIDTH + 32, mask--) { RenderLine(&dst, &src, 32 - i, tbl, *mask); src += i & 2; @@ -226,8 +252,12 @@ RenderTile(BYTE *pBuff) src += i & 2; dst += i; } +#endif break; case RT_LTRAPEZOID: +#if defined(__AMIGA__) + RenderTile_RT_LTRAPEZOID(dst,src,tbl,mask); +#else for (i = 30; i >= 0; i -= 2, dst -= BUFFER_WIDTH + 32, mask--) { src += i & 2; dst += i; @@ -236,8 +266,12 @@ RenderTile(BYTE *pBuff) for (i = 16; i != 0; i--, dst -= BUFFER_WIDTH + 32, mask--) { RenderLine(&dst, &src, 32, tbl, *mask); } +#endif break; case RT_RTRAPEZOID: +#if defined(__AMIGA__) + RenderTile_RT_RTRAPEZOID(dst,src,tbl,mask); +#else for (i = 30; i >= 0; i -= 2, dst -= BUFFER_WIDTH + 32, mask--) { RenderLine(&dst, &src, 32 - i, tbl, *mask); src += i & 2; @@ -246,6 +280,7 @@ RenderTile(BYTE *pBuff) for (i = 16; i != 0; i--, dst -= BUFFER_WIDTH + 32, mask--) { RenderLine(&dst, &src, 32, tbl, *mask); } +#endif break; } } diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s index 3e70058d986..690b5ac592f 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.s @@ -18,6 +18,8 @@ BUFFER_WIDTH set 768 ; FIXME: set the correct value here XREF __ZN3dvl10gpBufStartE XREF __ZN3dvl8gpBufEndE + XREF __ZN3dvl8lightmaxE + XREF __ZN3dvl17light_table_indexE cnop 0,4 @@ -28,7 +30,7 @@ BUFFER_WIDTH set 768 ; FIXME: set the correct value here * a1 = *src * d0 = n (1..32) * a2 = tbl -* d1 = *mask +* d1 = *mask * d2 = scratch * d3 = scratch * CC sets according to d1 value From f05cbc3e68a7feef68571d218d77c63e5634af12 Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Wed, 4 Dec 2019 15:13:12 +0100 Subject: [PATCH 007/107] SAGA started to work! --- SourceX/platform/amiga/render68k.s | 318 +++++++++++++++++++++++++---- 1 file changed, 282 insertions(+), 36 deletions(-) diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s index 690b5ac592f..2a4b6e082e3 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.s @@ -3,7 +3,10 @@ * ---------------------------------------------------------------------------------------------- section .text + machine 68080 + BUFFER_WIDTH set 768 ; FIXME: set the correct value here +VAMP_V4 set 0 XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -15,13 +18,223 @@ BUFFER_WIDTH set 768 ; FIXME: set the correct value here XDEF _RenderLine0 XDEF _RenderLine1 XDEF _RenderLine2 + XDEF _RenderLine0_AMMX + XDEF _RenderLine1_AMMX + XDEF _RenderLine2_AMMX XREF __ZN3dvl10gpBufStartE XREF __ZN3dvl8gpBufEndE XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE + XREF _ac68080 cnop 0,4 + +* ---------------------------------------------------------------------------------------------- +* debug: displays nothing + +_RenderLine_NONE + move.l -(a3),d1 + add.w d0,a1 + add.w d0,a0 + rts + +* ---------------------------------------------------------------------------------------------- +* AMMX version + +unroll_AMMX macro + btst #5,d0 + beq \1_16 +* 32 bytes in a row + \1 + \1 + \1 + \1 +* we can leave since there is never no more than 32 bytes + rts +\1_16 + btst #4,d0 + beq \1_8 +* 16 bytes in a row + \1 + \1 +\1_8 + btst #3,d0 + beq \1_0 +* 8 bytes in a row + \1 +\1_0 + moveq #7,d2 + and.l d2,d0 + beq \3 +* 1 to 7 bytes + \2 +* fixup ptrs +\3 + endm + +* case light_table_index == lightmax +_RenderLine1_AMMX + move.l -(a3),d1 + add.w d0,a1 + beq.b .nx + cmp.l a5,a0 + bcs.b .nx + cmp.l a6,a0 + bhi.b .nx + + peor d2,d2,d2 ; d2=0.q + moveq #1,d3 + add.l d1,d3 + bne .mask + +* no mask +.n8 macro + store d2,(a0)+ + endm +.n0 macro + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx + add.w d0,a0 + rts + +* mask version +.m8 macro + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0 macro + move.w #$ff00,d3 + lsr.w d0,d3 + rol.l #8,d1 + and.w d3,d1 + storem d2,d1,(a0) + endm +.mask + unroll_AMMX .m8,.m0,.mx + add.w d0,a0 + rts + +* case light_table_index == 0 +_RenderLine0_AMMX + move.l -(a3),d1 + beq.b .nx + cmp.l a5,a0 + bcs.b .nx + cmp.l a6,a0 + bhi.b .nx + + moveq #1,d2 + add.l d1,d2 + bne .mask + +* no mask +.n8 macro + load (a1)+,d2 + store d2,(a0)+ + endm +.n0 macro + load (a1),d2 + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx + add.w d0,a1 + add.w d0,a0 + rts + +* version with mask +.m8 macro + rol.l #8,d1 + load (a1)+,d2 + storem d2,d1,(a0)+ + endm +.m0 macro + move.w #$ff00,d2 + lsr.w d0,d2 + rol.l #8,d1 + and.w d2,d1 + load (a1),d2 + storem d2,d1,(a0) + endm +.mask + unroll_AMMX .m8,.m0,.mx + add.w d0,a1 + add.w d0,a0 + rts + +* other cases +_RenderLine2_AMMX + move.l -(a3),d1 + beq.b _RenderLine0_AMMX\.mx + cmp.l a5,a0 + bcs.b _RenderLine0_AMMX\.mx + cmp.l a6,a0 + bhi.b _RenderLine0_AMMX\.mx + + move.l d1,d3 ; \ fused + addq.l #1,d3 ; / + bne .mask + +* here d3=0 => no need to init + +.transf macro + vperm #$A7A5A3A1,d2,d3,d3 + vperm #$A6A4A2A0,d2,d3,d2 + move.w (a2,d2.w),d2 + move.b (a2,d3.w),d2 + swap d2 + swap d3 + move.w (a2,d2.w),d2 + move.b (a2,d3.w),d2 + vperm #$45670123,d2,d2,d2 +* lsrq #32,d3 ; doesn't compile with vasm + vperm #$00000123,d3,d3,d3 + move.w (a2,d2.w),d2 + move.b (a2,d3.w),d2 + swap d2 + swap d3 + move.w (a2,d2.w),d2 + move.b (a2,d3.w),d2 ; 12 cycles for 8 bytes ? + endm + +.n8 macro + load (a1)+,d2 + .transf + store d2,(a0)+ + endm +.n0 macro + load (a1),d2 + .transf + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx + add.w d0,a1 + add.w d0,a0 + rts + +* mask version +.m8 macro + load (a1)+,d2 + .transf + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0 macro + load (a1),d2 + .transf + move.w #$ff00,d3 + lsr.w d0,d3 + rol.l #8,d1 + and.w d3,d1 + storem d2,d1,(a0) + endm +.mask + moveq #0,d3 + unroll_AMMX .m8,.m0,.mx + add.w d0,a1 + add.w d0,a0 + rts * ---------------------------------------------------------------------------------------------- @@ -56,6 +269,7 @@ unroll macro \1 \1 \1 + rts \1_4 btst #4,d0 beq \1_2 @@ -113,7 +327,7 @@ _RenderLine0 bhi.b _RenderLine0_ not.l d1 - bne .l1 + bne .mask .m4 macro move.l (a1)+,(a0)+ endm @@ -125,7 +339,7 @@ _RenderLine0 endm unroll .m4,.m2,.m1 -.l1 +.mask cmp.l #$AAAAAAAA,d1 ; bg / fg / bg fg bne .l2 .p4 macro @@ -210,7 +424,7 @@ _RenderLine1 bhi.b _RenderLine1_ not.l d1 - bne .l1 + bne .mask .m4 macro clr.l (a0)+ @@ -222,7 +436,7 @@ _RenderLine1 clr.b (a0)+ endm unroll .m4,.m2,.m1 -.l1 +.mask cmp.l #$AAAAAAAA,d1 bne .l2 move.l #$FF00FF00,d2 @@ -270,9 +484,8 @@ _RenderLine2 moveq #0,d2 moveq #0,d3 - not.l d1 - bne .l1 + bne .mask .m4 macro move.b (a1)+,d2 ; \ merged ? move.b (a1)+,d3 ; / @@ -298,7 +511,7 @@ _RenderLine2 endm unroll .m4,.m2,.m1 -.l1 +.mask cmp.l #$AAAAAAAA,d1 bne .l2 .p4 macro @@ -349,30 +562,51 @@ _RenderLine2 *---------------------------------------------------------------------------------------- setup macro * get params from stack -* movem.l (4*(1+\1),sp),a0/a1/a2/a3 + IFNE VAMP_V4 + movem.l (4*(1+\1),sp),a0/a1/a2/a3 + ELSE move.l (4*(1+\1),sp),a0 ; \ move.l (4*(2+\1),sp),a1 ; / fused move.l (4*(3+\1),sp),a2 ; \ fused move.l (4*(4+\1),sp),a3 ; / + ENDC + bsr _setup + endm +_setup * determine renderFcn + tst.w _ac68080 + bne .ammx lea _RenderLine0(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 beq .L0 sub.b __ZN3dvl8lightmaxE,d2 lea _RenderLine2(pc),a4 bne.b .L0 - lea _RenderLine1(pc),a4 + lea _RenderLine1(pc),a4 + bra .L0 +.ammx + lea _RenderLine0_AMMX(pc),a4 + move.l __ZN3dvl17light_table_indexE,d2 + beq .L0 + sub.b __ZN3dvl8lightmaxE,d2 + lea _RenderLine2_AMMX(pc),a4 + bne.b .L0 + lea _RenderLine1_AMMX(pc),a4 +* ensure upper long word of d0 is clear, otherwise storec will overflow + pand #$00000000FFFFFFFF,d0,d0 * factorize constants in regs .L0 move.l __ZN3dvl10gpBufStartE,a5 - addq.l #4,a3 move.l __ZN3dvl8gpBufEndE,a6 - endm + addq.l #4,a3 + rts prologue_7 macro -* movem.l d2-d3/a2-a6,-(sp) + IFNE VAMP_V4 + movem.l d2-d3/a2-a6,-(sp) + ELSE sub.w #4*7,sp move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused @@ -384,23 +618,29 @@ prologue_7 macro move.l a5,4*5(sp) ; / fused move.l a6,4*6(sp) + ENDC setup 7 endm epilogue_7 macro -* movem.l (sp)+,d2-d3/a2-a3/a4-a6 + IFNE VAMP_V4 + movem.l (sp)+,d2-d3/a2-a3/a4-a6 + ELSE move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / move.l (sp)+,a2 ; \ fused move.l (sp)+,a3 ; / move.l (sp)+,a4 ; \ fused move.l (sp)+,a5 ; / - move.l (sp)+,a6 ; \ fused?? - rts ; / + move.l (sp)+,a6 + ENDC + rts endm prologue_11 macro -* movem.l d2-d7/a2-a6,-(sp) + IFNE VAMP_V4 + movem.l d2-d7/a2-a6,-(sp) + ELSE sub.w #4*11,sp move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused @@ -418,12 +658,14 @@ prologue_11 macro move.l a5,4*9(sp) ; / fused move.l a6,4*10(sp) - + ENDC setup 11 endm epilogue_11 macro -* movem.l (sp)+,d2-d7/a2-a6 + IFNE VAMP_V4 + movem.l (sp)+,d2-d7/a2-a6 + ELSE move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / move.l (sp)+,d4 ; \ fused @@ -434,8 +676,9 @@ epilogue_11 macro move.l (sp)+,a3 ; / move.l (sp)+,a4 ; \ fused move.l (sp)+,a5 ; / - move.l (sp)+,a6 ; \ fused?? - rts ; / + move.l (sp)+,a6 + ENDC + rts endm *---------------------------------------------------------------------------------------- @@ -477,6 +720,9 @@ _RenderTile_RT_SQUARE *---------------------------------------------------------------------------------------- XDEF block16 + XDEF triangL + XDEF triangR + block16 REPT 16 moveq #32,d0 @@ -514,6 +760,22 @@ triangR ENDR rts +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_LTRAPEZOID + prologue_7 + bsr triangL + bsr block16 + epilogue_7 + +*---------------------------------------------------------------------------------------- +* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_RTRAPEZOID + prologue_7 + bsr triangR + bsr block16 + epilogue_7 + *---------------------------------------------------------------------------------------- * extern void RenderTile_RT_LTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_LTRIANGLE @@ -551,20 +813,4 @@ _RenderTile_RT_RTRIANGLE ENDR epilogue_7 -*---------------------------------------------------------------------------------------- -* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_LTRAPEZOID - prologue_7 - bsr triangL - bsr block16 - epilogue_7 - -*---------------------------------------------------------------------------------------- -* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_RTRAPEZOID - prologue_7 - bsr triangR - bsr block16 - epilogue_7 - * end of file \ No newline at end of file From f7bcc017819fe10c6bfc4503c6b9f233adf276b3 Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Wed, 4 Dec 2019 23:56:57 +0100 Subject: [PATCH 008/107] AMMX speedup --- SourceX/platform/amiga/render68k.s | 211 +++++++++++++++++++++++++---- 1 file changed, 187 insertions(+), 24 deletions(-) diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s index 2a4b6e082e3..e14dde35aad 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.s @@ -6,7 +6,7 @@ machine 68080 BUFFER_WIDTH set 768 ; FIXME: set the correct value here -VAMP_V4 set 0 +VAMP_V4 set 1 XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -52,6 +52,7 @@ unroll_AMMX macro \1 * we can leave since there is never no more than 32 bytes rts + \1_16 btst #4,d0 beq \1_8 @@ -72,7 +73,16 @@ unroll_AMMX macro * fixup ptrs \3 endm - + +final_mask macro + bfclr d1{d0:8} + rol.l #8,d1 +** move.w #$ff00,d3 +* lsr.w d0,d3 +* rol.l #8,d1 +* and.w d3,d1 + endm + * case light_table_index == lightmax _RenderLine1_AMMX move.l -(a3),d1 @@ -105,10 +115,7 @@ _RenderLine1_AMMX storem d2,d1,(a0)+ endm .m0 macro - move.w #$ff00,d3 - lsr.w d0,d3 - rol.l #8,d1 - and.w d3,d1 + final_mask storem d2,d1,(a0) endm .mask @@ -145,16 +152,13 @@ _RenderLine0_AMMX * version with mask .m8 macro - rol.l #8,d1 load (a1)+,d2 + rol.l #8,d1 storem d2,d1,(a0)+ endm .m0 macro - move.w #$ff00,d2 - lsr.w d0,d2 - rol.l #8,d1 - and.w d2,d1 load (a1),d2 + final_mask storem d2,d1,(a0) endm .mask @@ -172,40 +176,72 @@ _RenderLine2_AMMX cmp.l a6,a0 bhi.b _RenderLine0_AMMX\.mx + +* here d3=0 => no need to init + + ifne 0 + move.l d1,d3 ; \ fused addq.l #1,d3 ; / bne .mask -* here d3=0 => no need to init - -.transf macro +transform macro + IFNE \1-$AA vperm #$A7A5A3A1,d2,d3,d3 + ENDC + IFNE \1-$55 vperm #$A6A4A2A0,d2,d3,d2 + ENDC + + IFNE \1&$80 move.w (a2,d2.w),d2 + ENDC + IFNE \1&$40 move.b (a2,d3.w),d2 - swap d2 + ENDC + + swap d2 swap d3 + + IFNE \1&$20 move.w (a2,d2.w),d2 + ENDC + IFNE \1&$10 move.b (a2,d3.w),d2 + ENDC + vperm #$45670123,d2,d2,d2 + IFNE \1-$AA * lsrq #32,d3 ; doesn't compile with vasm vperm #$00000123,d3,d3,d3 + ENDC + + IFNE \1&$8 move.w (a2,d2.w),d2 + ENDC + IFNE \1&$4 move.b (a2,d3.w),d2 + ENDC + swap d2 swap d3 + + IFNE \1&$2 move.w (a2,d2.w),d2 - move.b (a2,d3.w),d2 ; 12 cycles for 8 bytes ? + ENDC + IFNE \1&$1 + move.b (a2,d3.w),d2 + ENDC endm .n8 macro load (a1)+,d2 - .transf + transform $ff store d2,(a0)+ endm .n0 macro load (a1),d2 - .transf + transform $ff storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx @@ -216,25 +252,152 @@ _RenderLine2_AMMX * mask version .m8 macro load (a1)+,d2 - .transf + transform $ff rol.l #8,d1 storem d2,d1,(a0)+ endm .m0 macro load (a1),d2 - .transf - move.w #$ff00,d3 - lsr.w d0,d3 + transform $ff + final_mask + storem d2,d1,(a0) + endm +.mask + cmp.l #$AAAAAAAA,d1 + beq .maskAA + cmp.l #$55555555,d1 + beq .mask55 + + unroll_AMMX .m8,.m0,.mx + add.w d0,a1 + add.w d0,a0 + rts + +.m8AA macro + load (a1)+,d2 + transform $AA + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0AA macro + load (a1),d2 + transform $AA + final_mask + storem d2,d1,(a0) + endm +.maskAA + unroll_AMMX .m8AA,.m0AA,.mxAA + add.w d0,a1 + add.w d0,a0 + rts + +.m855 macro + load (a1)+,d2 + transform $55 rol.l #8,d1 - and.w d3,d1 + storem d2,d1,(a0)+ + endm +.m055 macro + load (a1),d2 + transform $55 + final_mask + storem d2,d1,(a0) + endm +.mask55 + unroll_AMMX .m855,.m055,.mx55 + add.w d0,a1 + add.w d0,a0 + rts + else + + movem.l d4/d5,-(sp) + + move.l d1,d3 ; \ fused + addq.l #1,d3 ; / + bne .mask + +transform macro +* input d3/d5 + move.l d3,d2 ; p1 + rol.l #8,d2 ; p1 d2=BBCCDDAA + move.l d5,d4 ; p2 + rol.l #8,d4 ; p2 2 + + and.l #$00FF00FF,d2 ; p1 d2=00CC00AA + and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD + and.l #$00FF00FF,d4 ; p1 + and.l #$00FF00FF,d5 ; p2 4 + swap d3 ; p1 d3=00DD00BB + swap d5 ; p2 5 + move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- + move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy + swap d2 ; p2 7 d2=xxyy00CC + swap d3 ; p1 d3=00BB00DD + move.w (a2,d4.w),d4 ; p2 8 + move.b (a2,d5.w),d4 ; p1 + swap d4 ; p2 9 + swap d5 ; p1 + move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- + move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt + move.w (a2,d4.w),d4 ; p1 12 + move.b (a2,d5.w),d4 ; p1 13 +* output d2/d4 + endm + +.n8 macro + move.l (a1)+,d3 ; F(used) d3=AABBCCDD + move.l (a1)+,d5 ; F 1 + transform + move.l d2,(a0)+ ; F + move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm +.zz set .zz+1 + ifeq .zz-4 + movem.l (sp)+,d4/d5 + endc + endm +.n0 macro + move.l (a1),d3 ; F(used) d3=AABBCCDD + move.l 4(a1),d5 ; F 1 + transform + vperm #$4567CDEF,d2,d4,d2 + storec d2,d0,(a0) + endm +.zz set 0 + unroll_AMMX .n8,.n0,.nx + movem.l (sp)+,d4/d5 + add.w d0,a1 + add.w d0,a0 + rts + +* mask version +.m8 macro + move.l (a1)+,d3 ; F(used) d3=AABBCCDD + move.l (a1)+,d5 ; F 1 + rol.l #8,d1 + transform + vperm #$4567CDEF,d2,d4,d2 + storem d2,d1,(a0)+ +.zz set .zz+1 + ifeq .zz-4 + movem.l (sp)+,d4/d5 + endc + endm +.m0 macro + move.l (a1),d3 ; F(used) d3=AABBCCDD + move.l 4(a1),d5 ; F 1 + transform + vperm #$4567CDEF,d2,d4,d2 + final_mask storem d2,d1,(a0) endm .mask - moveq #0,d3 +.zz set 0 unroll_AMMX .m8,.m0,.mx + movem.l (sp)+,d4/d5 add.w d0,a1 add.w d0,a0 rts + endc * ---------------------------------------------------------------------------------------------- From 97d0b67df890bb16a40ad929837c78dbaf9afab8 Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Sun, 8 Dec 2019 18:39:43 +0100 Subject: [PATCH 009/107] fixed random crashes due to SDL_library data being trashed --- 3rdParty/Storm/Source/storm.h | 16 + CMake/amiga/Configure.readme | 2 +- CMake/amiga/m68k-amigaos.cmake | 13 +- CMakeLists.txt | 3 +- Source/init.cpp | 2 +- SourceS/sdl_compat.h | 22 +- SourceX/dx.cpp | 18 +- .../amiga/include/clib/vampire_protos.h | 29 + .../platform/amiga/include/fd/vampire_lib.fd | 7 + .../platform/amiga/include/inline/vampire.h | 35 + .../platform/amiga/include/lvo/vampire_lib.i | 9 + .../amiga/include/pragmas/vampire_pragmas.h | 49 + .../platform/amiga/include/proto/vampire.h | 34 + .../amiga/include/sfd/vampire_lib.sfd | 9 + .../platform/amiga/include/vampire/vampire.h | 63 + .../platform/amiga/include/vampire/vampire.i | 62 + .../include/vbcc/inline/vampire_protos.h | 17 + .../amiga/include/vbcc/proto/vampire.h | 27 + SourceX/platform/amiga/render68k.s | 1163 +++++++++-------- 19 files changed, 1003 insertions(+), 577 deletions(-) create mode 100755 SourceX/platform/amiga/include/clib/vampire_protos.h create mode 100755 SourceX/platform/amiga/include/fd/vampire_lib.fd create mode 100755 SourceX/platform/amiga/include/inline/vampire.h create mode 100755 SourceX/platform/amiga/include/lvo/vampire_lib.i create mode 100755 SourceX/platform/amiga/include/pragmas/vampire_pragmas.h create mode 100755 SourceX/platform/amiga/include/proto/vampire.h create mode 100755 SourceX/platform/amiga/include/sfd/vampire_lib.sfd create mode 100755 SourceX/platform/amiga/include/vampire/vampire.h create mode 100755 SourceX/platform/amiga/include/vampire/vampire.i create mode 100755 SourceX/platform/amiga/include/vbcc/inline/vampire_protos.h create mode 100755 SourceX/platform/amiga/include/vbcc/proto/vampire.h diff --git a/3rdParty/Storm/Source/storm.h b/3rdParty/Storm/Source/storm.h index 1edfb0366a2..87104bc0210 100644 --- a/3rdParty/Storm/Source/storm.h +++ b/3rdParty/Storm/Source/storm.h @@ -55,21 +55,37 @@ typedef struct _WSIZE struct CCritSect { CRITICAL_SECTION m_critsect; +#ifdef __AMIGA__ + bool valid; +#endif CCritSect() { InitializeCriticalSection(&m_critsect); +#ifdef __AMIGA__ + valid = true; +#endif } ~CCritSect() { +#ifdef __AMIGA__ + valid = false; +#endif DeleteCriticalSection(&m_critsect); } + void Enter() { +#ifdef __AMIGA__ + if(valid) +#endif EnterCriticalSection(&m_critsect); } void Leave() { +#ifdef __AMIGA__ + if(valid) +#endif LeaveCriticalSection(&m_critsect); } }; diff --git a/CMake/amiga/Configure.readme b/CMake/amiga/Configure.readme index be12be308fc..a3a9efae528 100644 --- a/CMake/amiga/Configure.readme +++ b/CMake/amiga/Configure.readme @@ -1,3 +1,3 @@ export SDLDIR=/opt/amiga/m68k-amigaos/ -cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../CMake/amiga/m68k-amigaos.cmake -DM68K_TOOLCHAIN_PATH=/opt/amiga -DM68K_CPU=68080 -DM68K_FPU=hard .. +cmake -G"Unix Makefiles" -DVAMPIRE_V2=0 -DCMAKE_TOOLCHAIN_FILE=../CMake/amiga/m68k-amigaos.cmake -DM68K_TOOLCHAIN_PATH=/opt/amiga -DM68K_CPU=68080 -DM68K_FPU=hard .. diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 287d1a05abd..0128e1fecf9 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -26,6 +26,17 @@ set(AMIGA 1) set(AMIGAOS3 1) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + +if(VAMPIRE_V2) + set(MOVEM_OPT ${M68K_TOOLCHAIN_PATH}/bin/movem_opt.pl) + set(CMAKE_C_COMPILER_LAUNCHER ${MOVEM_OPT}) + set(CMAKE_CXX_COMPILER_LAUNCHER ${MOVEM_OPT}) + set(CMAKE_CPP_COMPILER_LAUNCHER ${MOVEM_OPT}) + set(CMAKE_ASM_COMPILER_LAUNCHER ${MOVEM_OPT}) +endif() + +include_directories(SourceX/platform/amiga/include) + set(CMAKE_C_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/m68k-amigaos-gcc) set(CMAKE_CXX_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/m68k-amigaos-g++) set(CMAKE_CPP_COMPILER ${M68K_TOOLCHAIN_PATH}/bin/m68k-amigaos-cpp) @@ -42,7 +53,7 @@ endif() set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") set(CMAKE_ASM_COMPILE_OBJECT " ${CMAKE_ASM_FLAGS} -o ") set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) diff --git a/CMakeLists.txt b/CMakeLists.txt index eda76ba5951..25df21a6e50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,7 +313,8 @@ endif() if(AMIGA) list(APPEND devilutionx_SRCS - SourceX/platform/amiga/render68k.s) + SourceX/platform/amiga/render68k.s + SourceX/platform/amiga/support.c) endif() add_executable(${BIN_TARGET} MACOSX_BUNDLE ${devilutionx_SRCS}) diff --git a/Source/init.cpp b/Source/init.cpp index 939e0664c8d..61851d43587 100644 --- a/Source/init.cpp +++ b/Source/init.cpp @@ -47,7 +47,7 @@ void init_create_window() if (!SpawnWindow(PROJECT_NAME, SCREEN_WIDTH, SCREEN_HEIGHT)) app_fatal("Unable to create main window"); dx_init(NULL); - atexit(dx_cleanup); + //atexit(dx_cleanup); gbActive = true; gpBufStart = &gpBuffer[BUFFER_WIDTH * SCREEN_Y]; gpBufEnd = &gpBuffer[BUFFER_WIDTH * (SCREEN_HEIGHT + SCREEN_Y)]; diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index dd3ff9cd171..efd57c5994d 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -12,27 +12,11 @@ #define SDLC_KEYSTATE_RIGHT SDL_SCANCODE_RIGHT #else #if defined(__AMIGA__) // Add other systems that require an 8bit screen here - -short ac68080 = 0; - extern "C" { - -#include -#include - -extern struct ExecBase *SysBase; - -int is_vampire() -{ - if (SysBase->AttnFlags &(1 << 10)) { - printf("Vampire accelerator detected, using SAGA Direct Draw\n"); - return 1; - } - else - return 0; -} - + short ac68080_saga; + short ac68080_ammx; + int vampire_Flip(SDL_Surface *surf); } //extern C #endif #define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT diff --git a/SourceX/dx.cpp b/SourceX/dx.cpp index 77b9f87118c..9f562704151 100644 --- a/SourceX/dx.cpp +++ b/SourceX/dx.cpp @@ -7,7 +7,8 @@ namespace dvl { #ifdef __AMIGA__ -Uint32 old_buffer; +#define SDL_Flip vampire_Flip +// #define SDL_Flip(x) (*(int*)0xDFF1EC = -32&(int)((x)->pixels), 0) #endif int sgdwLockCount; @@ -73,9 +74,6 @@ void dx_init(HWND hWnd) SDL_RaiseWindow(window); SDL_ShowWindow(window); -#ifdef __AMIGA__ - ac68080 = is_vampire(); -#endif dx_create_primary_surface(); palette_init(); dx_create_back_buffer(); @@ -230,12 +228,7 @@ void LimitFrameRate() void RenderPresent() { SDL_Surface *surface = GetOutputSurface(); -#ifdef __AMIGA__ - if (ac68080) { - old_buffer = surface->pixels; - surface->pixels = (void*)(~31 & (31+(Uint32)old_buffer)); - } -#endif + assert(!SDL_MUSTLOCK(surface)); if (!bufferUpdated) { @@ -268,11 +261,6 @@ void RenderPresent() LimitFrameRate(); } #else -#ifdef __AMIGA__ - if (ac68080) - *(volatile Uint32 *) 0xDFF1EC = (Uint32)surface->pixels; - else -#endif if (SDL_Flip(surface) <= -1) { ErrSdl(); } diff --git a/SourceX/platform/amiga/include/clib/vampire_protos.h b/SourceX/platform/amiga/include/clib/vampire_protos.h new file mode 100755 index 00000000000..219b5c858f9 --- /dev/null +++ b/SourceX/platform/amiga/include/clib/vampire_protos.h @@ -0,0 +1,29 @@ +/* Automatically generated header (sfdc 1.10)! Do not edit! */ + +#ifndef CLIB_VAMPIRE_PROTOS_H +#define CLIB_VAMPIRE_PROTOS_H + +/* +** $VER: vampire_protos.h $Id: vampire_protos.h 770 2017-08-31 19:47:43Z henrik $ $Id: vampire_protos.h 770 2017-08-31 19:47:43Z henrik $ +** +** C prototypes. For use with 32 bit integers only. +** +** Copyright (c) 2001 Amiga, Inc. +** All Rights Reserved +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +APTR V_AllocExpansionPort(ULONG unitNum, UBYTE *name); +VOID V_FreeExpansionPort(ULONG unitNum); +ULONG V_EnableAMMX(ULONG version); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CLIB_VAMPIRE_PROTOS_H */ diff --git a/SourceX/platform/amiga/include/fd/vampire_lib.fd b/SourceX/platform/amiga/include/fd/vampire_lib.fd new file mode 100755 index 00000000000..04418412831 --- /dev/null +++ b/SourceX/platform/amiga/include/fd/vampire_lib.fd @@ -0,0 +1,7 @@ +##base _VampireBase +##bias 6 +##public +V_AllocExpansionPort(unitNum,name)(D0,A1) +V_FreeExpansionPort(unitNum)(D0) +V_EnableAMMX(version)(D0) +##end diff --git a/SourceX/platform/amiga/include/inline/vampire.h b/SourceX/platform/amiga/include/inline/vampire.h new file mode 100755 index 00000000000..89a337d44e5 --- /dev/null +++ b/SourceX/platform/amiga/include/inline/vampire.h @@ -0,0 +1,35 @@ +/* Automatically generated header (sfdc 1.10)! Do not edit! */ + +#ifndef _INLINE_VAMPIRE_H +#define _INLINE_VAMPIRE_H + +#ifndef _SFDC_VARARG_DEFINED +#define _SFDC_VARARG_DEFINED +#ifdef __HAVE_IPTR_ATTR__ +typedef APTR _sfdc_vararg __attribute__((iptr)); +#else +typedef ULONG _sfdc_vararg; +#endif /* __HAVE_IPTR_ATTR__ */ +#endif /* _SFDC_VARARG_DEFINED */ + +#ifndef __INLINE_MACROS_H +#include +#endif /* !__INLINE_MACROS_H */ + +#ifndef VAMPIRE_BASE_NAME +#define VAMPIRE_BASE_NAME VampireBase +#endif /* !VAMPIRE_BASE_NAME */ + +#define V_AllocExpansionPort(___unitNum, ___name) \ + LP2(0x6, APTR, V_AllocExpansionPort , ULONG, ___unitNum, d0, UBYTE *, ___name, a1,\ + , VAMPIRE_BASE_NAME) + +#define V_FreeExpansionPort(___unitNum) \ + LP1NR(0xc, V_FreeExpansionPort , ULONG, ___unitNum, d0,\ + , VAMPIRE_BASE_NAME) + +#define V_EnableAMMX(___version) \ + LP1(0x12, ULONG, V_EnableAMMX , ULONG, ___version, d0,\ + , VAMPIRE_BASE_NAME) + +#endif /* !_INLINE_VAMPIRE_H */ diff --git a/SourceX/platform/amiga/include/lvo/vampire_lib.i b/SourceX/platform/amiga/include/lvo/vampire_lib.i new file mode 100755 index 00000000000..8f2a99f4fb7 --- /dev/null +++ b/SourceX/platform/amiga/include/lvo/vampire_lib.i @@ -0,0 +1,9 @@ +* Automatically generated header (sfdc 1.10)! Do not edit! + IFND LVO_VAMPIRE_LIB_I +LVO_VAMPIRE_LIB_I SET 1 + +_LVOV_AllocExpansionPort EQU -6 +_LVOV_FreeExpansionPort EQU -12 +_LVOV_EnableAMMX EQU -18 + + ENDC * LVO_VAMPIRE_LIB_I diff --git a/SourceX/platform/amiga/include/pragmas/vampire_pragmas.h b/SourceX/platform/amiga/include/pragmas/vampire_pragmas.h new file mode 100755 index 00000000000..20a45bb4a0b --- /dev/null +++ b/SourceX/platform/amiga/include/pragmas/vampire_pragmas.h @@ -0,0 +1,49 @@ +/* Automatically generated header (sfdc 1.10)! Do not edit! */ +#ifndef PRAGMAS_VAMPIRE_PRAGMAS_H +#define PRAGMAS_VAMPIRE_PRAGMAS_H + +/* +** $VER: vampire_pragmas.h $Id: vampire_pragmas.h 770 2017-08-31 19:47:43Z henrik $ $Id: vampire_pragmas.h 770 2017-08-31 19:47:43Z henrik $ +** +** Direct ROM interface (pragma) definitions. +** +** Copyright (c) 2001 Amiga, Inc. +** All Rights Reserved +*/ + +#if defined(LATTICE) || defined(__SASC) || defined(_DCC) +#ifndef __CLIB_PRAGMA_LIBCALL +#define __CLIB_PRAGMA_LIBCALL +#endif /* __CLIB_PRAGMA_LIBCALL */ +#else /* __MAXON__, __STORM__ or AZTEC_C */ +#ifndef __CLIB_PRAGMA_AMICALL +#define __CLIB_PRAGMA_AMICALL +#endif /* __CLIB_PRAGMA_AMICALL */ +#endif /* */ + +#if defined(__SASC_60) || defined(__STORM__) +#ifndef __CLIB_PRAGMA_TAGCALL +#define __CLIB_PRAGMA_TAGCALL +#endif /* __CLIB_PRAGMA_TAGCALL */ +#endif /* __MAXON__, __STORM__ or AZTEC_C */ + +#ifdef __CLIB_PRAGMA_LIBCALL + #pragma libcall VampireBase V_AllocExpansionPort 6 9002 +#endif /* __CLIB_PRAGMA_LIBCALL */ +#ifdef __CLIB_PRAGMA_AMICALL + #pragma amicall(VampireBase, 0x6, V_AllocExpansionPort(d0,a1)) +#endif /* __CLIB_PRAGMA_AMICALL */ +#ifdef __CLIB_PRAGMA_LIBCALL + #pragma libcall VampireBase V_FreeExpansionPort c 001 +#endif /* __CLIB_PRAGMA_LIBCALL */ +#ifdef __CLIB_PRAGMA_AMICALL + #pragma amicall(VampireBase, 0xc, V_FreeExpansionPort(d0)) +#endif /* __CLIB_PRAGMA_AMICALL */ +#ifdef __CLIB_PRAGMA_LIBCALL + #pragma libcall VampireBase V_EnableAMMX 12 001 +#endif /* __CLIB_PRAGMA_LIBCALL */ +#ifdef __CLIB_PRAGMA_AMICALL + #pragma amicall(VampireBase, 0x12, V_EnableAMMX(d0)) +#endif /* __CLIB_PRAGMA_AMICALL */ + +#endif /* PRAGMAS_VAMPIRE_PRAGMAS_H */ diff --git a/SourceX/platform/amiga/include/proto/vampire.h b/SourceX/platform/amiga/include/proto/vampire.h new file mode 100755 index 00000000000..b287288c666 --- /dev/null +++ b/SourceX/platform/amiga/include/proto/vampire.h @@ -0,0 +1,34 @@ +/* Automatically generated header (sfdc 1.10)! Do not edit! */ + +#ifndef PROTO_VAMPIRE_H +#define PROTO_VAMPIRE_H + +#include + +#ifndef _NO_INLINE +# if defined(__GNUC__) +# ifdef __AROS__ +# include +# else +# include +# endif +# else +# include +# endif +#endif /* _NO_INLINE */ + +#ifdef __amigaos4__ +# include +# ifndef __NOGLOBALIFACE__ + extern struct VampireIFace *IVampire; +# endif /* __NOGLOBALIFACE__*/ +#endif /* !__amigaos4__ */ +#ifndef __NOLIBBASE__ + extern struct Library * +# ifdef __CONSTLIBBASEDECL__ + __CONSTLIBBASEDECL__ +# endif /* __CONSTLIBBASEDECL__ */ + VampireBase; +#endif /* !__NOLIBBASE__ */ + +#endif /* !PROTO_VAMPIRE_H */ diff --git a/SourceX/platform/amiga/include/sfd/vampire_lib.sfd b/SourceX/platform/amiga/include/sfd/vampire_lib.sfd new file mode 100755 index 00000000000..8643de8a311 --- /dev/null +++ b/SourceX/platform/amiga/include/sfd/vampire_lib.sfd @@ -0,0 +1,9 @@ +==id $Id: vampire_lib.sfd $ +==base _VampireBase +==bias 6 +==public +==include +APTR V_AllocExpansionPort(ULONG unitNum, UBYTE *name) (d0,a1) +VOID V_FreeExpansionPort(ULONG unitNum) (d0) +ULONG V_EnableAMMX(ULONG version) (d0) +==end diff --git a/SourceX/platform/amiga/include/vampire/vampire.h b/SourceX/platform/amiga/include/vampire/vampire.h new file mode 100755 index 00000000000..68a1d3556d7 --- /dev/null +++ b/SourceX/platform/amiga/include/vampire/vampire.h @@ -0,0 +1,63 @@ +#ifndef _RESOURCES_VAMPIRE_H +#define _RESOURCES_VAMPIRE_H + +/* +;****************************************************************************************** +;* +;* $id: vampire.h $ +;* +;* Unit numbers and library call offsets for vampire.resource +;* +;* (C) 2017 Apollo Team +;* +;* author: Henryk Richter +;* +;****************************************************************************************** +*/ + +#ifndef EXEC_TYPES_H +#include "exec/types.h" +#endif /* EXEC_TYPES_H */ + +#ifndef EXEC_LIBRARIES_H +#include "exec/libraries.h" +#endif /* EXEC_LIBRARIES_H */ + +/* +;* Unit number definitions: Ownership of a resource grants low-level +;* bit access to the hardware registers. You are still obligated to follow +;* the rules for shared access of the interrupt system. +*/ +#define V_SDPORT 0 /* SD port on V500/600 */ +#define V_WIFIPORT 1 /* WiFi expansion port on V500+ */ +#define V_PAMELA_45 2 /* Pamela channels 4,5 = first two 16 bit capable channels */ +#define V_PAMELA_67 3 /* Pamela channels 6,7 = second two 16 bit capable channels */ + +/* +;* AMMX enable variants +;* Supported right now are AMMX1 (and associated checks) and AMMX2 +;* +*/ +#define V_AMMX_DISABLE 0 +#define V_AMMX_V1 1 +#define V_AMMX_V2 2 + +/* +;* +;* AMMX enable return codes +;* +*/ +#define VRES_ERROR 0 +#define VRES_OK 1 +#define VRES_AMMX_WAS_ON 2 + + +/* +;* +;* Name +;* +*/ +#define V_VAMPIRENAME "vampire.resource" + + +#endif /* RESOURCES_VAMPIRE_H */ diff --git a/SourceX/platform/amiga/include/vampire/vampire.i b/SourceX/platform/amiga/include/vampire/vampire.i new file mode 100755 index 00000000000..60dd9e82623 --- /dev/null +++ b/SourceX/platform/amiga/include/vampire/vampire.i @@ -0,0 +1,62 @@ + IFND _RESOURCES_VAMPIRE_I +_RESOURCES_VAMPIRE_I EQU 1 + +;****************************************************************************************** +;* +;* $id: vampire.i $ +;* +;* Unit numbers and library call offsets for vampire.resource +;* +;* (C) 2017 Apollo Team +;* +;* author: Henryk Richter +;* +;****************************************************************************************** + + IFND EXEC_TYPES_I + include "exec/types.i" + ENDC + + IFND EXEC_LIBRARIES_I + include "exec/libraries.i" + ENDC + +;* +;* Library vector offsets +;* + LIBINIT LIB_BASE + LIBDEF V_AllocExpansionPort ;-6 (V44) + LIBDEF V_FreeExpansionPort ;-12 (V44) + LIBDEF V_EnableAMMX ;-18 (V45) + +;* +;* Name +;* +V_VAMPIRENAME MACRO + dc.b "vampire.resource",0 + ENDM + +;* Unit number definitions: Ownership of a resource grants low-level +;* bit access to the hardware registers. You are still obligated to follow +;* the rules for shared access of the interrupt system. +;* +V_SDPORT EQU 0 ;SD port on V500/600 +V_WIFIPORT EQU 1 ;WiFi expansion port on V500+ +V_PAMELA_45 EQU 2 ;Pamela channels 4,5 = first two 16 bit capable channels +V_PAMELA_67 EQU 3 ;Pamela channels 6,7 = second two 16 bit capable channels + ENDC ;_RESOURCES_VAMPIRE_I + +;* AMMX enable variants +;* Supported right now are AMMX1 (and associated checks) and AMMX2 +;* +;* note: enumerate as binary exponential sequence +V_AMMX_DISABLE EQU 0 +V_AMMX_V1 EQU 1 +V_AMMX_V2 EQU 2 + +;* +;* AMMX enable return codes +;* +VRES_ERROR EQU 0 +VRES_OK EQU 1 +VRES_AMMX_WAS_ON EQU 2 \ No newline at end of file diff --git a/SourceX/platform/amiga/include/vbcc/inline/vampire_protos.h b/SourceX/platform/amiga/include/vbcc/inline/vampire_protos.h new file mode 100755 index 00000000000..67af9f73ca2 --- /dev/null +++ b/SourceX/platform/amiga/include/vbcc/inline/vampire_protos.h @@ -0,0 +1,17 @@ +#ifndef _VBCCINLINE_VAMPIRE_H +#define _VBCCINLINE_VAMPIRE_H + +#ifndef EXEC_TYPES_H +#include +#endif + +UBYTE * __V_AllocExpansionPort(__reg("a6") void *, __reg("d0") ULONG, __reg("a1") CONST_STRPTR)="\tjsr\t-6(a6)"; +#define V_AllocExpansionPort(unitNum, name) __V_AllocExpansionPort(VampireBase, (unitNum), (name)) + +VOID __V_FreeExpansionPort( __reg("a6") void *, __reg("d0") ULONG)="\tjsr\t-12(a6)"; +#define V_FreeExpansionPort(unitNum) __V_FreeExpansionPort(VampireBase, (unitNum)) + +ULONG __V_EnableAMMX( __reg("a6") void *, __reg("d0") ULONG) = "\tjsr\t-18(a6)"; +#define V_EnableAMMX( _version_ ) __V_EnableAMMX(VampireBase, (_version_)) + +#endif /* _VBCCINLINE_VAMPIRE_H */ diff --git a/SourceX/platform/amiga/include/vbcc/proto/vampire.h b/SourceX/platform/amiga/include/vbcc/proto/vampire.h new file mode 100755 index 00000000000..354abd7f416 --- /dev/null +++ b/SourceX/platform/amiga/include/vbcc/proto/vampire.h @@ -0,0 +1,27 @@ +#ifndef _PROTO_VAMPIRE_H +#define _PROTO_VAMPIRE_H + +#ifndef EXEC_TYPES_H +#include +#endif +#if !defined(CLIB_VAMPIRE_PROTOS_H) && !defined(__GNUC__) +#include +#endif + +#ifndef __NOLIBBASE__ +extern struct Library *VampireBase; +#endif + +#ifdef __GNUC__ +#ifdef __AROS__ +#include +#else +#include +#endif +#elif defined(__VBCC__) +#include +#else +#include +#endif + +#endif /* _PROTO_VAMPIRE_H */ diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s index e14dde35aad..3fe3867eeb4 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.s @@ -1,12 +1,12 @@ -* ---------------------------------------------------------------------------------------------- +* ----------------------------------------------------------------------------- * diablo.s -- replacement of C code by hand-written asm code by S.Devulder -* ---------------------------------------------------------------------------------------------- +* ----------------------------------------------------------------------------- section .text - machine 68080 + machine 68080 BUFFER_WIDTH set 768 ; FIXME: set the correct value here -VAMP_V4 set 1 +VAMP_V4 set 1 XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -15,391 +15,467 @@ VAMP_V4 set 1 XDEF _RenderTile_RT_LTRAPEZOID XDEF _RenderTile_RT_RTRAPEZOID - XDEF _RenderLine0 - XDEF _RenderLine1 - XDEF _RenderLine2 - XDEF _RenderLine0_AMMX - XDEF _RenderLine1_AMMX - XDEF _RenderLine2_AMMX + XDEF _RenderLine0 + XDEF _RenderLine1 + XDEF _RenderLine2 + XDEF _RenderLine0_AMMX + XDEF _RenderLine1_AMMX + XDEF _RenderLine2_AMMX XREF __ZN3dvl10gpBufStartE XREF __ZN3dvl8gpBufEndE - XREF __ZN3dvl8lightmaxE - XREF __ZN3dvl17light_table_indexE - XREF _ac68080 + XREF __ZN3dvl8lightmaxE + XREF __ZN3dvl17light_table_indexE + XREF _ac68080_ammx cnop 0,4 - -* ---------------------------------------------------------------------------------------------- + +* ----------------------------------------------------------------------------- * debug: displays nothing - + _RenderLine_NONE move.l -(a3),d1 - add.w d0,a1 - add.w d0,a0 - rts + add.w d0,a1 + add.w d0,a0 + rts -* ---------------------------------------------------------------------------------------------- +* ----------------------------------------------------------------------------- * AMMX version +rol_d1_mask macro + bfclr d1{d0:8} + rol.l #8,d1 +** move.w #$ff00,d3 +* lsr.w d0,d3 +* rol.l #8,d1 +* and.w d3,d1 + endm + unroll_AMMX macro btst #5,d0 beq \1_16 * 32 bytes in a row - \1 - \1 - \1 - \1 + \1 0 + \1 0 + \1 0 + \1 1 * we can leave since there is never no more than 32 bytes - rts - + rts \1_16 btst #4,d0 beq \1_8 * 16 bytes in a row - \1 - \1 + \1 0 + \1 0 \1_8 btst #3,d0 beq \1_0 * 8 bytes in a row - \1 + \1 0 \1_0 - moveq #7,d2 - and.l d2,d0 - beq \3 + moveq #7,d2 + and.l d2,d0 + beq \3 * 1 to 7 bytes - \2 + \2 * fixup ptrs \3 - endm - -final_mask macro - bfclr d1{d0:8} - rol.l #8,d1 -** move.w #$ff00,d3 -* lsr.w d0,d3 -* rol.l #8,d1 -* and.w d3,d1 - endm - + endm + * case light_table_index == lightmax _RenderLine1_AMMX move.l -(a3),d1 add.w d0,a1 - beq.b .nx +* beq.b .nx cmp.l a5,a0 bcs.b .nx cmp.l a6,a0 bhi.b .nx - peor d2,d2,d2 ; d2=0.q - moveq #1,d3 - add.l d1,d3 - bne .mask + peor d2,d2,d2 ; d2=0.q + moveq #1,d3 + add.l d1,d3 + bne .mask * no mask -.n8 macro - store d2,(a0)+ - endm -.n0 macro - storec d2,d0,(a0) - endm - unroll_AMMX .n8,.n0,.nx +.n8 macro + store d2,(a0)+ + endm +.n0 macro + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx add.w d0,a0 - rts + rts * mask version -.m8 macro - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m0 macro - final_mask - storem d2,d1,(a0) - endm +.m8 macro + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0 macro + rol_d1_mask + storem d2,d1,(a0) + endm .mask - unroll_AMMX .m8,.m0,.mx + unroll_AMMX .m8,.m0,.mx add.w d0,a0 - rts + rts * case light_table_index == 0 _RenderLine0_AMMX move.l -(a3),d1 - beq.b .nx +* beq.b .nx cmp.l a5,a0 bcs.b .nx cmp.l a6,a0 bhi.b .nx - - moveq #1,d2 - add.l d1,d2 - bne .mask + + moveq #1,d3 + add.l d1,d3 + bne .mask * no mask -.n8 macro - load (a1)+,d2 - store d2,(a0)+ - endm -.n0 macro - load (a1),d2 - storec d2,d0,(a0) - endm - unroll_AMMX .n8,.n0,.nx - add.w d0,a1 +.n8 macro + load (a1)+,d2 + store d2,(a0)+ + endm +.n0 macro + load (a1),d2 + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx + add.w d0,a1 add.w d0,a0 - rts + rts * version with mask -.m8 macro - load (a1)+,d2 - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m0 macro - load (a1),d2 - final_mask - storem d2,d1,(a0) - endm +.m8 macro + load (a1)+,d2 + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0 macro + load (a1),d2 + rol_d1_mask + storem d2,d1,(a0) + endm .mask - unroll_AMMX .m8,.m0,.mx - add.w d0,a1 + unroll_AMMX .m8,.m0,.mx + add.w d0,a1 add.w d0,a0 - rts + rts * other cases _RenderLine2_AMMX move.l -(a3),d1 - beq.b _RenderLine0_AMMX\.mx +* beq.b _RenderLine0_AMMX\.mx cmp.l a5,a0 bcs.b _RenderLine0_AMMX\.mx cmp.l a6,a0 bhi.b _RenderLine0_AMMX\.mx + movem.l d4/d5,-(sp) + + move.l d1,d3 ; \ fused + addq.l #1,d3 ; / + bne .mask + +transform macro +* move.l (a1)+,d3 ; F(used) d3=AABBCCDD +* move.l (a1)+,d5 ; F 1 +* input d3/d5 + move.l d3,d2 ; p1 d3=AABBCCDD + rol.l #8,d2 ; p1 d2=BBCCDDAA + move.l d5,d4 ; p2 + rol.l #8,d4 ; p2 2 + + and.l #$00FF00FF,d2 ; p1 d2=00CC00AA + and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD + and.l #$00FF00FF,d4 ; p1 + and.l #$00FF00FF,d5 ; p2 4 + swap d3 ; p1 d3=00DD00BB + swap d5 ; p2 5 + ifne \1&$80 + move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- + endc + ifne \1&$40 + move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy + endc + swap d2 ; p2 7 d2=xxyy00CC + swap d3 ; p1 d3=00BB00DD + ifne \1&$08 + move.w (a2,d4.w),d4 ; p2 8 + endc + ifne \1&$04 + move.b (a2,d5.w),d4 ; p1 + endc + swap d4 ; p2 9 + swap d5 ; p1 + ifne \1&$20 + move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- + endc + ifne \1&$10 + move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt + endc + ifne \1&$02 + move.w (a2,d4.w),d4 ; p1 12 + endc + ifne \1&$01 + move.b (a2,d5.w),d4 ; p1 13 + endc +* output d2/d4 +* move.l d2,(a0)+ ; F +* move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? + endm -* here d3=0 => no need to init - - ifne 0 - - move.l d1,d3 ; \ fused - addq.l #1,d3 ; / - bne .mask - -transform macro - IFNE \1-$AA - vperm #$A7A5A3A1,d2,d3,d3 - ENDC - IFNE \1-$55 - vperm #$A6A4A2A0,d2,d3,d2 - ENDC - - IFNE \1&$80 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$40 - move.b (a2,d3.w),d2 - ENDC - - swap d2 - swap d3 - - IFNE \1&$20 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$10 - move.b (a2,d3.w),d2 - ENDC - - vperm #$45670123,d2,d2,d2 - IFNE \1-$AA -* lsrq #32,d3 ; doesn't compile with vasm - vperm #$00000123,d3,d3,d3 - ENDC - - IFNE \1&$8 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$4 - move.b (a2,d3.w),d2 - ENDC - - swap d2 - swap d3 - - IFNE \1&$2 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$1 - move.b (a2,d3.w),d2 - ENDC - endm - -.n8 macro - load (a1)+,d2 - transform $ff - store d2,(a0)+ - endm -.n0 macro - load (a1),d2 - transform $ff - storec d2,d0,(a0) - endm - unroll_AMMX .n8,.n0,.nx +.n8 macro + move.l (a1)+,d3 + move.l (a1)+,d5 + transform $ff + move.l d2,(a0)+ + move.l d4,(a0)+ + ifne \1 + movem.l (sp)+,d4/d5 + endc + endm +.n0 macro + move.l (a1),d3 + move.l 4(a1),d5 + transform $ff + vperm #$4567CDEF,d2,d4,d2 + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx + movem.l (sp)+,d4/d5 add.w d0,a1 add.w d0,a0 - rts + rts * mask version -.m8 macro - load (a1)+,d2 - transform $ff - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m0 macro - load (a1),d2 - transform $ff - final_mask - storem d2,d1,(a0) - endm +.m8 macro + move.l (a1)+,d3 ; F(used) d3=AABBCCDD + move.l (a1)+,d5 ; F 1 + transform $ff + vperm #$4567CDEF,d2,d4,d2 + rol.l #8,d1 + storem d2,d1,(a0)+ + ifne \1 + movem.l (sp)+,d4/d5 + endc + endm +.m0 macro + move.l (a1),d3 ; F(used) d3=AABBCCDD + move.l 4(a1),d5 ; F 1 + transform $ff + vperm #$4567CDEF,d2,d4,d2 + rol_d1_mask + storem d2,d1,(a0) + endm .mask - cmp.l #$AAAAAAAA,d1 - beq .maskAA - cmp.l #$55555555,d1 - beq .mask55 - - unroll_AMMX .m8,.m0,.mx + cmp.l #$AAAAAAAA,d1 + beq .maskAA + cmp.l #$55555555,d1 + beq .mask55 + unroll_AMMX .m8,.m0,.mx + movem.l (sp)+,d4/d5 add.w d0,a1 add.w d0,a0 - rts - -.m8AA macro - load (a1)+,d2 - transform $AA - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m0AA macro - load (a1),d2 - transform $AA - final_mask - storem d2,d1,(a0) - endm + rts + +.m8AA macro + move.l (a1)+,d3 ; F(used) d3=AABBCCDD + move.l (a1)+,d5 ; F 1 + transform $AA + vperm #$4567CDEF,d2,d4,d2 + rol.l #8,d1 + storem d2,d1,(a0)+ + ifne \1 + movem.l (sp)+,d4/d5 + endc + endm +.m0AA macro + move.l (a1),d3 ; F(used) d3=AABBCCDD + move.l 4(a1),d5 ; F 1 + transform $AA + vperm #$4567CDEF,d2,d4,d2 + rol_d1_mask + storem d2,d1,(a0) + endm .maskAA - unroll_AMMX .m8AA,.m0AA,.mxAA + unroll_AMMX .m8AA,.m0AA,.mxAA add.w d0,a1 add.w d0,a0 - rts - -.m855 macro - load (a1)+,d2 - transform $55 - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m055 macro - load (a1),d2 - transform $55 - final_mask - storem d2,d1,(a0) + rts + +.m855 macro + move.l (a1)+,d3 ; F(used) d3=AABBCCDD + move.l (a1)+,d5 ; F 1 + transform $55 + vperm #$4567CDEF,d2,d4,d2 + rol.l #8,d1 + storem d2,d1,(a0)+ + ifne \1 + movem.l (sp)+,d4/d5 + endc endm +.m055 macro + move.l (a1),d3 ; F(used) d3=AABBCCDD + move.l 4(a1),d5 ; F 1 + transform $55 + vperm #$4567CDEF,d2,d4,d2 + rol_d1_mask + storem d2,d1,(a0) + endm .mask55 - unroll_AMMX .m855,.m055,.mx55 + unroll_AMMX .m855,.m055,.mx55 add.w d0,a1 add.w d0,a0 - rts - else - - movem.l d4/d5,-(sp) - - move.l d1,d3 ; \ fused - addq.l #1,d3 ; / - bne .mask - -transform macro -* input d3/d5 - move.l d3,d2 ; p1 - rol.l #8,d2 ; p1 d2=BBCCDDAA - move.l d5,d4 ; p2 - rol.l #8,d4 ; p2 2 - - and.l #$00FF00FF,d2 ; p1 d2=00CC00AA - and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD - and.l #$00FF00FF,d4 ; p1 - and.l #$00FF00FF,d5 ; p2 4 - swap d3 ; p1 d3=00DD00BB - swap d5 ; p2 5 - move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- - move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy - swap d2 ; p2 7 d2=xxyy00CC - swap d3 ; p1 d3=00BB00DD - move.w (a2,d4.w),d4 ; p2 8 - move.b (a2,d5.w),d4 ; p1 - swap d4 ; p2 9 - swap d5 ; p1 - move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- - move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt - move.w (a2,d4.w),d4 ; p1 12 - move.b (a2,d5.w),d4 ; p1 13 -* output d2/d4 - endm - -.n8 macro - move.l (a1)+,d3 ; F(used) d3=AABBCCDD - move.l (a1)+,d5 ; F 1 - transform - move.l d2,(a0)+ ; F - move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm -.zz set .zz+1 - ifeq .zz-4 - movem.l (sp)+,d4/d5 - endc - endm -.n0 macro - move.l (a1),d3 ; F(used) d3=AABBCCDD - move.l 4(a1),d5 ; F 1 - transform - vperm #$4567CDEF,d2,d4,d2 - storec d2,d0,(a0) - endm -.zz set 0 - unroll_AMMX .n8,.n0,.nx - movem.l (sp)+,d4/d5 + rts + * +* ----------------------------------------------------------------------------- + +_RenderLine2_AMMX_orig + move.l -(a3),d1 +* beq _RenderLine0_AMMX\.mx + cmp.l a5,a0 + bcs _RenderLine0_AMMX\.mx + cmp.l a6,a0 + bhi _RenderLine0_AMMX\.mx + + move.l d1,d3 ; \ fused + addq.l #1,d3 ; / + bne .mask + +* here d3=0 => no need to init + +transform macro + IFNE \1-$AA + vperm #$A7A5A3A1,d2,d3,d3 + ENDC + IFNE \1-$55 + vperm #$A6A4A2A0,d2,d3,d2 + ENDC + + IFNE \1&$80 + move.w (a2,d2.w),d2 + ENDC + IFNE \1&$40 + move.b (a2,d3.w),d2 + ENDC + + swap d2 + swap d3 + + IFNE \1&$20 + move.w (a2,d2.w),d2 + ENDC + IFNE \1&$10 + move.b (a2,d3.w),d2 + ENDC + + vperm #$45670123,d2,d2,d2 + IFNE \1-$AA +* lsrq #32,d3 ; doesn't compile with vasm + vperm #$00000123,d3,d3,d3 + ENDC + + IFNE \1&$8 + move.w (a2,d2.w),d2 + ENDC + IFNE \1&$4 + move.b (a2,d3.w),d2 + ENDC + + swap d2 + swap d3 + + IFNE \1&$2 + move.w (a2,d2.w),d2 + ENDC + IFNE \1&$1 + move.b (a2,d3.w),d2 + ENDC + endm + +.n8 macro + load (a1)+,d2 + transform $ff + store d2,(a0)+ + endm +.n0 macro + load (a1),d2 + transform $ff + storec d2,d0,(a0) + endm + unroll_AMMX .n8,.n0,.nx add.w d0,a1 add.w d0,a0 - rts + rts * mask version -.m8 macro - move.l (a1)+,d3 ; F(used) d3=AABBCCDD - move.l (a1)+,d5 ; F 1 - rol.l #8,d1 - transform - vperm #$4567CDEF,d2,d4,d2 - storem d2,d1,(a0)+ -.zz set .zz+1 - ifeq .zz-4 - movem.l (sp)+,d4/d5 - endc - endm -.m0 macro - move.l (a1),d3 ; F(used) d3=AABBCCDD - move.l 4(a1),d5 ; F 1 - transform - vperm #$4567CDEF,d2,d4,d2 - final_mask - storem d2,d1,(a0) - endm +.m8 macro + load (a1)+,d2 + transform $ff + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0 macro + load (a1),d2 + transform $ff + rol_d1_mask + storem d2,d1,(a0) + endm .mask -.zz set 0 - unroll_AMMX .m8,.m0,.mx - movem.l (sp)+,d4/d5 + moveq #0,d3 + + cmp.l #$AAAAAAAA,d1 + beq .maskAA + cmp.l #$55555555,d1 + beq .mask55 + + unroll_AMMX .m8,.m0,.mx add.w d0,a1 add.w d0,a0 - rts - endc + rts -* ---------------------------------------------------------------------------------------------- +.m8AA macro + load (a1)+,d2 + transform $AA + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m0AA macro + load (a1),d2 + transform $AA + rol_d1_mask + storem d2,d1,(a0) + endm +.maskAA + unroll_AMMX .m8AA,.m0AA,.mxAA + add.w d0,a1 + add.w d0,a0 + rts + +.m855 macro + load (a1)+,d2 + transform $55 + rol.l #8,d1 + storem d2,d1,(a0)+ + endm +.m055 macro + load (a1),d2 + transform $55 + rol_d1_mask + storem d2,d1,(a0) + endm +.mask55 + unroll_AMMX .m855,.m055,.mx55 + add.w d0,a1 + add.w d0,a0 + rts + +* ----------------------------------------------------------------------------- * inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD mask) * a0 = *dst @@ -432,7 +508,7 @@ unroll macro \1 \1 \1 - rts + rts \1_4 btst #4,d0 beq \1_2 @@ -458,9 +534,9 @@ unroll macro beq \3_2 \3 \3_2 - rts - endm - + rts + endm + loop macro \1__1 add.l d1,d1 @@ -473,24 +549,24 @@ loop macro \2 subq.w #1,d0 bne \1__1 - rts + rts endm * case light_table_index == 0 _RenderLine0_ - add.w d0,a1 + add.w d0,a1 add.w d0,a0 - rts + rts _RenderLine0 move.l -(a3),d1 - beq.b _RenderLine0_ +* beq.b _RenderLine0_ cmp.l a5,a0 bcs.b _RenderLine0_ cmp.l a6,a0 bhi.b _RenderLine0_ - - not.l d1 - bne .mask + + not.l d1 + bne .mask .m4 macro move.l (a1)+,(a0)+ endm @@ -503,167 +579,167 @@ _RenderLine0 unroll .m4,.m2,.m1 .mask - cmp.l #$AAAAAAAA,d1 ; bg / fg / bg fg - bne .l2 -.p4 macro + cmp.l #$AAAAAAAA,d1 ; bg / fg / bg fg + bne .l2 +.p4 macro ifeq 1 - move.b 1(a1),1(a0) ; 2 - move.b 3(a1),3(a0) ; 2 - addq.l #4,a1 ; .5 - addq.l #4,a0 ; .5 ==> 5 cycles - else - move.l (a1)+,d1 ; \ - and.l #$00FF00FF,d1 ; / 1 cycle (fused) ? - move.l (a0),d2 ; \ - and.l #$FF00FF00,d2 ; / 1 cycle (fused) ? - or.l d2,d1 ; 1 - move.l d1,(a0)+ ; 1 ==> 4 cycles - endc - endm -.p2 macro - move.b 1(a1),1(a0) - addq.l #2,a1 - addq.l #2,a0 - endm + move.b 1(a1),1(a0) ; 2 + move.b 3(a1),3(a0) ; 2 + addq.l #4,a1 ; .5 + addq.l #4,a0 ; .5 ==> 5 cycles + else + move.l (a1)+,d1 ; \ + and.l #$00FF00FF,d1 ; / 1 cycle (fused) ? + move.l (a0),d2 ; \ + and.l #$FF00FF00,d2 ; / 1 cycle (fused) ? + or.l d2,d1 ; 1 + move.l d1,(a0)+ ; 1 ==> 4 cycles + endc + endm +.p2 macro + move.b 1(a1),1(a0) + addq.l #2,a1 + addq.l #2,a0 + endm .p1 macro - addq.l #1,a1 - addq.l #1,a0 - endm - unroll .p4,.p2,.p1 + addq.l #1,a1 + addq.l #1,a0 + endm + unroll .p4,.p2,.p1 .l2 - cmp.l #$55555555,d1 ; fg / bg /fg / bg - bne .l3 - -.q4 macro - ifeq 1 - move.b (a1),(a0) ; 2 - move.b 2(a1),2(a0) ; 2 - addq.l #4,a1 ; .5 - addq.l #4,a0 ; .5 ==> 5 cycles - else - move.l #$FF00FF00,d1 - and.l (a1)+,d1 - move.l #$00FF00FF,d2 - and.l (a0),d2 - or.l d2,d1 - move.l d1,(a0)+ - endc - endm -.q2 macro - ifeq 0 - move.b (a1),(a0) - addq.l #2,a1 - addq.l #2,a0 - else - move.w #$FF00,d1 - and.w (a1)+,d1 - move.w #$00FF,d2 - and.w (a0),d2 - or.w d2,d1 - move.w d1,(a0)+ - endc - endm + cmp.l #$55555555,d1 ; fg / bg /fg / bg + bne .l3 + +.q4 macro + ifeq 1 + move.b (a1),(a0) ; 2 + move.b 2(a1),2(a0) ; 2 + addq.l #4,a1 ; .5 + addq.l #4,a0 ; .5 ==> 5 cycles + else + move.l #$FF00FF00,d1 + and.l (a1)+,d1 + move.l #$00FF00FF,d2 + and.l (a0),d2 + or.l d2,d1 + move.l d1,(a0)+ + endc + endm +.q2 macro + ifeq 0 + move.b (a1),(a0) + addq.l #2,a1 + addq.l #2,a0 + else + move.w #$FF00,d1 + and.w (a1)+,d1 + move.w #$00FF,d2 + and.w (a0),d2 + or.w d2,d1 + move.w d1,(a0)+ + endc + endm .q1 macro - move.b (a1)+,(a0)+ - endm - unroll .q4,.q2,.q1 + move.b (a1)+,(a0)+ + endm + unroll .q4,.q2,.q1 .l3 - loop .m1,inc_a0_a1 + loop .m1,inc_a0_a1 * case light_table_index == lightmax _RenderLine1_ - add.w d0,a0 - rts + add.w d0,a0 + rts _RenderLine1 move.l -(a3),d1 add.w d0,a1 - beq.b _RenderLine1_ +* beq.b _RenderLine1_ cmp.l a5,a0 bcs.b _RenderLine1_ cmp.l a6,a0 bhi.b _RenderLine1_ - - not.l d1 - bne .mask - + + not.l d1 + bne .mask + .m4 macro - clr.l (a0)+ + clr.l (a0)+ endm .m2 macro - clr.w (a0)+ + clr.w (a0)+ endm .m1 macro - clr.b (a0)+ + clr.b (a0)+ endm unroll .m4,.m2,.m1 .mask - cmp.l #$AAAAAAAA,d1 - bne .l2 - move.l #$FF00FF00,d2 -.p4 macro - and.l d2,(a0)+ - endm -.p2 macro - and.w d2,(a0)+ - endm + cmp.l #$AAAAAAAA,d1 + bne .l2 + move.l #$FF00FF00,d2 +.p4 macro + and.l d2,(a0)+ + endm +.p2 macro + and.w d2,(a0)+ + endm .p1 macro - addq.l #1,a0 - endm - unroll .p4,.p2,.p1 + addq.l #1,a0 + endm + unroll .p4,.p2,.p1 .l2 - cmp.l #$55555555,d1 - bne .l3 - move.l #$00FF00FF,d2 -.q4 macro - and.l d2,(a0)+ - endm -.q2 macro - and.w d2,(a0)+ - endm + cmp.l #$55555555,d1 + bne .l3 + move.l #$00FF00FF,d2 +.q4 macro + and.l d2,(a0)+ + endm +.q2 macro + and.w d2,(a0)+ + endm .q1 macro - clr.b (a0)+ - endm - unroll .q4,.q2,.q1 + clr.b (a0)+ + endm + unroll .q4,.q2,.q1 .l3 - loop .m1,inc_a0 + loop .m1,inc_a0 * other cases _RenderLine2_ - add.w d0,a1 - add.w d0,a0 - rts + add.w d0,a1 + add.w d0,a0 + rts _RenderLine2 move.l -(a3),d1 - beq _RenderLine2_ +* beq _RenderLine2_ cmp.l a5,a0 bcs.b _RenderLine2_ cmp.l a6,a0 bhi.b _RenderLine2_ - moveq #0,d2 - moveq #0,d3 - - not.l d1 - bne .mask + moveq #0,d2 + moveq #0,d3 + + not.l d1 + bne .mask .m4 macro - move.b (a1)+,d2 ; \ merged ? - move.b (a1)+,d3 ; / + move.b (a1)+,d2 ; \ merged ? + move.b (a1)+,d3 ; / move.w (a2,d2.w),d1 move.b (a2,d3.w),d1 swap d1 - move.b (a1)+,d2 ; \ - move.b (a1)+,d3 ; / + move.b (a1)+,d2 ; \ + move.b (a1)+,d3 ; / move.w (a2,d2.w),d1 move.b (a2,d3.w),d1 move.l d1,(a0)+ endm .m2 macro - move.b (a1)+,d2 ; \ - move.b (a1)+,d3 ; / + move.b (a1)+,d2 ; \ + move.b (a1)+,d3 ; / move.w (a2,d2.w),d1 move.b (a2,d3.w),d1 move.w d1,(a0)+ @@ -672,104 +748,104 @@ _RenderLine2 move.b (a1)+,d2 move.b (a2,d2.w),(a0)+ endm - unroll .m4,.m2,.m1 + unroll .m4,.m2,.m1 .mask - cmp.l #$AAAAAAAA,d1 - bne .l2 -.p4 macro + cmp.l #$AAAAAAAA,d1 + bne .l2 +.p4 macro move.b 1(a1),d2 move.b 3(a1),d3 move.b (a2,d2.w),1(a0) move.b (a2,d3.w),3(a0) - addq.l #4,a1 - addq.l #4,a0 + addq.l #4,a1 + addq.l #4,a0 endm .p2 macro move.b 1(a1),d2 move.b (a2,d2.w),1(a0) - addq.l #2,a1 - addq.l #2,a0 + addq.l #2,a1 + addq.l #2,a0 endm .p1 macro - inc_a0_a1 - endm - unroll .p4,.p2,.p1 - + inc_a0_a1 + endm + unroll .p4,.p2,.p1 + .l2 - cmp.l #$55555555,d1 - bne .l3 + cmp.l #$55555555,d1 + bne .l3 .q4 macro move.b (a1),d2 move.b 2(a1),d3 move.b (a2,d2.w),(a0) move.b (a2,d3.w),2(a0) - addq.l #4,a1 - addq.l #4,a0 + addq.l #4,a1 + addq.l #4,a0 endm .q2 macro move.b (a1),d2 - move.b (a2,d2.l),(a0) - addq.l #2,a1 - addq.l #2,a0 - endm + move.b (a2,d2.l),(a0) + addq.l #2,a1 + addq.l #2,a0 + endm .q1 macro move.b (a1)+,d2 move.b (a2,d2.l),(a0)+ endm - unroll .q4,.q2,.q1 + unroll .q4,.q2,.q1 .l3 - loop .m1,inc_a0_a1 + loop .m1,inc_a0_a1 -*---------------------------------------------------------------------------------------- +*------------------------------------------------------------------------------------ setup macro * get params from stack - IFNE VAMP_V4 + IFNE VAMP_V4 movem.l (4*(1+\1),sp),a0/a1/a2/a3 - ELSE + ELSE move.l (4*(1+\1),sp),a0 ; \ move.l (4*(2+\1),sp),a1 ; / fused move.l (4*(3+\1),sp),a2 ; \ fused move.l (4*(4+\1),sp),a3 ; / - ENDC - bsr _setup - endm + ENDC + bsr _setup + endm _setup * determine renderFcn - tst.w _ac68080 - bne .ammx - lea _RenderLine0(pc),a4 + tst.w _ac68080_ammx + bne .ammx + lea _RenderLine0(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 beq .L0 sub.b __ZN3dvl8lightmaxE,d2 - lea _RenderLine2(pc),a4 + lea _RenderLine2(pc),a4 bne.b .L0 - lea _RenderLine1(pc),a4 - bra .L0 + lea _RenderLine1(pc),a4 + bra .L0 .ammx - lea _RenderLine0_AMMX(pc),a4 + lea _RenderLine0_AMMX(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 beq .L0 sub.b __ZN3dvl8lightmaxE,d2 - lea _RenderLine2_AMMX(pc),a4 + lea _RenderLine2_AMMX(pc),a4 bne.b .L0 - lea _RenderLine1_AMMX(pc),a4 + lea _RenderLine1_AMMX(pc),a4 * ensure upper long word of d0 is clear, otherwise storec will overflow - pand #$00000000FFFFFFFF,d0,d0 +* pand #$00000000FFFFFFFF,d0,d0 * factorize constants in regs .L0 move.l __ZN3dvl10gpBufStartE,a5 move.l __ZN3dvl8gpBufEndE,a6 addq.l #4,a3 - rts + rts prologue_7 macro - IFNE VAMP_V4 + IFNE VAMP_V4 movem.l d2-d3/a2-a6,-(sp) - ELSE + ELSE sub.w #4*7,sp move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused @@ -781,14 +857,14 @@ prologue_7 macro move.l a5,4*5(sp) ; / fused move.l a6,4*6(sp) - ENDC + ENDC setup 7 endm epilogue_7 macro - IFNE VAMP_V4 + IFNE VAMP_V4 movem.l (sp)+,d2-d3/a2-a3/a4-a6 - ELSE + ELSE move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / move.l (sp)+,a2 ; \ fused @@ -796,14 +872,14 @@ epilogue_7 macro move.l (sp)+,a4 ; \ fused move.l (sp)+,a5 ; / move.l (sp)+,a6 - ENDC + ENDC rts endm prologue_11 macro - IFNE VAMP_V4 + IFNE VAMP_V4 movem.l d2-d7/a2-a6,-(sp) - ELSE + ELSE sub.w #4*11,sp move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused @@ -820,15 +896,15 @@ prologue_11 macro move.l a4,4*8(sp) ; \ move.l a5,4*9(sp) ; / fused - move.l a6,4*10(sp) - ENDC + move.l a6,4*10(sp) + ENDC setup 11 endm epilogue_11 macro - IFNE VAMP_V4 + IFNE VAMP_V4 movem.l (sp)+,d2-d7/a2-a6 - ELSE + ELSE move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / move.l (sp)+,d4 ; \ fused @@ -840,15 +916,15 @@ epilogue_11 macro move.l (sp)+,a4 ; \ fused move.l (sp)+,a5 ; / move.l (sp)+,a6 - ENDC + ENDC rts endm -*---------------------------------------------------------------------------------------- +*------------------------------------------------------------------------------------ * extern void RenderTile_RT_TRANSPARENT(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_TRANSPARENT prologue_11 - addq.l #2,a4 ; skip over load mask + addq.l #2,a4 ; skip over load mask moveq #31,d7 .L1 move.l -(a3),d6 ; m = *mask; mask-- @@ -859,7 +935,13 @@ _RenderTile_RT_TRANSPARENT bgt.b .L3 suba.w d5,a0 ; dst += (-v) neg.w d5 ; v =-v (parallel!) - bra.b .L4 +* bra.b .L4 + lsl.l d5,d6 ; m <<= v + sub.w d5,d4 ; j -= v + bne.b .L2 + sub.w #BUFFER_WIDTH+32,a0 + dbra d7,.L1 + epilogue_11 .L3 move.w d5,d0 move.l d6,d1 @@ -872,108 +954,111 @@ _RenderTile_RT_TRANSPARENT dbra d7,.L1 epilogue_11 -*---------------------------------------------------------------------------------------- + cnop 0,4 + + +*------------------------------------------------------------------------------------ * extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_SQUARE prologue_7 - bsr block16 - bsr block16 - epilogue_7 - -*---------------------------------------------------------------------------------------- - - XDEF block16 - XDEF triangL - XDEF triangR - + bsr block16 + bsr block16 + epilogue_7 + +*------------------------------------------------------------------------------------ + + XDEF block16 + XDEF triangL + XDEF triangR + block16 - REPT 16 - moveq #32,d0 + REPT 16 + moveq #32,d0 jsr (a4) sub.w #BUFFER_WIDTH+32,a0 ENDR - rts - + rts + triangL -.i set 30 - add.w #.i,a0 - REPT 16 - IFNE .i&2 - addq.w #2,a1 - ENDC +.i set 30 + add.w #.i,a0 + REPT 16 + IFNE .i&2 + addq.w #2,a1 + ENDC moveq #32-.i,d0 jsr (a4) - IFNE .i -.i set .i-2 - ENDC - sub.w #BUFFER_WIDTH+32-.i,a0 - ENDR - rts + IFNE .i +.i set .i-2 + ENDC + sub.w #BUFFER_WIDTH+32-.i,a0 + ENDR + rts triangR -.i set 30 - REPT 16 +.i set 30 + REPT 16 moveq #32-.i,d0 jsr (a4) - IFNE .i&2 - addq.w #2,a1 - ENDC + IFNE .i&2 + addq.w #2,a1 + ENDC sub.w #BUFFER_WIDTH+32-.i,a0 -.i set .i-2 - ENDR - rts +.i set .i-2 + ENDR + rts -*---------------------------------------------------------------------------------------- +*------------------------------------------------------------------------------------ * extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_LTRAPEZOID prologue_7 - bsr triangL - bsr block16 + bsr triangL + bsr block16 epilogue_7 -*---------------------------------------------------------------------------------------- +*------------------------------------------------------------------------------------ * extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_RTRAPEZOID prologue_7 - bsr triangR - bsr block16 + bsr triangR + bsr block16 epilogue_7 - -*---------------------------------------------------------------------------------------- + +*------------------------------------------------------------------------------------ * extern void RenderTile_RT_LTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_LTRIANGLE prologue_7 - bsr triangL -.i set 2 - addq.l #.i,a0 - REPT 15 - IFNE .i&2 - addq.w #2,a1 - ENDC + bsr triangL +.i set 2 + addq.l #.i,a0 + REPT 15 + IFNE .i&2 + addq.w #2,a1 + ENDC moveq #32-.i,d0 jsr (a4) - IFNE .i-30 -.i set .i+2 - sub.w #BUFFER_WIDTH+32-.i,a0 - ENDC - ENDR + IFNE .i-30 +.i set .i+2 + sub.w #BUFFER_WIDTH+32-.i,a0 + ENDC + ENDR epilogue_7 -*---------------------------------------------------------------------------------------- +*------------------------------------------------------------------------------------ * extern void RenderTile_RT_RTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_RTRIANGLE prologue_7 - bsr triangR -.i set 2 - REPT 15 + bsr triangR +.i set 2 + REPT 15 moveq #32-.i,d0 jsr (a4) - IFNE .i&2 - addq.w #2,a1 - ENDC + IFNE .i&2 + addq.w #2,a1 + ENDC sub.w #BUFFER_WIDTH+32-.i,a0 -.i set .i+2 - ENDR +.i set .i+2 + ENDR epilogue_7 * end of file \ No newline at end of file From d8cee8c5b52446b702902dbb84689e552b7822ad Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Sun, 8 Dec 2019 18:40:26 +0100 Subject: [PATCH 010/107] oops a file was missing --- SourceX/platform/amiga/support.c | 143 +++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100755 SourceX/platform/amiga/support.c diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c new file mode 100755 index 00000000000..74a6745c45a --- /dev/null +++ b/SourceX/platform/amiga/support.c @@ -0,0 +1,143 @@ +/* + * Various support functions or the amiga + */ + +//#include + +#include +#include +#include +#include + +#include +#include + +#include "../../../../defs.h" +#define FRAME_BUFFER_SZ ((SCREEN_WIDTH)*(SCREEN_HEIGHT)) + +#define DIRTY 0 // 1 = 32 fps 0 = 29fps + +#define CHECK_FIRSTSCREEN 1 // costs 0 fps +#define CHECK_SURFACE 0 +#define ROLL_PTR 0 + +#include + +extern int _ZN3dvl10fullscreenE; // diablo.h +// extern int _ZN3dvl27pal_surface_palette_versionE; +// extern void *_ZN3dvl6windowE; +// extern SDL_Palette *_ZN3dvl7paletteE; + +short ac68080_saga = 0; +short ac68080_ammx = 0; + +static UBYTE *bufmem = NULL; +static UBYTE started = 0; +static struct Screen *game_screen; +static struct SDL_Surface *game_surface; + +struct Library *VampireBase; +extern struct ExecBase *SysBase; +extern struct IntuitionBase *IntuitionBase; + +static void stop(void) +{ + if(bufmem) { + FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); + bufmem = NULL; + } +} +static void start(void) +{ + started = 255; + atexit(stop); + + if (SysBase->AttnFlags &(1 << 10)) { + ac68080_saga = 1; //!_ZN3dvl10fullscreenE; // disable if not fullscreen + + bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); + if(!bufmem) ac68080_saga = 0; + + if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); + if(VampireBase && VampireBase->lib_Version >= 45 && + (V_EnableAMMX( V_AMMX_V2 ) != VRES_ERROR) ) { + ac68080_ammx = 1; + } + + printf("Vampire accelerator detected"); + if(ac68080_ammx || ac68080_saga) { + printf(". Using"); + if(ac68080_saga) { + printf(" SAGA Direct Draw"); + } + if(ac68080_ammx) { + if(ac68080_saga) printf(" &"); + printf(" AMMX2"); + } + } + printf(".\n"); + } +} + +int vampire_Flip(SDL_Surface *surf) +{ + volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ +// volatile ULONG *pal = (ULONG*)0xDFF400; + struct Screen *first_screen; + + if(!started) start(); + +#if DIRTY + *dpy = (void*)(~31&(int)surf->pixels); + return; +#endif + + // check if saga is on or if surface is the game surface + if(!ac68080_ammx) goto legacy; + +#if CHECK_SURFACE + if(surf != game_surface && surf->h == SCREEN_HEIGHT && surf->pitch<=SCREEN_HEIGHT) + game_surface = surf; + if(surf != game_surface) goto legacy; +#endif + +#if CHECK_FIRSTSCREEN + // check if screen has changed + if(game_screen != (first_screen = IntuitionBase->FirstScreen) + && first_screen->Height == SCREEN_HEIGHT + && first_screen->Width == SCREEN_WIDTH) + game_screen = first_screen; + + // if we are running on the game scree + if(first_screen == game_screen) +#endif + { + UBYTE *ptr = surf->pixels; + + // if ptr ouside our memory + if((ULONG)(ptr - bufmem) >= (ULONG)(3*FRAME_BUFFER_SZ+31)) { // ! \\ ULONG trick + if(surf->flags & SDL_PREALLOC) goto legacy; + + ptr = (UBYTE*)(~31&(ULONG)(bufmem + 31)); + CopyMemQuick(surf->pixels, ptr, FRAME_BUFFER_SZ); + SDL_free(surf->pixels); + surf->flags |= SDL_PREALLOC; + surf->pixels = ptr; + } + + // display + *dpy = ptr; + + // advance ptr +#if ROLL_PTR + ptr += FRAME_BUFFER_SZ; + if(ptr >= bufmem + 3*FRAME_BUFFER_SZ) ptr -= 3*FRAME_BUFFER_SZ; + surf->pixels = ptr; +#endif + + return 0; + } + +legacy: + return SDL_Flip(surf); +} From 2d8fe3d10dea20b9e6e57cd03edb10a77a64a1de Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Tue, 10 Dec 2019 14:32:20 +0100 Subject: [PATCH 011/107] Speedup of render2 with Mask --- Source/scrollrt.cpp | 1 + SourceS/sdl_compat.h | 6 +- SourceX/platform/amiga/render68k.s | 589 ++++++++++++++++++----------- SourceX/platform/amiga/support.c | 22 +- 4 files changed, 394 insertions(+), 224 deletions(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index da74679ae20..7dbcf9d8093 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -6,6 +6,7 @@ int light_table_index; DWORD sgdwCursWdtOld; DWORD sgdwCursX; DWORD sgdwCursY; +// AMIGA important make Start first so that CMP2 works BYTE *gpBufStart; BYTE *gpBufEnd; DWORD sgdwCursHgt; diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index efd57c5994d..4ee52a9c7d1 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -14,9 +14,9 @@ #if defined(__AMIGA__) // Add other systems that require an 8bit screen here extern "C" { - short ac68080_saga; - short ac68080_ammx; - int vampire_Flip(SDL_Surface *surf); + char ac68080_saga; + char ac68080_ammx; + int vampire_Flip(SDL_Surface *surf); } //extern C #endif #define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s index 3fe3867eeb4..7c4594abe2a 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.s @@ -5,8 +5,11 @@ machine 68080 -BUFFER_WIDTH set 768 ; FIXME: set the correct value here -VAMP_V4 set 1 +BUFFER_WIDTH set 768 +VAMP_V4 set 1 ; 0 = replaces movem with separate moves +NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) +A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) +USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -21,15 +24,83 @@ VAMP_V4 set 1 XDEF _RenderLine0_AMMX XDEF _RenderLine1_AMMX XDEF _RenderLine2_AMMX - + + ifne NO_OVERDRAW XREF __ZN3dvl10gpBufStartE + ifeq USE_CMP2 XREF __ZN3dvl8gpBufEndE + endc + endc + XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE XREF _ac68080_ammx cnop 0,4 +* sanity + ifeq NO_OVERDRAW +A5_RELATIVE set 0 +USE_CMP2 set 0 + endc + + ifne A5_RELATIVE +USE_CMP2 set 0 + endc + + ifeq NO_OVERDRAW*(1-USE_CMP2) +SAVE_A5A6 set 0 + else +SAVE_A5A6 set 1 + endc + +* ----------------------------------------------------------------------------- +* check bounds + +rts_bounds macro + ifnb \1 + adda.w d0,\1 + endc + ifnb \2 + adda.w d0,\2 + endc + ifne A5_RELATIVE + suba.l a5,a0 + endc + rts + endm + +chk_bounds macro +* beq.b \1 ; 1 + + ifne NO_OVERDRAW + + ifne A5_RELATIVE + cmp.l a6,a0 ; 1 + adda.l a5,a0 ; 1 + bhi.b \1 ; 2 + else + + ifne USE_CMP2 + cmp2.l __ZN3dvl10gpBufStartE,a0 + bcs.b \1 + else + cmp.l a5,a0 ; 1 + bcs.b \1 ; 2 + cmp.l a6,a0 ; 3 + bhi.b \1 ; 4 + endc + +* move.l a0,d2 ; F p1 +* sub.l a5,d2 ; F p1 +* move.l a6,d3 ; F p2 +* sub.l a5,d3 ; F p2 = 1 cycles for all 4 isntructions +* cmp.l d3,d2 ; 2 +* bhi \1 ; 3 total cycles + endc + endc + endm + * ----------------------------------------------------------------------------- * debug: displays nothing @@ -40,7 +111,7 @@ _RenderLine_NONE rts * ----------------------------------------------------------------------------- -* AMMX version +* AMMX version rol_d1_mask macro bfclr d1{d0:8} @@ -59,8 +130,7 @@ unroll_AMMX macro \1 0 \1 0 \1 1 -* we can leave since there is never no more than 32 bytes - rts + rts_bounds \1_16 btst #4,d0 beq \1_8 @@ -85,15 +155,12 @@ unroll_AMMX macro * case light_table_index == lightmax _RenderLine1_AMMX move.l -(a3),d1 - add.w d0,a1 -* beq.b .nx - cmp.l a5,a0 - bcs.b .nx - cmp.l a6,a0 - bhi.b .nx + add.w d0,a1 + chk_bounds .nx peor d2,d2,d2 ; d2=0.q - moveq #1,d3 + + moveq #1,d3 add.l d1,d3 bne .mask @@ -105,8 +172,8 @@ _RenderLine1_AMMX storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx - add.w d0,a0 - rts + add.w d0,a0 + rts_bounds * mask version .m8 macro @@ -120,16 +187,12 @@ _RenderLine1_AMMX .mask unroll_AMMX .m8,.m0,.mx add.w d0,a0 - rts + rts_bounds * case light_table_index == 0 _RenderLine0_AMMX move.l -(a3),d1 -* beq.b .nx - cmp.l a5,a0 - bcs.b .nx - cmp.l a6,a0 - bhi.b .nx + chk_bounds .nx moveq #1,d3 add.l d1,d3 @@ -145,203 +208,277 @@ _RenderLine0_AMMX storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds * version with mask .m8 macro - load (a1)+,d2 rol.l #8,d1 + load (a1)+,d2 storem d2,d1,(a0)+ endm .m0 macro - load (a1),d2 rol_d1_mask + load (a1),d2 storem d2,d1,(a0) endm .mask unroll_AMMX .m8,.m0,.mx - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds * other cases -_RenderLine2_AMMX - move.l -(a3),d1 -* beq.b _RenderLine0_AMMX\.mx - cmp.l a5,a0 - bcs.b _RenderLine0_AMMX\.mx - cmp.l a6,a0 - bhi.b _RenderLine0_AMMX\.mx - - movem.l d4/d5,-(sp) - - move.l d1,d3 ; \ fused - addq.l #1,d3 ; / - bne .mask - transform macro * move.l (a1)+,d3 ; F(used) d3=AABBCCDD * move.l (a1)+,d5 ; F 1 * input d3/d5 + ifne \1&$a0 move.l d3,d2 ; p1 d3=AABBCCDD rol.l #8,d2 ; p1 d2=BBCCDDAA - move.l d5,d4 ; p2 + endc + ifne \1&$0a + move.l d5,d4 ; p2 rol.l #8,d4 ; p2 2 - + endc + + ifne \1&$a0 and.l #$00FF00FF,d2 ; p1 d2=00CC00AA + endc + ifne \1&$50 and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD + endc + ifne \1&$0a and.l #$00FF00FF,d4 ; p1 + endc + ifne \1&$05 and.l #$00FF00FF,d5 ; p2 4 + endc + ifne \1&$50 swap d3 ; p1 d3=00DD00BB + endc + ifne \1&$05 swap d5 ; p2 5 - ifne \1&$80 - move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- endc - ifne \1&$40 + ifne \1&$80 + move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- + endc + ifne \1&$40 move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy - endc + endc + ifne \1&$a0 swap d2 ; p2 7 d2=xxyy00CC + endc + ifne \1&$50 swap d3 ; p1 d3=00BB00DD - ifne \1&$08 - move.w (a2,d4.w),d4 ; p2 8 endc - ifne \1&$04 + ifne \1&$08 + move.w (a2,d4.w),d4 ; p2 8 + endc + ifne \1&$04 move.b (a2,d5.w),d4 ; p1 - endc + endc + ifne \1&$0a swap d4 ; p2 9 + endc + ifne \1&$05 swap d5 ; p1 - ifne \1&$20 - move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- endc - ifne \1&$10 + ifne \1&$20 + move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- + endc + ifne \1&$10 move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt - endc - ifne \1&$02 + endc + ifne \1&$02 move.w (a2,d4.w),d4 ; p1 12 - endc - ifne \1&$01 + endc + ifne \1&$01 move.b (a2,d5.w),d4 ; p1 13 - endc + endc * output d2/d4 * move.l d2,(a0)+ ; F * move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm +_RenderLine2_AMMX + move.l -(a3),d1 + chk_bounds _RenderLine0_AMMX\.mx + + movem.l d4/d5,-(sp) + + move.l d1,d3 ; \ fused + addq.l #1,d3 ; / + bne .mask + .n8 macro move.l (a1)+,d3 move.l (a1)+,d5 - transform $ff + transform $ff move.l d2,(a0)+ move.l d4,(a0)+ ifne \1 + ifne VAMP_V4 movem.l (sp)+,d4/d5 + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc endc endm .n0 macro move.l (a1),d3 move.l 4(a1),d5 - transform $ff + transform $ff vperm #$4567CDEF,d2,d4,d2 storec d2,d0,(a0) endm + unroll_AMMX .n8,.n0,.nx + ifne VAMP_V4 movem.l (sp)+,d4/d5 - add.w d0,a1 + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc add.w d0,a0 - rts + add.w d0,a1 + rts_bounds * mask version -.m8 macro - move.l (a1)+,d3 ; F(used) d3=AABBCCDD - move.l (a1)+,d5 ; F 1 - transform $ff - vperm #$4567CDEF,d2,d4,d2 - rol.l #8,d1 - storem d2,d1,(a0)+ - ifne \1 + +.transfAA55_8 macro + moveq #0,d2 + move.b \1(a1),d2 ; 1 + moveq #0,d3 + move.b \1+2(a1),d3 ; 2 + moveq #0,d4 + move.b \1+4(a1),d4 ; 3 + moveq #0,d5 + move.b \1+6(a1),d5 ; 4 + addq #8,a0 ; 4 + addq.l #8,a1 + move.w (a2,d2.w),d2 ; 5 + move.b (a2,d3.w),d2 , 6 + swap d2 ; 7 + move.w (a2,d4.w),d2 ; 8 + move.b (a2,d5.w),d2 ; 9 + movep.l d2,\1-9(a0) ; 10 + endm + +.transfAA55 macro + btst #5,d0 + bne .b4\2 + .transfAA55_8 \1 + .transfAA55_8 \1 + .transfAA55_8 \1 + .transfAA55_8 \1 + ifne VAMP_V4 movem.l (sp)+,d4/d5 - endc - endm -.m0 macro - move.l (a1),d3 ; F(used) d3=AABBCCDD - move.l 4(a1),d5 ; F 1 - transform $ff - vperm #$4567CDEF,d2,d4,d2 - rol_d1_mask - storem d2,d1,(a0) - endm + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc + rts_bounds +.b4\2 + btst #4,d0 + bne .b3\2 + .transfAA55_8 \1 + .transfAA55_8 \1 +.b3\2 + btst #3,d0 + bne .b2\2 + .transfAA55_8 \1 +.b2\2 + ifne VAMP_V4 + movem.l (sp)+,d4/d5 + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc + btst #2,d0 + bne .b1\2 + moveq #0,d2 + move.b \1(a1),d2 ; 1 + moveq #0,d3 + move.b \1+2(a1),d3 ; 2 + addq.l #4,a0 ; 3 + addq.l #4,a1 ; 2 + move.w (a2,d2.w),d2 ; 3+1 + move.b (a2,d3.w),d2 , 5 + movep.w d2,\1-5(a0) ; 6 +.b1\2 + btst #1,d0 + bne .b0\2 + moveq #0,d2 + move.b \1(a1),d2 ; 1 + addq.l #2,a0 + addq.l #2,a1 +; 2 bubbles + move.b (a2,d2.w),d2 ; 4 + move.b d2,\1(a0) ; 5 +.b0\2 + ifne \1 + addq.l #1,a0 + addq.l #1,a1 + else + move.b (a1)+,(a0)+ + endc + rts_bounds + endm .mask cmp.l #$AAAAAAAA,d1 - beq .maskAA + bne .mask1 + .transfAA55 0,_aa + +.mask1 cmp.l #$55555555,d1 - beq .mask55 - unroll_AMMX .m8,.m0,.mx - movem.l (sp)+,d4/d5 - add.w d0,a1 - add.w d0,a0 - rts + bne .mask2 + .transfAA55 1,_55 -.m8AA macro +.mask2 + +.m8 macro move.l (a1)+,d3 ; F(used) d3=AABBCCDD move.l (a1)+,d5 ; F 1 - transform $AA - vperm #$4567CDEF,d2,d4,d2 rol.l #8,d1 + transform $ff + vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0)+ ifne \1 + ifne VAMP_V4 movem.l (sp)+,d4/d5 + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc endc endm -.m0AA macro +.m0 macro move.l (a1),d3 ; F(used) d3=AABBCCDD move.l 4(a1),d5 ; F 1 - transform $AA - vperm #$4567CDEF,d2,d4,d2 rol_d1_mask - storem d2,d1,(a0) - endm -.maskAA - unroll_AMMX .m8AA,.m0AA,.mxAA - add.w d0,a1 - add.w d0,a0 - rts - -.m855 macro - move.l (a1)+,d3 ; F(used) d3=AABBCCDD - move.l (a1)+,d5 ; F 1 - transform $55 - vperm #$4567CDEF,d2,d4,d2 - rol.l #8,d1 - storem d2,d1,(a0)+ - ifne \1 - movem.l (sp)+,d4/d5 - endc - endm -.m055 macro - move.l (a1),d3 ; F(used) d3=AABBCCDD - move.l 4(a1),d5 ; F 1 - transform $55 + transform $ff vperm #$4567CDEF,d2,d4,d2 - rol_d1_mask storem d2,d1,(a0) endm -.mask55 - unroll_AMMX .m855,.m055,.mx55 - add.w d0,a1 + unroll_AMMX .m8,.m0,.mx + ifne VAMP_V4 + movem.l (sp)+,d4/d5 + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc add.w d0,a0 - rts - * + add.w d0,a1 + rts_bounds + * ----------------------------------------------------------------------------- _RenderLine2_AMMX_orig move.l -(a3),d1 -* beq _RenderLine0_AMMX\.mx - cmp.l a5,a0 - bcs _RenderLine0_AMMX\.mx - cmp.l a6,a0 - bhi _RenderLine0_AMMX\.mx + chk_bounds _RenderLine2_AMMX\.mx move.l d1,d3 ; \ fused addq.l #1,d3 ; / @@ -409,11 +546,19 @@ transform macro storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds * mask version +.mask + moveq #0,d3 + + cmp.l #$AAAAAAAA,d1 + beq .maskAA + cmp.l #$55555555,d1 + beq .mask55 + .m8 macro load (a1)+,d2 transform $ff @@ -426,18 +571,10 @@ transform macro rol_d1_mask storem d2,d1,(a0) endm -.mask - moveq #0,d3 - - cmp.l #$AAAAAAAA,d1 - beq .maskAA - cmp.l #$55555555,d1 - beq .mask55 - unroll_AMMX .m8,.m0,.mx - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds .m8AA macro load (a1)+,d2 @@ -453,9 +590,9 @@ transform macro endm .maskAA unroll_AMMX .m8AA,.m0AA,.mxAA - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds .m855 macro load (a1)+,d2 @@ -471,9 +608,9 @@ transform macro endm .mask55 unroll_AMMX .m855,.m055,.mx55 - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds * ----------------------------------------------------------------------------- @@ -493,38 +630,38 @@ inc_a0 macro inc_a0_a1 macro * cmp.b (a1)+,(a0)+ - addq.l #1,a1 addq.l #1,a0 + addq.l #1,a1 endm unroll macro btst #5,d0 beq \1_4 - \1 - \1 - \1 - \1 - \1 - \1 - \1 - \1 - rts + \1 0 + \1 0 + \1 0 + \1 0 + \1 0 + \1 0 + \1 0 + \1 1 + rts_bounds \1_4 btst #4,d0 beq \1_2 - \1 - \1 - \1 - \1 + \1 0 + \1 0 + \1 0 + \1 0 \1_2 btst #3,d0 beq \1_1 - \1 - \1 + \1 0 + \1 0 \1_1 btst #2,d0 beq \2_1 - \1 + \1 0 \2_1 btst #1,d0 beq \3_1 @@ -534,36 +671,32 @@ unroll macro beq \3_2 \3 \3_2 - rts + rts_bounds endm loop macro \1__1 add.l d1,d1 bcs \1__2 - \1 + \1 à subq.w #1,d0 bne \1__1 - rts + rts_bounds \1__2 \2 subq.w #1,d0 bne \1__1 - rts + rts_bounds endm * case light_table_index == 0 _RenderLine0_ - add.w d0,a1 add.w d0,a0 - rts + add.w d0,a1 + rts_bounds _RenderLine0 move.l -(a3),d1 -* beq.b _RenderLine0_ - cmp.l a5,a0 - bcs.b _RenderLine0_ - cmp.l a6,a0 - bhi.b _RenderLine0_ + chk_bounds _RenderLine0_ not.l d1 bne .mask @@ -585,8 +718,8 @@ _RenderLine0 ifeq 1 move.b 1(a1),1(a0) ; 2 move.b 3(a1),3(a0) ; 2 - addq.l #4,a1 ; .5 addq.l #4,a0 ; .5 ==> 5 cycles + addq.l #4,a1 ; .5 else move.l (a1)+,d1 ; \ and.l #$00FF00FF,d1 ; / 1 cycle (fused) ? @@ -598,12 +731,12 @@ _RenderLine0 endm .p2 macro move.b 1(a1),1(a0) - addq.l #2,a1 addq.l #2,a0 + addq.l #2,a1 endm .p1 macro - addq.l #1,a1 addq.l #1,a0 + addq.l #1,a1 endm unroll .p4,.p2,.p1 @@ -652,15 +785,11 @@ _RenderLine0 * case light_table_index == lightmax _RenderLine1_ add.w d0,a0 - rts + rts_bounds _RenderLine1 move.l -(a3),d1 add.w d0,a1 -* beq.b _RenderLine1_ - cmp.l a5,a0 - bcs.b _RenderLine1_ - cmp.l a6,a0 - bhi.b _RenderLine1_ + chk_bounds _RenderLine1_ not.l d1 bne .mask @@ -711,14 +840,10 @@ _RenderLine1 _RenderLine2_ add.w d0,a1 add.w d0,a0 - rts + rts_bounds _RenderLine2 move.l -(a3),d1 -* beq _RenderLine2_ - cmp.l a5,a0 - bcs.b _RenderLine2_ - cmp.l a6,a0 - bhi.b _RenderLine2_ + chk_bounds _RenderLine2_ moveq #0,d2 moveq #0,d3 @@ -815,7 +940,7 @@ setup macro _setup * determine renderFcn - tst.w _ac68080_ammx + tst.b _ac68080_ammx bne .ammx lea _RenderLine0(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 @@ -837,16 +962,32 @@ _setup * pand #$00000000FFFFFFFF,d0,d0 * factorize constants in regs .L0 + ifne NO_OVERDRAW + ifeq USE_CMP2 move.l __ZN3dvl10gpBufStartE,a5 move.l __ZN3dvl8gpBufEndE,a6 + endc + ifne A5_RELATIVE + sub.l a5,a0 + sub.l a5,a6 + endc + endc addq.l #4,a3 rts prologue_7 macro +.size set 7 + ifeq SAVE_A5A6 +.size set .size-2 + endc IFNE VAMP_V4 + ifne SAVE_A5A6 movem.l d2-d3/a2-a6,-(sp) + else + movem.l d2-d3/a2-a4,-(sp) + endc ELSE - sub.w #4*7,sp + sub.w #4*.size,sp move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused @@ -854,34 +995,51 @@ prologue_7 macro move.l a3,4*3(sp) ; / fused move.l a4,4*4(sp) ; \ + ifne SAVE_A5A6 move.l a5,4*5(sp) ; / fused move.l a6,4*6(sp) + endc ENDC - setup 7 + setup .size endm epilogue_7 macro IFNE VAMP_V4 + ifne SAVE_A5A6 movem.l (sp)+,d2-d3/a2-a3/a4-a6 + else + movem.l (sp)+,d2-d3/a2-a3/a4 + endc ELSE move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / move.l (sp)+,a2 ; \ fused move.l (sp)+,a3 ; / move.l (sp)+,a4 ; \ fused + ifne SAVE_A5A6 move.l (sp)+,a5 ; / move.l (sp)+,a6 + endc ENDC rts endm prologue_11 macro +.size set 11 + ifeq SAVE_A5A6 +.size set .size-2 + endc IFNE VAMP_V4 + ifne SAVE_A5A6 movem.l d2-d7/a2-a6,-(sp) + else + movem.l d2-d7/a2-a4,-(sp) + endc ELSE - sub.w #4*11,sp - move.l d2,4*0(sp) ; \ + sub.w #4*.size,sp + + move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused move.l d4,4*2(sp) ; \ @@ -893,17 +1051,23 @@ prologue_11 macro move.l a2,4*6(sp) ; \ move.l a3,4*7(sp) ; / fused - move.l a4,4*8(sp) ; \ + move.l a4,4*8(sp) ; \ + ifne SAVE_A5A6 move.l a5,4*9(sp) ; / fused move.l a6,4*10(sp) + endc ENDC - setup 11 + setup .size endm epilogue_11 macro IFNE VAMP_V4 + ifne SAVE_A5A6 movem.l (sp)+,d2-d7/a2-a6 + else + movem.l (sp)+,d2-d7/a2-a4 + endc ELSE move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / @@ -914,8 +1078,10 @@ epilogue_11 macro move.l (sp)+,a2 ; \ fused move.l (sp)+,a3 ; / move.l (sp)+,a4 ; \ fused + ifne SAVE_A5A6 move.l (sp)+,a5 ; / move.l (sp)+,a6 + endc ENDC rts endm @@ -954,9 +1120,6 @@ _RenderTile_RT_TRANSPARENT dbra d7,.L1 epilogue_11 - cnop 0,4 - - *------------------------------------------------------------------------------------ * extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_SQUARE @@ -979,6 +1142,22 @@ block16 ENDR rts +*------------------------------------------------------------------------------------ +* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_LTRAPEZOID + prologue_7 + bsr triangL + bsr block16 + epilogue_7 + +*------------------------------------------------------------------------------------ +* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_RTRAPEZOID + prologue_7 + bsr triangR + bsr block16 + epilogue_7 + triangL .i set 30 add.w #.i,a0 @@ -1008,22 +1187,6 @@ triangR ENDR rts -*------------------------------------------------------------------------------------ -* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_LTRAPEZOID - prologue_7 - bsr triangL - bsr block16 - epilogue_7 - -*------------------------------------------------------------------------------------ -* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_RTRAPEZOID - prologue_7 - bsr triangR - bsr block16 - epilogue_7 - *------------------------------------------------------------------------------------ * extern void RenderTile_RT_LTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_LTRIANGLE diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index 74a6745c45a..403af0a3a03 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -28,8 +28,8 @@ extern int _ZN3dvl10fullscreenE; // diablo.h // extern void *_ZN3dvl6windowE; // extern SDL_Palette *_ZN3dvl7paletteE; -short ac68080_saga = 0; -short ac68080_ammx = 0; +UBYTE ac68080_saga = 0; +UBYTE ac68080_ammx = 0; static UBYTE *bufmem = NULL; static UBYTE started = 0; @@ -53,7 +53,7 @@ static void start(void) atexit(stop); if (SysBase->AttnFlags &(1 << 10)) { - ac68080_saga = 1; //!_ZN3dvl10fullscreenE; // disable if not fullscreen + ac68080_saga = 255; //!_ZN3dvl10fullscreenE; // disable if not fullscreen bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); if(!bufmem) ac68080_saga = 0; @@ -61,7 +61,7 @@ static void start(void) if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); if(VampireBase && VampireBase->lib_Version >= 45 && (V_EnableAMMX( V_AMMX_V2 ) != VRES_ERROR) ) { - ac68080_ammx = 1; + ac68080_ammx = 255; } printf("Vampire accelerator detected"); @@ -79,7 +79,7 @@ static void start(void) } } -int vampire_Flip(SDL_Surface *surf) +int vampire_Flip(SDL_Surface* const surf) { volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ // volatile ULONG *pal = (ULONG*)0xDFF400; @@ -114,22 +114,28 @@ int vampire_Flip(SDL_Surface *surf) { UBYTE *ptr = surf->pixels; - // if ptr ouside our memory + // if ptr ouside our memory, then use out aligned one (this is done only once per game surface) if((ULONG)(ptr - bufmem) >= (ULONG)(3*FRAME_BUFFER_SZ+31)) { // ! \\ ULONG trick + // if not a std surface, do nothing if(surf->flags & SDL_PREALLOC) goto legacy; + // aligned memory ptr = (UBYTE*)(~31&(ULONG)(bufmem + 31)); + + // sync aligned memory content with current surface CopyMemQuick(surf->pixels, ptr, FRAME_BUFFER_SZ); + + // replace surface pixels by our aliged memory SDL_free(surf->pixels); - surf->flags |= SDL_PREALLOC; + surf->flags |= SDL_PREALLOC; // <== tell SDL not to bother with theses pixels surf->pixels = ptr; } // display *dpy = ptr; - // advance ptr #if ROLL_PTR + // advance ptr ptr += FRAME_BUFFER_SZ; if(ptr >= bufmem + 3*FRAME_BUFFER_SZ) ptr -= 3*FRAME_BUFFER_SZ; surf->pixels = ptr; From dc37d09fc7ea7afa6822dad3fa2e87aea1b1fd9a Mon Sep 17 00:00:00 2001 From: Samuel DEVULDER Date: Tue, 10 Dec 2019 22:06:07 +0100 Subject: [PATCH 012/107] now uses E4/E5 in place of D4/D5 by usage of BANK prefix --- SourceX/platform/amiga/render68k.s | 132 ++++++++++++++++------------- 1 file changed, 74 insertions(+), 58 deletions(-) diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.s index 7c4594abe2a..dedfb7be11e 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.s @@ -10,6 +10,7 @@ VAMP_V4 set 1 ; 0 = replaces movem with separate moves NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) +USE_BANK set 1 XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -54,6 +55,31 @@ SAVE_A5A6 set 0 SAVE_A5A6 set 1 endc + ifne USE_BANK +bank macro + inline +.aa equ * + dc.w (%0111000100000000+((\1)*%100)+(\2)+((.bb)*%1000000)) + ifb \5 + \3 \4 + else + \3 \4,\5 + endc +.bb equ (*-.aa-4)>>1 + einline + endm + + else + +bank macro + ifb \5 + \3 \4 + else + \3 \4,\5 + endc + endm + endc + * ----------------------------------------------------------------------------- * check bounds @@ -239,8 +265,8 @@ transform macro rol.l #8,d2 ; p1 d2=BBCCDDAA endc ifne \1&$0a - move.l d5,d4 ; p2 - rol.l #8,d4 ; p2 2 + bank 1,1,move.l,d5,d4 ; p2 + bank 1,1,rol.l,#8,d4 ; p2 2 endc ifne \1&$a0 @@ -250,16 +276,16 @@ transform macro and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD endc ifne \1&$0a - and.l #$00FF00FF,d4 ; p1 + bank 1,1,and.l,#$00FF00FF,d4 ; p1 endc ifne \1&$05 - and.l #$00FF00FF,d5 ; p2 4 + bank 1,1,and.l,#$00FF00FF,d5 ; p2 4 endc ifne \1&$50 swap d3 ; p1 d3=00DD00BB endc ifne \1&$05 - swap d5 ; p2 5 + bank 1,1,swap,d5 ; p2 5 endc ifne \1&$80 move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- @@ -274,16 +300,16 @@ transform macro swap d3 ; p1 d3=00BB00DD endc ifne \1&$08 - move.w (a2,d4.w),d4 ; p2 8 + bank 1,1,move.w,(a2,d4.w),d4 ; p2 8 endc ifne \1&$04 - move.b (a2,d5.w),d4 ; p1 + bank 1,1,move.b,(a2,d5.w),d4 ; p1 endc ifne \1&$0a - swap d4 ; p2 9 + bank 1,1,swap,d4 ; p2 9 endc ifne \1&$05 - swap d5 ; p1 + bank 1,1,swap,d5 ; p1 endc ifne \1&$20 move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- @@ -292,56 +318,63 @@ transform macro move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt endc ifne \1&$02 - move.w (a2,d4.w),d4 ; p1 12 + bank 1,1,move.w,(a2,d4.w),d4 ; p1 12 endc ifne \1&$01 - move.b (a2,d5.w),d4 ; p1 13 + bank 1,1,move.b,(a2,d5.w),d4 ; p1 13 endc * output d2/d4 * move.l d2,(a0)+ ; F * move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm + + +push_d4_d5 macro + ifeq USE_BANK + movem.l d4/d5,-(sp) + endc + endm +pull_d4_d5 macro + ifeq USE_BANK + ifne VAMP_V4 + movem.l (sp)+,d4/d5 + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc + endc + endm _RenderLine2_AMMX move.l -(a3),d1 chk_bounds _RenderLine0_AMMX\.mx - movem.l d4/d5,-(sp) - + push_d4_d5 + move.l d1,d3 ; \ fused addq.l #1,d3 ; / bne .mask .n8 macro move.l (a1)+,d3 - move.l (a1)+,d5 + bank 0,1,move.l,(a1)+,d5 transform $ff move.l d2,(a0)+ - move.l d4,(a0)+ + bank 1,0,move.l,d4,(a0)+ ifne \1 - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 + pull_d4_d5 endc - endc endm .n0 macro move.l (a1),d3 - move.l 4(a1),d5 + bank 0,1,move.l,4(a1),d5 transform $ff vperm #$4567CDEF,d2,d4,d2 storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc + pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds @@ -353,17 +386,17 @@ _RenderLine2_AMMX move.b \1(a1),d2 ; 1 moveq #0,d3 move.b \1+2(a1),d3 ; 2 - moveq #0,d4 - move.b \1+4(a1),d4 ; 3 - moveq #0,d5 - move.b \1+6(a1),d5 ; 4 + bank 0,1,moveq,#0,d4 + bank 0,1,move.b,\1+4(a1),d4 ; 3 + bank 0,1,moveq,#0,d5 + bank 0,1,move.b,\1+6(a1),d5 ; 4 addq #8,a0 ; 4 addq.l #8,a1 move.w (a2,d2.w),d2 ; 5 move.b (a2,d3.w),d2 , 6 swap d2 ; 7 - move.w (a2,d4.w),d2 ; 8 - move.b (a2,d5.w),d2 ; 9 + bank 1,0,move.w,(a2,d4.w),d2 ; 8 + bank 1,0,move.b,(a2,d5.w),d2 ; 9 movep.l d2,\1-9(a0) ; 10 endm @@ -374,12 +407,7 @@ _RenderLine2_AMMX .transfAA55_8 \1 .transfAA55_8 \1 .transfAA55_8 \1 - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc + pull_d4_d5 rts_bounds .b4\2 btst #4,d0 @@ -391,12 +419,7 @@ _RenderLine2_AMMX bne .b2\2 .transfAA55_8 \1 .b2\2 - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc + pull_d4_d5 btst #2,d0 bne .b1\2 moveq #0,d2 @@ -447,12 +470,7 @@ _RenderLine2_AMMX vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0)+ ifne \1 - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc + pull_d4_d5 endc endm .m0 macro @@ -464,12 +482,7 @@ _RenderLine2_AMMX storem d2,d1,(a0) endm unroll_AMMX .m8,.m0,.mx - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc + pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds @@ -935,6 +948,9 @@ setup macro move.l (4*(3+\1),sp),a2 ; \ fused move.l (4*(4+\1),sp),a3 ; / ENDC + ifne USE_BANK + bank 0,1,move.l,a2,a2 + endc bsr _setup endm From 1ecbd0f930e6709b611b0342ac5d126d2fa368ed Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 12 Dec 2019 20:26:09 +0100 Subject: [PATCH 013/107] made an AMMX version of memcpy --- CMake/amiga/m68k-amigaos.cmake | 4 +- CMakeLists.txt | 3 +- .../amiga/{render68k.s => render68k.asm} | 562 +++++++++--------- 3 files changed, 283 insertions(+), 286 deletions(-) rename SourceX/platform/amiga/{render68k.s => render68k.asm} (73%) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 0128e1fecf9..f0aafa422a9 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -50,6 +50,8 @@ if(WIN32) endif() # Compiler flags +#set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -pg -g -noixemul") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") @@ -59,7 +61,7 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -Wl,--wrap=memcpy -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") # user diff --git a/CMakeLists.txt b/CMakeLists.txt index 25df21a6e50..f12161605cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,7 +313,8 @@ endif() if(AMIGA) list(APPEND devilutionx_SRCS - SourceX/platform/amiga/render68k.s + SourceX/platform/amiga/render68k.asm + SourceX/platform/amiga/memopt.asm SourceX/platform/amiga/support.c) endif() diff --git a/SourceX/platform/amiga/render68k.s b/SourceX/platform/amiga/render68k.asm similarity index 73% rename from SourceX/platform/amiga/render68k.s rename to SourceX/platform/amiga/render68k.asm index dedfb7be11e..88e0454f24d 100755 --- a/SourceX/platform/amiga/render68k.s +++ b/SourceX/platform/amiga/render68k.asm @@ -1,16 +1,16 @@ * ----------------------------------------------------------------------------- -* diablo.s -- replacement of C code by hand-written asm code by S.Devulder +* render68k.asm -- replacement of C code by hand-written asm code by S.Devulder * ----------------------------------------------------------------------------- section .text machine 68080 BUFFER_WIDTH set 768 -VAMP_V4 set 1 ; 0 = replaces movem with separate moves -NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) -A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) -USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) -USE_BANK set 1 +VAMP_V4 set 1 ; 0 = replaces movem with separate moves +NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) +A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) +USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) +USE_BANK set 1 ; uses E4/E5 in place of D4/D5 in Render2_AMMX XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -25,14 +25,14 @@ USE_BANK set 1 XDEF _RenderLine0_AMMX XDEF _RenderLine1_AMMX XDEF _RenderLine2_AMMX - - ifne NO_OVERDRAW + + ifne NO_OVERDRAW XREF __ZN3dvl10gpBufStartE - ifeq USE_CMP2 + ifeq USE_CMP2 XREF __ZN3dvl8gpBufEndE - endc - endc - + endc + endc + XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE XREF _ac68080_ammx @@ -40,92 +40,85 @@ USE_BANK set 1 cnop 0,4 * sanity - ifeq NO_OVERDRAW + ifeq NO_OVERDRAW A5_RELATIVE set 0 -USE_CMP2 set 0 - endc - - ifne A5_RELATIVE -USE_CMP2 set 0 - endc - - ifeq NO_OVERDRAW*(1-USE_CMP2) -SAVE_A5A6 set 0 - else -SAVE_A5A6 set 1 - endc - - ifne USE_BANK -bank macro - inline -.aa equ * - dc.w (%0111000100000000+((\1)*%100)+(\2)+((.bb)*%1000000)) - ifb \5 - \3 \4 - else - \3 \4,\5 - endc -.bb equ (*-.aa-4)>>1 - einline - endm - - else +USE_CMP2 set 0 + endc + + ifne A5_RELATIVE +USE_CMP2 set 0 + endc + + ifeq NO_OVERDRAW*(1-USE_CMP2) +SAVE_A5A6 set 0 + else +SAVE_A5A6 set 1 + endc + bank macro - ifb \5 - \3 \4 - else - \3 \4,\5 - endc - endm - endc + ifne USE_BANK + inline +.aa equ * + dc.w (%0111000100000000+((\1)*%100)+(\2)+((.bb)*%1000000)) + ifb \5 + \3 \4 + else + \3 \4,\5 + endc +.bb equ (*-.aa-4)>>1 + einline + else + ifb \5 + \3 \4 + else + \3 \4,\5 + endc + endm + endc * ----------------------------------------------------------------------------- * check bounds rts_bounds macro - ifnb \1 - adda.w d0,\1 - endc - ifnb \2 - adda.w d0,\2 - endc - ifne A5_RELATIVE - suba.l a5,a0 - endc - rts - endm - -chk_bounds macro -* beq.b \1 ; 1 - - ifne NO_OVERDRAW - - ifne A5_RELATIVE - cmp.l a6,a0 ; 1 - adda.l a5,a0 ; 1 - bhi.b \1 ; 2 - else - - ifne USE_CMP2 - cmp2.l __ZN3dvl10gpBufStartE,a0 - bcs.b \1 - else - cmp.l a5,a0 ; 1 - bcs.b \1 ; 2 - cmp.l a6,a0 ; 3 - bhi.b \1 ; 4 - endc - -* move.l a0,d2 ; F p1 -* sub.l a5,d2 ; F p1 -* move.l a6,d3 ; F p2 -* sub.l a5,d3 ; F p2 = 1 cycles for all 4 isntructions -* cmp.l d3,d2 ; 2 -* bhi \1 ; 3 total cycles - endc + ifnb \1 + adda.w d0,\1 endc - endm + ifnb \2 + adda.w d0,\2 + endc + ifne A5_RELATIVE + suba.l a5,a0 + endc + rts + endm + +chk_bounds macro +* beq.b \1 ; 1 + ifne NO_OVERDRAW + ifne A5_RELATIVE + cmp.l a6,a0 ; 1 + adda.l a5,a0 ; 1 + bhi.b \1 ; 2 + else + ifne USE_CMP2 + cmp2.l __ZN3dvl10gpBufStartE,a0 + bcs.b \1 + else + cmp.l a5,a0 ; 1 + bcs.b \1 ; 2 + cmp.l a6,a0 ; 3 + bhi.b \1 ; 4 + endc +* move.l a0,d2 ; F p1 +* sub.l a5,d2 ; F p1 +* move.l a6,d3 ; F p2 +* sub.l a5,d3 ; F p2 = 1 cycles for all 4 isntructions +* cmp.l d3,d2 ; 2 +* bhi \1 ; 3 total cycles + endc + endc + endm * ----------------------------------------------------------------------------- * debug: displays nothing @@ -137,7 +130,7 @@ _RenderLine_NONE rts * ----------------------------------------------------------------------------- -* AMMX version +* AMMX version rol_d1_mask macro bfclr d1{d0:8} @@ -156,7 +149,7 @@ unroll_AMMX macro \1 0 \1 0 \1 1 - rts_bounds + rts_bounds \1_16 btst #4,d0 beq \1_8 @@ -181,12 +174,12 @@ unroll_AMMX macro * case light_table_index == lightmax _RenderLine1_AMMX move.l -(a3),d1 - add.w d0,a1 + add.w d0,a1 chk_bounds .nx peor d2,d2,d2 ; d2=0.q - - moveq #1,d3 + + moveq #1,d3 add.l d1,d3 bne .mask @@ -198,7 +191,7 @@ _RenderLine1_AMMX storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx - add.w d0,a0 + add.w d0,a0 rts_bounds * mask version @@ -260,121 +253,119 @@ transform macro * move.l (a1)+,d3 ; F(used) d3=AABBCCDD * move.l (a1)+,d5 ; F 1 * input d3/d5 - ifne \1&$a0 + ifne \1&$a0 move.l d3,d2 ; p1 d3=AABBCCDD rol.l #8,d2 ; p1 d2=BBCCDDAA - endc - ifne \1&$0a - bank 1,1,move.l,d5,d4 ; p2 - bank 1,1,rol.l,#8,d4 ; p2 2 - endc - - ifne \1&$a0 - and.l #$00FF00FF,d2 ; p1 d2=00CC00AA - endc - ifne \1&$50 - and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD - endc - ifne \1&$0a - bank 1,1,and.l,#$00FF00FF,d4 ; p1 - endc - ifne \1&$05 - bank 1,1,and.l,#$00FF00FF,d5 ; p2 4 - endc - ifne \1&$50 - swap d3 ; p1 d3=00DD00BB - endc - ifne \1&$05 - bank 1,1,swap,d5 ; p2 5 - endc - ifne \1&$80 + endc + ifne \1&$0a + bank 1,1,move.l,d5,d4 ; p2 + bank 1,1,rol.l,#8,d4 ; p2 2 + endc + ifne \1&$a0 + and.l #$00FF00FF,d2 ; p1 d2=00CC00AA + endc + ifne \1&$50 + and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD + endc + ifne \1&$0a + bank 1,1,and.l,#$00FF00FF,d4 ; p1 + endc + ifne \1&$05 + bank 1,1,and.l,#$00FF00FF,d5 ; p2 4 + endc + ifne \1&$50 + swap d3 ; p1 d3=00DD00BB + endc + ifne \1&$05 + bank 1,1,swap,d5 ; p2 5 + endc + ifne \1&$80 move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- - endc - ifne \1&$40 + endc + ifne \1&$40 move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy - endc - ifne \1&$a0 - swap d2 ; p2 7 d2=xxyy00CC - endc - ifne \1&$50 - swap d3 ; p1 d3=00BB00DD - endc - ifne \1&$08 - bank 1,1,move.w,(a2,d4.w),d4 ; p2 8 - endc - ifne \1&$04 - bank 1,1,move.b,(a2,d5.w),d4 ; p1 - endc - ifne \1&$0a - bank 1,1,swap,d4 ; p2 9 - endc - ifne \1&$05 - bank 1,1,swap,d5 ; p1 - endc - ifne \1&$20 + endc + ifne \1&$a0 + swap d2 ; p2 7 d2=xxyy00CC + endc + ifne \1&$50 + swap d3 ; p1 d3=00BB00DD + endc + ifne \1&$08 + bank 1,1,move.w,(a2,d4.w),d4 ; p2 8 + endc + ifne \1&$04 + bank 1,1,move.b,(a2,d5.w),d4 ; p1 + endc + ifne \1&$0a + bank 1,1,swap,d4 ; p2 9 + endc + ifne \1&$05 + bank 1,1,swap,d5 ; p1 + endc + ifne \1&$20 move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- - endc - ifne \1&$10 + endc + ifne \1&$10 move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt - endc - ifne \1&$02 - bank 1,1,move.w,(a2,d4.w),d4 ; p1 12 - endc - ifne \1&$01 - bank 1,1,move.b,(a2,d5.w),d4 ; p1 13 - endc + endc + ifne \1&$02 + bank 1,1,move.w,(a2,d4.w),d4 ; p1 12 + endc + ifne \1&$01 + bank 1,1,move.b,(a2,d5.w),d4 ; p1 13 + endc * output d2/d4 * move.l d2,(a0)+ ; F * move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? - endm - - -push_d4_d5 macro - ifeq USE_BANK + endm + + +push_d4_d5 macro + ifeq USE_BANK movem.l d4/d5,-(sp) - endc - endm -pull_d4_d5 macro - ifeq USE_BANK - ifne VAMP_V4 + endc + endm +pull_d4_d5 macro + ifeq USE_BANK + ifne VAMP_V4 movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc - endc - endm + else + move.l (sp)+,d4 + move.l (sp)+,d5 + endc + endc + endm _RenderLine2_AMMX move.l -(a3),d1 chk_bounds _RenderLine0_AMMX\.mx - push_d4_d5 - + push_d4_d5 + move.l d1,d3 ; \ fused addq.l #1,d3 ; / bne .mask .n8 macro move.l (a1)+,d3 - bank 0,1,move.l,(a1)+,d5 + bank 0,1,move.l,(a1)+,d5 transform $ff move.l d2,(a0)+ - bank 1,0,move.l,d4,(a0)+ + bank 1,0,move.l,d4,(a0)+ ifne \1 - pull_d4_d5 - endc - endm + pull_d4_d5 + endc + endm .n0 macro move.l (a1),d3 - bank 0,1,move.l,4(a1),d5 + bank 0,1,move.l,4(a1),d5 transform $ff vperm #$4567CDEF,d2,d4,d2 storec d2,d0,(a0) - endm - + endm unroll_AMMX .n8,.n0,.nx - pull_d4_d5 + pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds @@ -382,83 +373,84 @@ _RenderLine2_AMMX * mask version .transfAA55_8 macro - moveq #0,d2 - move.b \1(a1),d2 ; 1 - moveq #0,d3 - move.b \1+2(a1),d3 ; 2 - bank 0,1,moveq,#0,d4 - bank 0,1,move.b,\1+4(a1),d4 ; 3 - bank 0,1,moveq,#0,d5 - bank 0,1,move.b,\1+6(a1),d5 ; 4 - addq #8,a0 ; 4 - addq.l #8,a1 - move.w (a2,d2.w),d2 ; 5 - move.b (a2,d3.w),d2 , 6 - swap d2 ; 7 - bank 1,0,move.w,(a2,d4.w),d2 ; 8 - bank 1,0,move.b,(a2,d5.w),d2 ; 9 - movep.l d2,\1-9(a0) ; 10 - endm + moveq #0,d2 + move.b \1(a1),d2 ; 1 + moveq #0,d3 + move.b \1+2(a1),d3 ; 2 + bank 0,1,moveq,#0,d4 + bank 0,1,move.b,\1+4(a1),d4 ; 3 + bank 0,1,moveq,#0,d5 + bank 0,1,move.b,\1+6(a1),d5 ; 4 + addq #8,a0 ; 4 + addq.l #8,a1 + move.w (a2,d2.w),d2 ; 5 + move.b (a2,d3.w),d2 ; 6 + swap d2 ; 7 + bank 1,0,move.w,(a2,d4.w),d2 ; 8 + bank 1,0,move.b,(a2,d5.w),d2 ; 9 + movep.l d2,\1-9(a0) ; 10 + endm .transfAA55 macro - btst #5,d0 - bne .b4\2 - .transfAA55_8 \1 - .transfAA55_8 \1 - .transfAA55_8 \1 - .transfAA55_8 \1 - pull_d4_d5 - rts_bounds + btst #5,d0 + bne .b4\2 + .transfAA55_8 \1 + .transfAA55_8 \1 + .transfAA55_8 \1 + .transfAA55_8 \1 + pull_d4_d5 + rts_bounds .b4\2 - btst #4,d0 - bne .b3\2 - .transfAA55_8 \1 - .transfAA55_8 \1 + btst #4,d0 + bne .b3\2 + .transfAA55_8 \1 + .transfAA55_8 \1 .b3\2 - btst #3,d0 - bne .b2\2 - .transfAA55_8 \1 + btst #3,d0 + bne .b2\2 + .transfAA55_8 \1 .b2\2 - pull_d4_d5 - btst #2,d0 - bne .b1\2 - moveq #0,d2 - move.b \1(a1),d2 ; 1 - moveq #0,d3 - move.b \1+2(a1),d3 ; 2 - addq.l #4,a0 ; 3 - addq.l #4,a1 ; 2 - move.w (a2,d2.w),d2 ; 3+1 - move.b (a2,d3.w),d2 , 5 - movep.w d2,\1-5(a0) ; 6 + pull_d4_d5 + btst #2,d0 + bne .b1\2 + moveq #0,d2 + move.b \1(a1),d2 ; 1 + moveq #0,d3 + move.b \1+2(a1),d3 ; 2 + addq.l #4,a0 ; 2 + addq.l #4,a1 ; 3 + move.w (a2,d2.w),d2 ; 3+1 + move.b (a2,d3.w),d2 ; 5 + movep.w d2,\1-5(a0) ; 6 .b1\2 - btst #1,d0 - bne .b0\2 - moveq #0,d2 - move.b \1(a1),d2 ; 1 - addq.l #2,a0 - addq.l #2,a1 + btst #1,d0 + bne .b0\2 + moveq #0,d2 + move.b \1(a1),d2 ; 1 + addq.l #2,a0 + addq.l #2,a1 ; 2 ; 2 bubbles - move.b (a2,d2.w),d2 ; 4 - move.b d2,\1(a0) ; 5 + move.b (a2,d2.w),d2 ; 4 + move.b d2,\1(a0) ; 5 .b0\2 - ifne \1 - addq.l #1,a0 - addq.l #1,a1 - else - move.b (a1)+,(a0)+ - endc - rts_bounds - endm + ifne \1 + addq.l #1,a0 + addq.l #1,a1 + else + move.b (a1)+,(a0)+ + endc + rts_bounds + endm + .mask cmp.l #$AAAAAAAA,d1 - bne .mask1 - .transfAA55 0,_aa + bne .mask1 + .transfAA55 0,_aa .mask1 cmp.l #$55555555,d1 - bne .mask2 - .transfAA55 1,_55 + bne .mask2 + .transfAA55 1,_55 .mask2 @@ -470,7 +462,7 @@ _RenderLine2_AMMX vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0)+ ifne \1 - pull_d4_d5 + pull_d4_d5 endc endm .m0 macro @@ -482,11 +474,11 @@ _RenderLine2_AMMX storem d2,d1,(a0) endm unroll_AMMX .m8,.m0,.mx - pull_d4_d5 + pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds - + * ----------------------------------------------------------------------------- _RenderLine2_AMMX_orig @@ -650,31 +642,31 @@ inc_a0_a1 macro unroll macro btst #5,d0 beq \1_4 - \1 0 - \1 0 - \1 0 - \1 0 - \1 0 - \1 0 - \1 0 - \1 1 - rts_bounds + \1 0 + \1 0 + \1 0 + \1 0 + \1 0 + \1 0 + \1 0 + \1 1 + rts_bounds \1_4 btst #4,d0 beq \1_2 - \1 0 - \1 0 - \1 0 - \1 0 + \1 0 + \1 0 + \1 0 + \1 0 \1_2 btst #3,d0 beq \1_1 - \1 0 - \1 0 + \1 0 + \1 0 \1_1 btst #2,d0 beq \2_1 - \1 0 + \1 0 \2_1 btst #1,d0 beq \3_1 @@ -684,14 +676,14 @@ unroll macro beq \3_2 \3 \3_2 - rts_bounds + rts_bounds endm loop macro \1__1 add.l d1,d1 bcs \1__2 - \1 à + \1 subq.w #1,d0 bne \1__1 rts_bounds @@ -773,7 +765,7 @@ _RenderLine0 endc endm .q2 macro - ifeq 0 + ifeq 1 move.b (a1),(a0) addq.l #2,a1 addq.l #2,a0 @@ -948,9 +940,14 @@ setup macro move.l (4*(3+\1),sp),a2 ; \ fused move.l (4*(4+\1),sp),a3 ; / ENDC - ifne USE_BANK - bank 0,1,move.l,a2,a2 - endc + ifne USE_BANK + inline + tst.b _ac68080_ammx + beq .1 + bank 0,1,move.l,a2,a2 +.1 + einline + endc bsr _setup endm @@ -974,20 +971,17 @@ _setup lea _RenderLine2_AMMX(pc),a4 bne.b .L0 lea _RenderLine1_AMMX(pc),a4 -* ensure upper long word of d0 is clear, otherwise storec will overflow -* pand #$00000000FFFFFFFF,d0,d0 -* factorize constants in regs .L0 - ifne NO_OVERDRAW - ifeq USE_CMP2 - move.l __ZN3dvl10gpBufStartE,a5 - move.l __ZN3dvl8gpBufEndE,a6 - endc - ifne A5_RELATIVE - sub.l a5,a0 - sub.l a5,a6 - endc + ifne NO_OVERDRAW + ifeq USE_CMP2 + move.l __ZN3dvl10gpBufStartE,a5 + move.l __ZN3dvl8gpBufEndE,a6 endc + ifne A5_RELATIVE + sub.l a5,a0 + sub.l a5,a6 + endc + endc addq.l #4,a3 rts @@ -997,7 +991,7 @@ prologue_7 macro .size set .size-2 endc IFNE VAMP_V4 - ifne SAVE_A5A6 + ifne SAVE_A5A6 movem.l d2-d3/a2-a6,-(sp) else movem.l d2-d3/a2-a4,-(sp) @@ -1054,8 +1048,8 @@ prologue_11 macro endc ELSE sub.w #4*.size,sp - - move.l d2,4*0(sp) ; \ + + move.l d2,4*0(sp) ; \ move.l d3,4*1(sp) ; / fused move.l d4,4*2(sp) ; \ @@ -1117,7 +1111,7 @@ _RenderTile_RT_TRANSPARENT bgt.b .L3 suba.w d5,a0 ; dst += (-v) neg.w d5 ; v =-v (parallel!) -* bra.b .L4 +* bra.b .L4 lsl.l d5,d6 ; m <<= v sub.w d5,d4 ; j -= v bne.b .L2 From 403efe2a54f23d5cf42259304f5eb9938c1a7ffd Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 12 Dec 2019 21:20:18 +0100 Subject: [PATCH 014/107] fixed compilation issue --- SourceX/platform/amiga/render68k.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 88e0454f24d..57621a636ae 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -74,8 +74,8 @@ bank macro else \3 \4,\5 endc - endm endc + endm * ----------------------------------------------------------------------------- * check bounds From 81c0c9760fbf9ea51c7b50e0069751eadd076874 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 13 Dec 2019 15:17:44 +0100 Subject: [PATCH 015/107] now decodes smk bitstream with a faster algorithm ==> video at intros now plays fine on the vamp --- 3rdParty/libsmacker/smk_bitstream.c | 153 ++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 35797a747f3..ed549b60d46 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -14,6 +14,157 @@ /* malloc and friends */ #include "smk_malloc.h" +#if 1 /* SAM's version */ + +struct smk_bit_t +{ + unsigned short buf; + unsigned char *ptr, *end; + unsigned long siz; +}; + +struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) +{ + struct smk_bit_t* ret = NULL; + + /* sanity check */ + smk_assert(b); + + /* allocate a bitstream struct */ + smk_malloc(ret, sizeof(struct smk_bit_t)); + + /* set up the pointer to bitstream, and the size counter */ + ret->buf = 1; + ret->ptr = b; + ret->end = b + size; + ret->siz = size; + + /* point to initial byte: note, smk_malloc already sets these to 0 */ + /* ret->byte_num = 0; + ret->bit_num = 0; */ + + /* return ret or NULL if error : ) */ +error: + return ret; +} + +int _smk_error(struct smk_bit_t* bs) +{ + fprintf(stderr, "libsmacker::_smk_bs_read_1(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs->siz); + return -1; +} + +/* Reads a bit + Returns -1 if error encountered */ +char _smk_bs_read_1(struct smk_bit_t* bs) +{ + /* sanity check */ + // smk_assert(bs); + { +#ifdef __mc68000__ + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " moveq #0,d0 \n" + " lsr.w (a0) \n" + " bne.b .lab%= \n" + " move.l 2(a0),a1 \n" + " cmp.l 6(a0),a1 \n" + " bcc.w __smk_error \n" + " move.w #256,d1 \n" + " move.b (a1)+,d1 \n" + " lsr.w #1,d1 \n" + " move.w d1,(a0) \n" + " move.l a1,2(a0) \n" + ".lab%=: \n" + " addx.l d0,d0 \n" + : "=d" (ret) : "a" (bs_) + : ); +#else + unsigned short ret; + + ret = bs->buf; bs->buf >>= 1; + if(!bs->buf) { + if(bs->ptr >= bs->end) return _smk_error(bs); + ret = 256; ret |= *bs->ptr++; + bs->buf = ret>>1; + } + return ret & 1; +#endif + } +} + +void spy(int a,int b) +{ + printf("%x --> %d\n", b, a); +} + +/* Reads a byte + Returns -1 if error. */ +short _smk_bs_read_8(struct smk_bit_t* bs) +{ + /* sanity check */ + // smk_assert(bs); + { +#ifdef __mc68000__ + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " move.l 2(a0),a1 \n" + " cmp.l 6(a0),a1 \n" + " bcc.w __smk_error \n" + " addq.l #1,2(a0) \n" + " moveq #0,d0 \n" + " moveq #1,d1 \n" + " move.w (a0),d0 \n" + " cmp.w d1,d0 \n" + " bhi .lab%= \n" + " move.b (a1),d0 \n" + " rts \n" + ".lab%=: \n" + " swap d1 \n" + " move.w (a1),d1 \n" + " move.b d0,d1 \n" + " bfffo d0{24:8},d0 \n" + " sub.w #23,d0 \n" + " lsl.b d0,d1 \n" + " lsr.l d0,d1 \n" + " move.b d1,d0 \n" + " lsr.l #8,d1 \n" + " move.w d1,(a0) \n" + : "=d" (ret) : "a" (bs_) + : ); +#else + unsigned char ret; unsigned short a; + + if(bs->ptr >= bs->end) return _smk_error(bs); + + // aligned + a = bs->buf; + if(a <= 1) return *bs->ptr++; + + // find leftmost bit + ret = a; a |= a>>1; a |= a>>2; a |= a>>4; a >>= 1; a += 1; + + // remove it from current buffer + ret ^= a; + + // shift next byte + setup sentinel + a *= *bs->ptr++ | (unsigned short)256; + + // inject current + a |= ret; + + // setup result + shift buffer + ret = a; bs->buf = a>>8; + + return ret; +#endif + } +} + +#else + /* Bitstream structure Pointer to raw block of data and a size limit. @@ -117,3 +268,5 @@ short _smk_bs_read_8(struct smk_bit_t* bs) error: return ret; } + +#endif \ No newline at end of file From ad9fd9fcc9b1592171a247629ab218cab396dfc0 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 13 Dec 2019 15:19:40 +0100 Subject: [PATCH 016/107] code cleanup --- CMake/amiga/m68k-amigaos.cmake | 3 +-- SourceS/sdl_compat.h | 2 ++ SourceX/platform/amiga/support.c | 44 ++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index f0aafa422a9..cbedc8367b8 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -50,8 +50,7 @@ if(WIN32) endif() # Compiler flags -#set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -pg -g -noixemul") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") +# set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -pg -g -noixemul") set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 4ee52a9c7d1..35e486b01d3 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -17,6 +17,8 @@ extern "C" char ac68080_saga; char ac68080_ammx; int vampire_Flip(SDL_Surface *surf); + int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, + SDL_Surface *dst, SDL_Rect *dstRect); } //extern C #endif #define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index 403af0a3a03..da0baa28aaa 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -147,3 +147,47 @@ int vampire_Flip(SDL_Surface* const surf) legacy: return SDL_Flip(surf); } + +#define min(a,b) ((a)<=(b)?(a):(b)) + +int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, + SDL_Surface *dst, SDL_Rect *dstRect) +{ + register UBYTE *s, *d; + ULONG w; + WORD h; + + // if(dst!=SDL_GetVideoSurface()) + // return __real_SDL_BlitSurface(src, srcRect, dst, dstRect); + + if(!srcRect) { + static SDL_Rect r; + r.w = src->w; + r.h = src->h; + srcRect = &r; + } + if(!dstRect) { + static SDL_Rect r; + r.w = dst->w; + r.h = dst->h; + dstRect = &r; + } + + s = src->pixels + srcRect->x + srcRect->y*src->pitch; + d = dst->pixels + dstRect->x + dstRect->y*dst->pitch; + + w = min(srcRect->w, dstRect->w); + h = min(srcRect->h, dstRect->h); + + if(w == src->pitch && w == dst->pitch) { + memcpy(d, s, w*(UWORD)h); + return 0; + } + + for(; 1 + --h;) { + memcpy(d, s, w); + s += src->pitch; + d += dst->pitch; + } + return 0; +} From 217bd5901c46f1950b1b19c9b1c3f133b9b1eab2 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 13 Dec 2019 15:34:57 +0100 Subject: [PATCH 017/107] cleanup --- 3rdParty/libsmacker/smk_bitstream.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index ed549b60d46..b62fefeab76 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -94,11 +94,6 @@ char _smk_bs_read_1(struct smk_bit_t* bs) } } -void spy(int a,int b) -{ - printf("%x --> %d\n", b, a); -} - /* Reads a byte Returns -1 if error. */ short _smk_bs_read_8(struct smk_bit_t* bs) From b248352d494f21816ae3b626f2ce295cc2e5fbb3 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 14 Dec 2019 14:01:09 +0100 Subject: [PATCH 018/107] fixed random crash in intro-video --- SourceX/platform/amiga/support.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index da0baa28aaa..8cba5d50364 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -15,10 +15,11 @@ #include "../../../../defs.h" #define FRAME_BUFFER_SZ ((SCREEN_WIDTH)*(SCREEN_HEIGHT)) +#define DIRTY 0 // 1 = 32 fps 0 = 29fps #define DIRTY 0 // 1 = 32 fps 0 = 29fps #define CHECK_FIRSTSCREEN 1 // costs 0 fps -#define CHECK_SURFACE 0 +#define CHECK_SURFACE 1 // 0 makes random crash during video #define ROLL_PTR 0 #include @@ -28,13 +29,15 @@ extern int _ZN3dvl10fullscreenE; // diablo.h // extern void *_ZN3dvl6windowE; // extern SDL_Palette *_ZN3dvl7paletteE; +#define pal_surface _ZN3dvl11pal_surfaceE +extern SDL_Surface *pal_surface; + UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; static UBYTE *bufmem = NULL; static UBYTE started = 0; static struct Screen *game_screen; -static struct SDL_Surface *game_surface; struct Library *VampireBase; extern struct ExecBase *SysBase; @@ -93,12 +96,12 @@ int vampire_Flip(SDL_Surface* const surf) #endif // check if saga is on or if surface is the game surface - if(!ac68080_ammx) goto legacy; + if(!ac68080_saga) goto legacy; #if CHECK_SURFACE - if(surf != game_surface && surf->h == SCREEN_HEIGHT && surf->pitch<=SCREEN_HEIGHT) - game_surface = surf; - if(surf != game_surface) goto legacy; + // if(surf != game_surface && surf->h == SCREEN_HEIGHT && surf->pitch<=SCREEN_HEIGHT) + // game_surface = surf; + if(surf != pal_surface) goto legacy; #endif #if CHECK_FIRSTSCREEN @@ -113,17 +116,20 @@ int vampire_Flip(SDL_Surface* const surf) #endif { UBYTE *ptr = surf->pixels; - + +#if CHECK_SURFACE + if(0==(surf->flags & SDL_PREALLOC)) { +#else // if ptr ouside our memory, then use out aligned one (this is done only once per game surface) if((ULONG)(ptr - bufmem) >= (ULONG)(3*FRAME_BUFFER_SZ+31)) { // ! \\ ULONG trick // if not a std surface, do nothing if(surf->flags & SDL_PREALLOC) goto legacy; - +#endif // aligned memory ptr = (UBYTE*)(~31&(ULONG)(bufmem + 31)); // sync aligned memory content with current surface - CopyMemQuick(surf->pixels, ptr, FRAME_BUFFER_SZ); + memcpy(ptr, surf->pixels, FRAME_BUFFER_SZ); // replace surface pixels by our aliged memory SDL_free(surf->pixels); From 89acfd3f1b80eb89c88e4bcbbf6512e40ba8ab60 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 14 Dec 2019 15:52:01 +0100 Subject: [PATCH 019/107] speedup smk with a bit of 68k asm. --- 3rdParty/libsmacker/smk_bitstream.c | 21 +++--- 3rdParty/libsmacker/smk_hufftree.c | 112 ++++++++++++++++++++++++++-- 2 files changed, 118 insertions(+), 15 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index b62fefeab76..b707b77f585 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -48,9 +48,10 @@ struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) return ret; } -int _smk_error(struct smk_bit_t* bs) +unsigned char _smk_error(struct smk_bit_t* bs) { - fprintf(stderr, "libsmacker::_smk_bs_read_1(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs->siz); + fprintf(stderr, "libsmacker::_smk_bs_read_?(bs=%p): ERROR: bitstream (length=%lu, ptr=%p, end=%p) exhausted.\n", bs, bs->siz, bs->ptr, bs->end); + bs->buf=1; return -1; } @@ -70,7 +71,7 @@ char _smk_bs_read_1(struct smk_bit_t* bs) " bne.b .lab%= \n" " move.l 2(a0),a1 \n" " cmp.l 6(a0),a1 \n" - " bcc.w __smk_error \n" + " bcc.b __smk_error \n" " move.w #256,d1 \n" " move.b (a1)+,d1 \n" " lsr.w #1,d1 \n" @@ -79,7 +80,7 @@ char _smk_bs_read_1(struct smk_bit_t* bs) ".lab%=: \n" " addx.l d0,d0 \n" : "=d" (ret) : "a" (bs_) - : ); + : "d1","a1","a0" ); #else unsigned short ret; @@ -107,15 +108,15 @@ short _smk_bs_read_8(struct smk_bit_t* bs) __asm__ __volatile__ ( " move.l 2(a0),a1 \n" " cmp.l 6(a0),a1 \n" - " bcc.w __smk_error \n" + " bcc.b __smk_error \n" " addq.l #1,2(a0) \n" " moveq #0,d0 \n" " moveq #1,d1 \n" " move.w (a0),d0 \n" " cmp.w d1,d0 \n" - " bhi .lab%= \n" + " bhi.b .lab%= \n" " move.b (a1),d0 \n" - " rts \n" + " bra.b .xit%= \n" ".lab%=: \n" " swap d1 \n" " move.w (a1),d1 \n" @@ -124,11 +125,13 @@ short _smk_bs_read_8(struct smk_bit_t* bs) " sub.w #23,d0 \n" " lsl.b d0,d1 \n" " lsr.l d0,d1 \n" + // " moveq #0,d0\n" // necessaire ???? " move.b d1,d0 \n" " lsr.l #8,d1 \n" " move.w d1,(a0) \n" + ".xit%=: \n" : "=d" (ret) : "a" (bs_) - : ); + : "d1","a1","a0"); #else unsigned char ret; unsigned short a; @@ -140,7 +143,7 @@ short _smk_bs_read_8(struct smk_bit_t* bs) // find leftmost bit ret = a; a |= a>>1; a |= a>>2; a |= a>>4; a >>= 1; a += 1; - + // remove it from current buffer ret ^= a; diff --git a/3rdParty/libsmacker/smk_hufftree.c b/3rdParty/libsmacker/smk_hufftree.c index cd6c98d0da9..b9e2b5962d0 100644 --- a/3rdParty/libsmacker/smk_hufftree.c +++ b/3rdParty/libsmacker/smk_hufftree.c @@ -20,14 +20,14 @@ */ struct smk_huff8_t { - struct smk_huff8_t* b0; + struct smk_huff8_t* b0; // 0 union { - struct smk_huff8_t* b1; + struct smk_huff8_t* b1; // 4 struct { - unsigned short value; - unsigned char escapecode; + unsigned short value; // 4 + unsigned char escapecode; // 6 } leaf; } u; }; @@ -100,6 +100,27 @@ static struct smk_huff8_t* _smk_huff8_build_rec(struct smk_bit_t* bs) Return -1 on error. */ short _smk_huff8_lookup(struct smk_bit_t* bs, const struct smk_huff8_t* t) { +#ifdef __mc68000__ + if(t->b0) { + __asm__ __volatile__ ( + " move.l %2,-(sp) \n" + ".L0%=: \n" + " jsr %3 \n" + " tst.b d0 \n" + // TODO error ?? + " beq.b .L1%= \n" + " addq.l #4,%0 \n" + ".L1%=: \n" + " move.l (%0),%0 \n" + " tst.l (%0) \n" + " bne.b .L0%= \n" + " addq.l #4,sp \n" + : "=&a" (t) + : "0" (t), "am" (bs), "m" (_smk_bs_read_1) + : "d0","d1","a0","a1"); + } + return t->u.leaf.value; +#else char bit; /* sanity check */ @@ -126,6 +147,7 @@ short _smk_huff8_lookup(struct smk_bit_t* bs, const struct smk_huff8_t* t) error: return -1; +#endif } /** @@ -331,8 +353,86 @@ struct smk_huff16_t* _smk_huff16_build(struct smk_bit_t* bs) return NULL; } -static int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const struct smk_huff8_t* t) +int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const struct smk_huff8_t* t) { +#ifdef __mc68000__ + register struct smk_huff8_t *t_ asm("a2") = t; + if(t_->b0) { + __asm__ __volatile__ ( + " move.l %2,-(sp) \n" + ".L0%=: \n" + " jsr %3 \n" + " tst.b d0 \n" + // TODO error ?? + " beq.b .L1%= \n" + " addq.l #4,a2 \n" + ".L1%=: \n" + " move.l (a2),a2 \n" + " tst.l (a2) \n" + " bne.b .L0%= \n" + " addq.l #4,sp \n" + : "=&a" (t_) + : "0" (t_), "am" (bs), "m" (_smk_bs_read_1) + : "d0","d1","a0","a1"); + } + { + register unsigned long val asm("d0"); + register unsigned short *cache_ asm("a1") = cache; + __asm__ __volatile__ ( + " moveq #0,d0 \n" + " move.b (6,a2),d0 \n" + " addq.l #4,a2 \n" + " addq.b #1,d0 \n" + " beq.b .L1%= \n" + " lea -2(a1,d0.w*2),a2 \n" + ".L1%=: \n" + " move.w (a2),d0 \n" + " cmp.w (a1),d0 \n" + " beq.b .L2%= \n" + // " move.l (a1),2(a1) \n" + // " move.w d0,(a1) \n" + " move.l (a1),d1 \n" + " move.w d0,(a1)+ \n" + " move.l d1,(a1) \n" + ".L2%=: \n" + : "=d" (val), "=&a" (cache_), "=&a" (t_) + : "1" (cache_), "2" (t_) + : "d1"); + return val; + } +#elif 0 + unsigned short val; + char bit; + + while(t->b0) { + smk_bs_read_1(bs, bit); + t = bit ? t->u.b1 : t->b0; + } + + if (t->u.leaf.escapecode != 0xFF) + { + /* Found escape code. Retrieve value from Cache. */ + val = cache[t->u.leaf.escapecode]; + } + else + { + /* Use value directly. */ + val = t->u.leaf.value; + } + + if (cache[0] != val) + { + /* Update the cache, by moving val to the front of the queue, + if it isn't already there. */ + cache[2] = cache[1]; + cache[1] = cache[0]; + cache[0] = val; + } + + return val; +error: + return -1; +#else unsigned short val; char bit; @@ -377,9 +477,9 @@ static int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], } return _smk_huff16_lookup_rec(bs, cache, t->b0); - error: return -1; +#endif } /* Convenience call-out for recursive bigtree lookup function */ From db032d30d2b67f440774a77a52be67aebb197db0 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 15 Dec 2019 18:42:57 +0100 Subject: [PATCH 020/107] at least a working SAGA version that doesn't modify internal SDL data. Movie intro now works fine, at last! --- SourceX/dx.cpp | 3 +- SourceX/platform/amiga/support.c | 354 +++++++++++++++++++------------ 2 files changed, 216 insertions(+), 141 deletions(-) diff --git a/SourceX/dx.cpp b/SourceX/dx.cpp index 9f562704151..04352bffc0f 100644 --- a/SourceX/dx.cpp +++ b/SourceX/dx.cpp @@ -7,7 +7,8 @@ namespace dvl { #ifdef __AMIGA__ -#define SDL_Flip vampire_Flip +#define SDL_Flip vampire_Flip +#define SDL_BlitSurface vampire_BlitSurface // #define SDL_Flip(x) (*(int*)0xDFF1EC = -32&(int)((x)->pixels), 0) #endif diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index 8cba5d50364..c793544df5c 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -1,9 +1,9 @@ /* * Various support functions or the amiga */ - + //#include - + #include #include #include @@ -13,31 +13,48 @@ #include #include "../../../../defs.h" -#define FRAME_BUFFER_SZ ((SCREEN_WIDTH)*(SCREEN_HEIGHT)) +#define FRAME_BUFFER_SZ ((SCREEN_WIDTH)*(SCREEN_HEIGHT)) -#define DIRTY 0 // 1 = 32 fps 0 = 29fps -#define DIRTY 0 // 1 = 32 fps 0 = 29fps +#define DIRTY 0 // 1 = 32 fps 0 = 29fps +#define DIRTY 0 // 1 = 32 fps 0 = 29fps -#define CHECK_FIRSTSCREEN 1 // costs 0 fps -#define CHECK_SURFACE 1 // 0 makes random crash during video -#define ROLL_PTR 0 +#define CHECK_FIRSTSCREEN 1 // costs 0 fps +#define ROLL_PTR 1 #include extern int _ZN3dvl10fullscreenE; // diablo.h -// extern int _ZN3dvl27pal_surface_palette_versionE; // extern void *_ZN3dvl6windowE; -// extern SDL_Palette *_ZN3dvl7paletteE; + +#define pal_palette_version _ZN3dvl27pal_surface_palette_versionE +extern int pal_palette_version; + +#define pal_palette _ZN3dvl7paletteE +extern SDL_Palette *pal_palette; #define pal_surface _ZN3dvl11pal_surfaceE extern SDL_Surface *pal_surface; +// #define sgdwCursYOld _ZN3dvl12sgdwCursYOldE +// extern LONG sgdwCursYOld; + +// #define sgdwCursHgtOld _ZN3dvl14sgdwCursHgtOldE +// extern LONG sgdwCursHgtOld; + +// #define sgdwCursY _ZN3dvl9sgdwCursYE +// extern LONG sgdwCursY; + +// #define sgdwCursHgt _ZN3dvl11sgdwCursHgtE +// extern LONG sgdwCursHgt; + UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; +static USHORT copy_pane_mask = 0; static UBYTE *bufmem = NULL; static UBYTE started = 0; static struct Screen *game_screen; +static SDL_Surface *saga_surface; struct Library *VampireBase; extern struct ExecBase *SysBase; @@ -45,155 +62,212 @@ extern struct IntuitionBase *IntuitionBase; static void stop(void) { - if(bufmem) { - FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); - bufmem = NULL; - } + if(saga_surface) { + SDL_FreeSurface(saga_surface); + saga_surface = NULL; + } + if(bufmem) { + FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); + bufmem = NULL; + } } static void start(void) { - started = 255; - atexit(stop); + started = 255; + atexit(stop); - if (SysBase->AttnFlags &(1 << 10)) { - ac68080_saga = 255; //!_ZN3dvl10fullscreenE; // disable if not fullscreen - - bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); - if(!bufmem) ac68080_saga = 0; - - if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); - if(VampireBase && VampireBase->lib_Version >= 45 && - (V_EnableAMMX( V_AMMX_V2 ) != VRES_ERROR) ) { - ac68080_ammx = 255; - } - - printf("Vampire accelerator detected"); - if(ac68080_ammx || ac68080_saga) { - printf(". Using"); - if(ac68080_saga) { - printf(" SAGA Direct Draw"); - } - if(ac68080_ammx) { - if(ac68080_saga) printf(" &"); - printf(" AMMX2"); - } - } - printf(".\n"); - } + bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); + if(bufmem) { + saga_surface = SDL_CreateRGBSurfaceFrom( + (UBYTE*)(~31&(31+(ULONG)bufmem)), // 32 bits alignment for saga + SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, + 0, 0, 0, 0 + ); + if(!saga_surface) { + FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); + bufmem = NULL; + } + } + + if (SysBase->AttnFlags &(1 << 10)) { + ac68080_saga = 255; //!_ZN3dvl10fullscreenE; // disable if not fullscreen + + bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); + if(bufmem) { + saga_surface = SDL_CreateRGBSurfaceFrom( + (UBYTE*)(~31&(31+(ULONG)bufmem)), // 32 bits alignment for saga + SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, + 0, 0, 0, 0 + ); + if(!saga_surface) { + FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); + bufmem = NULL; + } + } + if(!bufmem) ac68080_saga = 0; + + if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); + if(VampireBase && VampireBase->lib_Version >= 45 && + (V_EnableAMMX( V_AMMX_V2 ) != VRES_ERROR) ) { + ac68080_ammx = 255; + } + + printf("Vampire accelerator detected"); + if(ac68080_ammx || ac68080_saga) { + printf(". Using"); + if(ac68080_saga) { + printf(" SAGA Direct Draw"); + } + if(ac68080_ammx) { + if(ac68080_saga) printf(" &"); + printf(" AMMX2"); + } + } + printf(".\n"); + } } -int vampire_Flip(SDL_Surface* const surf) +static int ok(SDL_Surface *const surf) { - volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ -// volatile ULONG *pal = (ULONG*)0xDFF400; - struct Screen *first_screen; - - if(!started) start(); - + if(!started) start(); + if(!ac68080_saga) return 0; + if(surf!=SDL_GetVideoSurface()) return 0; + if(surf->w != SCREEN_WIDTH || surf->h != SCREEN_HEIGHT) return 0; + return 1; +} + +int vampire_Flip(SDL_Surface* surf) +{ + volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ +// volatile ULONG *pal = (ULONG*)0xDFF400; + struct Screen *first_screen; + static UBYTE panel_cpy_flag = 4; + #if DIRTY - *dpy = (void*)(~31&(int)surf->pixels); - return; -#endif - - // check if saga is on or if surface is the game surface - if(!ac68080_saga) goto legacy; - -#if CHECK_SURFACE - // if(surf != game_surface && surf->h == SCREEN_HEIGHT && surf->pitch<=SCREEN_HEIGHT) - // game_surface = surf; - if(surf != pal_surface) goto legacy; + *dpy = (void*)(~31&(int)surf->pixels); + return; #endif + if(!ok(surf)) goto legacy; + + // SDL_SetColors(saga_surface, pal_palette->colors, 0, pal_palette->ncolors); + + surf = saga_surface; + #if CHECK_FIRSTSCREEN - // check if screen has changed - if(game_screen != (first_screen = IntuitionBase->FirstScreen) - && first_screen->Height == SCREEN_HEIGHT - && first_screen->Width == SCREEN_WIDTH) - game_screen = first_screen; - - // if we are running on the game scree - if(first_screen == game_screen) + // check if screen has changed + if(game_screen != (first_screen = IntuitionBase->FirstScreen) + && first_screen->Height == SCREEN_HEIGHT + && first_screen->Width == SCREEN_WIDTH) + game_screen = first_screen; + + // if we are running on the game scree + if(first_screen == game_screen) #endif - { - UBYTE *ptr = surf->pixels; - -#if CHECK_SURFACE - if(0==(surf->flags & SDL_PREALLOC)) { -#else - // if ptr ouside our memory, then use out aligned one (this is done only once per game surface) - if((ULONG)(ptr - bufmem) >= (ULONG)(3*FRAME_BUFFER_SZ+31)) { // ! \\ ULONG trick - // if not a std surface, do nothing - if(surf->flags & SDL_PREALLOC) goto legacy; -#endif - // aligned memory - ptr = (UBYTE*)(~31&(ULONG)(bufmem + 31)); - - // sync aligned memory content with current surface - memcpy(ptr, surf->pixels, FRAME_BUFFER_SZ); - - // replace surface pixels by our aliged memory - SDL_free(surf->pixels); - surf->flags |= SDL_PREALLOC; // <== tell SDL not to bother with theses pixels - surf->pixels = ptr; - } + { + UBYTE *ptr = surf->pixels, *old; + + // display + *dpy = ptr; - // display - *dpy = ptr; - #if ROLL_PTR - // advance ptr - ptr += FRAME_BUFFER_SZ; - if(ptr >= bufmem + 3*FRAME_BUFFER_SZ) ptr -= 3*FRAME_BUFFER_SZ; - surf->pixels = ptr; -#endif + old = ptr; + // advance ptr + if(ptr >= bufmem + 2*FRAME_BUFFER_SZ) + ptr -= 2*FRAME_BUFFER_SZ; + else + ptr += FRAME_BUFFER_SZ; + surf->pixels = ptr; - return 0; - } - + if(copy_pane_mask) { + copy_pane_mask >>= 1; + memcpy(ptr + PANEL_TOP*SCREEN_WIDTH, + old + PANEL_TOP*SCREEN_WIDTH, + PANEL_HEIGHT*SCREEN_WIDTH); + } +#endif + } + return 0; legacy: - return SDL_Flip(surf); + return SDL_Flip(surf); +} + +int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, + SDL_Surface *dst, SDL_Rect *dstRect) +{ + if(ok(dst)) { + static int last_version; + // if(srcRect==NULL || srcRect->w==SCREEN_HEIGHT) { + // /*resync*/ + // int ret = SDL_BlitSurface(src, srcRect, dst, dstRect); + // UBYTE *ptr = (UBYTE*)(~31&(31+(ULONG)bufmem)); + // memcpy(ptr, dst->pixels, FRAME_BUFFER_SZ); ptr += FRAME_BUFFER_SZ; + // memcpy(ptr, dst->pixels, FRAME_BUFFER_SZ); ptr += FRAME_BUFFER_SZ; + // memcpy(ptr, dst->pixels, FRAME_BUFFER_SZ); ptr += FRAME_BUFFER_SZ; + // return ret; + // } + if(srcRect + && srcRect->w < SCREEN_WIDTH // ignore full screen + && !(srcRect->w==288 && srcRect->h==60) // ignore descpane + && srcRect->y + srcRect->h >= PANEL_TOP + SCREEN_Y + ) copy_pane_mask = 4; // we need to copy 3 times the panel if something was drawn there + if(last_version!=pal_palette_version) { + last_version = pal_palette_version; + SDL_SetColors(saga_surface, pal_palette->colors, 0, pal_palette->ncolors); + } + return SDL_BlitSurface(src, srcRect, saga_surface, dstRect); + } + return SDL_BlitSurface(src, srcRect, dst, dstRect); } #define min(a,b) ((a)<=(b)?(a):(b)) -int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, - SDL_Surface *dst, SDL_Rect *dstRect) +int zzzvampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, + SDL_Surface *dst, SDL_Rect *dstRect) { - register UBYTE *s, *d; - ULONG w; - WORD h; - - // if(dst!=SDL_GetVideoSurface()) - // return __real_SDL_BlitSurface(src, srcRect, dst, dstRect); - - if(!srcRect) { - static SDL_Rect r; - r.w = src->w; - r.h = src->h; - srcRect = &r; - } - if(!dstRect) { - static SDL_Rect r; - r.w = dst->w; - r.h = dst->h; - dstRect = &r; - } - - s = src->pixels + srcRect->x + srcRect->y*src->pitch; - d = dst->pixels + dstRect->x + dstRect->y*dst->pitch; - - w = min(srcRect->w, dstRect->w); - h = min(srcRect->h, dstRect->h); - - if(w == src->pitch && w == dst->pitch) { - memcpy(d, s, w*(UWORD)h); - return 0; - } - - for(; 1 + --h;) { - memcpy(d, s, w); - s += src->pitch; - d += dst->pitch; - } - return 0; + register UBYTE *s, *d; + UWORD w; + WORD h; + + if(!ok(dst)) goto legacy; + + // replace sdl video output by our own + dst = saga_surface; + + if(!srcRect) { + static SDL_Rect r; + r.w = src->w; + r.h = src->h; + srcRect = &r; + } + if(!dstRect) { + static SDL_Rect r; + r.w = dst->w; + r.h = dst->h; + dstRect = &r; + } + + s = src->pixels + srcRect->x + srcRect->y*src->pitch; + d = dst->pixels + dstRect->x + dstRect->y*dst->pitch; + + w = min(srcRect->w, dstRect->w); + h = min(srcRect->h, dstRect->h); + + w = min(w, dst->w - dstRect->x); + h = min(h, dst->h - dstRect->y); + + // printf("Blit %d %d (%d %d) (%d %d)\n", w,h, srcRect->x, srcRect->y, dstRect->x, dstRect->y); + + if(w == src->pitch && w == dst->pitch) { + memcpy(d, s, w*(UWORD)h); + } else for(; 1 + --h;) { + memcpy(d, s, w); + s += src->pitch; + d += dst->pitch; + } + return 0; +legacy: + // if(srcRect && dstRect) + // return SDL_LowerBlit(src, srcRect, dst, dstRect); + return SDL_BlitSurface(src, srcRect, dst, dstRect); } From 4d9005c51d5aa77ad5522060a5075d7b9fd63cfa Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 15 Dec 2019 18:47:01 +0100 Subject: [PATCH 021/107] added AMMX replacement for memcpy/memset. --- .gitignore | 2 +- CMake/amiga/m68k-amigaos.cmake | 2 +- SourceX/platform/amiga/memopt.asm | 113 ++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100755 SourceX/platform/amiga/memopt.asm diff --git a/.gitignore b/.gitignore index fedca48b275..06d643d3337 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Generated by VC++ 6 builds /vc60.idb -*.asm +#*.asm -- used on amiga *.idb # macOS diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index cbedc8367b8..d8dec24040d 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -60,7 +60,7 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -Wl,--wrap=memcpy -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -Wl,--wrap=memcpy -Wl,--wrap=memset -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") # user diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm new file mode 100755 index 00000000000..f9cfae8999e --- /dev/null +++ b/SourceX/platform/amiga/memopt.asm @@ -0,0 +1,113 @@ +* ----------------------------------------------------------------------------- +* memopt.asm -- AC68080 replacement for memxxx() operation with by hand-written +* asm code by S.Devulder +* ----------------------------------------------------------------------------- + + section .text + + machine 68080 + + XREF _ac68080_ammx + XREF ___real_memcpy + XDEF ___wrap_memcpy + XREF ___real_memset + XDEF ___wrap_memset + + cnop 0,4 + +___wrap_memcpy +.entry + tst.b _ac68080_ammx + beq.l ___real_memcpy + +.memcpy + rsreset + rs.l 4 +.dst rs.l 1 +.src rs.l 1 +.len rs.l 1 + + move.l .dst(sp),a1 ; p1 1 + move.l .src(sp),a0 ; p1 2 + move.l .len(sp),d1 ; p1 3 + + moveq #63,d0 + and.l d1,d0 + lsr.l #8,d1 + beq .l32 +.l64 + REPT 8 + load (a0)+,e0 + store e0,(a1)+ + ENDR + subq.l #1,d1 + bne.s .l64 +.l32 + bclr #5,d0 + beq.b .l16 + REPT 4 + load (a0)+,e0 + store e0,(a1)+ + ENDR +.l16 + load (a0)+,e0 + storec e0,d0,(a1)+ + subq.l #8,d0 + bhi.b .l16 + move.l .dst(sp),d0 +.exit + nop +* remove initial comparison so that it now only costs 1 cycle + move.w #$203c,.entry(pc) ; move.l #nnnn,d0 + move.w #$223c,.entry+6(pc) ; move.l #nnnn,d1 + move.w #$4e75,.exit(pc) ; #rts + rts ; no need to ClearCacheU on apollo! + +___wrap_memset +.entry + tst.b _ac68080_ammx + beq.l ___real_memset + +.memset + rsreset + rs.l 4 +.dst rs.l 1 +.val rs.l 1 +.len rs.l 1 + + move.l .dst(sp),a1 ; p1 1 + move.l .val(sp),d0 ; p1 2 + move.l .len(sp),d1 ; p1 3 + + vperm #$77777777,d0,e0,e0 + + moveq #63,d0 + and.l d1,d0 + lsr.l #8,d1 + beq .l32 +.l64 + REPT 8 + store e0,(a1)+ + ENDR + subq.l #1,d1 + bne.s .l64 +.l32 + bclr #5,d0 + beq.b .l16 + REPT 4 + store e0,(a1)+ + ENDR +.l16 + storec e0,d0,(a1)+ + subq.l #8,d0 + bhi.b .l16 + move.l .dst(sp),d0 +.exit + nop +* remove initial comparison so that it now only costs 1 cycle + move.w #$203c,.entry(pc) ; move.l #nnnn,d0 + move.w #$223c,.entry+6(pc) ; move.l #nnnn,d1 + move.w #$4e75,.exit(pc) ; #rts + rts ; no need to ClearCacheU on apollo! + +* end of file \ No newline at end of file From 514fbedc1f93b7fc422d8fc5375bbaaaf0d3787d Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 00:04:43 +0100 Subject: [PATCH 022/107] Better handling of .gitignore to include amiga asm files --- .gitignore | 2 +- SourceX/platform/amiga/.gitignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 SourceX/platform/amiga/.gitignore diff --git a/.gitignore b/.gitignore index 06d643d3337..fedca48b275 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Generated by VC++ 6 builds /vc60.idb -#*.asm -- used on amiga +*.asm *.idb # macOS diff --git a/SourceX/platform/amiga/.gitignore b/SourceX/platform/amiga/.gitignore new file mode 100644 index 00000000000..f78b2f377eb --- /dev/null +++ b/SourceX/platform/amiga/.gitignore @@ -0,0 +1 @@ +!*.asm From 8cbf9557f7bed0c44f0b38e65a2ce8d4e601c60a Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 00:07:43 +0100 Subject: [PATCH 023/107] more asm optim + support for profiling in smk --- 3rdParty/libsmacker/smk_bitstream.c | 9 +++++++++ 3rdParty/libsmacker/smk_hufftree.c | 15 +++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index b707b77f585..22703b5c54b 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -71,7 +71,11 @@ char _smk_bs_read_1(struct smk_bit_t* bs) " bne.b .lab%= \n" " move.l 2(a0),a1 \n" " cmp.l 6(a0),a1 \n" +#ifdef __PROFILE__ + " bcc __smk_error \n" +#else " bcc.b __smk_error \n" +#endif " move.w #256,d1 \n" " move.b (a1)+,d1 \n" " lsr.w #1,d1 \n" @@ -81,6 +85,7 @@ char _smk_bs_read_1(struct smk_bit_t* bs) " addx.l d0,d0 \n" : "=d" (ret) : "a" (bs_) : "d1","a1","a0" ); + return ret; #else unsigned short ret; @@ -108,7 +113,11 @@ short _smk_bs_read_8(struct smk_bit_t* bs) __asm__ __volatile__ ( " move.l 2(a0),a1 \n" " cmp.l 6(a0),a1 \n" +#ifdef __PROFILE__ + " bcc __smk_error \n" +#else " bcc.b __smk_error \n" +#endif " addq.l #1,2(a0) \n" " moveq #0,d0 \n" " moveq #1,d1 \n" diff --git a/3rdParty/libsmacker/smk_hufftree.c b/3rdParty/libsmacker/smk_hufftree.c index b9e2b5962d0..cda61fd48a2 100644 --- a/3rdParty/libsmacker/smk_hufftree.c +++ b/3rdParty/libsmacker/smk_hufftree.c @@ -379,21 +379,20 @@ int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const register unsigned long val asm("d0"); register unsigned short *cache_ asm("a1") = cache; __asm__ __volatile__ ( - " moveq #0,d0 \n" - " move.b (6,a2),d0 \n" + " moveq #1,d0 \n" + " add.b (6,a2),d0 \n" " addq.l #4,a2 \n" - " addq.b #1,d0 \n" " beq.b .L1%= \n" " lea -2(a1,d0.w*2),a2 \n" ".L1%=: \n" " move.w (a2),d0 \n" " cmp.w (a1),d0 \n" " beq.b .L2%= \n" - // " move.l (a1),2(a1) \n" - // " move.w d0,(a1) \n" - " move.l (a1),d1 \n" - " move.w d0,(a1)+ \n" - " move.l d1,(a1) \n" + " move.l (a1),2(a1) \n" + " move.w d0,(a1) \n" + // " move.l (a1),d1 \n" + // " move.w d0,(a1)+ \n" + // " move.l d1,(a1) \n" ".L2%=: \n" : "=d" (val), "=&a" (cache_), "=&a" (t_) : "1" (cache_), "2" (t_) From 4a2963fb185696f438c6b440adfb5c5702a8a9ad Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 01:35:49 +0100 Subject: [PATCH 024/107] improved branch prediction in RenderTile_RT_TRANSPARENT --- SourceX/platform/amiga/render68k.asm | 34 ++++++++++++++++------------ 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 57621a636ae..11ff99a87ea 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -1106,26 +1106,30 @@ _RenderTile_RT_TRANSPARENT move.l -(a3),d6 ; m = *mask; mask-- moveq #32,d4 .L2 - move.b (a1)+,d5 ; v = *src++; - ext.w d5 + moveq #0,d0 ; TODO: remove ? + move.b (a1)+,d0 bgt.b .L3 - suba.w d5,a0 ; dst += (-v) - neg.w d5 ; v =-v (parallel!) -* bra.b .L4 - lsl.l d5,d6 ; m <<= v - sub.w d5,d4 ; j -= v - bne.b .L2 - sub.w #BUFFER_WIDTH+32,a0 - dbra d7,.L1 - epilogue_11 +.L22 + neg.b d0 ; p1 + lsl.l d0,d6 ; p1 + sub.l d0,d4 ; p2 + adda.l d0,a0 ; p1 doesnt affect the flags + beq.b .L5 ; p2 likely be false + move.b (a1)+,d0 ; p1 + ble.b .L22 ; p1 more likely to be false at this point .L3 - move.w d5,d0 move.l d6,d1 + lsl.l d0,d6 + sub.l d0,d4 + beq .L4 ; likely to be false most of the times jsr (a4) + moveq #0,d0 ; TODO: remove ? + move.b (a1)+,d0 + ble.b .L22 ; more likely at this point + bra .L3 .L4 - lsl.l d5,d6 ; m <<= v - sub.w d5,d4 ; j -= v - bne.b .L2 + jsr (a4) +.L5 sub.w #BUFFER_WIDTH+32,a0 dbra d7,.L1 epilogue_11 From c9753638c818bacdef5839aff2d8d93ebc346b41 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 13:59:42 +0100 Subject: [PATCH 025/107] added asm replacement for memcmp(). --- CMake/amiga/m68k-amigaos.cmake | 6 ++-- SourceX/platform/amiga/memopt.asm | 53 +++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index d8dec24040d..1bd9c7ae31d 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -50,8 +50,8 @@ if(WIN32) endif() # Compiler flags -# set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -pg -g -noixemul") -set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") +set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -D__PROFILE__ -pg -g -noixemul") +# set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") @@ -60,7 +60,7 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -Wl,--wrap=memcpy -Wl,--wrap=memset -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -Wl,--wrap=memcpy -Wl,--wrap=memset -Wl,--wrap=memcmp -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") # user diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index f9cfae8999e..ca1d675cdba 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -8,10 +8,15 @@ machine 68080 XREF _ac68080_ammx + XREF ___real_memcpy XDEF ___wrap_memcpy + XREF ___real_memset XDEF ___wrap_memset + +* XREF ___real_memcmp + XDEF ___wrap_memcmp cnop 0,4 @@ -22,7 +27,7 @@ ___wrap_memcpy .memcpy rsreset - rs.l 4 + rs.l 1 .dst rs.l 1 .src rs.l 1 .len rs.l 1 @@ -70,7 +75,7 @@ ___wrap_memset .memset rsreset - rs.l 4 + rs.l 1 .dst rs.l 1 .val rs.l 1 .len rs.l 1 @@ -110,4 +115,48 @@ ___wrap_memset move.w #$4e75,.exit(pc) ; #rts rts ; no need to ClearCacheU on apollo! +___wrap_memcmp + rsreset + rs.l 1 +.sc1 rs.l 1 +.sc2 rs.l 1 +.len rs.l 1 + + move.l .sc1(sp),a0 + move.l .sc2(sp),a1 + move.l .len(sp),d0 + +.l0 + subq.l #8,d0 + bcs .l1 + cmp.l (a1)+,(a0)+ + bne .ne + cmp.l (a1)+,(a0)+ + beq .l0 +.ne + bcs .lt + moveq #1,d0 + rts +.lt + moveq #-1,d0 + rts +.l1 + bclr #2,d0 + beq .l2 + cmp.l (a1)+,(a0)+ + bne .ne +.l2 + bclr #1,d0 + beq .l3 + cmp.w (a1)+,(a0)+ + bne .ne +.l3 + addq.l #8,d0 + beq .eq + cmp.b (a1)+,(a0)+ + bne .ne +.eq + moveq #0,d0 + rts + * end of file \ No newline at end of file From 88fb5be495681bbf6388bd63a39e5b148ab206ed Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 14:21:46 +0100 Subject: [PATCH 026/107] speedup --- SourceX/platform/amiga/memopt.asm | 37 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index ca1d675cdba..2b5bfdba842 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -34,20 +34,21 @@ ___wrap_memcpy move.l .dst(sp),a1 ; p1 1 move.l .src(sp),a0 ; p1 2 - move.l .len(sp),d1 ; p1 3 + move.l .len(sp),d0 ; p1 3 - moveq #63,d0 - and.l d1,d0 - lsr.l #8,d1 - beq .l32 + moveq #64,d1 + sub.l d1,d0 + bcs .l32 .l64 REPT 8 load (a0)+,e0 store e0,(a1)+ ENDR - subq.l #1,d1 - bne.s .l64 + sub.l d1,d0 + bcc .l64 .l32 + add. l d1,d0 + beq .exit2 bclr #5,d0 beq.b .l16 REPT 4 @@ -58,7 +59,10 @@ ___wrap_memcpy load (a0)+,e0 storec e0,d0,(a1)+ subq.l #8,d0 - bhi.b .l16 + bcs.b .exit2 + load (a0)+,e0 + storec e0,d0,(a1)+ +.exit2 move.l .dst(sp),d0 .exit nop @@ -86,17 +90,18 @@ ___wrap_memset vperm #$77777777,d0,e0,e0 - moveq #63,d0 - and.l d1,d0 - lsr.l #8,d1 - beq .l32 + moveq #64,d1 + sub.l d1,d0 + bcs .l32 .l64 REPT 8 store e0,(a1)+ ENDR - subq.l #1,d1 - bne.s .l64 + sub.l d1,d0 + bcc .l64 .l32 + add. l d1,d0 + beq .exit2 bclr #5,d0 beq.b .l16 REPT 4 @@ -105,7 +110,9 @@ ___wrap_memset .l16 storec e0,d0,(a1)+ subq.l #8,d0 - bhi.b .l16 + bcs.b .exit2 + storec e0,d0,(a1)+ +.exit2 move.l .dst(sp),d0 .exit nop From 6952e39386b4b8afaff8bcc4487e740f417491f5 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 14:34:05 +0100 Subject: [PATCH 027/107] fixed typo --- SourceX/platform/amiga/memopt.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 2b5bfdba842..2ccb0818adb 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -47,7 +47,7 @@ ___wrap_memcpy sub.l d1,d0 bcc .l64 .l32 - add. l d1,d0 + add.l d1,d0 beq .exit2 bclr #5,d0 beq.b .l16 From 75d25de8472945afb4d440824aca43aa81b97fee Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 14:37:07 +0100 Subject: [PATCH 028/107] fixed typo --- SourceX/platform/amiga/memopt.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 2b5bfdba842..2ccb0818adb 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -47,7 +47,7 @@ ___wrap_memcpy sub.l d1,d0 bcc .l64 .l32 - add. l d1,d0 + add.l d1,d0 beq .exit2 bclr #5,d0 beq.b .l16 From 413081dc726d62ca1580774d6d29e416ca10d998 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 14:37:58 +0100 Subject: [PATCH 029/107] fixed typo --- SourceX/platform/amiga/memopt.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 2ccb0818adb..258e24296da 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -100,7 +100,7 @@ ___wrap_memset sub.l d1,d0 bcc .l64 .l32 - add. l d1,d0 + add.l d1,d0 beq .exit2 bclr #5,d0 beq.b .l16 From bcac2487d8d91dbf45ee1c52b10a1276e3208bad Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 16:54:26 +0100 Subject: [PATCH 030/107] now uses dbmalloc()/dbfree() in smk resulting in faster video-intro --- 3rdParty/libsmacker/smk_malloc.h | 6 + CMake/amiga/m68k-amigaos.cmake | 4 +- SourceX/platform/amiga/malloc.c | 6280 ++++++++++++++++++++++++++++++ SourceX/platform/amiga/support.c | 68 + 4 files changed, 6356 insertions(+), 2 deletions(-) create mode 100755 SourceX/platform/amiga/malloc.c diff --git a/3rdParty/libsmacker/smk_malloc.h b/3rdParty/libsmacker/smk_malloc.h index ef70cb79a89..596a2c3d8a0 100644 --- a/3rdParty/libsmacker/smk_malloc.h +++ b/3rdParty/libsmacker/smk_malloc.h @@ -12,6 +12,12 @@ #ifndef SMK_MALLOC_H #define SMK_MALLOC_H +#ifdef __AMIGA__ +#define free dlfree +#define calloc dlcalloc +#define malloc dlmalloc +#endif + /* calloc */ #include /* fprintf */ diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 1bd9c7ae31d..1b4d02b50eb 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -50,8 +50,8 @@ if(WIN32) endif() # Compiler flags -set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -D__PROFILE__ -pg -g -noixemul") -# set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") +# set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -D__PROFILE__ -pg -g -noixemul") +set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") diff --git a/SourceX/platform/amiga/malloc.c b/SourceX/platform/amiga/malloc.c new file mode 100755 index 00000000000..649cfbc7054 --- /dev/null +++ b/SourceX/platform/amiga/malloc.c @@ -0,0 +1,6280 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/publicdomain/zero/1.0/ Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version 2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (minimum) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + It is also possible to limit the maximum total allocatable + space, using malloc_set_footprint_limit. This is not + designed as a security feature in itself (calls to set limits + are not screened or privileged), but may be useful as one + aspect of a secure implementation. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with a lock. By default, this uses a plain + pthread mutex, win32 critical section, or a spin-lock if if + available for the platform and not disabled by setting + USE_SPIN_LOCKS=0. However, if USE_RECURSIVE_LOCKS is defined, + recursive versions are used instead (which are not required for + base functionality but may be needed in layered extensions). + Using a global lock is not especially fast, and can be a major + bottleneck. It is designed only to provide minimal protection + in concurrent environments, and to provide a basis for + extensions. If you are using malloc in a concurrent program, + consider instead using nedmalloc + (http://www.nedprod.com/programs/portable/nedmalloc/) or + ptmalloc (See http://www.malloc.de), which are derived from + versions of this malloc. + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. In real-time + applications, you can optionally suppress segment traversals using + NO_SEGMENT_TRAVERSAL, which assures bounded execution even when + system allocators return non-contiguous spaces, at the typical + expense of carrying around more memory and increased fragmentation. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. Normally, this requires use of locks. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. You can also +use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. Beware that there seem to be some + cases where this malloc might not be a pure drop-in replacement for + Win32 malloc: Random-looking failures from Win32 GDI API's (eg; + SetDIBits()) may be due to bugs in some video driver implementations + when pixel buffers are malloc()ed, and the region spans more than + one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) + default granularity, pixel buffers may straddle virtual allocation + regions more often than when using the Microsoft allocator. You can + avoid this by using VirtualAlloc() and VirtualFree() for all pixel + buffers rather than using malloc(). If this is not possible, + recompile this malloc with a larger DEFAULT_GRANULARITY. Note: + in cases where MSC and gcc (cygwin) are known to differ on WIN32, + conditions use _MSC_VER to distinguish them. + +DLMALLOC_EXPORT default: extern + Defines how public APIs are declared. If you want to export via a + Windows DLL, you might define this as + #define DLMALLOC_EXPORT extern __declspec(dllexport) + If you want a POSIX ELF shared object, you might use + #define DLMALLOC_EXPORT extern __attribute__((visibility("default"))) + +MALLOC_ALIGNMENT default: (size_t)(2 * sizeof(void *)) + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) If set to a + non-zero value other than 1, locks are used, but their + implementation is left out, so lock functions must be supplied manually, + as described below. + +USE_SPIN_LOCKS default: 1 iff USE_LOCKS and spin locks available + If true, uses custom spin locks for locking. This is currently + supported only gcc >= 4.1, older gccs on x86 platforms, and recent + MS compilers. Otherwise, posix locks or win32 critical sections are + used. + +USE_RECURSIVE_LOCKS default: not defined + If defined nonzero, uses recursive (aka reentrant) locks, otherwise + uses plain mutexes. This is not required for malloc proper, but may + be needed for layered allocators such as nedmalloc. + +LOCK_AT_FORK default: not defined + If defined nonzero, performs pthread_atfork upon initialization + to initialize child lock while holding parent lock. The implementation + assumes that pthread locks (not custom locks) are being used. In other + cases, you may need to customize the implementation. + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +MALLOC_INSPECT_ALL default: NOT defined + If defined, compiles malloc_inspect_all and mspace_inspect_all, that + perform traversal of all heap space. Unless access to these + functions is otherwise restricted, you probably do not want to + include them in secure implementations. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. + +MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +NO_SEGMENT_TRAVERSAL default: 0 + If non-zero, suppresses traversals of memory segments + returned by either MORECORE or CALL_MMAP. This disables + merging of segments that are contiguous, and selectively + releasing them to the OS if unused, but bounds execution times. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 except on WINCE. + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero and on WIN32 except for WINCE. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. Similarly for Win32 under recent MS compilers. + (On most x86s, the asm version is only slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +NO_MALLOC_STATS default: 0 + If defined, don't compile "malloc_stats". This avoids calls to + fprintf and bringing in stdio dependencies you might not want. + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP + The number of consolidated frees between checks to release + unused segments when freeing. When using non-contiguous segments, + especially with multiple mspaces, checking only for topmost space + doesn't always suffice to trigger trimming. To compensate for this, + free() will, with a period of MAX_RELEASE_CHECK_RATE (or the + current number of segments, if greater) try to release unused + segments to the OS when freeing chunks that result in + consolidation. The best value for this parameter is a compromise + between slowing down frees with relatively costly checks that + rarely trigger versus holding on to unused memory. To effectively + disable, set to MAX_SIZE_T. This may lead to a very slight speed + improvement at the expense of carrying around more memory. +*/ + +/* Version identifier to allow people to support multiple versions */ +#ifndef DLMALLOC_VERSION +#define DLMALLOC_VERSION 20806 +#endif /* DLMALLOC_VERSION */ + +#ifndef DLMALLOC_EXPORT +#define DLMALLOC_EXPORT extern +#endif + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#ifdef _WIN32_WCE +#define LACKS_FCNTL_H +#define WIN32 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define LACKS_SCHED_H +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef MMAP_CLEARS +#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ +#define MMAP_CLEARS 0 +#else +#define MMAP_CLEARS 1 +#endif /* _WIN32_WCE */ +#endif /*MMAP_CLEARS */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +/* OSX allocators provide 16 byte alignment */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)16U) +#endif +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */ +#define USE_LOCKS ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \ + (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0)) +#endif /* USE_LOCKS */ + +#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */ +#if ((defined(__GNUC__) && \ + ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && _MSC_VER>=1310)) +#ifndef USE_SPIN_LOCKS +#define USE_SPIN_LOCKS 1 +#endif /* USE_SPIN_LOCKS */ +#elif USE_SPIN_LOCKS +#error "USE_SPIN_LOCKS defined without implementation" +#endif /* ... locks available... */ +#elif !defined(USE_SPIN_LOCKS) +#define USE_SPIN_LOCKS 0 +#endif /* USE_LOCKS */ + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *))) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ + +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef MALLOC_INSPECT_ALL +#define MALLOC_INSPECT_ALL 0 +#endif /* MALLOC_INSPECT_ALL */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#define _GNU_SOURCE /* Turns on mremap() definition */ +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#define MORECORE_DEFAULT sbrk +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if (MORECORE_CONTIGUOUS || defined(WIN32)) +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef MAX_RELEASE_CHECK_RATE +#if HAVE_MMAP +#define MAX_RELEASE_CHECK_RATE 4095 +#else +#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* MAX_RELEASE_CHECK_RATE */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ +#ifndef NO_MALLOC_STATS +#define NO_MALLOC_STATS 0 +#endif /* NO_MALLOC_STATS */ +#ifndef NO_SEGMENT_TRAVERSAL +#define NO_SEGMENT_TRAVERSAL 0 +#endif /* NO_SEGMENT_TRAVERSAL */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ +#ifndef STRUCT_MALLINFO_DECLARED +/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */ +#define _STRUCT_MALLINFO +#define STRUCT_MALLINFO_DECLARED 1 +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; +#endif /* STRUCT_MALLINFO_DECLARED */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +/* + Try to persuade compilers to inline. The most critical functions for + inlining are defined as macros, so these aren't used for them. +*/ + +#ifndef FORCEINLINE + #if defined(__GNUC__) +#define FORCEINLINE __inline __attribute__ ((always_inline)) + #elif defined(_MSC_VER) + #define FORCEINLINE __forceinline + #endif +#endif +#ifndef NOINLINE + #if defined(__GNUC__) + #define NOINLINE __attribute__ ((noinline)) + #elif defined(_MSC_VER) + #define NOINLINE __declspec(noinline) + #else + #define NOINLINE + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#ifndef FORCEINLINE + #define FORCEINLINE inline +#endif +#endif /* __cplusplus */ +#ifndef FORCEINLINE + #define FORCEINLINE +#endif + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlposix_memalign posix_memalign +#define dlrealloc realloc +#define dlrealloc_in_place realloc_in_place +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlmalloc_footprint_limit malloc_footprint_limit +#define dlmalloc_set_footprint_limit malloc_set_footprint_limit +#define dlmalloc_inspect_all malloc_inspect_all +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#define dlbulk_free bulk_free +#endif /* USE_DL_PREFIX */ + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +DLMALLOC_EXPORT void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +DLMALLOC_EXPORT void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +DLMALLOC_EXPORT void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ +DLMALLOC_EXPORT void* dlrealloc(void*, size_t); + +/* + realloc_in_place(void* p, size_t n) + Resizes the space allocated for p to size n, only if this can be + done without moving p (i.e., only if there is adjacent space + available if n is greater than p's current allocated size, or n is + less than or equal to p's size). This may be used instead of plain + realloc if an alternative allocation strategy is needed upon failure + to expand space; for example, reallocation of a buffer that must be + memory-aligned or cleared. You can use realloc_in_place to trigger + these alternatives only when needed. + + Returns p if successful; otherwise null. +*/ +DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +DLMALLOC_EXPORT void* dlmemalign(size_t, size_t); + +/* + int posix_memalign(void** pp, size_t alignment, size_t n); + Allocates a chunk of n bytes, aligned in accord with the alignment + argument. Differs from memalign only in that it (1) assigns the + allocated memory to *pp rather than returning it, (2) fails and + returns EINVAL if the alignment is not a power of two (3) fails and + returns ENOMEM if memory cannot be allocated. +*/ +DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +DLMALLOC_EXPORT void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. To workaround the fact that mallopt is specified to use int, + not size_t parameters, the value -1 is specially treated as the + maximum unsigned size_t value. + + SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +DLMALLOC_EXPORT int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +DLMALLOC_EXPORT size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void); + +/* + malloc_footprint_limit(); + Returns the number of bytes that the heap is allowed to obtain from + the system, returning the last value returned by + malloc_set_footprint_limit, or the maximum size_t value if + never set. The returned value reflects a permission. There is no + guarantee that this number of bytes can actually be obtained from + the system. +*/ +DLMALLOC_EXPORT size_t dlmalloc_footprint_limit(); + +/* + malloc_set_footprint_limit(); + Sets the maximum number of bytes to obtain from the system, causing + failure returns from malloc and related functions upon attempts to + exceed this value. The argument value may be subject to page + rounding to an enforceable limit; this actual value is returned. + Using an argument of the maximum possible size_t effectively + disables checks. If the argument is less than or equal to the + current malloc_footprint, then all future allocations that require + additional system memory will fail. However, invocation cannot + retroactively deallocate existing used memory. +*/ +DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes); + +#if MALLOC_INSPECT_ALL +/* + malloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg); + Traverses the heap and calls the given handler for each managed + region, skipping all bytes that are (or may be) used for bookkeeping + purposes. Traversal does not include include chunks that have been + directly memory mapped. Each reported region begins at the start + address, and continues up to but not including the end address. The + first used_bytes of the region contain allocated data. If + used_bytes is zero, the region is unallocated. The handler is + invoked with the given callback argument. If locks are defined, they + are held during the entire traversal. It is a bad idea to invoke + other malloc functions from within the handler. + + For example, to count the number of in-use chunks with size greater + than 1000, you could write: + static int count = 0; + void count_chunks(void* start, void* end, size_t used, void* arg) { + if (used >= 1000) ++count; + } + then: + malloc_inspect_all(count_chunks, NULL); + + malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined. +*/ +DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), + void* arg); + +#endif /* MALLOC_INSPECT_ALL */ + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be freed when it is no longer needed. This can be + done all at once using bulk_free. + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be freed when it is no longer needed. This can be + done all at once using bulk_free. + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**); + +/* + bulk_free(void* array[], size_t n_elements) + Frees and clears (sets to null) each non-null pointer in the given + array. This is likely to be faster than freeing them one-by-one. + If footers are used, pointers that have been allocated in different + mspaces are not freed or cleared, and the count of all such pointers + is returned. For large arrays of pointers with poor locality, it + may be worthwhile to sort this array before calling bulk_free. +*/ +DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements); + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +DLMALLOC_EXPORT void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +DLMALLOC_EXPORT int dlmalloc_trim(size_t); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +DLMALLOC_EXPORT void dlmalloc_stats(void); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + +#endif /* ONLY_MSPACES */ + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +DLMALLOC_EXPORT size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_track_large_chunks controls whether requests for large chunks + are allocated in their own untracked mmapped regions, separate from + others in this mspace. By default large chunks are not tracked, + which reduces fragmentation. However, such chunks are not + necessarily released to the system upon destroy_mspace. Enabling + tracking by setting to true may increase fragmentation, but avoids + leakage when relying on destroy_mspace to release all memory + allocated using this space. The function returns the previous + setting. +*/ +DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable); + + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +DLMALLOC_EXPORT size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + malloc_usable_size(void* p) behaves the same as malloc_usable_size; +*/ +DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem); + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +DLMALLOC_EXPORT int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef _MSC_VER +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* _MSC_VER */ +#if !NO_MALLOC_STATS +#include /* for printing in malloc_stats */ +#endif /* NO_MALLOC_STATS */ +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#undef assert +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#ifndef assert +#define assert(x) +#endif +#define DEBUG 0 +#endif /* DEBUG */ +#if !defined(WIN32) && !defined(LACKS_TIME_H) +#include /* for magic initialization */ +#endif /* WIN32 */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ +#if (defined(linux) && !defined(__USE_GNU)) +#define __USE_GNU 1 +#include /* for mmap */ +#undef __USE_GNU +#else +#include /* for mmap */ +#endif /* linux */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#ifndef LACKS_UNISTD_H +#include /* for sbrk, sysconf */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ + +/* Declarations for locking */ +#if USE_LOCKS +#ifndef WIN32 +#if defined (__SVR4) && defined (__sun) /* solaris */ +#include +#elif !defined(LACKS_SCHED_H) +#include +#endif /* solaris or LACKS_SCHED_H */ +#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS +#include +#endif /* USE_RECURSIVE_LOCKS ... */ +#elif defined(_MSC_VER) +#ifndef _M_AMD64 +/* These are already defined on AMD64 builds */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); +LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _M_AMD64 */ +#pragma intrinsic (_InterlockedCompareExchange) +#pragma intrinsic (_InterlockedExchange) +#define interlockedcompareexchange _InterlockedCompareExchange +#define interlockedexchange _InterlockedExchange +#elif defined(WIN32) && defined(__GNUC__) +#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) +#define interlockedexchange __sync_lock_test_and_set +#endif /* Win32 */ +#else /* USE_LOCKS */ +#endif /* USE_LOCKS */ + +#ifndef LOCK_AT_FORK +#define LOCK_AT_FORK 0 +#endif + +/* Declarations for bit scanning on win32 */ +#if defined(_MSC_VER) && _MSC_VER>=1300 +#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) +#endif /* BitScanForward */ +#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some platforms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define SIZE_T_FOUR ((size_t)4) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if HAVE_MMAP + +#ifndef WIN32 +#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static FORCEINLINE void* win32mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static FORCEINLINE void* win32direct_mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static FORCEINLINE int win32munmap(void* ptr, size_t size) { + MEMORY_BASIC_INFORMATION minfo; + char* cptr = (char*)ptr; + while (size) { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + return 0; +} + +#define MMAP_DEFAULT(s) win32mmap(s) +#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MREMAP +#ifndef WIN32 +#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#endif /* WIN32 */ +#endif /* HAVE_MREMAP */ + +/** + * Define CALL_MORECORE + */ +#if HAVE_MORECORE + #ifdef MORECORE + #define CALL_MORECORE(S) MORECORE(S) + #else /* MORECORE */ + #define CALL_MORECORE(S) MORECORE_DEFAULT(S) + #endif /* MORECORE */ +#else /* HAVE_MORECORE */ + #define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/** + * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP + */ +#if HAVE_MMAP + #define USE_MMAP_BIT (SIZE_T_ONE) + + #ifdef MMAP + #define CALL_MMAP(s) MMAP(s) + #else /* MMAP */ + #define CALL_MMAP(s) MMAP_DEFAULT(s) + #endif /* MMAP */ + #ifdef MUNMAP + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) + #else /* MUNMAP */ + #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) + #endif /* MUNMAP */ + #ifdef DIRECT_MMAP + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #else /* DIRECT_MMAP */ + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) + #endif /* DIRECT_MMAP */ +#else /* HAVE_MMAP */ + #define USE_MMAP_BIT (SIZE_T_ZERO) + + #define MMAP(s) MFAIL + #define MUNMAP(a, s) (-1) + #define DIRECT_MMAP(s) MFAIL + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #define CALL_MMAP(s) MMAP(s) + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#endif /* HAVE_MMAP */ + +/** + * Define CALL_MREMAP + */ +#if HAVE_MMAP && HAVE_MREMAP + #ifdef MREMAP + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) + #else /* MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) + #endif /* MREMAP */ +#else /* HAVE_MMAP && HAVE_MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +/* + When locks are defined, there is one global lock, plus + one per-mspace lock. + + The global lock_ensures that mparams.magic and other unique + mparams values are initialized only once. It also protects + sequences of calls to MORECORE. In many cases sys_alloc requires + two calls, that should not be interleaved with calls by other + threads. This does not protect against direct calls to MORECORE + by other threads not using this lock, so there is still code to + cope the best we can on interference. + + Per-mspace locks surround calls to malloc, free, etc. + By default, locks are simple non-reentrant mutexes. + + Because lock-protected regions generally have bounded times, it is + OK to use the supplied simple spinlocks. Spinlocks are likely to + improve performance for lightly contended applications, but worsen + performance under heavy contention. + + If USE_LOCKS is > 1, the definitions of lock routines here are + bypassed, in which case you will need to define the type MLOCK_T, + and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK + and TRY_LOCK. You must also declare a + static MLOCK_T malloc_global_mutex = { initialization values };. + +*/ + +#if !USE_LOCKS +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) (0) +#define DESTROY_LOCK(l) (0) +#define ACQUIRE_MALLOC_GLOBAL_LOCK() +#define RELEASE_MALLOC_GLOBAL_LOCK() + +#else +#if USE_LOCKS > 1 +/* ----------------------- User-defined locks ------------------------ */ +/* Define your own lock implementation here */ +/* #define INITIAL_LOCK(lk) ... */ +/* #define DESTROY_LOCK(lk) ... */ +/* #define ACQUIRE_LOCK(lk) ... */ +/* #define RELEASE_LOCK(lk) ... */ +/* #define TRY_LOCK(lk) ... */ +/* static MLOCK_T malloc_global_mutex = ... */ + +#elif USE_SPIN_LOCKS + +/* First, define CAS_LOCK and CLEAR_LOCK on ints */ +/* Note CAS_LOCK defined to return 0 on success */ + +#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) +#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) +#define CLEAR_LOCK(sl) __sync_lock_release(sl) + +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) +/* Custom spin locks for older gcc on x86 */ +static FORCEINLINE int x86_cas_lock(int *sl) { + int ret; + int val = 1; + int cmp = 0; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(sl)), "0"(cmp) + : "memory", "cc"); + return ret; +} + +static FORCEINLINE void x86_clear_lock(int* sl) { + assert(*sl != 0); + int prev = 0; + int ret; + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(sl)), "0"(prev) + : "memory"); +} + +#define CAS_LOCK(sl) x86_cas_lock(sl) +#define CLEAR_LOCK(sl) x86_clear_lock(sl) + +#else /* Win32 MSC */ +#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1) +#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0) + +#endif /* ... gcc spins locks ... */ + +/* How to yield for a spin lock */ +#define SPINS_PER_YIELD 63 +#if defined(_MSC_VER) +#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ +#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) +#elif defined (__SVR4) && defined (__sun) /* solaris */ +#define SPIN_LOCK_YIELD thr_yield(); +#elif !defined(LACKS_SCHED_H) +#define SPIN_LOCK_YIELD sched_yield(); +#else +#define SPIN_LOCK_YIELD +#endif /* ... yield ... */ + +#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0 +/* Plain spin locks use single word (embedded in malloc_states) */ +static int spin_acquire_lock(int *sl) { + int spins = 0; + while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) { + if ((++spins & SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } + } + return 0; +} + +#define MLOCK_T int +#define TRY_LOCK(sl) !CAS_LOCK(sl) +#define RELEASE_LOCK(sl) CLEAR_LOCK(sl) +#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0) +#define INITIAL_LOCK(sl) (*sl = 0) +#define DESTROY_LOCK(sl) (0) +static MLOCK_T malloc_global_mutex = 0; + +#else /* USE_RECURSIVE_LOCKS */ +/* types for lock owners */ +#ifdef WIN32 +#define THREAD_ID_T DWORD +#define CURRENT_THREAD GetCurrentThreadId() +#define EQ_OWNER(X,Y) ((X) == (Y)) +#else +/* + Note: the following assume that pthread_t is a type that can be + initialized to (casted) zero. If this is not the case, you will need to + somehow redefine these or not use spin locks. +*/ +#define THREAD_ID_T pthread_t +#define CURRENT_THREAD pthread_self() +#define EQ_OWNER(X,Y) pthread_equal(X, Y) +#endif + +struct malloc_recursive_lock { + int sl; + unsigned int c; + THREAD_ID_T threadid; +}; + +#define MLOCK_T struct malloc_recursive_lock +static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0}; + +static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) { + assert(lk->sl != 0); + if (--lk->c == 0) { + CLEAR_LOCK(&lk->sl); + } +} + +static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) { + THREAD_ID_T mythreadid = CURRENT_THREAD; + int spins = 0; + for (;;) { + if (*((volatile int *)(&lk->sl)) == 0) { + if (!CAS_LOCK(&lk->sl)) { + lk->threadid = mythreadid; + lk->c = 1; + return 0; + } + } + else if (EQ_OWNER(lk->threadid, mythreadid)) { + ++lk->c; + return 0; + } + if ((++spins & SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } + } +} + +static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) { + THREAD_ID_T mythreadid = CURRENT_THREAD; + if (*((volatile int *)(&lk->sl)) == 0) { + if (!CAS_LOCK(&lk->sl)) { + lk->threadid = mythreadid; + lk->c = 1; + return 1; + } + } + else if (EQ_OWNER(lk->threadid, mythreadid)) { + ++lk->c; + return 1; + } + return 0; +} + +#define RELEASE_LOCK(lk) recursive_release_lock(lk) +#define TRY_LOCK(lk) recursive_try_lock(lk) +#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk) +#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0) +#define DESTROY_LOCK(lk) (0) +#endif /* USE_RECURSIVE_LOCKS */ + +#elif defined(WIN32) /* Win32 critical sections */ +#define MLOCK_T CRITICAL_SECTION +#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0) +#define RELEASE_LOCK(lk) LeaveCriticalSection(lk) +#define TRY_LOCK(lk) TryEnterCriticalSection(lk) +#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000)) +#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0) +#define NEED_GLOBAL_LOCK_INIT + +static MLOCK_T malloc_global_mutex; +static volatile LONG malloc_global_mutex_status; + +/* Use spin loop to initialize global lock */ +static void init_malloc_global_mutex() { + for (;;) { + long stat = malloc_global_mutex_status; + if (stat > 0) + return; + /* transition to < 0 while initializing, then to > 0) */ + if (stat == 0 && + interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) { + InitializeCriticalSection(&malloc_global_mutex); + interlockedexchange(&malloc_global_mutex_status, (LONG)1); + return; + } + SleepEx(0, FALSE); + } +} + +#else /* pthreads-based locks */ +#define MLOCK_T pthread_mutex_t +#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk) +#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk) +#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk)) +#define INITIAL_LOCK(lk) pthread_init_lock(lk) +#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk) + +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE) +/* Cope with old-style linux recursive lock initialization by adding */ +/* skipped internal declaration from pthread.h */ +extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr, + int __kind)); +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) +#endif /* USE_RECURSIVE_LOCKS ... */ + +static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int pthread_init_lock (MLOCK_T *lk) { + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) return 1; +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1; +#endif + if (pthread_mutex_init(lk, &attr)) return 1; + if (pthread_mutexattr_destroy(&attr)) return 1; + return 0; +} + +#endif /* ... lock types ... */ + +/* Common code for all lock types */ +#define USE_LOCK_BIT (2U) + +#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK +#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); +#endif + +#ifndef RELEASE_MALLOC_GLOBAL_LOCK +#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); +#endif + +#endif /* USE_LOCKS */ + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 0) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse (unless the chunk is mmapped). This redundancy enables usage + checks within free and realloc, and reduces indirection when freeing + and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, have both cinuse and pinuse bits + cleared in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use, unless mmapped, in which case both bits are cleared. + + FLAG4_BIT is not used by this malloc, but might be useful in extensions. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define FLAG4_BIT (SIZE_T_FOUR) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) +#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define flag4inuse(p) ((p)->head & FLAG4_BIT) +#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) +#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) + +#define chunksize(p) ((p)->head & ~(FLAG_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define set_flag4(p) ((p)->head |= FLAG4_BIT) +#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If USE_MMAP_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Max allowed footprint + The maximum allowed bytes to allocate from system (zero means no limit) + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Trim support + Fields holding the amount of unused topmost memory that should trigger + trimming, and a counter to force periodic scanning to release unused + non-topmost segments. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. + + Extension support + A void* pointer and a size_t field that can be used to help implement + extensions to this malloc. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t release_checks; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + size_t footprint_limit; /* zero means no limit */ + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; + void* extp; /* Unused but available for extensions */ + size_t exts; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. Note that the non-zeroness of "magic" + also serves as an initialization flag. +*/ + +struct malloc_params { + size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* Ensure mparams initialized */ +#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams()) + +#if !ONLY_MSPACES + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) + +#endif /* !ONLY_MSPACES */ + +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#if USE_LOCKS +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) +#else +#define disable_lock(M) +#endif + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#if HAVE_MMAP +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) +#else +#define disable_mmap(M) +#endif + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity - SIZE_T_ONE))\ + & ~(mparams.granularity - SIZE_T_ONE)) + + +/* For mmap, use granularity alignment on windows, else page-align */ +#ifdef WIN32 +#define mmap_align(S) granularity_align(S) +#else +#define mmap_align(S) page_align(S) +#endif + +/* For sys_alloc, enough padding to ensure can malloc request on success */ +#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS +#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I. Use x86 asm if possible */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_tree_index(S, I)\ +{\ + unsigned int X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = _bit_scan_reverse (X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + _BitScanReverse((DWORD *) &K, (DWORD) X);\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + +/* index corresponding to given bit. Use x86 asm if possible */ + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = __builtin_ctz(X); \ + I = (bindex_t)J;\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = _bit_scan_forward (X); \ + I = (bindex_t)J;\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + _BitScanForward((DWORD *) &J, X);\ + I = (bindex_t)J;\ +} + +#elif USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* GNUC */ + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probabalistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has inuse status */ +#define ok_inuse(p) is_inuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_inuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Macros for setting head/foot of non-mmapped chunks */ + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +#if LOCK_AT_FORK +static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); } +static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); } +static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } +#endif /* LOCK_AT_FORK */ + +/* Initialize mparams */ +static int init_mparams(void) { +#ifdef NEED_GLOBAL_LOCK_INIT + if (malloc_global_mutex_status <= 0) + init_malloc_global_mutex(); +#endif + + ACQUIRE_MALLOC_GLOBAL_LOCK(); + if (mparams.magic == 0) { + size_t magic; + size_t psize; + size_t gsize; + +#ifndef WIN32 + psize = malloc_getpagesize; + gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + psize = system_info.dwPageSize; + gsize = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((gsize & (gsize-SIZE_T_ONE)) != 0) || + ((psize & (psize-SIZE_T_ONE)) != 0)) + ABORT; + mparams.granularity = gsize; + mparams.page_size = psize; + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if !ONLY_MSPACES + /* Set up lock for main malloc area */ + gm->mflags = mparams.default_mflags; + (void)INITIAL_LOCK(&gm->mutex); +#endif +#if LOCK_AT_FORK + pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); +#endif + + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + magic = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ +#ifdef WIN32 + magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); +#elif defined(LACKS_TIME_H) + magic = (size_t)&magic ^ (size_t)0x55555555U; +#else + magic = (size_t)(time(0) ^ (size_t)0x55555555U); +#endif + magic |= (size_t)8U; /* ensure nonzero */ + magic &= ~(size_t)7U; /* improve chances of fault for bad values */ + /* Until memory modes commonly available, use volatile-write */ + (*(volatile size_t *)(&(mparams.magic))) = magic; + } + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val; + ensure_initialization(); + val = (value == -1)? MAX_SIZE_T : (size_t)value; + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) { + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) { + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!pinuse(chunk_plus_offset(p, sz))); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) { + do_check_any_chunk(m, p); + assert(is_inuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!is_inuse(p)); + assert(!next_pinuse(p)); + assert (!is_mmapped(p)); + if (p != m->dv && p != m->top) { + if (sz >= MIN_CHUNK_SIZE) { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert (next == m->top || is_inuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + assert(sz == SIZE_T_SIZE); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~INUSE_BITS; + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) { + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); + + do { /* traverse through chain of same-sized nodes */ + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!is_inuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + if (u->parent == 0) { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); + if (u->child[0] != 0) { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + if (u->child[1] != 0) { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + if (u->child[0] != 0 && u->child[1] != 0) { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + u = u->fd; + } while (u != t); + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) { + tbinptr* tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) { + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + if (p == b) + assert(empty); + if (!empty) { + for (; p != b; p = p->bk) { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) { + size_t size = chunksize(x); + if (is_small(size)) { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + if (smallmap_is_marked(m, sidx)) { + mchunkptr p = b; + do { + if (p == x) + return 1; + } while ((p = p->fd) != b); + } + } + else { + bindex_t tidx; + compute_tree_index(size, tidx); + if (treemap_is_marked(m, tidx)) { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + while (t != 0 && chunksize(t) != size) { + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) { + tchunkptr u = t; + do { + if (u == (tchunkptr)x) + return 1; + } while ((u = u->fd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) { + size_t sum = 0; + if (is_initialized(m)) { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + sum += chunksize(q); + if (is_inuse(q)) { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + lastq = q; + q = next_chunk(q); + } + s = s->next; + } + } + return sum; +} + + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) { + bindex_t i; + size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + do_check_smallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + do_check_treebin(m, i); + + if (m->dvsize != 0) { /* check dv chunk */ + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) { /* check top chunk */ + do_check_top_chunk(m, m->top); + /*assert(m->topsize == chunksize(m->top)); redundant */ + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + ensure_initialization(); + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!is_inuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + return nm; +} +#endif /* !NO_MALLINFO */ + +#if !NO_MALLOC_STATS +static void internal_malloc_stats(mstate m) { + ensure_initialization(); + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!is_inuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + POSTACTION(m); /* drop lock */ + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + } +} +#endif /* NO_MALLOC_STATS */ + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(B == smallbin_at(M,I) ||\ + (ok_address(M, B) && B->fd == P))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + assert(is_small(DVS));\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + ((m == gm)? dlmalloc(b) : mspace_malloc(m, b)) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (m->footprint_limit != 0) { + size_t fp = m->footprint + mmsize; + if (fp <= m->footprint || fp > m->footprint_limit) + return 0; + } + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(CALL_DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset; + p->head = psize; + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (m->least_addr == 0 || mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { + size_t oldsize = chunksize(oldp); + (void)flags; /* placate people compiling -Wunused */ + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, flags); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = psize; + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallmap = m->treemap = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!is_inuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + size_t asize; /* allocation size */ + + ensure_initialization(); + + /* Directly map large chunks, but only if already initialized */ + if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + asize = granularity_align(nb + SYS_ALLOC_PADDING); + if (asize <= nb) + return 0; /* wraparound */ + if (m->footprint_limit != 0) { + size_t fp = m->footprint + asize; + if (fp <= m->footprint || fp > m->footprint_limit) + return 0; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + + In all cases, we need to request enough bytes from system to ensure + we can malloc nb bytes upon success, so pad with enough space for + top_foot, plus alignment-pad to make sure we don't lose bytes if + not on boundary, and round this up to a granularity unit. + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + size_t ssize = asize; /* sbrk call size */ + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + ACQUIRE_MALLOC_GLOBAL_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + size_t fp; + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + ssize += (page_align((size_t)base) - (size_t)base); + fp = m->footprint + ssize; /* recheck limits */ + if (ssize > nb && ssize < HALF_MAX_SIZE_T && + (m->footprint_limit == 0 || + (fp > m->footprint && fp <= m->footprint_limit)) && + (br = (char*)(CALL_MORECORE(ssize))) == base) { + tbase = base; + tsize = ssize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); + /* Use mem here only if it did continuously extend old space */ + if (ssize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) { + tbase = br; + tsize = ssize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (ssize < HALF_MAX_SIZE_T && + ssize < nb + SYS_ALLOC_PADDING) { + size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + ssize += esize; + else { /* Can't use; try to release */ + (void) CALL_MORECORE(-ssize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = ssize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + char* mp = (char*)(CALL_MMAP(asize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = asize; + mmap_flag = USE_MMAP_BIT; + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MALLOC_GLOBAL_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + if (m->least_addr == 0 || tbase < m->least_addr) + m->least_addr = tbase; + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + init_bins(m); +#if !ONLY_MSPACES + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else +#endif + { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + /* Only consider most recent segment if traversal suppressed */ + while (sp != 0 && tbase != sp->base + sp->size) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & USE_MMAP_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & USE_MMAP_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + int nsegs = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + ++nsegs; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + break; + pred = sp; + sp = next; + } + /* Reset check counter */ + m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)? + (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE); + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + ensure_initialization(); + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + (void)newsize; /* placate people compiling -Wunused-variable */ + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MALLOC_GLOBAL_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0 && m->topsize > m->trim_check) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + +/* Consolidate and bin a chunk. Differs from exported versions + of free mainly in that the chunk need not be marked as inuse. +*/ +static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + mchunkptr prev; + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + m->footprint -= psize; + return; + } + prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */ + if (p != m->dv) { + unlink_chunk(m, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + m->dvsize = psize; + set_free_with_pinuse(p, psize, next); + return; + } + } + else { + CORRUPTION_ERROR_ACTION(m); + return; + } + } + if (RTCHECK(ok_address(m, next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == m->top) { + size_t tsize = m->topsize += psize; + m->top = p; + p->head = tsize | PINUSE_BIT; + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + return; + } + else if (next == m->dv) { + size_t dsize = m->dvsize += psize; + m->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + return; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(m, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == m->dv) { + m->dvsize = psize; + return; + } + } + } + else { + set_free_with_pinuse(p, psize, next); + } + insert_chunk(m, p, psize); + } + else { + CORRUPTION_ERROR_ACTION(m); + } +} + +/* ---------------------------- malloc --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + +#if USE_LOCKS + ensure_initialization(); /* initialize in sys_alloc if not using locks */ +#endif + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +/* ---------------------------- free --------------------------- */ + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceeding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +#endif /* !ONLY_MSPACES */ + +/* ------------ Internal support for realloc, memalign, etc -------------- */ + +/* Try to realloc; only in-place unless can_move true */ +static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, + int can_move) { + mchunkptr newp = 0; + size_t oldsize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, oldsize); + if (RTCHECK(ok_address(m, p) && ok_inuse(p) && + ok_next(p, next) && ok_pinuse(next))) { + if (is_mmapped(p)) { + newp = mmap_resize(m, p, nb, can_move); + } + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + newp = p; + } + else if (next == m->top) { /* extend into top */ + if (oldsize + m->topsize > nb) { + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = p; + } + } + else if (next == m->dv) { /* extend into dv */ + size_t dvs = m->dvsize; + if (oldsize + dvs >= nb) { + size_t dsize = oldsize + dvs - nb; + if (dsize >= MIN_CHUNK_SIZE) { + mchunkptr r = chunk_plus_offset(p, nb); + mchunkptr n = chunk_plus_offset(r, dsize); + set_inuse(m, p, nb); + set_size_and_pinuse_of_free_chunk(r, dsize); + clear_pinuse(n); + m->dvsize = dsize; + m->dv = r; + } + else { /* exhaust dv */ + size_t newsize = oldsize + dvs; + set_inuse(m, p, newsize); + m->dvsize = 0; + m->dv = 0; + } + newp = p; + } + } + else if (!cinuse(next)) { /* extend into next free chunk */ + size_t nextsize = chunksize(next); + if (oldsize + nextsize >= nb) { + size_t rsize = oldsize + nextsize - nb; + unlink_chunk(m, next, nextsize); + if (rsize < MIN_CHUNK_SIZE) { + size_t newsize = oldsize + nextsize; + set_inuse(m, p, newsize); + } + else { + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + newp = p; + } + } + } + else { + USAGE_ERROR_ACTION(m, chunk2mem(p)); + } + return newp; +} + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + void* mem = 0; + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + mem = internal_malloc(m, req); + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (PREACTION(m)) + return 0; + if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = newsize; + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + dispose_chunk(m, p, leadsize); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + dispose_chunk(m, remainder, remainder_size); + } + } + + mem = chunk2mem(p); + assert (chunksize(p) >= nb); + assert(((size_t)mem & (alignment - 1)) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + } + } + return mem; +} + +/* + Common support for independent_X routines, handling + all of the combinations that can result. + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed +*/ +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + ensure_initialization(); + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + +/* Try to free all pointers in the given array. + Note: this could be made faster, by delaying consolidation, + at the price of disabling some user integrity checks, We + still optimize some consolidations by combining adjacent + chunks before freeing, which will occur often if allocated + with ialloc or the array is sorted. +*/ +static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) { + size_t unfreed = 0; + if (!PREACTION(m)) { + void** a; + void** fence = &(array[nelem]); + for (a = array; a != fence; ++a) { + void* mem = *a; + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t psize = chunksize(p); +#if FOOTERS + if (get_mstate_for(p) != m) { + ++unfreed; + continue; + } +#endif + check_inuse_chunk(m, p); + *a = 0; + if (RTCHECK(ok_address(m, p) && ok_inuse(p))) { + void ** b = a + 1; /* try to merge with next chunk */ + mchunkptr next = next_chunk(p); + if (b != fence && *b == chunk2mem(next)) { + size_t newsize = chunksize(next) + psize; + set_inuse(m, p, newsize); + *b = chunk2mem(p); + } + else + dispose_chunk(m, p, psize); + } + else { + CORRUPTION_ERROR_ACTION(m); + break; + } + } + } + if (should_trim(m, m->topsize)) + sys_trim(m, 0); + POSTACTION(m); + } + return unfreed; +} + +/* Traversal */ +#if MALLOC_INSPECT_ALL +static void internal_inspect_all(mstate m, + void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { + if (is_initialized(m)) { + mchunkptr top = m->top; + msegmentptr s; + for (s = &m->seg; s != 0; s = s->next) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) { + mchunkptr next = next_chunk(q); + size_t sz = chunksize(q); + size_t used; + void* start; + if (is_inuse(q)) { + used = sz - CHUNK_OVERHEAD; /* must not be mmapped */ + start = chunk2mem(q); + } + else { + used = 0; + if (is_small(sz)) { /* offset by possible bookkeeping */ + start = (void*)((char*)q + sizeof(struct malloc_chunk)); + } + else { + start = (void*)((char*)q + sizeof(struct malloc_tree_chunk)); + } + } + if (start < (void*)next) /* skip if all space is bookkeeping */ + handler(start, next, used, arg); + if (q == top) + break; + q = next; + } + } + } +} +#endif /* MALLOC_INSPECT_ALL */ + +/* ------------------ Exported realloc, memalign, etc -------------------- */ + +#if !ONLY_MSPACES + +void* dlrealloc(void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem == 0) { + mem = dlmalloc(bytes); + } + else if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } +#ifdef REALLOC_ZERO_BYTES_FREES + else if (bytes == 0) { + dlfree(oldmem); + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + if (newp != 0) { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } + else { + mem = internal_malloc(m, bytes); + if (mem != 0) { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + } + } + } + return mem; +} + +void* dlrealloc_in_place(void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem != 0) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); + POSTACTION(m); + if (newp == oldp) { + check_inuse_chunk(m, newp); + mem = oldmem; + } + } + } + } + return mem; +} + +void* dlmemalign(size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) { + return dlmalloc(bytes); + } + return internal_memalign(gm, alignment, bytes); +} + +int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { + void* mem = 0; + if (alignment == MALLOC_ALIGNMENT) + mem = dlmalloc(bytes); + else { + size_t d = alignment / sizeof(void*); + size_t r = alignment % sizeof(void*); + if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0) + return EINVAL; + else if (bytes <= MAX_REQUEST - alignment) { + if (alignment < MIN_CHUNK_SIZE) + alignment = MIN_CHUNK_SIZE; + mem = internal_memalign(gm, alignment, bytes); + } + } + if (mem == 0) + return ENOMEM; + else { + *pp = mem; + return 0; + } +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +size_t dlbulk_free(void* array[], size_t nelem) { + return internal_bulk_free(gm, array, nelem); +} + +#if MALLOC_INSPECT_ALL +void dlmalloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { + ensure_initialization(); + if (!PREACTION(gm)) { + internal_inspect_all(gm, handler, arg); + POSTACTION(gm); + } +} +#endif /* MALLOC_INSPECT_ALL */ + +int dlmalloc_trim(size_t pad) { + int result = 0; + ensure_initialization(); + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +size_t dlmalloc_footprint_limit(void) { + size_t maf = gm->footprint_limit; + return maf == 0 ? MAX_SIZE_T : maf; +} + +size_t dlmalloc_set_footprint_limit(size_t bytes) { + size_t result; /* invert sense of 0 */ + if (bytes == 0) + result = granularity_align(1); /* Use minimal size */ + if (bytes == MAX_SIZE_T) + result = 0; /* disable */ + else + result = granularity_align(bytes); + return gm->footprint_limit = result; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +#if !NO_MALLOC_STATS +void dlmalloc_stats() { + internal_malloc_stats(gm); +} +#endif /* NO_MALLOC_STATS */ + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (is_inuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +#endif /* !ONLY_MSPACES */ + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + (void)INITIAL_LOCK(&m->mutex); + msp->head = (msize|INUSE_BITS); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + m->mflags = mparams.default_mflags; + m->extp = 0; + m->exts = 0; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char* tbase = (char*)(CALL_MMAP(tsize)); + if (tbase != CMFAIL) { + m = init_user_mstate(tbase, tsize); + m->seg.sflags = USE_MMAP_BIT; + set_lock(m, locked); + } + } + return (mspace)m; +} + +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); + m->seg.sflags = EXTERN_BIT; + set_lock(m, locked); + } + return (mspace)m; +} + +int mspace_track_large_chunks(mspace msp, int enable) { + int ret = 0; + mstate ms = (mstate)msp; + if (!PREACTION(ms)) { + if (!use_mmap(ms)) { + ret = 1; + } + if (!enable) { + enable_mmap(ms); + } else { + disable_mmap(ms); + } + POSTACTION(ms); + } + return ret; +} + +size_t destroy_mspace(mspace msp) { + size_t freed = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + msegmentptr sp = &ms->seg; + (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */ + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + flag_t flag = sp->sflags; + (void)base; /* placate people compiling -Wunused-variable */ + sp = sp->next; + if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + freed += size; + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + +void* mspace_malloc(mspace msp, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + (void)msp; /* placate people compiling -Wunused */ +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +} + +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = internal_malloc(ms, req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem == 0) { + mem = mspace_malloc(msp, bytes); + } + else if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } +#ifdef REALLOC_ZERO_BYTES_FREES + else if (bytes == 0) { + mspace_free(msp, oldmem); + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = (mstate)msp; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + if (newp != 0) { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } + else { + mem = mspace_malloc(m, bytes); + if (mem != 0) { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes)? oc : bytes); + mspace_free(m, oldmem); + } + } + } + } + return mem; +} + +void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem != 0) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = (mstate)msp; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + (void)msp; /* placate people compiling -Wunused */ + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); + POSTACTION(m); + if (newp == oldp) { + check_inuse_chunk(m, newp); + mem = oldmem; + } + } + } + } + return mem; +} + +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (alignment <= MALLOC_ALIGNMENT) + return mspace_malloc(msp, bytes); + return internal_memalign(ms, alignment, bytes); +} + +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) { + return internal_bulk_free((mstate)msp, array, nelem); +} + +#if MALLOC_INSPECT_ALL +void mspace_inspect_all(mspace msp, + void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + internal_inspect_all(ms, handler, arg); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} +#endif /* MALLOC_INSPECT_ALL */ + +int mspace_trim(mspace msp, size_t pad) { + int result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +#if !NO_MALLOC_STATS +void mspace_malloc_stats(mspace msp) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + internal_malloc_stats(ms); + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} +#endif /* NO_MALLOC_STATS */ + +size_t mspace_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +size_t mspace_max_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->max_footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +size_t mspace_footprint_limit(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + size_t maf = ms->footprint_limit; + result = (maf == 0) ? MAX_SIZE_T : maf; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +size_t mspace_set_footprint_limit(mspace msp, size_t bytes) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (bytes == 0) + result = granularity_align(1); /* Use minimal size */ + if (bytes == MAX_SIZE_T) + result = 0; /* disable */ + else + result = granularity_align(bytes); + ms->footprint_limit = result; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +size_t mspace_usable_size(const void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (is_inuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int mspace_mallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea + * fix bad comparison in dlposix_memalign + * don't reuse adjusted asize in sys_alloc + * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion + * reduce compiler warnings -- thanks to all who reported/suggested these + + v2.8.5 Sun May 22 10:26:02 2011 Doug Lea (dl at gee) + * Always perform unlink checks unless INSECURE + * Add posix_memalign. + * Improve realloc to expand in more cases; expose realloc_in_place. + Thanks to Peter Buhr for the suggestion. + * Add footprint_limit, inspect_all, bulk_free. Thanks + to Barry Hayes and others for the suggestions. + * Internal refactorings to avoid calls while holding locks + * Use non-reentrant locks by default. Thanks to Roland McGrath + for the suggestion. + * Small fixes to mspace_destroy, reset_on_error. + * Various configuration extensions/changes. Thanks + to all who contributed these. + + V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu) + * Update Creative Commons URL + + V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee) + * Use zeros instead of prev foot for is_mmapped + * Add mspace_track_large_chunks; thanks to Jean Brouwers + * Fix set_inuse in internal_realloc; thanks to Jean Brouwers + * Fix insufficient sys_alloc padding when using 16byte alignment + * Fix bad error check in mspace_footprint + * Adaptations for ptmalloc; thanks to Wolfram Gloger. + * Reentrant spin locks; thanks to Earl Chew and others + * Win32 improvements; thanks to Niall Douglas and Earl Chew + * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options + * Extension hook in malloc_state + * Various small adjustments to reduce warnings on some compilers + * Various configuration extensions/changes for more platforms. Thanks + to all who contributed these. + + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index c793544df5c..f78558a54b3 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -35,6 +35,12 @@ extern SDL_Palette *pal_palette; #define pal_surface _ZN3dvl11pal_surfaceE extern SDL_Surface *pal_surface; +#define gbRunGame _ZN3dvl9gbRunGameE +extern int gbRunGame; + +#define gbRunGameResult _ZN3dvl15gbRunGameResultE +extern int gbRunGameResult; + // #define sgdwCursYOld _ZN3dvl12sgdwCursYOldE // extern LONG sgdwCursYOld; @@ -195,6 +201,16 @@ int vampire_Flip(SDL_Surface* surf) int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect) { + ULONG signal = SetSignal(0,0); + if(signal & SIGBREAKF_CTRL_F) { + SetSignal(0, SIGBREAKF_CTRL_F); + dlmalloc_stats(); + } + if(signal & SIGBREAKF_CTRL_C) { + SetSignal(0, SIGBREAKF_CTRL_C); + printf("Ctrl-C received\n"); + gbRunGameResult = gbRunGame = 0; + } if(ok(dst)) { static int last_version; // if(srcRect==NULL || srcRect->w==SCREEN_HEIGHT) { @@ -271,3 +287,55 @@ int zzzvampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, // return SDL_LowerBlit(src, srcRect, dst, dstRect); return SDL_BlitSurface(src, srcRect, dst, dstRect); } + + +/*****************************************************************************/ + +#define USE_DL_PREFIX +#define HAVE_MORECORE 0 + +#define HAVE_MMAP 1 +#define HAVE_MUNMAP 1 +#define MMAP_CLEARS 0 +#define HAVE_MREMAP 0 +#define LACKS_SYS_MMAN_H + +#define MMAP my_mmap +#define MUNMAP my_munmap +#define DIRECT_MMAP MMAP + +#define SANITY 0 + +static void* MMAP(size_t len) +{ + void *p = malloc(len+4); // +1 to avoid contiguous +#if SANITY + if(p) { + ULONG *q = p; + *q = q; + p = ++q; + } + printf("MMAP(%d) = %p\n", len, p); +#endif + return p; +} + +static int MUNMAP(void *p, size_t len) +{ +#if SANITY + printf("MUNMAP(%p, %d)\n", p, len); + if(p) { + ULONG *q = p; --q; + if(*q == q) p = q; + else { + errno = EINVAL; + printf("Not MMAP!\n"); + return -1; + } + } +#endif + free(p); + return 0; +} + +#include "malloc.c" \ No newline at end of file From b8168920bbb59efd5fd3b48958bc058f931a2a3d Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 16 Dec 2019 20:05:48 +0100 Subject: [PATCH 031/107] now uses a 16bits buffer ==> works even faster --- 3rdParty/libsmacker/smk_bitstream.c | 411 +++++++++++++++------------- 1 file changed, 223 insertions(+), 188 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 22703b5c54b..c71de97b018 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -1,12 +1,12 @@ /** - libsmacker - A C library for decoding .smk Smacker Video files - Copyright (C) 2012-2017 Greg Kennedy + libsmacker - A C library for decoding .smk Smacker Video files + Copyright (C) 2012-2017 Greg Kennedy - See smacker.h for more information. + See smacker.h for more information. - smk_bitstream.c - Implements a bitstream structure, which can extract and - return a bit at a time from a raw block of bytes. + smk_bitstream.c + Implements a bitstream structure, which can extract and + return a bit at a time from a raw block of bytes. */ #include "smk_bitstream.h" @@ -15,265 +15,300 @@ #include "smk_malloc.h" #if 1 /* SAM's version */ +// #undef __mc68000__ // to test C version struct smk_bit_t { - unsigned short buf; - unsigned char *ptr, *end; - unsigned long siz; + unsigned short buf; + unsigned char *ptr, *end_m1; + unsigned long siz; }; struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) { - struct smk_bit_t* ret = NULL; + struct smk_bit_t* ret = NULL; - /* sanity check */ - smk_assert(b); + /* sanity check */ + smk_assert(b); - /* allocate a bitstream struct */ - smk_malloc(ret, sizeof(struct smk_bit_t)); + /* allocate a bitstream struct */ + smk_malloc(ret, sizeof(struct smk_bit_t)); - /* set up the pointer to bitstream, and the size counter */ - ret->buf = 1; - ret->ptr = b; - ret->end = b + size; - ret->siz = size; + /* set up the pointer to bitstream, and the size counter */ + ret->buf = 1; + ret->ptr = b; + ret->end_m1 = b + size - 1; + ret->siz = size; - /* point to initial byte: note, smk_malloc already sets these to 0 */ - /* ret->byte_num = 0; - ret->bit_num = 0; */ + /* point to initial byte: note, smk_malloc already sets these to 0 */ + /* ret->byte_num = 0; + ret->bit_num = 0; */ - /* return ret or NULL if error : ) */ + /* return ret or NULL if error : ) */ error: - return ret; + return ret; } unsigned char _smk_error(struct smk_bit_t* bs) { - fprintf(stderr, "libsmacker::_smk_bs_read_?(bs=%p): ERROR: bitstream (length=%lu, ptr=%p, end=%p) exhausted.\n", bs, bs->siz, bs->ptr, bs->end); - bs->buf=1; - return -1; + fprintf(stderr, "libsmacker::_smk_bs_read_?(bs=%p): ERROR: bitstream (length=%lu, ptr=%p, end=%p) exhausted.\n", bs, bs->siz, bs->ptr, bs->end_m1+1); + bs->buf=1; + return -1; } /* Reads a bit - Returns -1 if error encountered */ + Returns -1 if error encountered */ char _smk_bs_read_1(struct smk_bit_t* bs) { - /* sanity check */ - // smk_assert(bs); - { + /* sanity check */ + // smk_assert(bs); + { #ifdef __mc68000__ - register unsigned char ret asm("d0"); - register struct smk_bit_t* bs_ asm("a0") = bs; - __asm__ __volatile__ ( - " moveq #0,d0 \n" - " lsr.w (a0) \n" - " bne.b .lab%= \n" - " move.l 2(a0),a1 \n" - " cmp.l 6(a0),a1 \n" + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " moveq #0,d0 \n" + " lsr.w (a0) \n" + " bne.b .result%= \n" + " move.l 2(a0),a1 \n" + " cmp.l 6(a0),a1 \n" #ifdef __PROFILE__ - " bcc __smk_error \n" + " bhi __smk_error \n" #else - " bcc.b __smk_error \n" + " bhi.b __smk_error \n" #endif - " move.w #256,d1 \n" - " move.b (a1)+,d1 \n" - " lsr.w #1,d1 \n" - " move.w d1,(a0) \n" - " move.l a1,2(a0) \n" - ".lab%=: \n" - " addx.l d0,d0 \n" - : "=d" (ret) : "a" (bs_) - : "d1","a1","a0" ); - return ret; + " beq.b .only_one%= \n" + " moveq #-1,d1 \n" + " move.w (a1)+,d1 \n" + " ror.w #8,d1 \n" + " lsr.l #1,d1 \n" + " bra.b .set_buf%= \n" + ".only_one%=: \n" + " move.w #256,d1 \n" + " move.b (a1)+,d1 \n" + " lsr.w #1,d1 \n" + ".set_buf%=: \n" + " move.w d1,(a0) \n" + " move.l a1,2(a0) \n" + ".result%=: \n" + " addx.l d0,d0 \n" + : "=d" (ret) : "a" (bs_) + : "d1","a1","a0" ); + return ret; #else - unsigned short ret; - - ret = bs->buf; bs->buf >>= 1; - if(!bs->buf) { - if(bs->ptr >= bs->end) return _smk_error(bs); - ret = 256; ret |= *bs->ptr++; - bs->buf = ret>>1; - } - return ret & 1; + unsigned short ret; + + ret = bs->buf; bs->buf >>= 1; + if(!bs->buf) { + if(bs->ptr > bs->end_m1) return _smk_error(bs); + if(bs->ptr == bs->end_m1) { // only 1 byte remaining in stream + ret = 256; ret |= *bs->ptr++; + bs->buf = ret>>1; + } else { + ret = *bs->ptr++; + ret |= (*bs->ptr++)<<8; + bs->buf = (ret>>1)|(unsigned short)32768; + } + } + return ret & 1; #endif - } + } } /* Reads a byte - Returns -1 if error. */ + Returns -1 if error. */ short _smk_bs_read_8(struct smk_bit_t* bs) { - /* sanity check */ - // smk_assert(bs); - { + /* sanity check */ + // smk_assert(bs); + { #ifdef __mc68000__ - register unsigned char ret asm("d0"); - register struct smk_bit_t* bs_ asm("a0") = bs; - __asm__ __volatile__ ( - " move.l 2(a0),a1 \n" - " cmp.l 6(a0),a1 \n" + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + + __asm__ __volatile__ ( + " move.l 2(a0),a1 \n" + " cmp.l 6(a0),a1 \n" #ifdef __PROFILE__ - " bcc __smk_error \n" + " bhi __smk_error \n" #else - " bcc.b __smk_error \n" + // " bhi.b __smk_error \n" #endif - " addq.l #1,2(a0) \n" - " moveq #0,d0 \n" - " moveq #1,d1 \n" - " move.w (a0),d0 \n" - " cmp.w d1,d0 \n" - " bhi.b .lab%= \n" - " move.b (a1),d0 \n" - " bra.b .xit%= \n" - ".lab%=: \n" - " swap d1 \n" - " move.w (a1),d1 \n" - " move.b d0,d1 \n" - " bfffo d0{24:8},d0 \n" - " sub.w #23,d0 \n" - " lsl.b d0,d1 \n" - " lsr.l d0,d1 \n" - // " moveq #0,d0\n" // necessaire ???? - " move.b d1,d0 \n" - " lsr.l #8,d1 \n" - " move.w d1,(a0) \n" - ".xit%=: \n" - : "=d" (ret) : "a" (bs_) - : "d1","a1","a0"); + // a = bs->buf + " moveq #0,d0 \n" + " move.w (a0),d0 \n" + // a <= 1 ? + " moveq #1,d1 \n" + " cmp.w d1,d0 \n" + " bhi.b .l1.%= \n" + // yes ==> return *bs-ptr++ + " addq.l #1,2(a0) \n" + " move.b (a1),d0 \n" + " bra.b .xit%= \n" + ".l1.%=: \n" + // a < 256 ? + " cmp.w #256,d0 \n" + " bcs.b .l2.%= \n" + // no ==> more than 1 byte left, extract it + " exg d0,d1 \n" + " bra.b .l3.%= \n" + ".l2.%=: \n" + // yes ==> inject next byte + " addq.l #1,2(a0) \n" + " swap d1 \n" + " move.w (a1),d1 \n" + " move.b d0,d1 \n" + " bfffo d0{24:8},d0 \n" + " sub.w #23,d0 \n" + " lsl.b d0,d1 \n" + " lsr.l d0,d1 \n" + ".l3.%=: \n" + " move.b d1,d0 \n" + " lsr.l #8,d1 \n" + " move.w d1,(a0) \n" + ".xit%=: \n" + : "=d" (ret) : "a" (bs_) + : "d1","a1","a0"); #else - unsigned char ret; unsigned short a; - - if(bs->ptr >= bs->end) return _smk_error(bs); - - // aligned - a = bs->buf; - if(a <= 1) return *bs->ptr++; - - // find leftmost bit - ret = a; a |= a>>1; a |= a>>2; a |= a>>4; a >>= 1; a += 1; - - // remove it from current buffer - ret ^= a; - - // shift next byte + setup sentinel - a *= *bs->ptr++ | (unsigned short)256; - - // inject current - a |= ret; - - // setup result + shift buffer - ret = a; bs->buf = a>>8; - - return ret; + unsigned char ret; unsigned short a; + + if(bs->ptr > bs->end_m1) return _smk_error(bs); + + // aligned + a = bs->buf; + if(a <= 1) return *bs->ptr++; + + // more than 1 byte left + a = bs->buf; + if(a>=256) { + ret = a; + bs->buf = a>>8; + } else { + // find leftmost bit + ret = a; a |= a>>1; a |= a>>2; a |= a>>4; a >>= 1; a += 1; + + // remove it from current buffer + ret ^= a; + + // shift next byte + setup sentinel + a *= *bs->ptr++ | (unsigned short)256; + + // inject current + a |= ret; + + // setup result + shift buffer + ret = a; bs->buf = a>>8; + } + + return ret; #endif - } + } } #else /* - Bitstream structure - Pointer to raw block of data and a size limit. - Maintains internal pointers to byte_num and bit_number. + Bitstream structure + Pointer to raw block of data and a size limit. + Maintains internal pointers to byte_num and bit_number. */ struct smk_bit_t { - const unsigned char* buffer; - unsigned long size; + const unsigned char* buffer; + unsigned long size; - unsigned long byte_num; - char bit_num; + unsigned long byte_num; + char bit_num; }; /* BITSTREAM Functions */ struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) { - struct smk_bit_t* ret = NULL; + struct smk_bit_t* ret = NULL; - /* sanity check */ - smk_assert(b); + /* sanity check */ + smk_assert(b); - /* allocate a bitstream struct */ - smk_malloc(ret, sizeof(struct smk_bit_t)); + /* allocate a bitstream struct */ + smk_malloc(ret, sizeof(struct smk_bit_t)); - /* set up the pointer to bitstream, and the size counter */ - ret->buffer = b; - ret->size = size; + /* set up the pointer to bitstream, and the size counter */ + ret->buffer = b; + ret->size = size; - /* point to initial byte: note, smk_malloc already sets these to 0 */ - /* ret->byte_num = 0; - ret->bit_num = 0; */ + /* point to initial byte: note, smk_malloc already sets these to 0 */ + /* ret->byte_num = 0; + ret->bit_num = 0; */ - /* return ret or NULL if error : ) */ + /* return ret or NULL if error : ) */ error: - return ret; + return ret; } /* Reads a bit - Returns -1 if error encountered */ + Returns -1 if error encountered */ char _smk_bs_read_1(struct smk_bit_t* bs) { - unsigned char ret = -1; + unsigned char ret = -1; - /* sanity check */ - smk_assert(bs); + /* sanity check */ + smk_assert(bs); - /* don't die when running out of bits, but signal */ - if (bs->byte_num >= bs->size) - { - fprintf(stderr, "libsmacker::_smk_bs_read_1(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs->size); - goto error; - } + /* don't die when running out of bits, but signal */ + if (bs->byte_num >= bs->size) + { + fprintf(stderr, "libsmacker::_smk_bs_read_1(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs->size); + goto error; + } - /* get next bit and return */ - ret = (((bs->buffer[bs->byte_num]) & (1 << bs->bit_num)) != 0); + /* get next bit and return */ + ret = (((bs->buffer[bs->byte_num]) & (1 << bs->bit_num)) != 0); - /* advance to next bit */ - bs->bit_num ++; + /* advance to next bit */ + bs->bit_num ++; - /* Out of bits in this byte: next! */ - if (bs->bit_num > 7) - { - bs->byte_num ++; - bs->bit_num = 0; - } + /* Out of bits in this byte: next! */ + if (bs->bit_num > 7) + { + bs->byte_num ++; + bs->bit_num = 0; + } - /* return ret, or (default) -1 if error */ + /* return ret, or (default) -1 if error */ error: - return ret; + return ret; } /* Reads a byte - Returns -1 if error. */ + Returns -1 if error. */ short _smk_bs_read_8(struct smk_bit_t* bs) { - unsigned char ret = -1; - - /* sanity check */ - smk_assert(bs); - - /* don't die when running out of bits, but signal */ - if (bs->byte_num + (bs->bit_num > 0) >= bs->size) - { - fprintf(stderr, "libsmacker::_smk_bs_read_8(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs->size); - goto error; - } - - if (bs->bit_num) - { - /* unaligned read */ - ret = bs->buffer[bs->byte_num] >> bs->bit_num; - bs->byte_num ++; - ret |= (bs->buffer[bs->byte_num] << (8 - bs->bit_num)); - } else { - /* aligned read */ - ret = bs->buffer[bs->byte_num ++]; - } - - /* return ret, or (default) -1 if error */ + unsigned char ret = -1; + + /* sanity check */ + smk_assert(bs); + + /* don't die when running out of bits, but signal */ + if (bs->byte_num + (bs->bit_num > 0) >= bs->size) + { + fprintf(stderr, "libsmacker::_smk_bs_read_8(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs->size); + goto error; + } + + if (bs->bit_num) + { + /* unaligned read */ + ret = bs->buffer[bs->byte_num] >> bs->bit_num; + bs->byte_num ++; + ret |= (bs->buffer[bs->byte_num] << (8 - bs->bit_num)); + } else { + /* aligned read */ + ret = bs->buffer[bs->byte_num ++]; + } + + /* return ret, or (default) -1 if error */ error: - return ret; + return ret; } #endif \ No newline at end of file From 4421e53722e04df42e14bbe3dcd8773639f253d1 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 11:55:17 +0100 Subject: [PATCH 032/107] get rid of SDL clipping when rendering video --- CMake/amiga/m68k-amigaos.cmake | 19 ++++++++++++++++--- SourceX/storm/storm.cpp | 9 +++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 1b4d02b50eb..f1973a625e1 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -24,6 +24,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(AMIGA 1) set(AMIGAOS3 1) +set(PROFILE 0) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") @@ -50,8 +51,12 @@ if(WIN32) endif() # Compiler flags -# set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -Dfomit-frame-pointer -D__PROFILE__ -pg -g -noixemul") -set(FLAGS_COMMON "-m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -fomit-frame-pointer -g -noixemul") +if(PROFILE) + set(FLAGS_COMMON "-D__PROFILE__ -pg") +else() + set(FLAGS_COMMON "-fomit-frame-pointer") +endif() +set(FLAGS_COMMON "${FLAGS_COMMON} -m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") @@ -60,7 +65,15 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -Wl,--wrap=memcpy -Wl,--wrap=memset -Wl,--wrap=memcmp -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") + +# wrapper - replace gcc functions by our own +foreach(_wrapped + memcpy + memset + memcmp) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=${_wrapped}") +endforeach(_wrapped) set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") # user diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 03591c5bfd1..01c38979912 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -673,6 +673,15 @@ BOOL SVidPlayContinue(void) return false; } } else +#endif +#ifdef __AMIGA__ + // speedup get rid of SDL here + if(GetOutputSurface()->pitch == SVidSurface->pitch + && GetOutputSurface()->h >= SVidSurface->h) { + SDL_Surface *out = GetOutputSurface(); + unsigned char *dst = out->pixels + out->pitch*((out->h - SVidSurface->h)/2); + memcpy(dst, SVidSurface->pixels, SVidSurface->pitch*SVidSurface->h); + } else #endif { int factor; From 2d4dc8492c3ef80ebaf4afdac738b3fa0fb7f8ad Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 11:55:39 +0100 Subject: [PATCH 033/107] typo --- SourceX/platform/amiga/render68k.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 11ff99a87ea..45815f79ea5 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -650,7 +650,7 @@ unroll macro \1 0 \1 0 \1 1 - rts_bounds + rts_bounds \1_4 btst #4,d0 beq \1_2 @@ -676,7 +676,7 @@ unroll macro beq \3_2 \3 \3_2 - rts_bounds + rts_bounds endm loop macro From ffef61bd690a72a7fa09433a955d1d426660b3e0 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 12:18:37 +0100 Subject: [PATCH 034/107] slight speedup in smk --- 3rdParty/libsmacker/smk_bitstream.c | 17 +++++++++-------- 3rdParty/libsmacker/smk_hufftree.c | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index c71de97b018..2137c18698a 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -77,16 +77,17 @@ char _smk_bs_read_1(struct smk_bit_t* bs) #else " bhi.b __smk_error \n" #endif - " beq.b .only_one%= \n" - " moveq #-1,d1 \n" - " move.w (a1)+,d1 \n" - " ror.w #8,d1 \n" - " lsr.l #1,d1 \n" - " bra.b .set_buf%= \n" + " bne.b .get_two%= \n" ".only_one%=: \n" " move.w #256,d1 \n" " move.b (a1)+,d1 \n" " lsr.w #1,d1 \n" + " bra.b .set_buf%= \n" + ".get_two%=: \n" + " moveq #-1,d1 \n" + " move.w (a1)+,d1 \n" + " ror.w #8,d1 \n" + " lsr.l #1,d1 \n" ".set_buf%=: \n" " move.w d1,(a0) \n" " move.l a1,2(a0) \n" @@ -125,7 +126,7 @@ short _smk_bs_read_8(struct smk_bit_t* bs) #ifdef __mc68000__ register unsigned char ret asm("d0"); register struct smk_bit_t* bs_ asm("a0") = bs; - + __asm__ __volatile__ ( " move.l 2(a0),a1 \n" " cmp.l 6(a0),a1 \n" @@ -153,7 +154,7 @@ short _smk_bs_read_8(struct smk_bit_t* bs) " exg d0,d1 \n" " bra.b .l3.%= \n" ".l2.%=: \n" - // yes ==> inject next byte + // yes ==> inject next byte " addq.l #1,2(a0) \n" " swap d1 \n" " move.w (a1),d1 \n" diff --git a/3rdParty/libsmacker/smk_hufftree.c b/3rdParty/libsmacker/smk_hufftree.c index cda61fd48a2..0c7bee3092d 100644 --- a/3rdParty/libsmacker/smk_hufftree.c +++ b/3rdParty/libsmacker/smk_hufftree.c @@ -361,7 +361,7 @@ int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const __asm__ __volatile__ ( " move.l %2,-(sp) \n" ".L0%=: \n" - " jsr %3 \n" + " bsr %3 \n" " tst.b d0 \n" // TODO error ?? " beq.b .L1%= \n" From 1ef3c13bea275c78907965bafe38d5ee62c8a1ab Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 14:19:10 +0100 Subject: [PATCH 035/107] Ctrl-C now should work even when menus are active --- SourceX/platform/amiga/support.c | 59 +++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index f78558a54b3..71b838e56d8 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -35,11 +35,22 @@ extern SDL_Palette *pal_palette; #define pal_surface _ZN3dvl11pal_surfaceE extern SDL_Surface *pal_surface; -#define gbRunGame _ZN3dvl9gbRunGameE -extern int gbRunGame; +// #define gbRunGame _ZN3dvl9gbRunGameE +// extern int gbRunGame; -#define gbRunGameResult _ZN3dvl15gbRunGameResultE -extern int gbRunGameResult; +// #define gbRunGameResult _ZN3dvl15gbRunGameResultE +// extern int gbRunGameResult; + +// #define MainMenuResult __ZN3dvl16gbProcessPlayersE + +// #define PressEscKey _ZN3dvl11PressEscKeyEv +// extern int PressEscKey(void); + +#define gamemenu_quit_game _ZN3dvl18gamemenu_quit_gameEi +extern void gamemenu_quit_game(int); + +// #define mainmenu_Esc _ZN3dvl12mainmenu_EscEv +// extern void mainmenu_Esc(void); // #define sgdwCursYOld _ZN3dvl12sgdwCursYOldE // extern LONG sgdwCursYOld; @@ -133,6 +144,32 @@ static void start(void) } } +static void chkSignals(void) +{ + ULONG signal = SetSignal(0,0); + if(signal & SIGBREAKF_CTRL_E) { + SetSignal(0, SIGBREAKF_CTRL_E); + dlmalloc_stats(); + } + if(signal & SIGBREAKF_CTRL_C) { + WORD i; + + SetSignal(0, SIGBREAKF_CTRL_C); + printf("Ctrl-C received\n"); + gamemenu_quit_game(0); + + // when in menu use esc + for(i=5; i-->=0;) { + SDL_Event sdlevent; + sdlevent.type = SDL_KEYDOWN; + sdlevent.key.keysym.sym = SDLK_ESCAPE; + SDL_PushEvent(&sdlevent); + } + +// gbRunGameResult = gbRunGame = 0; + } +} + static int ok(SDL_Surface *const surf) { if(!started) start(); @@ -149,6 +186,8 @@ int vampire_Flip(SDL_Surface* surf) struct Screen *first_screen; static UBYTE panel_cpy_flag = 4; + chkSignals(); + #if DIRTY *dpy = (void*)(~31&(int)surf->pixels); return; @@ -156,8 +195,6 @@ int vampire_Flip(SDL_Surface* surf) if(!ok(surf)) goto legacy; - // SDL_SetColors(saga_surface, pal_palette->colors, 0, pal_palette->ncolors); - surf = saga_surface; #if CHECK_FIRSTSCREEN @@ -201,16 +238,6 @@ int vampire_Flip(SDL_Surface* surf) int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect) { - ULONG signal = SetSignal(0,0); - if(signal & SIGBREAKF_CTRL_F) { - SetSignal(0, SIGBREAKF_CTRL_F); - dlmalloc_stats(); - } - if(signal & SIGBREAKF_CTRL_C) { - SetSignal(0, SIGBREAKF_CTRL_C); - printf("Ctrl-C received\n"); - gbRunGameResult = gbRunGame = 0; - } if(ok(dst)) { static int last_version; // if(srcRect==NULL || srcRect->w==SCREEN_HEIGHT) { From 3faf0207123016814903fd2eb50b46317ffea15b Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 17:35:00 +0100 Subject: [PATCH 036/107] improved ctrl-c support when in character selection menu --- SourceX/platform/amiga/support.c | 183 ++++++++++++++++--------------- 1 file changed, 93 insertions(+), 90 deletions(-) diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index 71b838e56d8..693fcb0cbf1 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -3,6 +3,7 @@ */ //#include +#include #include #include @@ -49,6 +50,9 @@ extern SDL_Surface *pal_surface; #define gamemenu_quit_game _ZN3dvl18gamemenu_quit_gameEi extern void gamemenu_quit_game(int); +#define mainmenu_restart_repintro _ZN3dvl25mainmenu_restart_repintroEv +extern void mainmenu_restart_repintro(void); + // #define mainmenu_Esc _ZN3dvl12mainmenu_EscEv // extern void mainmenu_Esc(void); @@ -77,6 +81,64 @@ struct Library *VampireBase; extern struct ExecBase *SysBase; extern struct IntuitionBase *IntuitionBase; +/*****************************************************************************/ +/* malloc replacement */ + +#define USE_DL_PREFIX + +#define SANITY_CHK 0 + +#define lower_malloc malloc +#define lower_free free + +#define HAVE_MORECORE 0 + +#define HAVE_MMAP 1 +#define HAVE_MUNMAP 1 +#define MMAP_CLEARS 0 +#define HAVE_MREMAP 0 +#define LACKS_SYS_MMAN_H + +#define MMAP my_mmap +#define MUNMAP my_munmap +#define DIRECT_MMAP MMAP + +static void* MMAP(size_t len) +{ + void *p = lower_malloc(len+4); // +1 to avoid contiguous +#if SANITY_CHK + if(p) { + ULONG *q = p; + *q = q; + p = ++q; + } + printf("MMAP(%d) = %p\n", len, p); +#endif + return p; +} + +static int MUNMAP(void *p, size_t len) +{ +#if SANITY_CHK + printf("MUNMAP(%p, %d)\n", p, len); + if(p) { + ULONG *q = p; --q; + if(*q == q) p = q; + else { + errno = EINVAL; + printf("Not MMAP!\n"); + return -1; + } + } +#endif + lower_free(p); + return 0; +} + +#include "malloc.c" + +/*****************************************************************************/ + static void stop(void) { if(saga_surface) { @@ -84,7 +146,7 @@ static void stop(void) saga_surface = NULL; } if(bufmem) { - FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); + dlfree(bufmem); bufmem = NULL; } } @@ -93,34 +155,22 @@ static void start(void) started = 255; atexit(stop); - bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); - if(bufmem) { - saga_surface = SDL_CreateRGBSurfaceFrom( - (UBYTE*)(~31&(31+(ULONG)bufmem)), // 32 bits alignment for saga - SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, - 0, 0, 0, 0 - ); - if(!saga_surface) { - FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); - bufmem = NULL; - } - } - if (SysBase->AttnFlags &(1 << 10)) { ac68080_saga = 255; //!_ZN3dvl10fullscreenE; // disable if not fullscreen - bufmem = AllocMem(3*FRAME_BUFFER_SZ + 31, MEMF_PUBLIC|MEMF_CLEAR); - if(bufmem) { - saga_surface = SDL_CreateRGBSurfaceFrom( - (UBYTE*)(~31&(31+(ULONG)bufmem)), // 32 bits alignment for saga - SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, - 0, 0, 0, 0 - ); - if(!saga_surface) { - FreeMem(bufmem, 3*FRAME_BUFFER_SZ + 31); - bufmem = NULL; - } - } + bufmem = dlmemalign(32/* byte alignment for saga */, 3*FRAME_BUFFER_SZ); + if(bufmem) { + saga_surface = SDL_CreateRGBSurfaceFrom( + bufmem, + SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, + 0, 0, 0, 0 + ); + if(!saga_surface) { + dlfree(bufmem); + bufmem = NULL; + } + } + if(!bufmem) ac68080_saga = 0; if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); @@ -146,27 +196,32 @@ static void start(void) static void chkSignals(void) { + static UBYTE closing; ULONG signal = SetSignal(0,0); + if(closing) { + SDL_Event sdlevent; + sdlevent.type = SDL_KEYDOWN; + sdlevent.key.keysym.sym = SDLK_ESCAPE; + SDL_PushEvent(&sdlevent); + sdlevent.type = SDL_KEYUP; + sdlevent.key.keysym.sym = SDLK_ESCAPE; + SDL_PushEvent(&sdlevent); + } if(signal & SIGBREAKF_CTRL_E) { + time_t t; SetSignal(0, SIGBREAKF_CTRL_E); + + t = time(0); + printf("\nMemory statistics on %s", ctime(&t)); dlmalloc_stats(); + printf("\n"); } if(signal & SIGBREAKF_CTRL_C) { - WORD i; - SetSignal(0, SIGBREAKF_CTRL_C); + printf("Ctrl-C received\n"); gamemenu_quit_game(0); - - // when in menu use esc - for(i=5; i-->=0;) { - SDL_Event sdlevent; - sdlevent.type = SDL_KEYDOWN; - sdlevent.key.keysym.sym = SDLK_ESCAPE; - SDL_PushEvent(&sdlevent); - } - -// gbRunGameResult = gbRunGame = 0; + closing = 255; } } @@ -314,55 +369,3 @@ int zzzvampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, // return SDL_LowerBlit(src, srcRect, dst, dstRect); return SDL_BlitSurface(src, srcRect, dst, dstRect); } - - -/*****************************************************************************/ - -#define USE_DL_PREFIX -#define HAVE_MORECORE 0 - -#define HAVE_MMAP 1 -#define HAVE_MUNMAP 1 -#define MMAP_CLEARS 0 -#define HAVE_MREMAP 0 -#define LACKS_SYS_MMAN_H - -#define MMAP my_mmap -#define MUNMAP my_munmap -#define DIRECT_MMAP MMAP - -#define SANITY 0 - -static void* MMAP(size_t len) -{ - void *p = malloc(len+4); // +1 to avoid contiguous -#if SANITY - if(p) { - ULONG *q = p; - *q = q; - p = ++q; - } - printf("MMAP(%d) = %p\n", len, p); -#endif - return p; -} - -static int MUNMAP(void *p, size_t len) -{ -#if SANITY - printf("MUNMAP(%p, %d)\n", p, len); - if(p) { - ULONG *q = p; --q; - if(*q == q) p = q; - else { - errno = EINVAL; - printf("Not MMAP!\n"); - return -1; - } - } -#endif - free(p); - return 0; -} - -#include "malloc.c" \ No newline at end of file From cc465201d012c4a00d871ea2c58e15e98636deee Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 17:37:29 +0100 Subject: [PATCH 037/107] make StormLib use dlmalloc --- 3rdParty/StormLib/src/StormCommon.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/3rdParty/StormLib/src/StormCommon.h b/3rdParty/StormLib/src/StormCommon.h index 08ab6620bb4..822c1c0bf6e 100644 --- a/3rdParty/StormLib/src/StormCommon.h +++ b/3rdParty/StormLib/src/StormCommon.h @@ -114,6 +114,17 @@ typedef struct _MPQ_SIGNATURE_INFO //#define STORM_FREE(ptr) HeapFree(GetProcessHeap(), 0, ptr) // //#else + +#ifdef __AMIGA__ +#define malloc dlmalloc +#define realloc dlrealloc +#define free dlfree +extern "C" { +void *malloc(size_t len); +void *realloc(void *ptr, size_t len); +void free(void *ptr); +} +#endif #define STORM_ALLOC(type, nitems) (type *)malloc((nitems) * sizeof(type)) #define STORM_REALLOC(type, ptr, nitems) (type *)realloc(ptr, ((nitems) * sizeof(type))) From ff3dc3fcb6d88524879564c74f18e43841a00d86 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 17 Dec 2019 18:50:10 +0100 Subject: [PATCH 038/107] Now automatically check that stack is at least 128kb (experimental minimum being around 64kb) --- CMake/amiga/m68k-amigaos.cmake | 4 +++- SourceX/platform/amiga/support.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index f1973a625e1..019d2b53083 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -65,7 +65,7 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul -Xlinker --allow-multiple-definition ") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul -Xlinker --allow-multiple-definition") # wrapper - replace gcc functions by our own foreach(_wrapped @@ -75,6 +75,8 @@ foreach(_wrapped set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=${_wrapped}") endforeach(_wrapped) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${M68K_TOOLCHAIN_PATH}/m68k-amigaos/libnix/lib/swapstack.o") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -ldebug ") # user set(FREETYPE_INCLUDE_DIRS ${M68K_TOOLCHAIN_PATH}/m68k-amigaos/include) diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/support.c index 693fcb0cbf1..9facf829d7a 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/support.c @@ -50,8 +50,8 @@ extern SDL_Surface *pal_surface; #define gamemenu_quit_game _ZN3dvl18gamemenu_quit_gameEi extern void gamemenu_quit_game(int); -#define mainmenu_restart_repintro _ZN3dvl25mainmenu_restart_repintroEv -extern void mainmenu_restart_repintro(void); +// #define mainmenu_restart_repintro _ZN3dvl25mainmenu_restart_repintroEv +// extern void mainmenu_restart_repintro(void); // #define mainmenu_Esc _ZN3dvl12mainmenu_EscEv // extern void mainmenu_Esc(void); @@ -81,6 +81,15 @@ struct Library *VampireBase; extern struct ExecBase *SysBase; extern struct IntuitionBase *IntuitionBase; +/*****************************************************************************/ +/* stack requirements */ + +#define MINSTACK (128*1024) /* 128kb */ +#ifdef __SASC +__near /* sas/c */ +#endif +size_t __stack = MINSTACK; /* ixemul, vbcc */ + /*****************************************************************************/ /* malloc replacement */ From 8282761f7111a75519c27c18dc16fa932577a76a Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 18 Dec 2019 22:09:05 +0100 Subject: [PATCH 039/107] speedup: now usess regparm(2) for smk bitstreams fcn --- 3rdParty/libsmacker/smk_bitstream.c | 6 +++--- 3rdParty/libsmacker/smk_bitstream.h | 12 ++++++++++-- 3rdParty/libsmacker/smk_hufftree.c | 17 +++++++++++++++-- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 2137c18698a..25f9da5d5c1 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -49,7 +49,7 @@ struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) return ret; } -unsigned char _smk_error(struct smk_bit_t* bs) +REGPARM unsigned char _smk_error(struct smk_bit_t* bs) { fprintf(stderr, "libsmacker::_smk_bs_read_?(bs=%p): ERROR: bitstream (length=%lu, ptr=%p, end=%p) exhausted.\n", bs, bs->siz, bs->ptr, bs->end_m1+1); bs->buf=1; @@ -58,7 +58,7 @@ unsigned char _smk_error(struct smk_bit_t* bs) /* Reads a bit Returns -1 if error encountered */ -char _smk_bs_read_1(struct smk_bit_t* bs) +REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) { /* sanity check */ // smk_assert(bs); @@ -118,7 +118,7 @@ char _smk_bs_read_1(struct smk_bit_t* bs) /* Reads a byte Returns -1 if error. */ -short _smk_bs_read_8(struct smk_bit_t* bs) +REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) { /* sanity check */ // smk_assert(bs); diff --git a/3rdParty/libsmacker/smk_bitstream.h b/3rdParty/libsmacker/smk_bitstream.h index 3a99e209e49..75f0a7dbcf7 100644 --- a/3rdParty/libsmacker/smk_bitstream.h +++ b/3rdParty/libsmacker/smk_bitstream.h @@ -15,6 +15,14 @@ /** Bitstream structure, Forward declaration */ struct smk_bit_t; +#ifdef __AMIGA__ +#define USE_REGPARM 1 +#define REGPARM __attribute__((regparm(2))) +#else +#define USE_REGPARM 0 +#define REGPARM +#endif + /* BITSTREAM Functions */ /** Initialize a bitstream */ struct smk_bit_t* smk_bs_init(const unsigned char* b, unsigned long size); @@ -31,7 +39,7 @@ struct smk_bit_t* smk_bs_init(const unsigned char* b, unsigned long size); } /** Read a single bit from the bitstream, and advance. Returns -1 on error. */ -char _smk_bs_read_1(struct smk_bit_t* bs); +REGPARM char _smk_bs_read_1(struct smk_bit_t* bs); /** This macro checks return code from _smk_bs_read_8 and jumps to error label if problems occur. */ @@ -45,6 +53,6 @@ char _smk_bs_read_1(struct smk_bit_t* bs); } /** Read eight bits from the bitstream (one byte), and advance. Returns -1 on error. */ -short _smk_bs_read_8(struct smk_bit_t* bs); +REGPARM short _smk_bs_read_8(struct smk_bit_t* bs); #endif diff --git a/3rdParty/libsmacker/smk_hufftree.c b/3rdParty/libsmacker/smk_hufftree.c index 0c7bee3092d..9c97d0e73ad 100644 --- a/3rdParty/libsmacker/smk_hufftree.c +++ b/3rdParty/libsmacker/smk_hufftree.c @@ -103,19 +103,25 @@ short _smk_huff8_lookup(struct smk_bit_t* bs, const struct smk_huff8_t* t) #ifdef __mc68000__ if(t->b0) { __asm__ __volatile__ ( +#if !USE_REGPARM " move.l %2,-(sp) \n" +#else + " move.l %2,a0 \n" +#endif ".L0%=: \n" " jsr %3 \n" " tst.b d0 \n" // TODO error ?? " beq.b .L1%= \n" " addq.l #4,%0 \n" - ".L1%=: \n" + ".L1%=: \n" " move.l (%0),%0 \n" " tst.l (%0) \n" " bne.b .L0%= \n" +#if !USE_REGPARM " addq.l #4,sp \n" - : "=&a" (t) +#endif + : "=&a" (t) : "0" (t), "am" (bs), "m" (_smk_bs_read_1) : "d0","d1","a0","a1"); } @@ -353,13 +359,18 @@ struct smk_huff16_t* _smk_huff16_build(struct smk_bit_t* bs) return NULL; } +static inline int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const struct smk_huff8_t* t) { #ifdef __mc68000__ register struct smk_huff8_t *t_ asm("a2") = t; if(t_->b0) { __asm__ __volatile__ ( +#if !USE_REGPARM " move.l %2,-(sp) \n" +#else + " move.l %2,a0 \n" +#endif ".L0%=: \n" " bsr %3 \n" " tst.b d0 \n" @@ -370,7 +381,9 @@ int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const " move.l (a2),a2 \n" " tst.l (a2) \n" " bne.b .L0%= \n" +#if !USE_REGPARM " addq.l #4,sp \n" +#endif : "=&a" (t_) : "0" (t_), "am" (bs), "m" (_smk_bs_read_1) : "d0","d1","a0","a1"); From e3ba799032b5adb7cbfed2f9d819d79a426acfe2 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 18 Dec 2019 22:09:59 +0100 Subject: [PATCH 040/107] speedup WastBit (most used fcn in there) with a bit of inline asm --- 3rdParty/PKWare/explode.cpp | 40 ++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/3rdParty/PKWare/explode.cpp b/3rdParty/PKWare/explode.cpp index 2702c4bfe90..22354131595 100644 --- a/3rdParty/PKWare/explode.cpp +++ b/3rdParty/PKWare/explode.cpp @@ -28,6 +28,9 @@ static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" "Version 1.11\r\n"; +//#define static __attribute__ ((noinline,regparam(2))) +#define static static __attribute__ ((regparam(2))) + //----------------------------------------------------------------------------- // Tables @@ -227,9 +230,43 @@ static void PKWAREAPI GenAscTabs(TDcmpStruct * pWork) // Returns: PKDCL_OK: Operation was successful // PKDCL_STREAM_END: There are no more bits in the input buffer -static int PKWAREAPI WasteBits(TDcmpStruct * pWork, unsigned int nBits) +static int PKWAREAPI WasteBits(TDcmpStruct * const pWork, unsigned int const nBits) { +#ifdef __mc68000__ + unsigned int m; int t = pWork->extra_bits; + // If number of bits required is less than number of (bits in the buffer) ? + if((t -= nBits)<0) { + const TDcmpStruct *zero = 0; + m = 1; // should be 0 but causes a gcc bug + pWork->extra_bits = (t+=8); t += nBits; + + // Load input buffer if necessary + if(pWork->in_pos == pWork->in_bytes) + { + pWork->in_pos = sizeof(pWork->in_buff); + if((pWork->in_bytes = pWork->read_buf(pWork->in_buff, &pWork->in_pos, pWork->param)) == 0) + return PKDCL_STREAM_END; + pWork->in_pos = 0; + } + // Update bit buffer + __asm__ __volatile__ ( + " move.b (%5,%4,%1.l),%0 \n" + " addq.l #1,%1 \n" + " lsl.l %2,%0 \n" + " or.l %3,%0 \n" + : "+d" (m), "+r" (pWork->in_pos) + : "d" (t), "m" (pWork->bit_buff), + "a" (pWork), "m" (zero->in_buff) ); + } else { + pWork->extra_bits = t; + m = pWork->bit_buff; + } +end: + pWork->bit_buff = m >> nBits; + return PKDCL_OK; +#else + // If number of bits required is less than number of (bits in the buffer) ? if(nBits <= pWork->extra_bits) { pWork->extra_bits -= nBits; @@ -252,6 +289,7 @@ static int PKWAREAPI WasteBits(TDcmpStruct * pWork, unsigned int nBits) pWork->bit_buff >>= (nBits - pWork->extra_bits); pWork->extra_bits = (pWork->extra_bits - nBits) + 8; return PKDCL_OK; +#endif } //----------------------------------------------------------------------------- From a6489d44526d55f6eaa379fa4bfd445a903598dc Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 18 Dec 2019 22:10:36 +0100 Subject: [PATCH 041/107] asm + ammx speedup --- 3rdParty/StormLib/src/SBaseCommon.cpp | 114 ++++++++++++++++++++++---- SourceX/platform/amiga/memopt.asm | 53 ++++++++++++ 2 files changed, 149 insertions(+), 18 deletions(-) diff --git a/3rdParty/StormLib/src/SBaseCommon.cpp b/3rdParty/StormLib/src/SBaseCommon.cpp index 4ff2cfe39af..c6757540e5f 100644 --- a/3rdParty/StormLib/src/SBaseCommon.cpp +++ b/3rdParty/StormLib/src/SBaseCommon.cpp @@ -416,6 +416,56 @@ void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) { +#ifdef __mc68000__ + +#define _DataBlock "a0" +#define _StormBuffer "a1" +#define _dwLength "d0" +#define _dwKey1 "d1" +#define _dwKey2 "d2" +#define _dwValue32 "d3" +#define _dwTmp "d4" + + register DWORD dwLength_ asm(_dwLength); + + if(dwLength_ = dwLength>>2) { + register LPDWORD DataBlock asm(_DataBlock) = (LPDWORD)pvDataBlock; + register LPDWORD StormBuffer_ asm(_StormBuffer) = &StormBuffer[MPQ_HASH_KEY2_MIX]; + register DWORD dwKey1_ asm(_dwKey1) = dwKey1; + register DWORD dwKey2 asm(_dwKey2) = 0xEEEEEEEE; + register DWORD dwValue32 asm(_dwValue32); + register DWORD dwTmp asm(_dwTmp); + __asm__ __volatile__ ( + "\n" + ".loop%=:\n" + " move.l ("_DataBlock"),"_dwTmp" \n" + " moveq #0,"_dwValue32" \n" + " move.b "_dwKey1","_dwValue32" \n" + " add.l ("_StormBuffer","_dwValue32".l*4),"_dwKey2" \n" + " move.l "_dwKey1","_dwValue32" \n" + " add.l "_dwKey2","_dwValue32" \n" + " eor.l "_dwTmp","_dwValue32" \n" + " move.l "_dwValue32",("_DataBlock")+ \n" + " add.l "_dwKey2","_dwValue32" \n" + " lsl.l #5,"_dwKey2" \n" + " addq.l #3,"_dwValue32" \n" + " add.l "_dwValue32","_dwKey2" \n" + " moveq #0x15,"_dwValue32" \n" + " rol.l "_dwValue32","_dwKey1" \n" + " move.l "_dwKey1","_dwValue32" \n" + " not.l "_dwKey1" \n" + " and.l #-1<<0x15,"_dwKey1" \n" + " and.l #~(-1<<0x15),"_dwValue32" \n" + " add.l #0x11111111,"_dwKey1" \n" + " or.l "_dwValue32","_dwKey1" \n" + " subq.l #1,"_dwLength" \n" + " bne.b .loop%= \n" + : "+r" (dwKey1_), "+r" (dwKey2), "=r" (dwValue32), "+r" (dwLength_), "+r" (DataBlock), "=r" (dwTmp) + : "r" (StormBuffer_) + : "cc", "memory" + ); + } +#else LPDWORD DataBlock = (LPDWORD)pvDataBlock; DWORD dwValue32; DWORD dwKey2 = 0xEEEEEEEE; @@ -435,6 +485,7 @@ void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; } +#endif } /** @@ -1813,42 +1864,69 @@ uint64_t SwapUInt64( uint64_t val ) } #endif +#ifdef __AMIGA__ +extern "C" { + char ac68080_ammx; + void ConvertUInt16BufferAMMX(void * ptr, size_t length); + void ConvertUInt32BufferAMMX(void * ptr, size_t length); + void ConvertUInt64BufferAMMX(void * ptr, size_t length); +}; +#endif + // Swaps array of unsigned 16-bit integers void ConvertUInt16Buffer(void * ptr, size_t length) { - uint16_t * buffer = (uint16_t *)ptr; - uint32_t nElements = (uint32_t)(length / sizeof(uint16_t)); - - while(nElements-- > 0) +#ifdef __AMIGA__ + if(ac68080_ammx) ConvertUInt16BufferAMMX(ptr, length); + else +#endif { - *buffer = SwapUInt16(*buffer); - buffer++; + uint16_t * buffer = (uint16_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint16_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt16(*buffer); + buffer++; + } } } // Swaps array of unsigned 32-bit integers void ConvertUInt32Buffer(void * ptr, size_t length) { - uint32_t * buffer = (uint32_t *)ptr; - uint32_t nElements = (uint32_t)(length / sizeof(uint32_t)); - - while(nElements-- > 0) +#ifdef __AMIGA__ + if(ac68080_ammx) ConvertUInt32BufferAMMX(ptr, length); + else +#endif { - *buffer = SwapUInt32(*buffer); - buffer++; + uint32_t * buffer = (uint32_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint32_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt32(*buffer); + buffer++; + } } } // Swaps array of unsigned 64-bit integers void ConvertUInt64Buffer(void * ptr, size_t length) { - uint64_t * buffer = (uint64_t *)ptr; - uint32_t nElements = (uint32_t)(length / sizeof(uint64_t)); - - while(nElements-- > 0) +#ifdef __AMIGA__ + if(ac68080_ammx) ConvertUInt64BufferAMMX(ptr, length); + else +#endif { - *buffer = SwapUInt64(*buffer); - buffer++; + uint64_t * buffer = (uint64_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint64_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt64(*buffer); + buffer++; + } } } diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 258e24296da..eb7e41117e3 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -17,6 +17,10 @@ * XREF ___real_memcmp XDEF ___wrap_memcmp + + XDEF _ConvertUInt16BufferAMMX + XDEF _ConvertUInt32BufferAMMX + XDEF _ConvertUInt64BufferAMMX cnop 0,4 @@ -165,5 +169,54 @@ ___wrap_memcmp .eq moveq #0,d0 rts + +_ConvertUInt16BufferAMMX + rsreset + rs.l 1 +.ptr rs.l 1 +.len rs.l 1 + + move.l .ptr(sp),a0 + move.l .len(sp),d0 +.loop + load (a0),d1 + vperm #$10325476,d1,d1,d1 + storec d1,d0,(a0)+ + subq.l #8,d0 + bhi .loop + rts + + +_ConvertUInt32BufferAMMX + rsreset + rs.l 1 +.ptr rs.l 1 +.len rs.l 1 + move.l .ptr(sp),a0 + move.l .len(sp),d0 +.loop + load (a0),d1 + vperm #$32107654,d1,d1,d1 + storec d1,d0,(a0)+ + subq.l #8,d0 + bhi .loop + rts + +_ConvertUInt64BufferAMMX + rsreset + rs.l 1 +.ptr rs.l 1 +.len rs.l 1 + + move.l .ptr(sp),a0 + move.l .len(sp),d0 +.loop + load (a0),d1 + vperm #$76543210,d1,d1,d1 + storec d1,d0,(a0)+ + subq.l #8,d0 + bhi .loop + rts + * end of file \ No newline at end of file From 7e826dcce8191dd230b844ba4a9e6606727f4a7c Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 20 Dec 2019 17:15:17 +0100 Subject: [PATCH 042/107] restored removed atexit --- Source/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/init.cpp b/Source/init.cpp index 61851d43587..939e0664c8d 100644 --- a/Source/init.cpp +++ b/Source/init.cpp @@ -47,7 +47,7 @@ void init_create_window() if (!SpawnWindow(PROJECT_NAME, SCREEN_WIDTH, SCREEN_HEIGHT)) app_fatal("Unable to create main window"); dx_init(NULL); - //atexit(dx_cleanup); + atexit(dx_cleanup); gbActive = true; gpBufStart = &gpBuffer[BUFFER_WIDTH * SCREEN_Y]; gpBufEnd = &gpBuffer[BUFFER_WIDTH * (SCREEN_HEIGHT + SCREEN_Y)]; From ada2cdb2e6957f0737fa9da53ed58657f7ca4de4 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 20 Dec 2019 17:22:29 +0100 Subject: [PATCH 043/107] made change amiga-specific --- 3rdParty/PKWare/explode.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/3rdParty/PKWare/explode.cpp b/3rdParty/PKWare/explode.cpp index 22354131595..7e3295e2402 100644 --- a/3rdParty/PKWare/explode.cpp +++ b/3rdParty/PKWare/explode.cpp @@ -28,8 +28,10 @@ static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" "Version 1.11\r\n"; -//#define static __attribute__ ((noinline,regparam(2))) +#fidef __AMIGA__ +// pass values in d0/d1 regs for speedup #define static static __attribute__ ((regparam(2))) +#endif //----------------------------------------------------------------------------- // Tables From aaf4d3f0dcedcfbe9c0b41a4a7c141091edeae8e Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 20 Dec 2019 17:29:42 +0100 Subject: [PATCH 044/107] made change amiga-specific --- 3rdParty/PKWare/explode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/PKWare/explode.cpp b/3rdParty/PKWare/explode.cpp index 7e3295e2402..12361ed5a60 100644 --- a/3rdParty/PKWare/explode.cpp +++ b/3rdParty/PKWare/explode.cpp @@ -28,7 +28,7 @@ static char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" "Version 1.11\r\n"; -#fidef __AMIGA__ +#ifdef __AMIGA__ // pass values in d0/d1 regs for speedup #define static static __attribute__ ((regparam(2))) #endif From 623cd3cb7e9e4f83353890ed2dc68b33c085d4b8 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 22 Dec 2019 16:02:32 +0100 Subject: [PATCH 045/107] more amiga / mc68k improvements --- 3rdParty/StormLib/src/SBaseCommon.cpp | 9 ++++++ Source/control.cpp | 46 +++++++++++++++++++-------- SourceX/platform/amiga/memopt.asm | 41 ++++++++++++++++++++++-- SourceX/platform/amiga/render68k.asm | 2 +- SourceX/storm/storm.cpp | 4 +-- 5 files changed, 82 insertions(+), 20 deletions(-) diff --git a/3rdParty/StormLib/src/SBaseCommon.cpp b/3rdParty/StormLib/src/SBaseCommon.cpp index c6757540e5f..78586de4859 100644 --- a/3rdParty/StormLib/src/SBaseCommon.cpp +++ b/3rdParty/StormLib/src/SBaseCommon.cpp @@ -313,6 +313,14 @@ DWORD HashStringLower(const char * szFileName, DWORD dwHashType) // If the value is already a power of two, returns the same value DWORD GetNearestPowerOfTwo(DWORD dwFileCount) { +#ifdef __mc68000__ + DWORD ret = 1; + __asm__ __volatile__( + " bfffo %1{0:31},%1 \n" + " bfins %0,%0{0:%1} \n" + : "+d" (ret), "+d" (dwFileCount) : ); + return ret; +#else dwFileCount --; dwFileCount |= dwFileCount >> 1; @@ -322,6 +330,7 @@ DWORD GetNearestPowerOfTwo(DWORD dwFileCount) dwFileCount |= dwFileCount >> 16; return dwFileCount + 1; +#endif } /* DWORD GetNearestPowerOfTwo(DWORD dwFileCount) diff --git a/Source/control.cpp b/Source/control.cpp index 2b62377606e..256a51a93eb 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -1651,37 +1651,55 @@ int DrawDurIcon4Item(ItemStruct *pItem, int x, int c) return x - 40; } +#pragma GCC push_options +#pragma GCC optimize ("unroll-loops") + +static +#ifdef __AMIGA__ +__attribute__((regparm(2))) +#endif +void doLine(BYTE *src, BYTE *tbl) +{ + int d0 = 0, d1 = 0, d2 = 0, d3 = 0; + BYTE *dst = src; + for(WORD i=SCREEN_WIDTH>>2; i--;) { +#ifdef __mc68000__ +#define SET(x,y) __asm__ __volatile__(" move.b %1,%0\n" : "+dm" (x) : "m" (y)) +#else +#define SET(x,y) x = (y)&255 +#endif + SET(d0, *src++); SET(d1, *src++); SET(d2, *src++); SET(d3, *src++); + SET(d0, tbl[d0]); SET(d1, tbl[d1]); SET(d2, tbl[d2]); SET(d3 , tbl[d3]); + *dst++ = d0; *dst++ = d1; *dst++ = d2; *dst++ = d3; + } +} +#pragma GCC pop_options + void RedBack() { + BYTE tbl2[256]; int idx; idx = light4flag ? 1536 : 4608; /// ASSERT: assert(gpBuffer); - int w, h; + int h; BYTE *dst, *tbl; if (leveltype != DTYPE_HELL) { dst = &gpBuffer[SCREENXY(0, 0)]; tbl = &pLightTbl[idx]; - for (h = VIEWPORT_HEIGHT; h; h--, dst += BUFFER_WIDTH - SCREEN_WIDTH) { - for (w = SCREEN_WIDTH; w; w--) { - *dst = tbl[*dst]; - dst++; - } - } } else { dst = &gpBuffer[SCREENXY(0, 0)]; tbl = &pLightTbl[idx]; - for (h = VIEWPORT_HEIGHT; h; h--, dst += BUFFER_WIDTH - SCREEN_WIDTH) { - for (w = SCREEN_WIDTH; w; w--) { - if (*dst >= 32) - *dst = tbl[*dst]; - dst++; - } - } + + for(int i=32; --i>=0;) tbl2[i] = i; + memcpy(tbl2+32, tbl+32, 256-32); + + tbl = tbl2; } + for (h = VIEWPORT_HEIGHT; h; h--, dst += BUFFER_WIDTH) doLine(dst,tbl); } char GetSBookTrans(int ii, BOOL townok) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index eb7e41117e3..071c53f1ed5 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -195,12 +195,47 @@ _ConvertUInt32BufferAMMX move.l .ptr(sp),a0 move.l .len(sp),d0 -.loop + + movem.l d2/d3,-(sp) + move.l a0,a1 + moveq #64,d1 + sub.l d1,d0 + bcs .l32 +.l64 + REPT 8 + movex.l (a0)+,d2 + movex.l (a0)+,d3 + move.l d2,(a1)+ + move.l d3,(a1)+ + ENDR + sub.l d1,d0 + bcc .l64 +.l32 + add.l d1,d0 + beq .exit2 + bclr #5,d0 + beq.b .l16 + REPT 4 + movex.l (a0)+,d2 + movex.l (a0)+,d3 + move.l d2,(a1)+ + move.l d3,(a1)+ + ENDR +.l16 + bclr #4,d0 + beq.b .l8 + REPT 4 + movex.l (a0)+,d2 + movex.l (a0)+,d3 + move.l d2,(a1)+ + move.l d3,(a1)+ + ENDR +.l8 load (a0),d1 vperm #$32107654,d1,d1,d1 storec d1,d0,(a0)+ - subq.l #8,d0 - bhi .loop +.exit2 + movem.l (sp)+,d2/d3 rts _ConvertUInt64BufferAMMX diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 45815f79ea5..74b9ef10ece 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -103,7 +103,7 @@ chk_bounds macro else ifne USE_CMP2 cmp2.l __ZN3dvl10gpBufStartE,a0 - bcs.b \1 + bcs.b \1 else cmp.l a5,a0 ; 1 bcs.b \1 ; 2 diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 01c38979912..1d04fbed632 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -712,9 +712,9 @@ BOOL SVidPlayContinue(void) Uint32 format = SDL_GetWindowPixelFormat(window); SDL_Surface *tmp = SDL_ConvertSurfaceFormat(SVidSurface, format, 0); #endif -#ifndef __AMIGA__ +// #ifndef __AMIGA__ ScaleOutputRect(&pal_surface_offset); // somehow this lead to pb with amiga's SDL -#endif +// #endif if (SDL_BlitScaled(tmp, NULL, GetOutputSurface(), &pal_surface_offset) <= -1) { SDL_Log(SDL_GetError()); return false; From 980339a5ec3199ed399f592ad69da8a4ad016df9 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 23 Dec 2019 23:51:57 +0100 Subject: [PATCH 046/107] bug https://github.com/Samuel-DEVULDER/devilutionX/issues/1 fixed --- 3rdParty/StormLib/src/SBaseCommon.cpp | 8 +- CMake/amiga/m68k-amigaos.cmake | 4 +- CMakeLists.txt | 2 +- Source/scrollrt.cpp | 35 ++- SourceS/sdl_compat.h | 8 +- .../amiga/{support.c => ac68080_support.c} | 6 +- SourceX/platform/amiga/memopt.asm | 139 +++++------- SourceX/platform/amiga/render68k.asm | 204 +++++++++--------- 8 files changed, 213 insertions(+), 193 deletions(-) rename SourceX/platform/amiga/{support.c => ac68080_support.c} (95%) diff --git a/3rdParty/StormLib/src/SBaseCommon.cpp b/3rdParty/StormLib/src/SBaseCommon.cpp index 78586de4859..eb8cd3f3e24 100644 --- a/3rdParty/StormLib/src/SBaseCommon.cpp +++ b/3rdParty/StormLib/src/SBaseCommon.cpp @@ -1875,10 +1875,10 @@ uint64_t SwapUInt64( uint64_t val ) #ifdef __AMIGA__ extern "C" { - char ac68080_ammx; - void ConvertUInt16BufferAMMX(void * ptr, size_t length); - void ConvertUInt32BufferAMMX(void * ptr, size_t length); - void ConvertUInt64BufferAMMX(void * ptr, size_t length); + extern char ac68080_ammx; + extern void ConvertUInt16BufferAMMX(void * ptr, size_t length); + extern void ConvertUInt32BufferAMMX(void * ptr, size_t length); + extern void ConvertUInt64BufferAMMX(void * ptr, size_t length); }; #endif diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 019d2b53083..dd4ba68e77e 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -59,13 +59,13 @@ endif() set(FLAGS_COMMON "${FLAGS_COMMON} -m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Faout -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Fhunk -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") set(CMAKE_ASM_COMPILE_OBJECT " ${CMAKE_ASM_FLAGS} -o ") set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul -Xlinker --allow-multiple-definition") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul") # wrapper - replace gcc functions by our own foreach(_wrapped diff --git a/CMakeLists.txt b/CMakeLists.txt index f12161605cc..ee0a2325327 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,7 +315,7 @@ if(AMIGA) list(APPEND devilutionx_SRCS SourceX/platform/amiga/render68k.asm SourceX/platform/amiga/memopt.asm - SourceX/platform/amiga/support.c) + SourceX/platform/amiga/ac68080_support.c) endif() add_executable(${BIN_TARGET} MACOSX_BUNDLE ${devilutionx_SRCS}) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 7dbcf9d8093..0b43dbd9e85 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -66,6 +66,10 @@ void ClearCursor() // CODE_FIX: this was supposed to be in cursor.cpp sgdwCursWdtOld = 0; } +#ifdef __AMIGA__ +#define static static __attribute__((regparm(2))) +#endif + /** * @brief Remove the cursor from the backbuffer */ @@ -468,6 +472,35 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy, int eflag); static void drawRow(int x, int y, int sx, int sy, int eflag) { +#ifdef __mc68000__ // this code is better for 68k + BYTE *dst; + MICROS *pMap; + WORD *mt; + + level_piece_id = dPiece[x][y]; + light_table_index = dLight[x][y]; + + dst = &gpBuffer[sx + sy * BUFFER_WIDTH]; + pMap = &dpiece_defs_map_2[x][y]; + cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); + + mt = &pMap->mt[0]; + arch_draw_type = 1; + level_cel_block = *mt++; + if (level_cel_block != 0) drawUpperScreen(dst); + arch_draw_type = 2; + level_cel_block = *mt++; + if (level_cel_block != 0) drawUpperScreen(dst + 32); + arch_draw_type = 0; + for(WORD i = MicroTileLen>>1; --i>0;) { + dst -= BUFFER_WIDTH * 32; + level_cel_block = *mt++; + if (level_cel_block != 0) drawUpperScreen(dst); + level_cel_block = *mt++; + if (level_cel_block != 0) drawUpperScreen(dst + 32); + } + +#else BYTE *dst; MICROS *pMap; @@ -490,7 +523,7 @@ static void drawRow(int x, int y, int sx, int sy, int eflag) } dst -= BUFFER_WIDTH * 32; } - +#endif scrollrt_draw_dungeon(x, y, sx, sy, eflag); } diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 35e486b01d3..bdf6c0adea4 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -14,10 +14,10 @@ #if defined(__AMIGA__) // Add other systems that require an 8bit screen here extern "C" { - char ac68080_saga; - char ac68080_ammx; - int vampire_Flip(SDL_Surface *surf); - int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, + extern char ac68080_saga; + extern char ac68080_ammx; + extern int vampire_Flip(SDL_Surface *surf); + extern int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect); } //extern C #endif diff --git a/SourceX/platform/amiga/support.c b/SourceX/platform/amiga/ac68080_support.c similarity index 95% rename from SourceX/platform/amiga/support.c rename to SourceX/platform/amiga/ac68080_support.c index 9facf829d7a..8bdbe441c87 100755 --- a/SourceX/platform/amiga/support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -70,6 +70,7 @@ extern void gamemenu_quit_game(int); UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; + static USHORT copy_pane_mask = 0; static UBYTE *bufmem = NULL; @@ -159,11 +160,12 @@ static void stop(void) bufmem = NULL; } } + static void start(void) { started = 255; atexit(stop); - + if (SysBase->AttnFlags &(1 << 10)) { ac68080_saga = 255; //!_ZN3dvl10fullscreenE; // disable if not fullscreen @@ -196,7 +198,7 @@ static void start(void) } if(ac68080_ammx) { if(ac68080_saga) printf(" &"); - printf(" AMMX2"); + printf(" AMMX"); } } printf(".\n"); diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 071c53f1ed5..6ccbfe069ea 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -2,13 +2,11 @@ * memopt.asm -- AC68080 replacement for memxxx() operation with by hand-written * asm code by S.Devulder * ----------------------------------------------------------------------------- - + section .text machine 68080 - XREF _ac68080_ammx - XREF ___real_memcpy XDEF ___wrap_memcpy @@ -21,109 +19,76 @@ XDEF _ConvertUInt16BufferAMMX XDEF _ConvertUInt32BufferAMMX XDEF _ConvertUInt64BufferAMMX + XREF _ac68080_ammx cnop 0,4 + +memcpy_68k + jmp ___real_memcpy ___wrap_memcpy -.entry - tst.b _ac68080_ammx - beq.l ___real_memcpy -.memcpy - rsreset + rsreset rs.l 1 .dst rs.l 1 .src rs.l 1 .len rs.l 1 - move.l .dst(sp),a1 ; p1 1 - move.l .src(sp),a0 ; p1 2 - move.l .len(sp),d0 ; p1 3 +* bra memcpy_68k - moveq #64,d1 - sub.l d1,d0 - bcs .l32 -.l64 - REPT 8 - load (a0)+,e0 - store e0,(a1)+ - ENDR - sub.l d1,d0 - bcc .l64 -.l32 - add.l d1,d0 - beq .exit2 - bclr #5,d0 - beq.b .l16 - REPT 4 - load (a0)+,e0 - store e0,(a1)+ - ENDR -.l16 - load (a0)+,e0 - storec e0,d0,(a1)+ - subq.l #8,d0 - bcs.b .exit2 +.entry + tst.b _ac68080_ammx + beq.b memcpy_68k + + move.l .dst(sp),d0 ; p1 1 + move.l .src(sp),a0 ; p1 2 + add.l .len(sp),d1 ; p1 3 + movea.l d0,a1 + +.loop load (a0)+,e0 - storec e0,d0,(a1)+ -.exit2 - move.l .dst(sp),d0 + storec e0,d1,(a1)+ + subq.l #8,d1 + bhi.s .loop + .exit - nop * remove initial comparison so that it now only costs 1 cycle - move.w #$203c,.entry(pc) ; move.l #nnnn,d0 - move.w #$223c,.entry+6(pc) ; move.l #nnnn,d1 - move.w #$4e75,.exit(pc) ; #rts + move.w #$203c,.entry ; move.l #nnnn,d0 + move.w #$7200,.entry+6 ; moveq.w #0,d1 + move.w #$4e75,.exit ; #rts rts ; no need to ClearCacheU on apollo! +memset_68k + jmp ___real_memset + ___wrap_memset -.entry - tst.b _ac68080_ammx - beq.l ___real_memset - -.memset - rsreset + rsreset rs.l 1 .dst rs.l 1 .val rs.l 1 .len rs.l 1 - move.l .dst(sp),a1 ; p1 1 +.entry + tst.b _ac68080_ammx + beq.b memset_68k + + move.l .dst(sp),a0 ; p1 1 move.l .val(sp),d0 ; p1 2 move.l .len(sp),d1 ; p1 3 vperm #$77777777,d0,e0,e0 + move.l a0,d0 + +.loop + storec e0,d1,(a0)+ + subq.l #8,d1 + bhi.b .loop - moveq #64,d1 - sub.l d1,d0 - bcs .l32 -.l64 - REPT 8 - store e0,(a1)+ - ENDR - sub.l d1,d0 - bcc .l64 -.l32 - add.l d1,d0 - beq .exit2 - bclr #5,d0 - beq.b .l16 - REPT 4 - store e0,(a1)+ - ENDR -.l16 - storec e0,d0,(a1)+ - subq.l #8,d0 - bcs.b .exit2 - storec e0,d0,(a1)+ -.exit2 - move.l .dst(sp),d0 .exit - nop * remove initial comparison so that it now only costs 1 cycle - move.w #$203c,.entry(pc) ; move.l #nnnn,d0 - move.w #$223c,.entry+6(pc) ; move.l #nnnn,d1 - move.w #$4e75,.exit(pc) ; #rts + move.w #$203c,.entry ; move.l #nnnn,d0 + move.w #$7200,.entry+6 ; moveq #0,d1 + move.w #$4e75,.exit ; #rts rts ; no need to ClearCacheU on apollo! ___wrap_memcmp @@ -178,6 +143,7 @@ _ConvertUInt16BufferAMMX move.l .ptr(sp),a0 move.l .len(sp),d0 + and.w #-2,d0 .loop load (a0),d1 vperm #$10325476,d1,d1,d1 @@ -195,11 +161,12 @@ _ConvertUInt32BufferAMMX move.l .ptr(sp),a0 move.l .len(sp),d0 - + and.w #-4,d0 + movem.l d2/d3,-(sp) - move.l a0,a1 moveq #64,d1 sub.l d1,d0 + movea.l a0,a1 bcs .l32 .l64 REPT 8 @@ -224,16 +191,21 @@ _ConvertUInt32BufferAMMX .l16 bclr #4,d0 beq.b .l8 - REPT 4 + REPT 2 movex.l (a0)+,d2 movex.l (a0)+,d3 move.l d2,(a1)+ move.l d3,(a1)+ ENDR .l8 - load (a0),d1 - vperm #$32107654,d1,d1,d1 - storec d1,d0,(a0)+ + load (a0)+,d2 + vperm #$32107654,d2,d2,d2 + storec d2,d0,(a1)+ + subq.l #8,d0 + bls.b .exit2 + load (a0)+,d2 + vperm #$32107654,d2,d2,d2 + storec d2,d0,(a1)+ .exit2 movem.l (sp)+,d2/d3 rts @@ -246,6 +218,7 @@ _ConvertUInt64BufferAMMX move.l .ptr(sp),a0 move.l .len(sp),d0 + and.w #-8,d0 .loop load (a0),d1 vperm #$76543210,d1,d1,d1 diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 74b9ef10ece..8edf0b1d48c 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -1,16 +1,16 @@ * ----------------------------------------------------------------------------- * render68k.asm -- replacement of C code by hand-written asm code by S.Devulder * ----------------------------------------------------------------------------- - section .text - machine 68080 + section .text + BUFFER_WIDTH set 768 VAMP_V4 set 1 ; 0 = replaces movem with separate moves NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) -USE_BANK set 1 ; uses E4/E5 in place of D4/D5 in Render2_AMMX +USE_BANK set 0 ; uses E4/E5 in place of D4/D5 in Render2_AMMX XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -36,7 +36,7 @@ USE_BANK set 1 ; uses E4/E5 in place of D4/D5 in Render2_AMMX XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE XREF _ac68080_ammx - + cnop 0,4 * sanity @@ -142,30 +142,27 @@ rol_d1_mask macro endm unroll_AMMX macro - btst #5,d0 + bclr #5,d0 beq \1_16 * 32 bytes in a row \1 0 \1 0 \1 0 \1 1 - rts_bounds + rts_bounds \1_16 - btst #4,d0 + bclr #4,d0 beq \1_8 * 16 bytes in a row \1 0 \1 0 \1_8 - btst #3,d0 + bclr #3,d0 beq \1_0 * 8 bytes in a row \1 0 \1_0 - moveq #7,d2 - and.l d2,d0 - beq \3 -* 1 to 7 bytes +* 0 to 7 bytes \2 * fixup ptrs \3 @@ -320,7 +317,6 @@ transform macro * move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm - push_d4_d5 macro ifeq USE_BANK movem.l d4/d5,-(sp) @@ -370,30 +366,31 @@ _RenderLine2_AMMX add.w d0,a1 rts_bounds -* mask version +* mask versions .transfAA55_8 macro - moveq #0,d2 move.b \1(a1),d2 ; 1 - moveq #0,d3 move.b \1+2(a1),d3 ; 2 - bank 0,1,moveq,#0,d4 bank 0,1,move.b,\1+4(a1),d4 ; 3 - bank 0,1,moveq,#0,d5 bank 0,1,move.b,\1+6(a1),d5 ; 4 - addq #8,a0 ; 4 - addq.l #8,a1 - move.w (a2,d2.w),d2 ; 5 - move.b (a2,d3.w),d2 ; 6 - swap d2 ; 7 - bank 1,0,move.w,(a2,d4.w),d2 ; 8 - bank 1,0,move.b,(a2,d5.w),d2 ; 9 - movep.l d2,\1-9(a0) ; 10 + addq.l #8,a0 ; 4 + addq.l #8,a1 ; 5 + move.w (a2,d2.w),d1 ; 5 + move.b (a2,d3.w),d1 ; 6 + swap d1 ; 7 + bank 1,0,move.w,(a2,d4.w),d1 ; 8 + bank 1,0,move.b,(a2,d5.w),d1 ; 9 + movep.l d1,\1-8(a0) ; 10 endm .transfAA55 macro - btst #5,d0 - bne .b4\2 + moveq #0,d2 + moveq #0,d3 + bank 0,1,moveq,#0,d4 + bank 0,1,moveq,#0,d5 + + bclr #5,d0 + beq .b4\2 .transfAA55_8 \1 .transfAA55_8 \1 .transfAA55_8 \1 @@ -401,58 +398,60 @@ _RenderLine2_AMMX pull_d4_d5 rts_bounds .b4\2 - btst #4,d0 - bne .b3\2 + bclr #4,d0 + beq.b .b3\2 .transfAA55_8 \1 .transfAA55_8 \1 .b3\2 - btst #3,d0 - bne .b2\2 + bclr #3,d0 + beq.b .b2\2 .transfAA55_8 \1 .b2\2 pull_d4_d5 - btst #2,d0 - bne .b1\2 - moveq #0,d2 + bclr #2,d0 + beq.b .b1\2 move.b \1(a1),d2 ; 1 - moveq #0,d3 move.b \1+2(a1),d3 ; 2 addq.l #4,a0 ; 2 addq.l #4,a1 ; 3 - move.w (a2,d2.w),d2 ; 3+1 - move.b (a2,d3.w),d2 ; 5 - movep.w d2,\1-5(a0) ; 6 + move.w (a2,d2.w),d1 ; 3+1 + move.b (a2,d3.w),d1 ; 5 + movep.w d1,\1-4(a0) ; 6 .b1\2 - btst #1,d0 - bne .b0\2 - moveq #0,d2 + bclr #1,d0 + beq.b .b0\2 move.b \1(a1),d2 ; 1 addq.l #2,a0 addq.l #2,a1 ; 2 ; 2 bubbles - move.b (a2,d2.w),d2 ; 4 - move.b d2,\1(a0) ; 5 + move.b (a2,d2.w),d1 ; 4 + move.b d1,\1-2(a0) ; 5 .b0\2 - ifne \1 - addq.l #1,a0 - addq.l #1,a1 - else + ifeq \1 + tst.b d0 + beq.b .bb0\2 move.b (a1)+,(a0)+ +.bb0\2 + else + add.w d0,a0 + add.w d0,a1 endc rts_bounds endm - -.mask - cmp.l #$AAAAAAAA,d1 - bne .mask1 + +.maskAA .transfAA55 0,_aa -.mask1 - cmp.l #$55555555,d1 - bne .mask2 +.mask55 .transfAA55 1,_55 -.mask2 + +.mask + move.l #$AAAAAAAA,d3 + eor.l d1,d3 + beq .maskAA + not.l d3 + beq .mask55 .m8 macro move.l (a1)+,d3 ; F(used) d3=AABBCCDD @@ -473,11 +472,14 @@ _RenderLine2_AMMX vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0) endm + +.maskXX unroll_AMMX .m8,.m0,.mx pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds + * ----------------------------------------------------------------------------- @@ -640,8 +642,8 @@ inc_a0_a1 macro endm unroll macro - btst #5,d0 - beq \1_4 + bclr #5,d0 + beq \1_4 \1 0 \1 0 \1 0 @@ -652,28 +654,28 @@ unroll macro \1 1 rts_bounds \1_4 - btst #4,d0 - beq \1_2 + bclr #4,d0 + beq \1_2 \1 0 \1 0 \1 0 \1 0 \1_2 - btst #3,d0 - beq \1_1 + bclr #3,d0 + beq \1_1 \1 0 \1 0 \1_1 - btst #2,d0 - beq \2_1 + bclr #2,d0 + beq \2_1 \1 0 \2_1 - btst #1,d0 - beq \3_1 + bclr #1,d0 + beq \3_1 \2 \3_1 - btst #0,d0 - beq \3_2 + tst.b d0 + beq \3_2 \3 \3_2 rts_bounds @@ -886,15 +888,15 @@ _RenderLine2 .p4 macro move.b 1(a1),d2 move.b 3(a1),d3 - move.b (a2,d2.w),1(a0) - move.b (a2,d3.w),3(a0) addq.l #4,a1 + move.b (a2,d2.w),1(a0) addq.l #4,a0 + move.b (a2,d3.w),-1(a0) endm .p2 macro move.b 1(a1),d2 - move.b (a2,d2.w),1(a0) addq.l #2,a1 + move.b (a2,d2.w),1(a0) addq.l #2,a0 endm .p1 macro @@ -908,15 +910,15 @@ _RenderLine2 .q4 macro move.b (a1),d2 move.b 2(a1),d3 - move.b (a2,d2.w),(a0) - move.b (a2,d3.w),2(a0) addq.l #4,a1 + move.b (a2,d2.w),(a0) addq.l #4,a0 + move.b (a2,d3.w),-2(a0) endm .q2 macro move.b (a1),d2 - move.b (a2,d2.l),(a0) addq.l #2,a1 + move.b (a2,d2.l),(a0) addq.l #2,a0 endm .q1 macro @@ -951,10 +953,40 @@ setup macro bsr _setup endm + xdef _setup + _setup + ifne NO_OVERDRAW + ifeq USE_CMP2 + move.l __ZN3dvl10gpBufStartE,a5 + move.l __ZN3dvl8gpBufEndE,a6 + endc + ifne A5_RELATIVE + sub.l a5,a0 + sub.l a5,a6 + endc + endc + addq.l #4,a3 * determine renderFcn +.ammx tst.b _ac68080_ammx - bne .ammx + beq.b .m68k + + lea _RenderLine0_AMMX(pc),a4 + move.l __ZN3dvl17light_table_indexE,d2 + beq.b .exit + sub.b __ZN3dvl8lightmaxE,d2 + lea _RenderLine2_AMMX(pc),a4 + bne.b .exit + lea _RenderLine1_AMMX(pc),a4 +.exit +* remove initial comparison so that it now only costs 1 cycle + move.w #$203c,.ammx ; move.l #nnnn,d0 + move.w #$7200,.ammx+6 ; moveq #0,d1 + move.w #$4e75,.exit ; #rts + rts ; no need to ClearCacheU on apollo! + +.m68k lea _RenderLine0(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 beq .L0 @@ -962,29 +994,9 @@ _setup lea _RenderLine2(pc),a4 bne.b .L0 lea _RenderLine1(pc),a4 - bra .L0 -.ammx - lea _RenderLine0_AMMX(pc),a4 - move.l __ZN3dvl17light_table_indexE,d2 - beq .L0 - sub.b __ZN3dvl8lightmaxE,d2 - lea _RenderLine2_AMMX(pc),a4 - bne.b .L0 - lea _RenderLine1_AMMX(pc),a4 .L0 - ifne NO_OVERDRAW - ifeq USE_CMP2 - move.l __ZN3dvl10gpBufStartE,a5 - move.l __ZN3dvl8gpBufEndE,a6 - endc - ifne A5_RELATIVE - sub.l a5,a0 - sub.l a5,a6 - endc - endc - addq.l #4,a3 rts - + prologue_7 macro .size set 7 ifeq SAVE_A5A6 From a01cffddf9528113546d1693afee9a4a7d19e6bd Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 24 Dec 2019 14:04:29 +0100 Subject: [PATCH 047/107] better handling of 'copy_pane_mask' --- SourceX/platform/amiga/ac68080_support.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 8bdbe441c87..b6f76c5d85f 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -71,7 +71,7 @@ extern void gamemenu_quit_game(int); UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; -static USHORT copy_pane_mask = 0; +static volatile USHORT copy_pane_mask = 0; static UBYTE *bufmem = NULL; static UBYTE started = 0; @@ -236,8 +236,9 @@ static void chkSignals(void) } } -static int ok(SDL_Surface *const surf) +static __attribute__((noinline)) int ok(SDL_Surface *const surf) { + chkSignals(); if(!started) start(); if(!ac68080_saga) return 0; if(surf!=SDL_GetVideoSurface()) return 0; @@ -251,8 +252,6 @@ int vampire_Flip(SDL_Surface* surf) // volatile ULONG *pal = (ULONG*)0xDFF400; struct Screen *first_screen; static UBYTE panel_cpy_flag = 4; - - chkSignals(); #if DIRTY *dpy = (void*)(~31&(int)surf->pixels); @@ -288,12 +287,14 @@ int vampire_Flip(SDL_Surface* surf) ptr += FRAME_BUFFER_SZ; surf->pixels = ptr; - if(copy_pane_mask) { - copy_pane_mask >>= 1; + // if(copy_pane_mask) { + // copy_pane_mask >>= 1; + asm goto ("lsr.w %0\n\tbeq.s %l1" : : "m"(copy_pane_mask) : : skip); memcpy(ptr + PANEL_TOP*SCREEN_WIDTH, old + PANEL_TOP*SCREEN_WIDTH, PANEL_HEIGHT*SCREEN_WIDTH); - } + // } + skip: (void)0; #endif } return 0; @@ -316,7 +317,7 @@ int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, // return ret; // } if(srcRect - && srcRect->w < SCREEN_WIDTH // ignore full screen + // && srcRect->w < SCREEN_WIDTH // ignore full screen && !(srcRect->w==288 && srcRect->h==60) // ignore descpane && srcRect->y + srcRect->h >= PANEL_TOP + SCREEN_Y ) copy_pane_mask = 4; // we need to copy 3 times the panel if something was drawn there From 4b2a2cc866396917b315616bac1defbd929c1cc4 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 24 Dec 2019 14:05:36 +0100 Subject: [PATCH 048/107] bank corrections --- SourceX/platform/amiga/render68k.asm | 30 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 8edf0b1d48c..b6b5f960df3 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -10,7 +10,7 @@ VAMP_V4 set 1 ; 0 = replaces movem with separate moves NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) -USE_BANK set 0 ; uses E4/E5 in place of D4/D5 in Render2_AMMX +USE_BANK set 1 ; uses E4/E5 in place of D4/D5 in Render2_AMMX XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -256,7 +256,7 @@ transform macro endc ifne \1&$0a bank 1,1,move.l,d5,d4 ; p2 - bank 1,1,rol.l,#8,d4 ; p2 2 + bank 0,1,rol.l,#8,d4 ; p2 2 endc ifne \1&$a0 and.l #$00FF00FF,d2 ; p1 d2=00CC00AA @@ -265,16 +265,16 @@ transform macro and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD endc ifne \1&$0a - bank 1,1,and.l,#$00FF00FF,d4 ; p1 + bank 0,1,and.l,#$00FF00FF,d4 ; p1 endc ifne \1&$05 - bank 1,1,and.l,#$00FF00FF,d5 ; p2 4 + bank 0,1,and.l,#$00FF00FF,d5 ; p2 4 endc ifne \1&$50 swap d3 ; p1 d3=00DD00BB endc ifne \1&$05 - bank 1,1,swap,d5 ; p2 5 + bank 0,1,swap,d5 ; p2 5 endc ifne \1&$80 move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- @@ -295,10 +295,10 @@ transform macro bank 1,1,move.b,(a2,d5.w),d4 ; p1 endc ifne \1&$0a - bank 1,1,swap,d4 ; p2 9 + bank 0,1,swap,d4 ; p2 9 endc ifne \1&$05 - bank 1,1,swap,d5 ; p1 + bank 0,1,swap,d5 ; p1 endc ifne \1&$20 move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- @@ -357,7 +357,11 @@ _RenderLine2_AMMX move.l (a1),d3 bank 0,1,move.l,4(a1),d5 transform $ff + ifne USE_BANK + vperm #$4567CDEF,d2,e4,d2 + else vperm #$4567CDEF,d2,d4,d2 + endc storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx @@ -455,10 +459,14 @@ _RenderLine2_AMMX .m8 macro move.l (a1)+,d3 ; F(used) d3=AABBCCDD - move.l (a1)+,d5 ; F 1 + bank 0,1,move.l,(a1)+,d5 ; F 1 rol.l #8,d1 transform $ff + ifne USE_BANK + vperm #$4567CDEF,d2,e4,d2 + else vperm #$4567CDEF,d2,d4,d2 + endc storem d2,d1,(a0)+ ifne \1 pull_d4_d5 @@ -466,10 +474,14 @@ _RenderLine2_AMMX endm .m0 macro move.l (a1),d3 ; F(used) d3=AABBCCDD - move.l 4(a1),d5 ; F 1 + bank 0,1,move.l,4(a1),d5 ; F 1 rol_d1_mask transform $ff + ifne USE_BANK + vperm #$4567CDEF,d2,e4,d2 + else vperm #$4567CDEF,d2,d4,d2 + endc storem d2,d1,(a0) endm From ff0a01753d55d222750c5997350f1451a1564f1a Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 24 Dec 2019 14:06:39 +0100 Subject: [PATCH 049/107] disable VAAPIRE_2 by default (slower code) --- CMake/amiga/m68k-amigaos.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index dd4ba68e77e..5cd1a39f7de 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -25,6 +25,7 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(AMIGA 1) set(AMIGAOS3 1) set(PROFILE 0) +set(VAMPIRE_V2 0) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") From 09e1d6b7c4fb9ae0945314544af951dedc18d521 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 25 Dec 2019 00:03:59 +0100 Subject: [PATCH 050/107] removed BANK which didn't work (got garbage on screen when it is on) --- SourceX/platform/amiga/render68k.asm | 180 +++++++++------------------ 1 file changed, 62 insertions(+), 118 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index b6b5f960df3..befab2d7726 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -10,7 +10,6 @@ VAMP_V4 set 1 ; 0 = replaces movem with separate moves NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) -USE_BANK set 1 ; uses E4/E5 in place of D4/D5 in Render2_AMMX XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -57,7 +56,6 @@ SAVE_A5A6 set 1 bank macro - ifne USE_BANK inline .aa equ * dc.w (%0111000100000000+((\1)*%100)+(\2)+((.bb)*%1000000)) @@ -68,13 +66,6 @@ bank macro endc .bb equ (*-.aa-4)>>1 einline - else - ifb \5 - \3 \4 - else - \3 \4,\5 - endc - endc endm * ----------------------------------------------------------------------------- @@ -253,52 +244,52 @@ transform macro ifne \1&$a0 move.l d3,d2 ; p1 d3=AABBCCDD rol.l #8,d2 ; p1 d2=BBCCDDAA - endc - ifne \1&$0a - bank 1,1,move.l,d5,d4 ; p2 - bank 0,1,rol.l,#8,d4 ; p2 2 - endc - ifne \1&$a0 - and.l #$00FF00FF,d2 ; p1 d2=00CC00AA - endc - ifne \1&$50 - and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD - endc - ifne \1&$0a - bank 0,1,and.l,#$00FF00FF,d4 ; p1 - endc - ifne \1&$05 - bank 0,1,and.l,#$00FF00FF,d5 ; p2 4 - endc - ifne \1&$50 - swap d3 ; p1 d3=00DD00BB - endc - ifne \1&$05 - bank 0,1,swap,d5 ; p2 5 - endc - ifne \1&$80 + endc + ifne \1&$0a + move.l d5,d4 ; p2 + rol.l #8,d4 ; p2 2 + endc + ifne \1&$a0 + and.l #$00FF00FF,d2 ; p1 d2=00CC00AA + endc + ifne \1&$50 + and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD + endc + ifne \1&$0a + and.l #$00FF00FF,d4 ; p1 + endc + ifne \1&$05 + and.l #$00FF00FF,d5 ; p2 4 + endc + ifne \1&$50 + swap d3 ; p1 d3=00DD00BB + endc + ifne \1&$05 + swap d5 ; p2 5 + endc + ifne \1&$80 move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- - endc - ifne \1&$40 + endc + ifne \1&$40 move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy - endc - ifne \1&$a0 - swap d2 ; p2 7 d2=xxyy00CC - endc - ifne \1&$50 - swap d3 ; p1 d3=00BB00DD - endc - ifne \1&$08 - bank 1,1,move.w,(a2,d4.w),d4 ; p2 8 - endc - ifne \1&$04 - bank 1,1,move.b,(a2,d5.w),d4 ; p1 - endc - ifne \1&$0a - bank 0,1,swap,d4 ; p2 9 + endc + ifne \1&$a0 + swap d2 ; p2 7 d2=xxyy00CC + endc + ifne \1&$50 + swap d3 ; p1 d3=00BB00DD + endc + ifne \1&$08 + move.w (a2,d4.w),d4 ; p2 8 + endc + ifne \1&$04 + move.b (a2,d5.w),d4 ; p1 + endc + ifne \1&$0a + swap d4 ; p2 9 endc ifne \1&$05 - bank 0,1,swap,d5 ; p1 + swap d5 ; p1 endc ifne \1&$20 move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- @@ -307,65 +298,39 @@ transform macro move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt endc ifne \1&$02 - bank 1,1,move.w,(a2,d4.w),d4 ; p1 12 + move.w (a2,d4.w),d4 ; p1 12 endc ifne \1&$01 - bank 1,1,move.b,(a2,d5.w),d4 ; p1 13 + move.b (a2,d5.w),d4 ; p1 13 endc * output d2/d4 * move.l d2,(a0)+ ; F * move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm -push_d4_d5 macro - ifeq USE_BANK - movem.l d4/d5,-(sp) - endc - endm -pull_d4_d5 macro - ifeq USE_BANK - ifne VAMP_V4 - movem.l (sp)+,d4/d5 - else - move.l (sp)+,d4 - move.l (sp)+,d5 - endc - endc - endm - _RenderLine2_AMMX move.l -(a3),d1 chk_bounds _RenderLine0_AMMX\.mx - push_d4_d5 - move.l d1,d3 ; \ fused addq.l #1,d3 ; / bne .mask .n8 macro move.l (a1)+,d3 - bank 0,1,move.l,(a1)+,d5 + move.l (a1)+,d5 transform $ff move.l d2,(a0)+ - bank 1,0,move.l,d4,(a0)+ - ifne \1 - pull_d4_d5 - endc + move.l d4,(a0)+ endm .n0 macro move.l (a1),d3 - bank 0,1,move.l,4(a1),d5 + move.l (a1),d5 transform $ff - ifne USE_BANK - vperm #$4567CDEF,d2,e4,d2 - else vperm #$4567CDEF,d2,d4,d2 - endc storec d2,d0,(a0) endm unroll_AMMX .n8,.n0,.nx - pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds @@ -375,23 +340,23 @@ _RenderLine2_AMMX .transfAA55_8 macro move.b \1(a1),d2 ; 1 move.b \1+2(a1),d3 ; 2 - bank 0,1,move.b,\1+4(a1),d4 ; 3 - bank 0,1,move.b,\1+6(a1),d5 ; 4 + move.b \1+4(a1),d4 ; 3 + move.b \1+6(a1),d5 ; 4 addq.l #8,a0 ; 4 addq.l #8,a1 ; 5 move.w (a2,d2.w),d1 ; 5 move.b (a2,d3.w),d1 ; 6 swap d1 ; 7 - bank 1,0,move.w,(a2,d4.w),d1 ; 8 - bank 1,0,move.b,(a2,d5.w),d1 ; 9 + move.w (a2,d4.w),d1 ; 8 + move.b (a2,d5.w),d1 ; 9 movep.l d1,\1-8(a0) ; 10 endm .transfAA55 macro moveq #0,d2 moveq #0,d3 - bank 0,1,moveq,#0,d4 - bank 0,1,moveq,#0,d5 + moveq #0,d4 + moveq #0,d5 bclr #5,d0 beq .b4\2 @@ -399,7 +364,6 @@ _RenderLine2_AMMX .transfAA55_8 \1 .transfAA55_8 \1 .transfAA55_8 \1 - pull_d4_d5 rts_bounds .b4\2 bclr #4,d0 @@ -411,7 +375,6 @@ _RenderLine2_AMMX beq.b .b2\2 .transfAA55_8 \1 .b2\2 - pull_d4_d5 bclr #2,d0 beq.b .b1\2 move.b \1(a1),d2 ; 1 @@ -449,7 +412,6 @@ _RenderLine2_AMMX .mask55 .transfAA55 1,_55 - .mask move.l #$AAAAAAAA,d3 eor.l d1,d3 @@ -459,35 +421,23 @@ _RenderLine2_AMMX .m8 macro move.l (a1)+,d3 ; F(used) d3=AABBCCDD - bank 0,1,move.l,(a1)+,d5 ; F 1 + move.l (a1)+,d5 ; F 1 rol.l #8,d1 transform $ff - ifne USE_BANK - vperm #$4567CDEF,d2,e4,d2 - else vperm #$4567CDEF,d2,d4,d2 - endc storem d2,d1,(a0)+ - ifne \1 - pull_d4_d5 - endc endm .m0 macro move.l (a1),d3 ; F(used) d3=AABBCCDD - bank 0,1,move.l,4(a1),d5 ; F 1 + move.l 4(a1),d5 ; F 1 rol_d1_mask transform $ff - ifne USE_BANK - vperm #$4567CDEF,d2,e4,d2 - else vperm #$4567CDEF,d2,d4,d2 - endc storem d2,d1,(a0) endm .maskXX unroll_AMMX .m8,.m0,.mx - pull_d4_d5 add.w d0,a0 add.w d0,a1 rts_bounds @@ -954,14 +904,6 @@ setup macro move.l (4*(3+\1),sp),a2 ; \ fused move.l (4*(4+\1),sp),a3 ; / ENDC - ifne USE_BANK - inline - tst.b _ac68080_ammx - beq .1 - bank 0,1,move.l,a2,a2 -.1 - einline - endc bsr _setup endm @@ -1125,10 +1067,11 @@ epilogue_11 macro _RenderTile_RT_TRANSPARENT prologue_11 addq.l #2,a4 ; skip over load mask - moveq #31,d7 + REPT 32 + inline .L1 move.l -(a3),d6 ; m = *mask; mask-- - moveq #32,d4 + moveq #32,d7 .L2 moveq #0,d0 ; TODO: remove ? move.b (a1)+,d0 @@ -1136,7 +1079,7 @@ _RenderTile_RT_TRANSPARENT .L22 neg.b d0 ; p1 lsl.l d0,d6 ; p1 - sub.l d0,d4 ; p2 + sub.l d0,d7 ; p2 adda.l d0,a0 ; p1 doesnt affect the flags beq.b .L5 ; p2 likely be false move.b (a1)+,d0 ; p1 @@ -1144,7 +1087,7 @@ _RenderTile_RT_TRANSPARENT .L3 move.l d6,d1 lsl.l d0,d6 - sub.l d0,d4 + sub.l d0,d7 beq .L4 ; likely to be false most of the times jsr (a4) moveq #0,d0 ; TODO: remove ? @@ -1155,7 +1098,8 @@ _RenderTile_RT_TRANSPARENT jsr (a4) .L5 sub.w #BUFFER_WIDTH+32,a0 - dbra d7,.L1 + einline + ENDR epilogue_11 *------------------------------------------------------------------------------------ From fb7444801472ff82a93b3c60fc9098e4baa1a66c Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 25 Dec 2019 14:44:58 +0100 Subject: [PATCH 051/107] fixed cr/lf --- SourceS/sdl_compat.h | 200 +++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 865c922c542..9d204446f6d 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -1,100 +1,100 @@ -// Compatibility wrappers for SDL 1 & 2. -#pragma once -#include - -#ifndef USE_SDL1 -#define SDLC_KEYSTATE_LEFTSHIFT SDL_SCANCODE_LSHIFT -#define SDLC_KEYSTATE_RIGHTSHIFT SDL_SCANCODE_RSHIFT -#define SDLC_KEYSTATE_MENU SDL_SCANCODE_MENU -#define SDLC_KEYSTATE_UP SDL_SCANCODE_UP -#define SDLC_KEYSTATE_DOWN SDL_SCANCODE_DOWN -#define SDLC_KEYSTATE_LEFT SDL_SCANCODE_LEFT -#define SDLC_KEYSTATE_RIGHT SDL_SCANCODE_RIGHT -#else -#if defined(__AMIGA__) // Add other systems that require an 8bit screen here -extern "C" -{ - extern char ac68080_saga; - extern char ac68080_ammx; - extern int vampire_Flip(SDL_Surface *surf); - extern int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, - SDL_Surface *dst, SDL_Rect *dstRect); -} //extern C -#endif -#define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT -#define SDLC_KEYSTATE_RIGHTSHIFT SDLK_LSHIFT -#define SDLC_KEYSTATE_MENU SDLK_MENU -#define SDLC_KEYSTATE_UP SDLK_UP -#define SDLC_KEYSTATE_DOWN SDLK_DOWN -#define SDLC_KEYSTATE_LEFT SDLK_LEFT -#define SDLC_KEYSTATE_RIGHT SDLK_RIGHT -#endif - -inline const Uint8 *SDLC_GetKeyState() -{ -#ifndef USE_SDL1 - return SDL_GetKeyboardState(nullptr); -#else - return SDL_GetKeyState(nullptr); -#endif -} - -inline int SDLC_SetColorKey(SDL_Surface *surface, Uint32 key) -{ -#ifdef USE_SDL1 - return SDL_SetColorKey(surface, SDL_SRCCOLORKEY, key); -#else - return SDL_SetColorKey(surface, SDL_TRUE, key); -#endif -} - -// Copies the colors into the surface's palette. -inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors) -{ -#ifdef USE_SDL1 - int flags = SDL_LOGPAL; -#if SDL1_VIDEO_MODE_BPP == 8 - flags |= SDL_PHYSPAL; -#endif - return SDL_SetPalette(surface, flags, colors, firstcolor, ncolors) - 1; -#else - return SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, ncolors); -#endif -} - -// Copies the colors into the surface's palette. -inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Palette *palette) -{ - return SDLC_SetSurfaceColors(surface, palette->colors, 0, palette->ncolors); -} - -// Sets the palette's colors and: -// SDL2: Points the surface's palette to the given palette if necessary. -// SDL1: Sets the surface's colors. -inline int SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *palette, SDL_Color *colors, int firstcolor, int ncolors) -{ -#ifdef USE_SDL1 - if (ncolors > (palette->ncolors - firstcolor)) { - SDL_SetError("ncolors > (palette->ncolors - firstcolor)"); - return -1; - } - if (colors != (palette->colors + firstcolor)) - SDL_memcpy(palette->colors + firstcolor, colors, ncolors * sizeof(*colors)); - - #if SDL1_VIDEO_MODE_BPP == 8 - - // When the video surface is 8bit, we need to set the output pallet as well. - SDL_SetColors(SDL_GetVideoSurface(), colors, firstcolor, ncolors); - - #endif - // In SDL1, the surface always has its own distinct palette, so we need to - // update it as well. - return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) - 1; -#else - if (SDL_SetPaletteColors(palette, colors, firstcolor, ncolors) < 0) - return -1; - if (surface->format->palette != palette) - return SDL_SetSurfacePalette(surface, palette); - return 0; -#endif -} +// Compatibility wrappers for SDL 1 & 2. +#pragma once +#include + +#ifndef USE_SDL1 +#define SDLC_KEYSTATE_LEFTSHIFT SDL_SCANCODE_LSHIFT +#define SDLC_KEYSTATE_RIGHTSHIFT SDL_SCANCODE_RSHIFT +#define SDLC_KEYSTATE_MENU SDL_SCANCODE_MENU +#define SDLC_KEYSTATE_UP SDL_SCANCODE_UP +#define SDLC_KEYSTATE_DOWN SDL_SCANCODE_DOWN +#define SDLC_KEYSTATE_LEFT SDL_SCANCODE_LEFT +#define SDLC_KEYSTATE_RIGHT SDL_SCANCODE_RIGHT +#else +#if defined(__AMIGA__) // Add other systems that require an 8bit screen here +extern "C" +{ + extern char ac68080_saga; + extern char ac68080_ammx; + extern int vampire_Flip(SDL_Surface *surf); + extern int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, + SDL_Surface *dst, SDL_Rect *dstRect); +} //extern C +#endif +#define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT +#define SDLC_KEYSTATE_RIGHTSHIFT SDLK_LSHIFT +#define SDLC_KEYSTATE_MENU SDLK_MENU +#define SDLC_KEYSTATE_UP SDLK_UP +#define SDLC_KEYSTATE_DOWN SDLK_DOWN +#define SDLC_KEYSTATE_LEFT SDLK_LEFT +#define SDLC_KEYSTATE_RIGHT SDLK_RIGHT +#endif + +inline const Uint8 *SDLC_GetKeyState() +{ +#ifndef USE_SDL1 + return SDL_GetKeyboardState(nullptr); +#else + return SDL_GetKeyState(nullptr); +#endif +} + +inline int SDLC_SetColorKey(SDL_Surface *surface, Uint32 key) +{ +#ifdef USE_SDL1 + return SDL_SetColorKey(surface, SDL_SRCCOLORKEY, key); +#else + return SDL_SetColorKey(surface, SDL_TRUE, key); +#endif +} + +// Copies the colors into the surface's palette. +inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors) +{ +#ifdef USE_SDL1 + int flags = SDL_LOGPAL; +#if SDL1_VIDEO_MODE_BPP == 8 + flags |= SDL_PHYSPAL; +#endif + return SDL_SetPalette(surface, flags, colors, firstcolor, ncolors) - 1; +#else + return SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, ncolors); +#endif +} + +// Copies the colors into the surface's palette. +inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Palette *palette) +{ + return SDLC_SetSurfaceColors(surface, palette->colors, 0, palette->ncolors); +} + +// Sets the palette's colors and: +// SDL2: Points the surface's palette to the given palette if necessary. +// SDL1: Sets the surface's colors. +inline int SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *palette, SDL_Color *colors, int firstcolor, int ncolors) +{ +#ifdef USE_SDL1 + if (ncolors > (palette->ncolors - firstcolor)) { + SDL_SetError("ncolors > (palette->ncolors - firstcolor)"); + return -1; + } + if (colors != (palette->colors + firstcolor)) + SDL_memcpy(palette->colors + firstcolor, colors, ncolors * sizeof(*colors)); + + #if SDL1_VIDEO_MODE_BPP == 8 + + // When the video surface is 8bit, we need to set the output pallet as well. + SDL_SetColors(SDL_GetVideoSurface(), colors, firstcolor, ncolors); + + #endif + // In SDL1, the surface always has its own distinct palette, so we need to + // update it as well. + return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) - 1; +#else + if (SDL_SetPaletteColors(palette, colors, firstcolor, ncolors) < 0) + return -1; + if (surface->format->palette != palette) + return SDL_SetSurfacePalette(surface, palette); + return 0; +#endif +} From 37b6df02303aecc792873be1d5dc98df18ce04ca Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 26 Dec 2019 13:52:45 +0100 Subject: [PATCH 052/107] faster vampire_SurfaceFlip() --- SourceX/platform/amiga/ac68080_support.c | 122 +++++++++++++++++------ 1 file changed, 90 insertions(+), 32 deletions(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index b6f76c5d85f..cfd810b0336 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -71,9 +71,9 @@ extern void gamemenu_quit_game(int); UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; -static volatile USHORT copy_pane_mask = 0; +static USHORT copy_pane_mask = 0; -static UBYTE *bufmem = NULL; +static UBYTE *bufmem = NULL, *bufmem_roll; static UBYTE started = 0; static struct Screen *game_screen; static SDL_Surface *saga_surface; @@ -157,7 +157,7 @@ static void stop(void) } if(bufmem) { dlfree(bufmem); - bufmem = NULL; + bufmem_roll = bufmem = NULL; } } @@ -179,6 +179,8 @@ static void start(void) if(!saga_surface) { dlfree(bufmem); bufmem = NULL; + } else { + bufmem_roll = bufmem + 2*FRAME_BUFFER_SZ; } } @@ -205,7 +207,7 @@ static void start(void) } } -static void chkSignals(void) +static __attribute__((noinline)) void doChkSignals(void) { static UBYTE closing; ULONG signal = SetSignal(0,0); @@ -236,31 +238,56 @@ static void chkSignals(void) } } -static __attribute__((noinline)) int ok(SDL_Surface *const surf) +static void chkSignals(void) { - chkSignals(); + static UBYTE closing, ctr; + if(!ctr) { + ctr = 4; + doChkSignals(); + } else { + --ctr; + } +} + +static __attribute__((noinline, regparm(2))) int ok(SDL_Surface *surf) +{ + int t; if(!started) start(); if(!ac68080_saga) return 0; - if(surf!=SDL_GetVideoSurface()) return 0; - if(surf->w != SCREEN_WIDTH || surf->h != SCREEN_HEIGHT) return 0; - return 1; + // always true + // if(surf!=SDL_GetVideoSurface()) return 0; + return surf->w == SCREEN_WIDTH && surf->h == SCREEN_HEIGHT ? -1 : 0; } -int vampire_Flip(SDL_Surface* surf) +int vampire_Flip(const SDL_Surface* surf) { volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ // volatile ULONG *pal = (ULONG*)0xDFF400; struct Screen *first_screen; static UBYTE panel_cpy_flag = 4; + + chkSignals(); #if DIRTY *dpy = (void*)(~31&(int)surf->pixels); return; #endif - if(!ok(surf)) goto legacy; - - surf = saga_surface; +#define USE_ASM 1 + +#if USE_ASM + // a bit risky as it assumes nothing is pushed on stack + // before this point, but I better like this code than + // the one from gcc + __asm__ __volatile__( + " move.l 4(sp),a0 \n" + " bsr.w _ok \n" + " tst.l d0 \n" + " beq.l _SDL_Flip \n" + : : : "d0", "a0"); +#else + if(!ok(surf)) return SDL_Flip(surf); +#endif #if CHECK_FIRSTSCREEN // check if screen has changed @@ -273,33 +300,61 @@ int vampire_Flip(SDL_Surface* surf) if(first_screen == game_screen) #endif { - UBYTE *ptr = surf->pixels, *old; + register UBYTE *ptr asm("a0") = saga_surface->pixels; + register LONG dlt = -FRAME_BUFFER_SZ; // display *dpy = ptr; #if ROLL_PTR - old = ptr; +#if USE_ASM + __asm__ __volatile( + " cmpa.l %2,%0 \n" + " bne.s .l1%= \n" + " move.l %6,%1 \n" + ".l1%=: \n" + " suba.l %1,%0 \n" + " move.l %0,%3 \n" + " adda.l %7,%0 \n" + " lsr.w %4 \n" + " beq .l2%= \n" +// " pea %8 \n" +// " pea (%0,%1.l) \n" +// " pea (%0) \n" +// " bsr %5 \n" +// " add.w #12,sp \n" + " lea (%0,%1.l),a1 \n" + " move.l %8,d0 \n" + ".l3%=: \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " move.l (a1)+,(%0)+ \n" + " subq.l #1,d0 \n" + " bne.s .l3%= \n" + ".l2%=: \n" + : "+a"(ptr), "+d"(dlt) + : "m" (bufmem_roll), "m" (saga_surface->pixels), + "m" (copy_pane_mask), "m"(memcpy), + "i"(2*FRAME_BUFFER_SZ), "i"(PANEL_TOP*SCREEN_WIDTH), "i" (PANEL_HEIGHT*SCREEN_WIDTH/32)); +#else // advance ptr - if(ptr >= bufmem + 2*FRAME_BUFFER_SZ) - ptr -= 2*FRAME_BUFFER_SZ; - else - ptr += FRAME_BUFFER_SZ; - surf->pixels = ptr; + if(ptr == bufmem_roll) dlt = 2*FRAME_BUFFER_SZ; + saga_surface->pixels = (ptr -= dlt); - // if(copy_pane_mask) { - // copy_pane_mask >>= 1; - asm goto ("lsr.w %0\n\tbeq.s %l1" : : "m"(copy_pane_mask) : : skip); - memcpy(ptr + PANEL_TOP*SCREEN_WIDTH, - old + PANEL_TOP*SCREEN_WIDTH, - PANEL_HEIGHT*SCREEN_WIDTH); - // } - skip: (void)0; + if(copy_pane_mask) + { + copy_pane_mask >>= 1; + memcpy(ptr + PANEL_TOP*SCREEN_WIDTH, ptr + PANEL_TOP*SCREEN_WIDTH + dlt, PANEL_HEIGHT*SCREEN_WIDTH); + } +#endif #endif } return 0; -legacy: - return SDL_Flip(surf); } int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, @@ -319,8 +374,11 @@ int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, if(srcRect // && srcRect->w < SCREEN_WIDTH // ignore full screen && !(srcRect->w==288 && srcRect->h==60) // ignore descpane - && srcRect->y + srcRect->h >= PANEL_TOP + SCREEN_Y - ) copy_pane_mask = 4; // we need to copy 3 times the panel if something was drawn there + && srcRect->y + srcRect->h > PANEL_TOP + SCREEN_Y + ) { + //printf("copy because of %d %d %d %d\n", srcRect->x, srcRect->y, srcRect->w, srcRect->h); + copy_pane_mask = 4; // we need to copy 3 times the panel if something was drawn there + } if(last_version!=pal_palette_version) { last_version = pal_palette_version; SDL_SetColors(saga_surface, pal_palette->colors, 0, pal_palette->ncolors); From 6c74404ee281885e3a7e6d93348a9a878144c293 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER <33961444+Samuel-DEVULDER@users.noreply.github.com> Date: Fri, 27 Dec 2019 21:21:48 +0100 Subject: [PATCH 053/107] Update SourceS/sdl_compat.h Co-Authored-By: Marlon Beijer --- SourceS/sdl_compat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 9d204446f6d..3df4dc65f02 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -82,7 +82,6 @@ inline int SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *pa SDL_memcpy(palette->colors + firstcolor, colors, ncolors * sizeof(*colors)); #if SDL1_VIDEO_MODE_BPP == 8 - // When the video surface is 8bit, we need to set the output pallet as well. SDL_SetColors(SDL_GetVideoSurface(), colors, firstcolor, ncolors); From e0c6f57ecbcce9fffc6fd1bac6b89ccea02dc982 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 29 Dec 2019 15:47:46 +0100 Subject: [PATCH 054/107] just in case --- 3rdParty/libsmacker/smk_bitstream.c | 4 +- Source/scrollrt.cpp | 12 + SourceS/sdl_compat.h | 2 + SourceX/dx.cpp | 14 +- SourceX/platform/amiga/ac68080_support.c | 273 ++++++++++++----------- SourceX/storm/storm.cpp | 9 +- 6 files changed, 170 insertions(+), 144 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 25f9da5d5c1..45baeb1fc09 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -248,7 +248,7 @@ struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) /* Reads a bit Returns -1 if error encountered */ -char _smk_bs_read_1(struct smk_bit_t* bs) +char REGPARM _smk_bs_read_1(struct smk_bit_t* bs) { unsigned char ret = -1; @@ -282,7 +282,7 @@ char _smk_bs_read_1(struct smk_bit_t* bs) /* Reads a byte Returns -1 if error. */ -short _smk_bs_read_8(struct smk_bit_t* bs) +short REGPARM _smk_bs_read_8(struct smk_bit_t* bs) { unsigned char ret = -1; diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index d61304db88e..0dc5d502715 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1261,12 +1261,24 @@ void DrawAndBlit() unlock_buf(0); +#ifdef __AMIGA__ + vampire_BypassSDL(1); +#endif + DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag); +#ifdef __AMIGA__ + vampire_BypassSDL(-1); +#endif + lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); +#ifdef __AMIGA__ + vampire_BypassSDL(0); +#endif + drawhpflag = FALSE; drawmanaflag = FALSE; drawbtnflag = FALSE; diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 9d204446f6d..223dc89aa54 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -16,9 +16,11 @@ extern "C" { extern char ac68080_saga; extern char ac68080_ammx; + extern void vampire_BypassSDL(int enable_flip_disable); extern int vampire_Flip(SDL_Surface *surf); extern int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect); + extern SDL_Surface *vampire_MakeTripleBuffer(SDL_Surface *surf); } //extern C #endif #define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT diff --git a/SourceX/dx.cpp b/SourceX/dx.cpp index 04352bffc0f..96c478ef000 100644 --- a/SourceX/dx.cpp +++ b/SourceX/dx.cpp @@ -7,9 +7,17 @@ namespace dvl { #ifdef __AMIGA__ -#define SDL_Flip vampire_Flip -#define SDL_BlitSurface vampire_BlitSurface -// #define SDL_Flip(x) (*(int*)0xDFF1EC = -32&(int)((x)->pixels), 0) +static inline SDL_Surface* wrap_CreateRGBSurfaceWithFormat(Uint32 flags, + int width, + int height, + int depth, + Uint32 format) +{ + return vampire_MakeTripleBuffer(SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format)); +} +#define SDL_Flip vampire_Flip +#define SDL_BlitSurface vampire_BlitSurface +#define SDL_CreateRGBSurfaceWithFormat wrap_CreateRGBSurfaceWithFormat #endif int sgdwLockCount; diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index cfd810b0336..39a80ec48e8 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -9,14 +9,17 @@ #include #include #include +#include #include #include +#include + #include "../../../../defs.h" -#define FRAME_BUFFER_SZ ((SCREEN_WIDTH)*(SCREEN_HEIGHT)) -#define DIRTY 0 // 1 = 32 fps 0 = 29fps +#define FRAME_BUFFER_SZ ((BUFFER_WIDTH)*(BUFFER_HEIGHT)) + #define DIRTY 0 // 1 = 32 fps 0 = 29fps #define CHECK_FIRSTSCREEN 1 // costs 0 fps @@ -71,12 +74,12 @@ extern void gamemenu_quit_game(int); UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; -static USHORT copy_pane_mask = 0; +static UBYTE copy_previous = 0, copy_panel_only = 0; static UBYTE *bufmem = NULL, *bufmem_roll; -static UBYTE started = 0; +static UBYTE started = 0, bypass_sdl = 0, pane; static struct Screen *game_screen; -static SDL_Surface *saga_surface; +static struct View *view; struct Library *VampireBase; extern struct ExecBase *SysBase; @@ -151,10 +154,6 @@ static int MUNMAP(void *p, size_t len) static void stop(void) { - if(saga_surface) { - SDL_FreeSurface(saga_surface); - saga_surface = NULL; - } if(bufmem) { dlfree(bufmem); bufmem_roll = bufmem = NULL; @@ -171,21 +170,11 @@ static void start(void) bufmem = dlmemalign(32/* byte alignment for saga */, 3*FRAME_BUFFER_SZ); if(bufmem) { - saga_surface = SDL_CreateRGBSurfaceFrom( - bufmem, - SCREEN_WIDTH, SCREEN_HEIGHT, 8, SCREEN_WIDTH, - 0, 0, 0, 0 - ); - if(!saga_surface) { - dlfree(bufmem); - bufmem = NULL; - } else { - bufmem_roll = bufmem + 2*FRAME_BUFFER_SZ; - } + bufmem_roll = bufmem + 2*FRAME_BUFFER_SZ; + } else { + ac68080_saga = 0; } - if(!bufmem) ac68080_saga = 0; - if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); if(VampireBase && VampireBase->lib_Version >= 45 && (V_EnableAMMX( V_AMMX_V2 ) != VRES_ERROR) ) { @@ -207,6 +196,22 @@ static void start(void) } } +SDL_Surface* vampire_MakeTripleBuffer(SDL_Surface *surf) +{ + if(!started) start(); + + if(ac68080_saga + && surf->w==BUFFER_WIDTH + && surf->h==BUFFER_HEIGHT + && surf->pitch==BUFFER_WIDTH + ) { + surf->flags |= SDL_PREALLOC; + SDL_free(surf->pixels); + surf->pixels = bufmem; + } else ac68080_saga = 0; + return surf; +} + static __attribute__((noinline)) void doChkSignals(void) { static UBYTE closing; @@ -249,46 +254,48 @@ static void chkSignals(void) } } -static __attribute__((noinline, regparm(2))) int ok(SDL_Surface *surf) +static void blitRect(UBYTE *dst, UBYTE *src, UWORD x, UWORD y, size_t w, UWORD h) { - int t; - if(!started) start(); - if(!ac68080_saga) return 0; - // always true - // if(surf!=SDL_GetVideoSurface()) return 0; - return surf->w == SCREEN_WIDTH && surf->h == SCREEN_HEIGHT ? -1 : 0; + src += SCREENXY(x,y); + dst += SCREENXY(x,y); + memcpy(dst-x, src-x, BUFFER_WIDTH*h); + + // do { + // memcpy(dst, src, w); + // src += BUFFER_WIDTH; + // dst += BUFFER_WIDTH; + // } while(--h); } -int vampire_Flip(const SDL_Surface* surf) +// check if palette has changed +static void doPalette(void) +{ + static int last_version = 0; + if(last_version!=pal_palette_version) { + last_version = pal_palette_version; + SDL_SetColors(SDL_GetVideoSurface(), pal_palette->colors, 0, pal_palette->ncolors); + } +} + +static void setFrameBufferRegs(UBYTE *ptr, UWORD modulo) +{ + volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ + volatile UWORD *mod = (UBYTE**)0xDFF1E6; /* Frame buffer modulo */ + + *dpy = ptr; + *mod = modulo; +} + +static void doFlip(void) { - volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ -// volatile ULONG *pal = (ULONG*)0xDFF400; struct Screen *first_screen; - static UBYTE panel_cpy_flag = 4; - chkSignals(); - #if DIRTY - *dpy = (void*)(~31&(int)surf->pixels); + // hacky way to debug + *dpy = (void*)(~31&(int)pal_surface->pixels); return; #endif -#define USE_ASM 1 - -#if USE_ASM - // a bit risky as it assumes nothing is pushed on stack - // before this point, but I better like this code than - // the one from gcc - __asm__ __volatile__( - " move.l 4(sp),a0 \n" - " bsr.w _ok \n" - " tst.l d0 \n" - " beq.l _SDL_Flip \n" - : : : "d0", "a0"); -#else - if(!ok(surf)) return SDL_Flip(surf); -#endif - #if CHECK_FIRSTSCREEN // check if screen has changed if(game_screen != (first_screen = IntuitionBase->FirstScreen) @@ -300,108 +307,106 @@ int vampire_Flip(const SDL_Surface* surf) if(first_screen == game_screen) #endif { - register UBYTE *ptr asm("a0") = saga_surface->pixels; - register LONG dlt = -FRAME_BUFFER_SZ; + UBYTE *ptr = pal_surface->pixels; + LONG dlt = ptr == bufmem_roll ? -2*FRAME_BUFFER_SZ : FRAME_BUFFER_SZ; - // display - *dpy = ptr; + setFrameBufferRegs(ptr + SCREENXY(0,0), BUFFER_WIDTH - SCREEN_WIDTH); #if ROLL_PTR -#if USE_ASM - __asm__ __volatile( - " cmpa.l %2,%0 \n" - " bne.s .l1%= \n" - " move.l %6,%1 \n" - ".l1%=: \n" - " suba.l %1,%0 \n" - " move.l %0,%3 \n" - " adda.l %7,%0 \n" - " lsr.w %4 \n" - " beq .l2%= \n" -// " pea %8 \n" -// " pea (%0,%1.l) \n" -// " pea (%0) \n" -// " bsr %5 \n" -// " add.w #12,sp \n" - " lea (%0,%1.l),a1 \n" - " move.l %8,d0 \n" - ".l3%=: \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " move.l (a1)+,(%0)+ \n" - " subq.l #1,d0 \n" - " bne.s .l3%= \n" - ".l2%=: \n" - : "+a"(ptr), "+d"(dlt) - : "m" (bufmem_roll), "m" (saga_surface->pixels), - "m" (copy_pane_mask), "m"(memcpy), - "i"(2*FRAME_BUFFER_SZ), "i"(PANEL_TOP*SCREEN_WIDTH), "i" (PANEL_HEIGHT*SCREEN_WIDTH/32)); -#else - // advance ptr - if(ptr == bufmem_roll) dlt = 2*FRAME_BUFFER_SZ; - saga_surface->pixels = (ptr -= dlt); - - if(copy_pane_mask) + // printf("ptr=%p // %p %p %p %p\n", ptr,bufmem, bufmem+FRAME_BUFFER_SZ, bufmem+2*FRAME_BUFFER_SZ, bufmem+3*FRAME_BUFFER_SZ); + + // need to copy parts of previous screen? + if(copy_previous) { - copy_pane_mask >>= 1; - memcpy(ptr + PANEL_TOP*SCREEN_WIDTH, ptr + PANEL_TOP*SCREEN_WIDTH + dlt, PANEL_HEIGHT*SCREEN_WIDTH); + --copy_previous; + if(copy_panel_only) + blitRect(ptr+dlt, ptr, PANEL_LEFT, PANEL_TOP, PANEL_WIDTH, PANEL_HEIGHT); + else + blitRect(ptr+dlt, ptr, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); } -#endif + + // advance ptr + pal_surface->pixels = (ptr += dlt); #endif } - return 0; + doPalette(); +} + +void vampire_BypassSDL(int enable_flip_disable) +{ + if(ac68080_saga) { + bypass_sdl = enable_flip_disable; + if(enable_flip_disable<0) doFlip(); + } +} + +int vampire_Flip(const SDL_Surface* surf) +{ + static SDL_Rect palRect = {SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT}; + static UBYTE old_was_saga; + + chkSignals(); + if(bypass_sdl) { + if(!old_was_saga) { + old_was_saga = 255; + SDL_BlitSurface(surf, NULL, pal_surface, &palRect); + } + return 0; + } else { + if(old_was_saga) { + SDL_BlitSurface(pal_surface, &palRect, surf, NULL); + if(game_screen==IntuitionBase->FirstScreen) { + // struct Screen *s = IntuitionBase->FirstScreen, *t=s->NextScreen; + // s->NextScreen = t->NextScreen; + // t->NextScreen = s; + // IntuitionBase->FirstScreen = t; + // ScreenToFront(s); + + ULONG bufmem; + APTR handle = LockBitMapTags(&game_screen->BitMap, + LBMI_BASEADDRESS, (ULONG)&bufmem,(ULONG)TAG_DONE); + if(handle) { + setFrameBufferRegs((UBYTE*)(bufmem&-32), 0); + UnLockBitMap(handle); + // old_was_saga = 0; + printf("reset intui\n"); + } else printf("failed to reset intui\n"); + } + } + return SDL_Flip(surf); + } } int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect) { - if(ok(dst)) { - static int last_version; - // if(srcRect==NULL || srcRect->w==SCREEN_HEIGHT) { - // /*resync*/ - // int ret = SDL_BlitSurface(src, srcRect, dst, dstRect); - // UBYTE *ptr = (UBYTE*)(~31&(31+(ULONG)bufmem)); - // memcpy(ptr, dst->pixels, FRAME_BUFFER_SZ); ptr += FRAME_BUFFER_SZ; - // memcpy(ptr, dst->pixels, FRAME_BUFFER_SZ); ptr += FRAME_BUFFER_SZ; - // memcpy(ptr, dst->pixels, FRAME_BUFFER_SZ); ptr += FRAME_BUFFER_SZ; - // return ret; - // } - if(srcRect - // && srcRect->w < SCREEN_WIDTH // ignore full screen - && !(srcRect->w==288 && srcRect->h==60) // ignore descpane - && srcRect->y + srcRect->h > PANEL_TOP + SCREEN_Y - ) { - //printf("copy because of %d %d %d %d\n", srcRect->x, srcRect->y, srcRect->w, srcRect->h); - copy_pane_mask = 4; // we need to copy 3 times the panel if something was drawn there - } - if(last_version!=pal_palette_version) { - last_version = pal_palette_version; - SDL_SetColors(saga_surface, pal_palette->colors, 0, pal_palette->ncolors); - } - return SDL_BlitSurface(src, srcRect, saga_surface, dstRect); - } - return SDL_BlitSurface(src, srcRect, dst, dstRect); + if(!bypass_sdl) + return SDL_BlitSurface(src, srcRect, dst, dstRect); + + // check if something is displayed in the panel + if(!srcRect || srcRect->h>=SCREEN_HEIGHT) { + copy_panel_only = 0; + copy_previous = 3; + } else if(srcRect->y + srcRect->h > PANEL_Y + && !(srcRect->w==288 && srcRect->h==60) // ignore descpane + ) { + if(!copy_previous) + copy_panel_only = 1; + copy_previous = 3; + } + + return 0; } #define min(a,b) ((a)<=(b)?(a):(b)) -int zzzvampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, +int simple_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect) { register UBYTE *s, *d; UWORD w; WORD h; - if(!ok(dst)) goto legacy; - - // replace sdl video output by our own - dst = saga_surface; - if(!srcRect) { static SDL_Rect r; r.w = src->w; @@ -434,8 +439,4 @@ int zzzvampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, d += dst->pitch; } return 0; -legacy: - // if(srcRect && dstRect) - // return SDL_LowerBlit(src, srcRect, dst, dstRect); - return SDL_BlitSurface(src, srcRect, dst, dstRect); } diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 1d04fbed632..81242940ec9 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -712,9 +712,12 @@ BOOL SVidPlayContinue(void) Uint32 format = SDL_GetWindowPixelFormat(window); SDL_Surface *tmp = SDL_ConvertSurfaceFormat(SVidSurface, format, 0); #endif -// #ifndef __AMIGA__ - ScaleOutputRect(&pal_surface_offset); // somehow this lead to pb with amiga's SDL -// #endif +#ifndef __AMIGA__ + // somehow this cann to ScaleOututputRect lead to pb with amiga's SDL: + // the rotating blizzard logo at startup freeze randomly. + // ==> so this operation is disabled on the amiga + ScaleOutputRect(&pal_surface_offset); +#endif if (SDL_BlitScaled(tmp, NULL, GetOutputSurface(), &pal_surface_offset) <= -1) { SDL_Log(SDL_GetError()); return false; From b8dfd75bc089a6fc5c5719dd8b69d3ef0ffda41b Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 29 Dec 2019 16:47:33 +0100 Subject: [PATCH 055/107] ok this one works --- Source/scrollrt.cpp | 15 ++--- SourceS/sdl_compat.h | 1 - SourceX/platform/amiga/ac68080_support.c | 81 +++++++----------------- 3 files changed, 28 insertions(+), 69 deletions(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 0dc5d502715..89000103688 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1200,6 +1200,10 @@ void scrollrt_draw_game_screen(BOOL draw_cursor) DrawMain(hgt, 0, 0, 0, 0, 0); if (draw_cursor) { +#ifdef __AMIGA__ + lock_buf(0); + unlock_buf(0); // forces flip before cursor restore display +#endif lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); @@ -1261,24 +1265,17 @@ void DrawAndBlit() unlock_buf(0); -#ifdef __AMIGA__ - vampire_BypassSDL(1); -#endif - DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag); #ifdef __AMIGA__ - vampire_BypassSDL(-1); + lock_buf(0); + unlock_buf(0); // forces flip before cursor restore display #endif lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); -#ifdef __AMIGA__ - vampire_BypassSDL(0); -#endif - drawhpflag = FALSE; drawmanaflag = FALSE; drawbtnflag = FALSE; diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 223dc89aa54..4d6fe4a8599 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -16,7 +16,6 @@ extern "C" { extern char ac68080_saga; extern char ac68080_ammx; - extern void vampire_BypassSDL(int enable_flip_disable); extern int vampire_Flip(SDL_Surface *surf); extern int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect); diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 39a80ec48e8..25b27bfc629 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -74,10 +74,10 @@ extern void gamemenu_quit_game(int); UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; -static UBYTE copy_previous = 0, copy_panel_only = 0; +static USHORT copy_previous = 0; static UBYTE *bufmem = NULL, *bufmem_roll; -static UBYTE started = 0, bypass_sdl = 0, pane; +static UBYTE started = 0, last_was_pal, last_was_other, copy_all; static struct Screen *game_screen; static struct View *view; @@ -277,6 +277,7 @@ static void doPalette(void) } } +// set saga regs to dsplay screen at ptr (modulo bytes to skip at end of line) static void setFrameBufferRegs(UBYTE *ptr, UWORD modulo) { volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ @@ -319,10 +320,8 @@ static void doFlip(void) if(copy_previous) { --copy_previous; - if(copy_panel_only) - blitRect(ptr+dlt, ptr, PANEL_LEFT, PANEL_TOP, PANEL_WIDTH, PANEL_HEIGHT); - else - blitRect(ptr+dlt, ptr, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + if(copy_all) blitRect(ptr+dlt, ptr, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + else blitRect(ptr+dlt, ptr, PANEL_LEFT, PANEL_TOP, PANEL_WIDTH, PANEL_HEIGHT); } // advance ptr @@ -332,47 +331,14 @@ static void doFlip(void) doPalette(); } -void vampire_BypassSDL(int enable_flip_disable) -{ - if(ac68080_saga) { - bypass_sdl = enable_flip_disable; - if(enable_flip_disable<0) doFlip(); - } -} - int vampire_Flip(const SDL_Surface* surf) { - static SDL_Rect palRect = {SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT}; - static UBYTE old_was_saga; - chkSignals(); - if(bypass_sdl) { - if(!old_was_saga) { - old_was_saga = 255; - SDL_BlitSurface(surf, NULL, pal_surface, &palRect); - } - return 0; + + if(last_was_pal) { + last_was_pal = 0; + doFlip(); } else { - if(old_was_saga) { - SDL_BlitSurface(pal_surface, &palRect, surf, NULL); - if(game_screen==IntuitionBase->FirstScreen) { - // struct Screen *s = IntuitionBase->FirstScreen, *t=s->NextScreen; - // s->NextScreen = t->NextScreen; - // t->NextScreen = s; - // IntuitionBase->FirstScreen = t; - // ScreenToFront(s); - - ULONG bufmem; - APTR handle = LockBitMapTags(&game_screen->BitMap, - LBMI_BASEADDRESS, (ULONG)&bufmem,(ULONG)TAG_DONE); - if(handle) { - setFrameBufferRegs((UBYTE*)(bufmem&-32), 0); - UnLockBitMap(handle); - // old_was_saga = 0; - printf("reset intui\n"); - } else printf("failed to reset intui\n"); - } - } return SDL_Flip(surf); } } @@ -380,22 +346,19 @@ int vampire_Flip(const SDL_Surface* surf) int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect) { - if(!bypass_sdl) - return SDL_BlitSurface(src, srcRect, dst, dstRect); - - // check if something is displayed in the panel - if(!srcRect || srcRect->h>=SCREEN_HEIGHT) { - copy_panel_only = 0; - copy_previous = 3; - } else if(srcRect->y + srcRect->h > PANEL_Y - && !(srcRect->w==288 && srcRect->h==60) // ignore descpane - ) { - if(!copy_previous) - copy_panel_only = 1; - copy_previous = 3; - } - - return 0; + if(ac68080_saga && src==pal_surface) { + last_was_pal = 255; + if(!srcRect || srcRect->h>=SCREEN_HEIGHT) { + copy_all = 255; + copy_previous = 3; + } else if(srcRect->y + srcRect->h > PANEL_Y // something drawn in panel + && !(srcRect->w==288 && srcRect->h==60) // ignore descpane + ) { + copy_all = 0; + copy_previous = 3; + } + return 0; + } else return SDL_BlitSurface(src, srcRect, dst, dstRect); } #define min(a,b) ((a)<=(b)?(a):(b)) From 679cb41a5a8f92f1c714db7b8baa365464075749 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 29 Dec 2019 23:59:27 +0100 Subject: [PATCH 056/107] fastest ever! --- SourceX/platform/amiga/render68k.asm | 52 ++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index befab2d7726..13b3ff4bcc4 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -915,12 +915,14 @@ _setup move.l __ZN3dvl10gpBufStartE,a5 move.l __ZN3dvl8gpBufEndE,a6 endc + addq.l #4,a3 ifne A5_RELATIVE sub.l a5,a0 sub.l a5,a6 endc + else + addq.l #4,a3 endc - addq.l #4,a3 * determine renderFcn .ammx tst.b _ac68080_ammx @@ -1064,16 +1066,13 @@ epilogue_11 macro *------------------------------------------------------------------------------------ * extern void RenderTile_RT_TRANSPARENT(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_TRANSPARENT - prologue_11 - addq.l #2,a4 ; skip over load mask - REPT 32 +RT_TRANS macro inline .L1 move.l -(a3),d6 ; m = *mask; mask-- moveq #32,d7 -.L2 moveq #0,d0 ; TODO: remove ? +.L2 move.b (a1)+,d0 bgt.b .L3 .L22 @@ -1089,18 +1088,49 @@ _RenderTile_RT_TRANSPARENT lsl.l d0,d6 sub.l d0,d7 beq .L4 ; likely to be false most of the times - jsr (a4) - moveq #0,d0 ; TODO: remove ? + \1 \2 move.b (a1)+,d0 - ble.b .L22 ; more likely at this point - bra .L3 + bgt.b .L3 ; more likely at this point + bra .L22 .L4 - jsr (a4) + \1 \2 .L5 sub.w #BUFFER_WIDTH+32,a0 einline + endm + +_RenderTile_RT_TRANSPARENT + prologue_11 + cmp.l #_RenderLine0_AMMX,a4 + beq _RenderTile_RT_TRANSPARENT_0_AMMX + cmp.l #_RenderLine2_AMMX,a4 + beq _RenderTile_RT_TRANSPARENT_2_AMMX + addq.l #2,a4 ; skip over load mask + REPT 32 + RT_TRANS jsr,(a4) ENDR epilogue_11 + + XDEF _RenderTile_RT_TRANSPARENT_0_AMMX +_RenderTile_RT_TRANSPARENT_0_AMMX + move.l #32,a4 +.loop + RT_TRANS bsr,_RenderLine0_AMMX+2 + subq.l #1,a4 + tst.l a4 + bne .loop + epilogue_11 + + XDEF _RenderTile_RT_TRANSPARENT_2_AMMX +_RenderTile_RT_TRANSPARENT_2_AMMX + move.l #32,a4 +.loop + RT_TRANS bsr,_RenderLine2_AMMX+2 + subq.l #1,a4 + tst.l a4 + bne .loop + epilogue_11 + *------------------------------------------------------------------------------------ * extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) From 2fc192ea3a4542b6c851dba0db75e43b207dd720 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 30 Dec 2019 21:31:56 +0100 Subject: [PATCH 057/107] faster version of bitstream --- 3rdParty/libsmacker/smk_bitstream.c | 206 +++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 2 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 45baeb1fc09..74de4d44f63 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -14,7 +14,209 @@ /* malloc and friends */ #include "smk_malloc.h" -#if 1 /* SAM's version */ +#define BUFFER_LEN 24 + +#if BUFFER_LEN==24 +//#undef __mc68000__ // to test C version + +struct smk_bit_t +{ + unsigned long buf; + unsigned char *ptr, *end; + unsigned long siz; +}; + +struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) +{ + struct smk_bit_t* ret = NULL; + + /* sanity check */ + smk_assert(b); + + /* allocate a bitstream struct */ + smk_malloc(ret, sizeof(struct smk_bit_t)); + + /* set up the pointer to bitstream, and the size counter */ + ret->buf = 1; + ret->ptr = b; + ret->end = b + size; + ret->siz = size; + + /* point to initial byte: note, smk_malloc already sets these to 0 */ + /* ret->byte_num = 0; + ret->bit_num = 0; */ + + /* return ret or NULL if error : ) */ +error: + return ret; +} + +REGPARM unsigned char _smk_error(struct smk_bit_t* bs) +{ + fprintf(stderr, "libsmacker::_smk_bs_read_?(bs=%p): ERROR: bitstream (length=%lu, ptr=%p, end=%p) exhausted.\n", bs, bs->siz, bs->ptr, bs->end); + bs->buf=1; + return 2; +} + +REGPARM unsigned long _smk_refill(struct smk_bit_t* bs) +{ +#ifdef __mc68000__ + register unsigned long ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " move.l 4(a0),a1 \n" + " move.l 8(a0),d1 \n" + " sub.l a1,d1 \n" + " bhi.b .l1%= \n" + " move.l a0,-(sp) \n" + " bsr %2 \n" + " move.l (sp)+,a0 \n" + " bra.b .l5%= \n" + ".l1%=: \n" + " move.l (a1),d0 \n" // AABBCCDD + " ror.w #8,d0 \n" // AABBDDCC + " swap d0 \n" // DDCCAABB + " ror.w #8,d0 \n" // DDCCBBAA + + " addq.l #1,a1 \n" + " subq.l #1,d1 \n" + " bne.b .l2%= \n" + " move.l #0xFF,d1 \n" + " bra.b .l4%= \n" + + ".l2%=: \n" + " addq.l #1,a1 \n" + " subq.l #1,d1 \n" + " bne.b .l3%= \n" + " move.l #0xFFFF,d1 \n" + " bra.b .l4%= \n" + + ".l3%=: \n" + " addq.l #1,a1 \n" + " move.l #0xFFFFFF,d1\n" + + ".l4%=: \n" + " and.l d1,d0 \n" + " addq.l #1,d1 \n" + " move.l a1,4(a0) \n" + " or.l d1,d0 \n" + + ".l5%=: \n" + : "=d" (ret) : "a" (bs_), "m"(_smk_refill) + : "d1","a1","a0" ); + return ret; +#define CALL_REFILL(adr) "\tbsr "#adr"\n" // refill now preserves a0 reg +#else + unsigned char *a0 = bs->ptr; + unsigned long d0, d1; + if(a0==bs->end) return _smk_error(bs); + d0 = *a0++; d1=256; + if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} + if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} + d0 |= d1; + bs->ptr = a0; + return d0; +#define CALL_REFILL(adr) "\tmove.l a0,-(sp)\n\tbsr "#adr"\n\tmove.l (sp)+,a0\n" +#endif +} + +/* Reads a bit + Returns -1 if error encountered */ +REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) +{ + /* sanity check */ + // smk_assert(bs); + { +#ifdef __mc68000__ + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " move.l (a0),d0 \n" + " lsr.l #1,d0 \n" + " bne.b .result%= \n" + CALL_REFILL("%2") + " lsr.l #1,d0 \n" + ".result%=: \n" + " move.l d0,(a0) \n" + " moveq #0,d0 \n" + " addx.l d0,d0 \n" + : "=d" (ret) : "a" (bs_), "m"(_smk_refill) + : "d1","a1","a0" ); + return ret; +#else + unsigned long ret; + ret = bs->buf; bs->buf >>= 1; + if(!bs->buf) { ret = _smk_refill(bs); bs->buf = ret>>1; } + return ret & 1; +#endif + } +} + +/* Reads a byte + Returns -1 if error. */ +REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) +{ + /* sanity check */ + // smk_assert(bs); + { +#ifdef __mc68000__ + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + + __asm__ __volatile__ ( + " move.l (a0),d1 \n" + " cmp.l #256,d1 \n" + " bcc.s .l1%= \n" + CALL_REFILL("%2") + " move.l (a0),d1 \n" + " cmp.w #1,d1 \n" + " bls.s .l2%= \n" + + " subq.l #1,d0 \n" + " move.l d0,a1 \n" + + " move.l d1,d0 \n" + " lsr.l #1,d0 \n" + " or.l d0,d1 \n" + + " move.l d1,d0 \n" + " lsr.l #2,d0 \n" + " or.l d0,d1 \n" + + " move.l d1,d0 \n" + " lsr.l #4,d0 \n" + " or.l d0,d1 \n" + + " lsr.l #1,d1 \n" + " addq.l #1,d1 \n" + + " move.l a1,d0 \n" + " mulu.l d1,d0 \n" + " add.l (a0),d0 \n" + ".l2%=: \n" + " move.l d0,d1 \n" + ".l1%=: \n" + " moveq #0,d0 \n" + " move.b d1,d0 \n" + " lsr.l #8,d1 \n" + " move.l d1,(a0) \n" + : "=d" (ret) : "a" (bs_), "m" (_smk_refill) + : "d1","a1","a0"); +#else + unsigned long a = bs->buf; + if(a<=1) a = _smk_refill(bs); + else if(a<256) { + unsigned long b = a>>1; b |= b>>1; b |= b>>2; b |= b>>4; ++b; + a += b*(_smk_refill(bs)-1); + } + bs->buf = a>>8; + return a&255; +#endif + } +} + +#elif BUFFER_LEN==16 + // #undef __mc68000__ // to test C version struct smk_bit_t @@ -206,7 +408,7 @@ REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) } } -#else +#else // original code /* Bitstream structure From 2f3b6727721b45b1ba6aa1ce6066fea41c4e027b Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 30 Dec 2019 21:33:39 +0100 Subject: [PATCH 058/107] faster version of bitstream --- 3rdParty/libsmacker/smk_bitstream.c | 206 +++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 2 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 45baeb1fc09..74de4d44f63 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -14,7 +14,209 @@ /* malloc and friends */ #include "smk_malloc.h" -#if 1 /* SAM's version */ +#define BUFFER_LEN 24 + +#if BUFFER_LEN==24 +//#undef __mc68000__ // to test C version + +struct smk_bit_t +{ + unsigned long buf; + unsigned char *ptr, *end; + unsigned long siz; +}; + +struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size) +{ + struct smk_bit_t* ret = NULL; + + /* sanity check */ + smk_assert(b); + + /* allocate a bitstream struct */ + smk_malloc(ret, sizeof(struct smk_bit_t)); + + /* set up the pointer to bitstream, and the size counter */ + ret->buf = 1; + ret->ptr = b; + ret->end = b + size; + ret->siz = size; + + /* point to initial byte: note, smk_malloc already sets these to 0 */ + /* ret->byte_num = 0; + ret->bit_num = 0; */ + + /* return ret or NULL if error : ) */ +error: + return ret; +} + +REGPARM unsigned char _smk_error(struct smk_bit_t* bs) +{ + fprintf(stderr, "libsmacker::_smk_bs_read_?(bs=%p): ERROR: bitstream (length=%lu, ptr=%p, end=%p) exhausted.\n", bs, bs->siz, bs->ptr, bs->end); + bs->buf=1; + return 2; +} + +REGPARM unsigned long _smk_refill(struct smk_bit_t* bs) +{ +#ifdef __mc68000__ + register unsigned long ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " move.l 4(a0),a1 \n" + " move.l 8(a0),d1 \n" + " sub.l a1,d1 \n" + " bhi.b .l1%= \n" + " move.l a0,-(sp) \n" + " bsr %2 \n" + " move.l (sp)+,a0 \n" + " bra.b .l5%= \n" + ".l1%=: \n" + " move.l (a1),d0 \n" // AABBCCDD + " ror.w #8,d0 \n" // AABBDDCC + " swap d0 \n" // DDCCAABB + " ror.w #8,d0 \n" // DDCCBBAA + + " addq.l #1,a1 \n" + " subq.l #1,d1 \n" + " bne.b .l2%= \n" + " move.l #0xFF,d1 \n" + " bra.b .l4%= \n" + + ".l2%=: \n" + " addq.l #1,a1 \n" + " subq.l #1,d1 \n" + " bne.b .l3%= \n" + " move.l #0xFFFF,d1 \n" + " bra.b .l4%= \n" + + ".l3%=: \n" + " addq.l #1,a1 \n" + " move.l #0xFFFFFF,d1\n" + + ".l4%=: \n" + " and.l d1,d0 \n" + " addq.l #1,d1 \n" + " move.l a1,4(a0) \n" + " or.l d1,d0 \n" + + ".l5%=: \n" + : "=d" (ret) : "a" (bs_), "m"(_smk_refill) + : "d1","a1","a0" ); + return ret; +#define CALL_REFILL(adr) "\tbsr "#adr"\n" // refill now preserves a0 reg +#else + unsigned char *a0 = bs->ptr; + unsigned long d0, d1; + if(a0==bs->end) return _smk_error(bs); + d0 = *a0++; d1=256; + if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} + if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} + d0 |= d1; + bs->ptr = a0; + return d0; +#define CALL_REFILL(adr) "\tmove.l a0,-(sp)\n\tbsr "#adr"\n\tmove.l (sp)+,a0\n" +#endif +} + +/* Reads a bit + Returns -1 if error encountered */ +REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) +{ + /* sanity check */ + // smk_assert(bs); + { +#ifdef __mc68000__ + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + __asm__ __volatile__ ( + " move.l (a0),d0 \n" + " lsr.l #1,d0 \n" + " bne.b .result%= \n" + CALL_REFILL("%2") + " lsr.l #1,d0 \n" + ".result%=: \n" + " move.l d0,(a0) \n" + " moveq #0,d0 \n" + " addx.l d0,d0 \n" + : "=d" (ret) : "a" (bs_), "m"(_smk_refill) + : "d1","a1","a0" ); + return ret; +#else + unsigned long ret; + ret = bs->buf; bs->buf >>= 1; + if(!bs->buf) { ret = _smk_refill(bs); bs->buf = ret>>1; } + return ret & 1; +#endif + } +} + +/* Reads a byte + Returns -1 if error. */ +REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) +{ + /* sanity check */ + // smk_assert(bs); + { +#ifdef __mc68000__ + register unsigned char ret asm("d0"); + register struct smk_bit_t* bs_ asm("a0") = bs; + + __asm__ __volatile__ ( + " move.l (a0),d1 \n" + " cmp.l #256,d1 \n" + " bcc.s .l1%= \n" + CALL_REFILL("%2") + " move.l (a0),d1 \n" + " cmp.w #1,d1 \n" + " bls.s .l2%= \n" + + " subq.l #1,d0 \n" + " move.l d0,a1 \n" + + " move.l d1,d0 \n" + " lsr.l #1,d0 \n" + " or.l d0,d1 \n" + + " move.l d1,d0 \n" + " lsr.l #2,d0 \n" + " or.l d0,d1 \n" + + " move.l d1,d0 \n" + " lsr.l #4,d0 \n" + " or.l d0,d1 \n" + + " lsr.l #1,d1 \n" + " addq.l #1,d1 \n" + + " move.l a1,d0 \n" + " mulu.l d1,d0 \n" + " add.l (a0),d0 \n" + ".l2%=: \n" + " move.l d0,d1 \n" + ".l1%=: \n" + " moveq #0,d0 \n" + " move.b d1,d0 \n" + " lsr.l #8,d1 \n" + " move.l d1,(a0) \n" + : "=d" (ret) : "a" (bs_), "m" (_smk_refill) + : "d1","a1","a0"); +#else + unsigned long a = bs->buf; + if(a<=1) a = _smk_refill(bs); + else if(a<256) { + unsigned long b = a>>1; b |= b>>1; b |= b>>2; b |= b>>4; ++b; + a += b*(_smk_refill(bs)-1); + } + bs->buf = a>>8; + return a&255; +#endif + } +} + +#elif BUFFER_LEN==16 + // #undef __mc68000__ // to test C version struct smk_bit_t @@ -206,7 +408,7 @@ REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) } } -#else +#else // original code /* Bitstream structure From dff3fdee689a66d673140e02ab21f6d431dd28e5 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 30 Dec 2019 21:34:47 +0100 Subject: [PATCH 059/107] faster version of bitstream --- 3rdParty/libsmacker/smk_bitstream.c | 196 ++++++++++++++-------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 74de4d44f63..efa5e64a4de 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -64,59 +64,59 @@ REGPARM unsigned long _smk_refill(struct smk_bit_t* bs) register unsigned long ret asm("d0"); register struct smk_bit_t* bs_ asm("a0") = bs; __asm__ __volatile__ ( - " move.l 4(a0),a1 \n" - " move.l 8(a0),d1 \n" - " sub.l a1,d1 \n" - " bhi.b .l1%= \n" - " move.l a0,-(sp) \n" - " bsr %2 \n" - " move.l (sp)+,a0 \n" - " bra.b .l5%= \n" - ".l1%=: \n" - " move.l (a1),d0 \n" // AABBCCDD - " ror.w #8,d0 \n" // AABBDDCC - " swap d0 \n" // DDCCAABB - " ror.w #8,d0 \n" // DDCCBBAA - - " addq.l #1,a1 \n" - " subq.l #1,d1 \n" - " bne.b .l2%= \n" - " move.l #0xFF,d1 \n" - " bra.b .l4%= \n" - - ".l2%=: \n" - " addq.l #1,a1 \n" - " subq.l #1,d1 \n" - " bne.b .l3%= \n" - " move.l #0xFFFF,d1 \n" - " bra.b .l4%= \n" - - ".l3%=: \n" - " addq.l #1,a1 \n" - " move.l #0xFFFFFF,d1\n" - - ".l4%=: \n" - " and.l d1,d0 \n" - " addq.l #1,d1 \n" - " move.l a1,4(a0) \n" - " or.l d1,d0 \n" - - ".l5%=: \n" + " move.l 4(a0),a1 \n" + " move.l 8(a0),d1 \n" + " sub.l a1,d1 \n" + " bhi.b .l1%= \n" + " move.l a0,-(sp) \n" + " bsr %2 \n" + " move.l (sp)+,a0 \n" + " bra.b .l5%= \n" + ".l1%=: \n" + " move.l (a1),d0 \n" // AABBCCDD + " ror.w #8,d0 \n" // AABBDDCC + " swap d0 \n" // DDCCAABB + " ror.w #8,d0 \n" // DDCCBBAA + + " addq.l #1,a1 \n" + " subq.l #1,d1 \n" + " bne.b .l2%= \n" + " move.l #0xFF,d1 \n" + " bra.b .l4%= \n" + + ".l2%=: \n" + " addq.l #1,a1 \n" + " subq.l #1,d1 \n" + " bne.b .l3%= \n" + " move.l #0xFFFF,d1 \n" + " bra.b .l4%= \n" + + ".l3%=: \n" + " addq.l #1,a1 \n" + " move.l #0xFFFFFF,d1\n" + + ".l4%=: \n" + " and.l d1,d0 \n" + " addq.l #1,d1 \n" + " move.l a1,4(a0) \n" + " or.l d1,d0 \n" + + ".l5%=: \n" : "=d" (ret) : "a" (bs_), "m"(_smk_refill) : "d1","a1","a0" ); return ret; -#define CALL_REFILL(adr) "\tbsr "#adr"\n" // refill now preserves a0 reg +#define CALL_REFILL(adr) "\tbsr "#adr"\n" // refill now preserves a0 reg #else - unsigned char *a0 = bs->ptr; - unsigned long d0, d1; - if(a0==bs->end) return _smk_error(bs); - d0 = *a0++; d1=256; - if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} - if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} - d0 |= d1; - bs->ptr = a0; - return d0; -#define CALL_REFILL(adr) "\tmove.l a0,-(sp)\n\tbsr "#adr"\n\tmove.l (sp)+,a0\n" + unsigned char *a0 = bs->ptr; + unsigned long d0, d1; + if(a0==bs->end) return _smk_error(bs); + d0 = *a0++; d1=256; + if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} + if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} + d0 |= d1; + bs->ptr = a0; + return d0; +#define CALL_REFILL(adr) "\tmove.l a0,-(sp)\n\tbsr "#adr"\n\tmove.l (sp)+,a0\n" #endif } @@ -131,15 +131,15 @@ REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) register unsigned char ret asm("d0"); register struct smk_bit_t* bs_ asm("a0") = bs; __asm__ __volatile__ ( - " move.l (a0),d0 \n" - " lsr.l #1,d0 \n" - " bne.b .result%= \n" - CALL_REFILL("%2") - " lsr.l #1,d0 \n" + " move.l (a0),d0 \n" + " lsr.l #1,d0 \n" + " bne.b .result%= \n" + CALL_REFILL("%2") + " lsr.l #1,d0 \n" ".result%=: \n" - " move.l d0,(a0) \n" - " moveq #0,d0 \n" - " addx.l d0,d0 \n" + " move.l d0,(a0) \n" + " moveq #0,d0 \n" + " addx.l d0,d0 \n" : "=d" (ret) : "a" (bs_), "m"(_smk_refill) : "d1","a1","a0" ); return ret; @@ -165,52 +165,52 @@ REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) __asm__ __volatile__ ( " move.l (a0),d1 \n" - " cmp.l #256,d1 \n" - " bcc.s .l1%= \n" - CALL_REFILL("%2") - " move.l (a0),d1 \n" - " cmp.w #1,d1 \n" - " bls.s .l2%= \n" - - " subq.l #1,d0 \n" - " move.l d0,a1 \n" - - " move.l d1,d0 \n" - " lsr.l #1,d0 \n" - " or.l d0,d1 \n" - - " move.l d1,d0 \n" - " lsr.l #2,d0 \n" - " or.l d0,d1 \n" - - " move.l d1,d0 \n" - " lsr.l #4,d0 \n" - " or.l d0,d1 \n" - - " lsr.l #1,d1 \n" - " addq.l #1,d1 \n" - - " move.l a1,d0 \n" - " mulu.l d1,d0 \n" - " add.l (a0),d0 \n" - ".l2%=: \n" - " move.l d0,d1 \n" + " cmp.l #256,d1 \n" + " bcc.s .l1%= \n" + CALL_REFILL("%2") + " move.l (a0),d1 \n" + " cmp.w #1,d1 \n" + " bls.s .l2%= \n" + + " subq.l #1,d0 \n" + " move.l d0,a1 \n" + + " move.l d1,d0 \n" + " lsr.l #1,d0 \n" + " or.l d0,d1 \n" + + " move.l d1,d0 \n" + " lsr.l #2,d0 \n" + " or.l d0,d1 \n" + + " move.l d1,d0 \n" + " lsr.l #4,d0 \n" + " or.l d0,d1 \n" + + " lsr.l #1,d1 \n" + " addq.l #1,d1 \n" + + " move.l a1,d0 \n" + " mulu.l d1,d0 \n" + " add.l (a0),d0 \n" + ".l2%=: \n" + " move.l d0,d1 \n" ".l1%=: \n" - " moveq #0,d0 \n" - " move.b d1,d0 \n" - " lsr.l #8,d1 \n" - " move.l d1,(a0) \n" + " moveq #0,d0 \n" + " move.b d1,d0 \n" + " lsr.l #8,d1 \n" + " move.l d1,(a0) \n" : "=d" (ret) : "a" (bs_), "m" (_smk_refill) : "d1","a1","a0"); #else unsigned long a = bs->buf; - if(a<=1) a = _smk_refill(bs); - else if(a<256) { - unsigned long b = a>>1; b |= b>>1; b |= b>>2; b |= b>>4; ++b; - a += b*(_smk_refill(bs)-1); - } - bs->buf = a>>8; - return a&255; + if(a<=1) a = _smk_refill(bs); + else if(a<256) { + unsigned long b = a>>1; b |= b>>1; b |= b>>2; b |= b>>4; ++b; + a += b*(_smk_refill(bs)-1); + } + bs->buf = a>>8; + return a&255; #endif } } From e8e7a0bb671accd82b02aebcb6894ebf889298be Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 31 Dec 2019 15:48:22 +0100 Subject: [PATCH 060/107] added comment --- 3rdParty/libsmacker/smk_bitstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 74de4d44f63..fa0d44f03eb 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -14,7 +14,7 @@ /* malloc and friends */ #include "smk_malloc.h" -#define BUFFER_LEN 24 +#define BUFFER_LEN 24 // fastest version it seem #if BUFFER_LEN==24 //#undef __mc68000__ // to test C version From 4199d20f0a20ee6e143b56a59e341a7c7274f808 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 31 Dec 2019 16:08:49 +0100 Subject: [PATCH 061/107] fixed video not being vertically centered --- SourceX/storm/storm.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 81242940ec9..caf2eb96462 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -577,7 +577,13 @@ void SVidPlayBegin(char *filename, int a2, int a3, int a4, int a5, int flags, HA } } #elif SDL1_VIDEO_MODE_BPP == 8 - SDL_SetVideoMode(SVidWidth, SVidHeight, SDL1_VIDEO_MODE_BPP, GetOutputSurface()->flags); + SDL_SetVideoMode(SVidWidth, +#ifdef __AMIGA__ // fixes video not being centered + SVidHeight<200?200:SVidHeight, +#else + SVidHeight, +#endif + SDL1_VIDEO_MODE_BPP, GetOutputSurface()->flags); #endif memcpy(SVidPreviousPalette, orig_palette, 1024); From 7f0e216339182f97a72b850ea22d0893479b10c8 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 31 Dec 2019 16:22:04 +0100 Subject: [PATCH 062/107] made fps round to closest integer + better C code for gcc/68k in renderRow() --- Source/scrollrt.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 89000103688..a0b1bea4a78 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -21,6 +21,8 @@ void (*DrawPlrProc)(int, int, int, int, int, BYTE *, int, int, int, int); BYTE sgSaveBack[8192]; DWORD sgdwCursHgtOld; +//#define static static __attribute__((regparm)) + /* data */ /* used in 1.00 debug */ @@ -477,25 +479,23 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy, int eflag); static void drawRow(int x, int y, int sx, int sy, int eflag) { -#ifdef __mc68000__ // this code is better for 68k - BYTE *dst; - MICROS *pMap; - WORD *mt; - - level_piece_id = dPiece[x][y]; - light_table_index = dLight[x][y]; +#ifdef __mc68000__ // this code is better for gcc + BYTE *dst = &gpBuffer[sx + (unsigned short)sy * (unsigned short)BUFFER_WIDTH]; + int xy= (unsigned short)x*(unsigned short)MAXDUNY+y; +#define xy(T) (&T[0][0]+xy)[0] + WORD *mt = &xy(dpiece_defs_map_2).mt[0]; - dst = &gpBuffer[sx + sy * BUFFER_WIDTH]; - pMap = &dpiece_defs_map_2[x][y]; - cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]); + cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[xy(dTransVal)]); - mt = &pMap->mt[0]; + level_piece_id = xy(dPiece); + light_table_index = xy(dLight); + arch_draw_type = 1; - level_cel_block = *mt++; - if (level_cel_block != 0) drawUpperScreen(dst); + if ((level_cel_block = *mt++)) drawUpperScreen(dst); + arch_draw_type = 2; - level_cel_block = *mt++; - if (level_cel_block != 0) drawUpperScreen(dst + 32); + if ((level_cel_block = *mt++)) drawUpperScreen(dst + 32); + arch_draw_type = 0; for(WORD i = MicroTileLen>>1; --i>0;) { dst -= BUFFER_WIDTH * 32; @@ -1096,7 +1096,7 @@ static void DrawFPS() frames = tc - framestart; if (tc - framestart >= 1000) { framestart = tc; - framerate = 1000 * frameend / frames; + framerate = (1000 * frameend + frames/2) / frames; frameend = 0; } wsprintf(String, "%d FPS", framerate); From af5542fd3a5875ed81b3ffe082920d62e330cb8d Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 31 Dec 2019 20:50:47 +0100 Subject: [PATCH 063/107] fixed new EA macro --- SourceX/platform/amiga/render68k.asm | 115 +++++++++++++++++++-------- 1 file changed, 84 insertions(+), 31 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 13b3ff4bcc4..b6f2149ba58 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -10,6 +10,7 @@ VAMP_V4 set 1 ; 0 = replaces movem with separate moves NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) +BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -85,7 +86,6 @@ rts_bounds macro endm chk_bounds macro -* beq.b \1 ; 1 ifne NO_OVERDRAW ifne A5_RELATIVE cmp.l a6,a0 ; 1 @@ -115,7 +115,6 @@ chk_bounds macro * debug: displays nothing _RenderLine_NONE - move.l -(a3),d1 add.w d0,a1 add.w d0,a0 rts @@ -161,8 +160,6 @@ unroll_AMMX macro * case light_table_index == lightmax _RenderLine1_AMMX - move.l -(a3),d1 - add.w d0,a1 chk_bounds .nx peor d2,d2,d2 ; d2=0.q @@ -180,6 +177,7 @@ _RenderLine1_AMMX endm unroll_AMMX .n8,.n0,.nx add.w d0,a0 + add.w d0,a1 rts_bounds * mask version @@ -198,7 +196,6 @@ _RenderLine1_AMMX * case light_table_index == 0 _RenderLine0_AMMX - move.l -(a3),d1 chk_bounds .nx moveq #1,d3 @@ -237,6 +234,9 @@ _RenderLine0_AMMX rts_bounds * other cases + + ifeq BYTE_INDEX_MODE + transform macro * move.l (a1)+,d3 ; F(used) d3=AABBCCDD * move.l (a1)+,d5 ; F 1 @@ -249,23 +249,23 @@ transform macro move.l d5,d4 ; p2 rol.l #8,d4 ; p2 2 endc - ifne \1&$a0 - and.l #$00FF00FF,d2 ; p1 d2=00CC00AA - endc ifne \1&$50 - and.l #$00FF00FF,d3 ; p2 3 d3=00BB00DD + swap d3 ; p1 d3=CDCDDAABB endc - ifne \1&$0a - and.l #$00FF00FF,d4 ; p1 + ifne \1&$a0 + and.l #$00FF00FF,d2 ; p2 3 d2=00CC00AA endc ifne \1&$05 - and.l #$00FF00FF,d5 ; p2 4 + swap d5 ; p1 endc ifne \1&$50 - swap d3 ; p1 d3=00DD00BB + and.l #$00FF00FF,d3 ; p2 4 d3=00DD00BB + endc + ifne \1&$0a + and.l #$00FF00FF,d4 ; p1 endc ifne \1&$05 - swap d5 ; p2 5 + and.l #$00FF00FF,d5 ; p2 5 endc ifne \1&$80 move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- @@ -307,9 +307,44 @@ transform macro * move.l d2,(a0)+ ; F * move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? endm + + else ; BYTE_INDEX_MODE + +move_ macro +; move.\1 (a2,d\2 . b\3),d\4 + dc.w %0000000000110010+%0001000000000000*\1+%0000001000000000*\4 + dc.w %0000000100001000+%0001000000000000*\2+\3 + endm + +transform macro +* move.l (a1)+,d3 ; F(used) d3=AABBCCDD +* move.l (a1)+,d5 ; F 1 +* input d3/d5 ; 2 cycles bubble +; move.w (a2,d3.b3),d2 ; 4 b3 + move_ %11,3,3,2 +; move.b (a2,d3.b2),d2 ; 5 b2 + move_ %01,3,2,2 +; move.w (a2,d5.b3),d4 ; 6 b3 + move_ %11,5,3,4 + swap d2 ; p2 6 +; move.b (a2,d5.b2),d4 ; 7 b2 + move_ %01,5,2,4 +; move.w (a2,d3.b1),d2 ; 8 b1 + move_ %11,3,1,2 + swap d4 ; p2 8 +; move.b (a2,d3.b0),d2 ; 9 b0 + move_ %01,3,0,2 +; move.w (a2,d5.b1),d4 ; 10 b1 + move_ %11,5,1,4 +; move.b (a2,d5.b0),d4 ; 11 b0 + move_ %01,5,0,4 +* output d2/d4 +* move.l d2,(a0)+ ; F +* move.l d4,(a0)+ ; F 12 ==> 12 cycles for 8 pixels ? + endm + endc ; BYTE_INDEX_MODE _RenderLine2_AMMX - move.l -(a3),d1 chk_bounds _RenderLine0_AMMX\.mx move.l d1,d3 ; \ fused @@ -325,7 +360,7 @@ _RenderLine2_AMMX endm .n0 macro move.l (a1),d3 - move.l (a1),d5 + move.l 4(a1),d5 transform $ff vperm #$4567CDEF,d2,d4,d2 storec d2,d0,(a0) @@ -337,6 +372,8 @@ _RenderLine2_AMMX * mask versions + ifeq BYTE_INDEX_MODE + .transfAA55_8 macro move.b \1(a1),d2 ; 1 move.b \1+2(a1),d3 ; 2 @@ -351,6 +388,27 @@ _RenderLine2_AMMX move.b (a2,d5.w),d1 ; 9 movep.l d1,\1-8(a0) ; 10 endm + + else ; BYTE_INDEX_MODE + +.transfAA55_8 macro + move.l \1(a1),d2 ; 1 F + move.l \1+4(a1),d4 ; 1 F +; move.w (a2,d2.b3),d1 ; 4 + move_ %11,2,3,1 +; move.b (a2,d2.b1),d1 ; 5 + move_ %01,2,1,1 + addq.l #8,a1 ; 5 + swap d1 ; 6 + addq.l #8,a0 ; 6 +; move.w (a2,d4.b3),d1 ; 7 + move_ %11,4,3,1 +; move.b (a2,d4.b1),d1 ; 8 + move_ %01,4,1,1 + movep.l d1,\1-8(a0) ; 9 + endm + + endc ; BYTE_INDEX_MODE .transfAA55 macro moveq #0,d2 @@ -446,7 +504,6 @@ _RenderLine2_AMMX * ----------------------------------------------------------------------------- _RenderLine2_AMMX_orig - move.l -(a3),d1 chk_bounds _RenderLine2_AMMX\.mx move.l d1,d3 ; \ fused @@ -593,10 +650,6 @@ transform macro * d3 = scratch * CC sets according to d1 value -inc_a0 macro - addq.l #1,a0 - endm - inc_a0_a1 macro * cmp.b (a1)+,(a0)+ addq.l #1,a0 @@ -664,7 +717,6 @@ _RenderLine0_ add.w d0,a1 rts_bounds _RenderLine0 - move.l -(a3),d1 chk_bounds _RenderLine0_ not.l d1 @@ -754,10 +806,9 @@ _RenderLine0 * case light_table_index == lightmax _RenderLine1_ add.w d0,a0 + add.w d0,a1 rts_bounds _RenderLine1 - move.l -(a3),d1 - add.w d0,a1 chk_bounds _RenderLine1_ not.l d1 @@ -803,7 +854,7 @@ _RenderLine1 endm unroll .q4,.q2,.q1 .l3 - loop .m1,inc_a0 + loop .m1,inc_a0_a1 * other cases _RenderLine2_ @@ -811,7 +862,6 @@ _RenderLine2_ add.w d0,a0 rts_bounds _RenderLine2 - move.l -(a3),d1 chk_bounds _RenderLine2_ moveq #0,d2 @@ -1095,6 +1145,7 @@ RT_TRANS macro .L4 \1 \2 .L5 + \3 \4 sub.w #BUFFER_WIDTH+32,a0 einline endm @@ -1105,7 +1156,6 @@ _RenderTile_RT_TRANSPARENT beq _RenderTile_RT_TRANSPARENT_0_AMMX cmp.l #_RenderLine2_AMMX,a4 beq _RenderTile_RT_TRANSPARENT_2_AMMX - addq.l #2,a4 ; skip over load mask REPT 32 RT_TRANS jsr,(a4) ENDR @@ -1115,9 +1165,8 @@ _RenderTile_RT_TRANSPARENT _RenderTile_RT_TRANSPARENT_0_AMMX move.l #32,a4 .loop - RT_TRANS bsr,_RenderLine0_AMMX+2 subq.l #1,a4 - tst.l a4 + RT_TRANS bsr,_RenderLine0_AMMX,tst.l,a4 bne .loop epilogue_11 @@ -1125,9 +1174,8 @@ _RenderTile_RT_TRANSPARENT_0_AMMX _RenderTile_RT_TRANSPARENT_2_AMMX move.l #32,a4 .loop - RT_TRANS bsr,_RenderLine2_AMMX+2 subq.l #1,a4 - tst.l a4 + RT_TRANS bsr,_RenderLine2_AMMX,tst.l,a4 bne .loop epilogue_11 @@ -1149,6 +1197,7 @@ _RenderTile_RT_SQUARE block16 REPT 16 moveq #32,d0 + move.l -(a3),d1 jsr (a4) sub.w #BUFFER_WIDTH+32,a0 ENDR @@ -1178,6 +1227,7 @@ triangL addq.w #2,a1 ENDC moveq #32-.i,d0 + move.l -(a3),d1 jsr (a4) IFNE .i .i set .i-2 @@ -1190,6 +1240,7 @@ triangR .i set 30 REPT 16 moveq #32-.i,d0 + move.l -(a3),d1 jsr (a4) IFNE .i&2 addq.w #2,a1 @@ -1211,6 +1262,7 @@ _RenderTile_RT_LTRIANGLE addq.w #2,a1 ENDC moveq #32-.i,d0 + move.l -(a3),d1 jsr (a4) IFNE .i-30 .i set .i+2 @@ -1227,6 +1279,7 @@ _RenderTile_RT_RTRIANGLE .i set 2 REPT 15 moveq #32-.i,d0 + move.l -(a3),d1 jsr (a4) IFNE .i&2 addq.w #2,a1 From 5d940dce2545c67664521b8504d04946af099035 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 31 Dec 2019 23:46:41 +0100 Subject: [PATCH 064/107] fixed code format --- 3rdParty/libsmacker/smk_bitstream.c | 120 ---------------------------- 1 file changed, 120 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index 32919021566..b9df45115ad 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -14,11 +14,7 @@ /* malloc and friends */ #include "smk_malloc.h" -<<<<<<< HEAD #define BUFFER_LEN 24 // fastest version it seem -======= -#define BUFFER_LEN 24 ->>>>>>> 7f0e216339182f97a72b850ea22d0893479b10c8 #if BUFFER_LEN==24 //#undef __mc68000__ // to test C version @@ -68,61 +64,6 @@ REGPARM unsigned long _smk_refill(struct smk_bit_t* bs) register unsigned long ret asm("d0"); register struct smk_bit_t* bs_ asm("a0") = bs; __asm__ __volatile__ ( -<<<<<<< HEAD - " move.l 4(a0),a1 \n" - " move.l 8(a0),d1 \n" - " sub.l a1,d1 \n" - " bhi.b .l1%= \n" - " move.l a0,-(sp) \n" - " bsr %2 \n" - " move.l (sp)+,a0 \n" - " bra.b .l5%= \n" - ".l1%=: \n" - " move.l (a1),d0 \n" // AABBCCDD - " ror.w #8,d0 \n" // AABBDDCC - " swap d0 \n" // DDCCAABB - " ror.w #8,d0 \n" // DDCCBBAA - - " addq.l #1,a1 \n" - " subq.l #1,d1 \n" - " bne.b .l2%= \n" - " move.l #0xFF,d1 \n" - " bra.b .l4%= \n" - - ".l2%=: \n" - " addq.l #1,a1 \n" - " subq.l #1,d1 \n" - " bne.b .l3%= \n" - " move.l #0xFFFF,d1 \n" - " bra.b .l4%= \n" - - ".l3%=: \n" - " addq.l #1,a1 \n" - " move.l #0xFFFFFF,d1\n" - - ".l4%=: \n" - " and.l d1,d0 \n" - " addq.l #1,d1 \n" - " move.l a1,4(a0) \n" - " or.l d1,d0 \n" - - ".l5%=: \n" - : "=d" (ret) : "a" (bs_), "m"(_smk_refill) - : "d1","a1","a0" ); - return ret; -#define CALL_REFILL(adr) "\tbsr "#adr"\n" // refill now preserves a0 reg -#else - unsigned char *a0 = bs->ptr; - unsigned long d0, d1; - if(a0==bs->end) return _smk_error(bs); - d0 = *a0++; d1=256; - if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} - if(a0!=bs->end) {d0 |= *a0++ * d1; d1<<=8;} - d0 |= d1; - bs->ptr = a0; - return d0; -#define CALL_REFILL(adr) "\tmove.l a0,-(sp)\n\tbsr "#adr"\n\tmove.l (sp)+,a0\n" -======= " move.l 4(a0),a1 \n" " move.l 8(a0),d1 \n" " sub.l a1,d1 \n" @@ -176,7 +117,6 @@ REGPARM unsigned long _smk_refill(struct smk_bit_t* bs) bs->ptr = a0; return d0; #define CALL_REFILL(adr) "\tmove.l a0,-(sp)\n\tbsr "#adr"\n\tmove.l (sp)+,a0\n" ->>>>>>> 7f0e216339182f97a72b850ea22d0893479b10c8 #endif } @@ -191,17 +131,6 @@ REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) register unsigned char ret asm("d0"); register struct smk_bit_t* bs_ asm("a0") = bs; __asm__ __volatile__ ( -<<<<<<< HEAD - " move.l (a0),d0 \n" - " lsr.l #1,d0 \n" - " bne.b .result%= \n" - CALL_REFILL("%2") - " lsr.l #1,d0 \n" - ".result%=: \n" - " move.l d0,(a0) \n" - " moveq #0,d0 \n" - " addx.l d0,d0 \n" -======= " move.l (a0),d0 \n" " lsr.l #1,d0 \n" " bne.b .result%= \n" @@ -211,7 +140,6 @@ REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) " move.l d0,(a0) \n" " moveq #0,d0 \n" " addx.l d0,d0 \n" ->>>>>>> 7f0e216339182f97a72b850ea22d0893479b10c8 : "=d" (ret) : "a" (bs_), "m"(_smk_refill) : "d1","a1","a0" ); return ret; @@ -237,43 +165,6 @@ REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) __asm__ __volatile__ ( " move.l (a0),d1 \n" -<<<<<<< HEAD - " cmp.l #256,d1 \n" - " bcc.s .l1%= \n" - CALL_REFILL("%2") - " move.l (a0),d1 \n" - " cmp.w #1,d1 \n" - " bls.s .l2%= \n" - - " subq.l #1,d0 \n" - " move.l d0,a1 \n" - - " move.l d1,d0 \n" - " lsr.l #1,d0 \n" - " or.l d0,d1 \n" - - " move.l d1,d0 \n" - " lsr.l #2,d0 \n" - " or.l d0,d1 \n" - - " move.l d1,d0 \n" - " lsr.l #4,d0 \n" - " or.l d0,d1 \n" - - " lsr.l #1,d1 \n" - " addq.l #1,d1 \n" - - " move.l a1,d0 \n" - " mulu.l d1,d0 \n" - " add.l (a0),d0 \n" - ".l2%=: \n" - " move.l d0,d1 \n" - ".l1%=: \n" - " moveq #0,d0 \n" - " move.b d1,d0 \n" - " lsr.l #8,d1 \n" - " move.l d1,(a0) \n" -======= " cmp.l #256,d1 \n" " bcc.s .l1%= \n" CALL_REFILL("%2") @@ -309,20 +200,10 @@ REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) " move.b d1,d0 \n" " lsr.l #8,d1 \n" " move.l d1,(a0) \n" ->>>>>>> 7f0e216339182f97a72b850ea22d0893479b10c8 : "=d" (ret) : "a" (bs_), "m" (_smk_refill) : "d1","a1","a0"); #else unsigned long a = bs->buf; -<<<<<<< HEAD - if(a<=1) a = _smk_refill(bs); - else if(a<256) { - unsigned long b = a>>1; b |= b>>1; b |= b>>2; b |= b>>4; ++b; - a += b*(_smk_refill(bs)-1); - } - bs->buf = a>>8; - return a&255; -======= if(a<=1) a = _smk_refill(bs); else if(a<256) { unsigned long b = a>>1; b |= b>>1; b |= b>>2; b |= b>>4; ++b; @@ -330,7 +211,6 @@ REGPARM short _smk_bs_read_8(struct smk_bit_t* bs) } bs->buf = a>>8; return a&255; ->>>>>>> 7f0e216339182f97a72b850ea22d0893479b10c8 #endif } } From db7e893665b1bc7f9cdd892f7d044752ed032163 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 2 Jan 2020 01:12:42 +0100 Subject: [PATCH 065/107] first successfull compil --- SourceX/platform/amiga/render68k.asm | 1090 ++++++++------------------ 1 file changed, 329 insertions(+), 761 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index b6f2149ba58..dc7d49d98e5 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -2,14 +2,14 @@ * render68k.asm -- replacement of C code by hand-written asm code by S.Devulder * ----------------------------------------------------------------------------- machine 68080 + + section .bss +_epilogue + rs.l 1 section .text BUFFER_WIDTH set 768 -VAMP_V4 set 1 ; 0 = replaces movem with separate moves -NO_OVERDRAW set 1 ; 1 = tests for out of screen drawings (0=crash) -A5_RELATIVE set 1 ; 1 = faster out of bounds tests (AMMX) -USE_CMP2 set 0 ; 1 = uses CMP2 (might be faster on 68K) BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 XDEF _RenderTile_RT_SQUARE @@ -26,12 +26,8 @@ BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 XDEF _RenderLine1_AMMX XDEF _RenderLine2_AMMX - ifne NO_OVERDRAW XREF __ZN3dvl10gpBufStartE - ifeq USE_CMP2 XREF __ZN3dvl8gpBufEndE - endc - endc XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE @@ -39,23 +35,6 @@ BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 cnop 0,4 -* sanity - ifeq NO_OVERDRAW -A5_RELATIVE set 0 -USE_CMP2 set 0 - endc - - ifne A5_RELATIVE -USE_CMP2 set 0 - endc - - ifeq NO_OVERDRAW*(1-USE_CMP2) -SAVE_A5A6 set 0 - else -SAVE_A5A6 set 1 - endc - - bank macro inline .aa equ * @@ -70,117 +49,87 @@ bank macro endm * ----------------------------------------------------------------------------- -* check bounds - -rts_bounds macro - ifnb \1 - adda.w d0,\1 - endc - ifnb \2 - adda.w d0,\2 - endc - ifne A5_RELATIVE - suba.l a5,a0 - endc - rts - endm - -chk_bounds macro - ifne NO_OVERDRAW - ifne A5_RELATIVE - cmp.l a6,a0 ; 1 - adda.l a5,a0 ; 1 - bhi.b \1 ; 2 - else - ifne USE_CMP2 - cmp2.l __ZN3dvl10gpBufStartE,a0 - bcs.b \1 - else - cmp.l a5,a0 ; 1 - bcs.b \1 ; 2 - cmp.l a6,a0 ; 3 - bhi.b \1 ; 4 - endc -* move.l a0,d2 ; F p1 -* sub.l a5,d2 ; F p1 -* move.l a6,d3 ; F p2 -* sub.l a5,d3 ; F p2 = 1 cycles for all 4 isntructions -* cmp.l d3,d2 ; 2 -* bhi \1 ; 3 total cycles - endc - endc - endm - -* ----------------------------------------------------------------------------- -* debug: displays nothing +* inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD mask) +* a0 = *dst +* a1 = *src +* d0 = n (1..32) +* a2 = tbl +* d1 = *mask +* d2 = scratch +* d3 = scratch +* d4 = scratch +* d6 = scratch _RenderLine_NONE add.w d0,a1 add.w d0,a0 rts +chk_bounds macro + cmpa.l a5,a0 + bcs.b .chk_bounds + move.l _epilogue,(sp) + rts +.chk_bounds + endm + * ----------------------------------------------------------------------------- * AMMX version +* final extraction of a mask rol_d1_mask macro bfclr d1{d0:8} rol.l #8,d1 -** move.w #$ff00,d3 -* lsr.w d0,d3 -* rol.l #8,d1 -* and.w d3,d1 endm -unroll_AMMX macro +* binary search from 32 up to 7 +binAMMX macro + inline bclr #5,d0 - beq \1_16 + beq .l16_31 * 32 bytes in a row - \1 0 - \1 0 - \1 0 - \1 1 - rts_bounds -\1_16 + \1 + \1 + \1 + \1 + rts +.l16_31 +* 16 to 31 bytes bclr #4,d0 - beq \1_8 -* 16 bytes in a row - \1 0 - \1 0 -\1_8 + beq .l8_15 + \1 + \1 +.l8_15 +* 8 to 15 bytes bclr #3,d0 - beq \1_0 + beq .l0_7 * 8 bytes in a row - \1 0 -\1_0 + \1 +.l0_7 * 0 to 7 bytes \2 * fixup ptrs -\3 + ifne \3&%01 + add.w d0,a0 + endc + ifne \3&%10 + add.w d0,a1 + endc + rts + einline endm +* ----------------------------------------------------------------------------- * case light_table_index == lightmax -_RenderLine1_AMMX - chk_bounds .nx - peor d2,d2,d2 ; d2=0.q - - moveq #1,d3 - add.l d1,d3 - bne .mask - -* no mask +_RenderLine1_AMMX + chk_bounds .n8 macro store d2,(a0)+ endm .n0 macro storec d2,d0,(a0) endm - unroll_AMMX .n8,.n0,.nx - add.w d0,a0 - add.w d0,a1 - rts_bounds - -* mask version .m8 macro rol.l #8,d1 storem d2,d1,(a0)+ @@ -189,20 +138,21 @@ _RenderLine1_AMMX rol_d1_mask storem d2,d1,(a0) endm -.mask - unroll_AMMX .m8,.m0,.mx - add.w d0,a0 - rts_bounds - -* case light_table_index == 0 -_RenderLine0_AMMX - chk_bounds .nx + peor d2,d2,d2 ; d2=0.q moveq #1,d3 add.l d1,d3 + add.l d0,a1 ; advance bne .mask + binAMMX .n8,.n0,%01 +.mask + binAMMX .m8,.m0,%01 -* no mask +* ----------------------------------------------------------------------------- +* case light_table_index == 0 + +_RenderLine0_AMMX + chk_bounds .n8 macro load (a1)+,d2 store d2,(a0)+ @@ -211,12 +161,6 @@ _RenderLine0_AMMX load (a1),d2 storec d2,d0,(a0) endm - unroll_AMMX .n8,.n0,.nx - add.w d0,a0 - add.w d0,a1 - rts_bounds - -* version with mask .m8 macro rol.l #8,d1 load (a1)+,d2 @@ -227,154 +171,69 @@ _RenderLine0_AMMX load (a1),d2 storem d2,d1,(a0) endm + + moveq #1,d3 + add.l d1,d3 + bne .mask + binAMMX .n8,.n0,%11 .mask - unroll_AMMX .m8,.m0,.mx - add.w d0,a0 - add.w d0,a1 - rts_bounds + binAMMX .m8,.m0,%11 +* ----------------------------------------------------------------------------- * other cases - ifeq BYTE_INDEX_MODE +move_ macro +; move.\1 (a2,d\2 . b\3),d\4 + dc.w %0000000000110010+%0001000000000000*\1+%0000001000000000*\4 + dc.w %0000000100001000+%0001000000000000*\2+\3 + endm transform macro * move.l (a1)+,d3 ; F(used) d3=AABBCCDD * move.l (a1)+,d5 ; F 1 * input d3/d5 - ifne \1&$a0 + ifeq BYTE_INDEX_MODE move.l d3,d2 ; p1 d3=AABBCCDD rol.l #8,d2 ; p1 d2=BBCCDDAA - endc - ifne \1&$0a move.l d5,d4 ; p2 rol.l #8,d4 ; p2 2 - endc - ifne \1&$50 - swap d3 ; p1 d3=CDCDDAABB - endc - ifne \1&$a0 - and.l #$00FF00FF,d2 ; p2 3 d2=00CC00AA - endc - ifne \1&$05 - swap d5 ; p1 - endc - ifne \1&$50 - and.l #$00FF00FF,d3 ; p2 4 d3=00DD00BB - endc - ifne \1&$0a - and.l #$00FF00FF,d4 ; p1 - endc - ifne \1&$05 - and.l #$00FF00FF,d5 ; p2 5 - endc - ifne \1&$80 + swap d3 ; p1 d3=CDCDDAABB + and.l #$00FF00FF,d2 ; p2 3 d2=00CC00AA + swap d5 ; p1 + and.l #$00FF00FF,d3 ; p2 4 d3=00DD00BB + and.l #$00FF00FF,d4 ; p1 + and.l #$00FF00FF,d5 ; p2 5 move.w (a2,d2.w),d2 ; p1 6 d2=00CCxx-- - endc - ifne \1&$40 move.b (a2,d3.w),d2 ; p1 d2=00CCxxyy - endc - ifne \1&$a0 - swap d2 ; p2 7 d2=xxyy00CC - endc - ifne \1&$50 - swap d3 ; p1 d3=00BB00DD - endc - ifne \1&$08 + swap d2 ; p2 7 d2=xxyy00CC + swap d3 ; p1 d3=00BB00DD move.w (a2,d4.w),d4 ; p2 8 - endc - ifne \1&$04 move.b (a2,d5.w),d4 ; p1 - endc - ifne \1&$0a - swap d4 ; p2 9 - endc - ifne \1&$05 - swap d5 ; p1 - endc - ifne \1&$20 + swap d4 ; p2 9 + swap d5 ; p1 move.w (a2,d2.w),d2 ; p2 10 d2=xxyyzz-- - endc - ifne \1&$10 move.b (a2,d3.w),d2 ; p1 11 d2=xxyyzztt - endc - ifne \1&$02 move.w (a2,d4.w),d4 ; p1 12 - endc - ifne \1&$01 move.b (a2,d5.w),d4 ; p1 13 - endc -* output d2/d4 -* move.l d2,(a0)+ ; F -* move.l d4,(a0)+ ; F 14 ==> 14 cycles for 8 pixels ? - endm - else ; BYTE_INDEX_MODE - -move_ macro -; move.\1 (a2,d\2 . b\3),d\4 - dc.w %0000000000110010+%0001000000000000*\1+%0000001000000000*\4 - dc.w %0000000100001000+%0001000000000000*\2+\3 - endm - -transform macro -* move.l (a1)+,d3 ; F(used) d3=AABBCCDD -* move.l (a1)+,d5 ; F 1 -* input d3/d5 ; 2 cycles bubble -; move.w (a2,d3.b3),d2 ; 4 b3 - move_ %11,3,3,2 -; move.b (a2,d3.b2),d2 ; 5 b2 - move_ %01,3,2,2 -; move.w (a2,d5.b3),d4 ; 6 b3 - move_ %11,5,3,4 - swap d2 ; p2 6 -; move.b (a2,d5.b2),d4 ; 7 b2 - move_ %01,5,2,4 -; move.w (a2,d3.b1),d2 ; 8 b1 - move_ %11,3,1,2 - swap d4 ; p2 8 -; move.b (a2,d3.b0),d2 ; 9 b0 - move_ %01,3,0,2 -; move.w (a2,d5.b1),d4 ; 10 b1 - move_ %11,5,1,4 -; move.b (a2,d5.b0),d4 ; 11 b0 - move_ %01,5,0,4 + move_ %11,3,3,2 ; p1 4 move.w (a2,d3.b3),d2 + move_ %01,3,2,2 ; p1 5 move.b (a2,d3.b2),d2 + move_ %11,5,3,4 ; p1 6 move.w (a2,d5.b3),d4 + swap d2 ; p2 6 + move_ %01,5,2,4 ; p1 7 move.b (a2,d5.b2),d4 + move_ %11,3,1,2 ; p1 8 move.w (a2,d3.b1),d2 + swap d4 ; p2 8 + move_ %01,3,0,2 ; p1 9 move.b (a2,d3.b0),d2 + move_ %11,5,1,4 ; p1 10 move.w (a2,d5.b1),d4 + move_ %01,5,0,4 ; p1 11 move.b (a2,d5.b0),d4 + endc ; BYTE_INDEX_MODE * output d2/d4 * move.l d2,(a0)+ ; F * move.l d4,(a0)+ ; F 12 ==> 12 cycles for 8 pixels ? endm - endc ; BYTE_INDEX_MODE - -_RenderLine2_AMMX - chk_bounds _RenderLine0_AMMX\.mx - - move.l d1,d3 ; \ fused - addq.l #1,d3 ; / - bne .mask - -.n8 macro - move.l (a1)+,d3 - move.l (a1)+,d5 - transform $ff - move.l d2,(a0)+ - move.l d4,(a0)+ - endm -.n0 macro - move.l (a1),d3 - move.l 4(a1),d5 - transform $ff - vperm #$4567CDEF,d2,d4,d2 - storec d2,d0,(a0) - endm - unroll_AMMX .n8,.n0,.nx - add.w d0,a0 - add.w d0,a1 - rts_bounds - -* mask versions +transfAA55_8 macro ifeq BYTE_INDEX_MODE - -.transfAA55_8 macro move.b \1(a1),d2 ; 1 move.b \1+2(a1),d3 ; 2 move.b \1+4(a1),d4 ; 3 @@ -387,54 +246,47 @@ _RenderLine2_AMMX move.w (a2,d4.w),d1 ; 8 move.b (a2,d5.w),d1 ; 9 movep.l d1,\1-8(a0) ; 10 - endm - else ; BYTE_INDEX_MODE - -.transfAA55_8 macro move.l \1(a1),d2 ; 1 F move.l \1+4(a1),d4 ; 1 F -; move.w (a2,d2.b3),d1 ; 4 - move_ %11,2,3,1 -; move.b (a2,d2.b1),d1 ; 5 - move_ %01,2,1,1 + move_ %11,2,3,1 ; 4 move.w (a2,d2.b3),d1 + move_ %01,2,1,1 ; 5 move.b (a2,d2.b1),d1 addq.l #8,a1 ; 5 swap d1 ; 6 addq.l #8,a0 ; 6 -; move.w (a2,d4.b3),d1 ; 7 - move_ %11,4,3,1 -; move.b (a2,d4.b1),d1 ; 8 - move_ %01,4,1,1 + move_ %11,4,3,1 ; 7 move.w (a2,d4.b3),d1 + move_ %01,4,1,1 ; 8 move.b (a2,d4.b1),d1 movep.l d1,\1-8(a0) ; 9 + endc ; BYTE_INDEX_MODE endm - endc ; BYTE_INDEX_MODE - -.transfAA55 macro +transfAA55 macro + inline + ifeq BYTE_INDEX_MODE moveq #0,d2 moveq #0,d3 moveq #0,d4 moveq #0,d5 - + endc bclr #5,d0 - beq .b4\2 - .transfAA55_8 \1 - .transfAA55_8 \1 - .transfAA55_8 \1 - .transfAA55_8 \1 - rts_bounds -.b4\2 + beq .b4 + transfAA55_8 \1 + transfAA55_8 \1 + transfAA55_8 \1 + transfAA55_8 \1 + rts +.b4 bclr #4,d0 - beq.b .b3\2 - .transfAA55_8 \1 - .transfAA55_8 \1 -.b3\2 + beq.b .b3 + transfAA55_8 \1 + transfAA55_8 \1 +.b3 bclr #3,d0 - beq.b .b2\2 - .transfAA55_8 \1 -.b2\2 + beq.b .b2 + transfAA55_8 \1 +.b2 bclr #2,d0 - beq.b .b1\2 + beq.b .b1 move.b \1(a1),d2 ; 1 move.b \1+2(a1),d3 ; 2 addq.l #4,a0 ; 2 @@ -442,46 +294,50 @@ _RenderLine2_AMMX move.w (a2,d2.w),d1 ; 3+1 move.b (a2,d3.w),d1 ; 5 movep.w d1,\1-4(a0) ; 6 -.b1\2 +.b1 bclr #1,d0 - beq.b .b0\2 + beq.b .b0 move.b \1(a1),d2 ; 1 addq.l #2,a0 addq.l #2,a1 ; 2 ; 2 bubbles move.b (a2,d2.w),d1 ; 4 move.b d1,\1-2(a0) ; 5 -.b0\2 +.b0 ifeq \1 tst.b d0 - beq.b .bb0\2 + beq.b .bb0 move.b (a1)+,(a0)+ -.bb0\2 +.bb0 else add.w d0,a0 add.w d0,a1 endc - rts_bounds + rts + einline endm - -.maskAA - .transfAA55 0,_aa - -.mask55 - .transfAA55 1,_55 - -.mask - move.l #$AAAAAAAA,d3 - eor.l d1,d3 - beq .maskAA - not.l d3 - beq .mask55 +_RenderLine2_AMMX + chk_bounds +.n8 macro + move.l (a1)+,d3 + move.l (a1)+,d5 + transform + move.l d2,(a0)+ + move.l d4,(a0)+ + endm +.n0 macro + move.l (a1),d3 + move.l 4(a1),d5 + transform + vperm #$4567CDEF,d2,d4,d2 + storec d2,d0,(a0) + endm .m8 macro move.l (a1)+,d3 ; F(used) d3=AABBCCDD move.l (a1)+,d5 ; F 1 rol.l #8,d1 - transform $ff + transform vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0)+ endm @@ -489,238 +345,104 @@ _RenderLine2_AMMX move.l (a1),d3 ; F(used) d3=AABBCCDD move.l 4(a1),d5 ; F 1 rol_d1_mask - transform $ff + transform vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0) endm - -.maskXX - unroll_AMMX .m8,.m0,.mx - add.w d0,a0 - add.w d0,a1 - rts_bounds - -* ----------------------------------------------------------------------------- - -_RenderLine2_AMMX_orig - chk_bounds _RenderLine2_AMMX\.mx - move.l d1,d3 ; \ fused addq.l #1,d3 ; / bne .mask - -* here d3=0 => no need to init - -transform macro - IFNE \1-$AA - vperm #$A7A5A3A1,d2,d3,d3 - ENDC - IFNE \1-$55 - vperm #$A6A4A2A0,d2,d3,d2 - ENDC - - IFNE \1&$80 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$40 - move.b (a2,d3.w),d2 - ENDC - - swap d2 - swap d3 - - IFNE \1&$20 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$10 - move.b (a2,d3.w),d2 - ENDC - - vperm #$45670123,d2,d2,d2 - IFNE \1-$AA -* lsrq #32,d3 ; doesn't compile with vasm - vperm #$00000123,d3,d3,d3 - ENDC - - IFNE \1&$8 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$4 - move.b (a2,d3.w),d2 - ENDC - - swap d2 - swap d3 - - IFNE \1&$2 - move.w (a2,d2.w),d2 - ENDC - IFNE \1&$1 - move.b (a2,d3.w),d2 - ENDC - endm - -.n8 macro - load (a1)+,d2 - transform $ff - store d2,(a0)+ - endm -.n0 macro - load (a1),d2 - transform $ff - storec d2,d0,(a0) - endm - unroll_AMMX .n8,.n0,.nx - add.w d0,a0 - add.w d0,a1 - rts_bounds - -* mask version -.mask - moveq #0,d3 - - cmp.l #$AAAAAAAA,d1 - beq .maskAA - cmp.l #$55555555,d1 - beq .mask55 - -.m8 macro - load (a1)+,d2 - transform $ff - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m0 macro - load (a1),d2 - transform $ff - rol_d1_mask - storem d2,d1,(a0) - endm - unroll_AMMX .m8,.m0,.mx - add.w d0,a0 - add.w d0,a1 - rts_bounds - -.m8AA macro - load (a1)+,d2 - transform $AA - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m0AA macro - load (a1),d2 - transform $AA - rol_d1_mask - storem d2,d1,(a0) - endm + binAMMX .n8,.n0,%11 .maskAA - unroll_AMMX .m8AA,.m0AA,.mxAA - add.w d0,a0 - add.w d0,a1 - rts_bounds - -.m855 macro - load (a1)+,d2 - transform $55 - rol.l #8,d1 - storem d2,d1,(a0)+ - endm -.m055 macro - load (a1),d2 - transform $55 - rol_d1_mask - storem d2,d1,(a0) - endm + transfAA55 0 .mask55 - unroll_AMMX .m855,.m055,.mx55 - add.w d0,a0 - add.w d0,a1 - rts_bounds + transfAA55 1 +.mask + move.l #$AAAAAAAA,d3 + eor.l d1,d3 + beq .maskAA + not.l d3 + beq .mask55 +.maskXX + binAMMX .m8,.m0,%11 * ----------------------------------------------------------------------------- -* inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD mask) -* a0 = *dst -* a1 = *src -* d0 = n (1..32) -* a2 = tbl -* d1 = *mask -* d2 = scratch -* d3 = scratch -* CC sets according to d1 value +inc_a0 macro + addq.l #1,a0 + endm inc_a0_a1 macro -* cmp.b (a1)+,(a0)+ - addq.l #1,a0 - addq.l #1,a1 + cmp.b (a1)+,(a0)+ +* addq.l #1,a0 +* addq.l #1,a1 endm -unroll macro +bin68k macro + inline bclr #5,d0 - beq \1_4 - \1 0 - \1 0 - \1 0 - \1 0 - \1 0 - \1 0 - \1 0 - \1 1 - rts_bounds -\1_4 + beq .l16_31 + \1 + \1 + \1 + \1 + \1 + \1 + \1 + \1 + rts +.l16_31 bclr #4,d0 - beq \1_2 - \1 0 - \1 0 - \1 0 - \1 0 -\1_2 + beq .l8_15 + \1 + \1 + \1 + \1 +.l8_15 bclr #3,d0 - beq \1_1 - \1 0 - \1 0 -\1_1 + beq .l4_7 + \1 + \1 +.l4_7 bclr #2,d0 - beq \2_1 - \1 0 -\2_1 - bclr #1,d0 - beq \3_1 + beq .l2_3 + \1 +.l2_3 + bclr #1,d0 + beq .l1 \2 -\3_1 +.l1 tst.b d0 - beq \3_2 + beq .l0 \3 -\3_2 - rts_bounds +.l0 + einline + rts endm -loop macro -\1__1 +msk68k macro + inline +.l1 add.l d1,d1 - bcs \1__2 + bcs .l2 \1 - subq.w #1,d0 - bne \1__1 - rts_bounds -\1__2 + subq.l #1,d0 + bne .l1 + rts +.l2 \2 - subq.w #1,d0 - bne \1__1 - rts_bounds + subq.l #1,d0 + bne .l1 + einline + rts endm +* ----------------------------------------------------------------------------- * case light_table_index == 0 -_RenderLine0_ - add.w d0,a0 - add.w d0,a1 - rts_bounds -_RenderLine0 - chk_bounds _RenderLine0_ - not.l d1 - bne .mask +_RenderLine0 + chk_bounds .m4 macro move.l (a1)+,(a0)+ endm @@ -730,90 +452,57 @@ _RenderLine0 .m1 macro move.b (a1)+,(a0)+ endm - unroll .m4,.m2,.m1 - -.mask - cmp.l #$AAAAAAAA,d1 ; bg / fg / bg fg - bne .l2 -.p4 macro - ifeq 1 +.a4 macro move.b 1(a1),1(a0) ; 2 - move.b 3(a1),3(a0) ; 2 - addq.l #4,a0 ; .5 ==> 5 cycles addq.l #4,a1 ; .5 - else - move.l (a1)+,d1 ; \ - and.l #$00FF00FF,d1 ; / 1 cycle (fused) ? - move.l (a0),d2 ; \ - and.l #$FF00FF00,d2 ; / 1 cycle (fused) ? - or.l d2,d1 ; 1 - move.l d1,(a0)+ ; 1 ==> 4 cycles - endc + move.b -1(a1),3(a0) ; 2 + addq.l #4,a0 ; .5 ==> 5 cycles endm -.p2 macro - move.b 1(a1),1(a0) - addq.l #2,a0 +.a2 macro + move.b 1(a1),d1 addq.l #2,a1 + move.b d1,1(a0) + addq.l #2,a0 endm -.p1 macro +.a1 macro addq.l #1,a0 addq.l #1,a1 endm - unroll .p4,.p2,.p1 - -.l2 - cmp.l #$55555555,d1 ; fg / bg /fg / bg - bne .l3 - -.q4 macro - ifeq 1 +.b4 macro move.b (a1),(a0) ; 2 - move.b 2(a1),2(a0) ; 2 addq.l #4,a1 ; .5 + move.b -2(a1),2(a0) ; 2 addq.l #4,a0 ; .5 ==> 5 cycles - else - move.l #$FF00FF00,d1 - and.l (a1)+,d1 - move.l #$00FF00FF,d2 - and.l (a0),d2 - or.l d2,d1 - move.l d1,(a0)+ - endc endm -.q2 macro - ifeq 1 - move.b (a1),(a0) +.b2 macro + move.b (a1),d1 addq.l #2,a1 + move.b d1,(a0) addq.l #2,a0 - else - move.w #$FF00,d1 - and.w (a1)+,d1 - move.w #$00FF,d2 - and.w (a0),d2 - or.w d2,d1 - move.w d1,(a0)+ - endc endm -.q1 macro +.b1 macro move.b (a1)+,(a0)+ endm - unroll .q4,.q2,.q1 + not.l d1 + bne .mask + bin68k .m4,.m2,.m1 +.mask + cmp.l #$AAAAAAAA,d1 ; bg / fg / bg fg + bne .l2 + bin68k .a4,.a2,.a1 +.l2 + cmp.l #$55555555,d1 ; fg / bg /fg / bg + bne .l3 + bin68k .b4,.b2,.b1 .l3 - loop .m1,inc_a0_a1 - + msk68k .m1,inc_a0_a1 +* ----------------------------------------------------------------------------- * case light_table_index == lightmax -_RenderLine1_ - add.w d0,a0 - add.w d0,a1 - rts_bounds -_RenderLine1 - chk_bounds _RenderLine1_ - - not.l d1 - bne .mask +_RenderLine1 + chk_bounds .m4 macro clr.l (a0)+ endm @@ -823,11 +512,6 @@ _RenderLine1 .m1 macro clr.b (a0)+ endm - unroll .m4,.m2,.m1 -.mask - cmp.l #$AAAAAAAA,d1 - bne .l2 - move.l #$FF00FF00,d2 .p4 macro and.l d2,(a0)+ endm @@ -835,40 +519,30 @@ _RenderLine1 and.w d2,(a0)+ endm .p1 macro - addq.l #1,a0 + and.b d2,(a0)+ endm - unroll .p4,.p2,.p1 + not.l d1 + add.w d0,a1 + bne .mask + bin68k .m4,.m2,.m1 +.mask + cmp.l #$AAAAAAAA,d1 + bne .l2 + move.l #$FF00FF00,d2 + bin68k .p4,.p2,.p1 .l2 cmp.l #$55555555,d1 bne .l3 move.l #$00FF00FF,d2 -.q4 macro - and.l d2,(a0)+ - endm -.q2 macro - and.w d2,(a0)+ - endm -.q1 macro - clr.b (a0)+ - endm - unroll .q4,.q2,.q1 + bin68k .p4,.p2,.p1 .l3 - loop .m1,inc_a0_a1 + msk68k .m1,inc_a0 +* ----------------------------------------------------------------------------- * other cases -_RenderLine2_ - add.w d0,a1 - add.w d0,a0 - rts_bounds _RenderLine2 - chk_bounds _RenderLine2_ - - moveq #0,d2 - moveq #0,d3 - - not.l d1 - bne .mask + chk_bounds .m4 macro move.b (a1)+,d2 ; \ merged ? move.b (a1)+,d3 ; / @@ -892,11 +566,6 @@ _RenderLine2 move.b (a1)+,d2 move.b (a2,d2.w),(a0)+ endm - unroll .m4,.m2,.m1 - -.mask - cmp.l #$AAAAAAAA,d1 - bne .l2 .p4 macro move.b 1(a1),d2 move.b 3(a1),d3 @@ -914,11 +583,6 @@ _RenderLine2 .p1 macro inc_a0_a1 endm - unroll .p4,.p2,.p1 - -.l2 - cmp.l #$55555555,d1 - bne .l3 .q4 macro move.b (a1),d2 move.b 2(a1),d3 @@ -937,166 +601,100 @@ _RenderLine2 move.b (a1)+,d2 move.b (a2,d2.l),(a0)+ endm - unroll .q4,.q2,.q1 + moveq #0,d2 + moveq #0,d3 + not.l d1 + bne .mask + bin68k .m4,.m2,.m1 +.mask + cmp.l #$AAAAAAAA,d1 + bne .l2 + bin68k .p4,.p2,.p1 +.l2 + cmp.l #$55555555,d1 + bne .l3 + bin68k .q4,.q2,.q1 .l3 - loop .m1,inc_a0_a1 + msk68k .m1,inc_a0_a1 *------------------------------------------------------------------------------------ -setup macro -* get params from stack - IFNE VAMP_V4 - movem.l (4*(1+\1),sp),a0/a1/a2/a3 - ELSE - move.l (4*(1+\1),sp),a0 ; \ - move.l (4*(2+\1),sp),a1 ; / fused - - move.l (4*(3+\1),sp),a2 ; \ fused - move.l (4*(4+\1),sp),a3 ; / - ENDC - bsr _setup - endm - - xdef _setup - + xdef _setup + +* a3 = stack params ptr +* a4 = .epilogue _setup - ifne NO_OVERDRAW - ifeq USE_CMP2 - move.l __ZN3dvl10gpBufStartE,a5 - move.l __ZN3dvl8gpBufEndE,a6 - endc - addq.l #4,a3 - ifne A5_RELATIVE - sub.l a5,a0 - sub.l a5,a6 - endc - else - addq.l #4,a3 - endc -* determine renderFcn + move.l (a3)+,a0 ; \ points to bottom + move.l (a3)+,a1 ; / fused + move.l (a3)+,a2 ; \ fused + move.l (a3)+,a3 ; / + movea.l __ZN3dvl10gpBufStartE,a5 + sub.w #31*4,a3 ; point to start + move.l a4,_epilogue + moveq #0,d3 + cmpa.l __ZN3dvl8gpBufEndE,a0 + bcc.b .setup_drawLine + cmpa.l a5,a0 + bcs _RenderLine2\.chk_bounds-2 + moveq #_RenderLine2\.chk_bounds-_RenderLine2,d3 +.setup_drawLine + sub.w #32*BUFFER_WIDTH,a0 ; point to start .ammx tst.b _ac68080_ammx beq.b .m68k - lea _RenderLine0_AMMX(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 - beq.b .exit + beq.b .l1 sub.b __ZN3dvl8lightmaxE,d2 lea _RenderLine2_AMMX(pc),a4 - bne.b .exit + bne.b .l1 lea _RenderLine1_AMMX(pc),a4 -.exit +.l1 add.w d3,a4 * remove initial comparison so that it now only costs 1 cycle move.w #$203c,.ammx ; move.l #nnnn,d0 move.w #$7200,.ammx+6 ; moveq #0,d1 - move.w #$4e75,.exit ; #rts + move.w #$4e75,.l1+2 ; #rts rts ; no need to ClearCacheU on apollo! - .m68k lea _RenderLine0(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 - beq .L0 + beq .l2 sub.b __ZN3dvl8lightmaxE,d2 lea _RenderLine2(pc),a4 - bne.b .L0 + bne.b .l2 lea _RenderLine1(pc),a4 -.L0 +.l2 add.w d3,a4 rts prologue_7 macro -.size set 7 - ifeq SAVE_A5A6 -.size set .size-2 - endc - IFNE VAMP_V4 - ifne SAVE_A5A6 - movem.l d2-d3/a2-a6,-(sp) - else - movem.l d2-d3/a2-a4,-(sp) - endc - ELSE - sub.w #4*.size,sp - move.l d2,4*0(sp) ; \ - move.l d3,4*1(sp) ; / fused - - move.l a2,4*2(sp) ; \ - move.l a3,4*3(sp) ; / fused - - move.l a4,4*4(sp) ; \ - ifne SAVE_A5A6 - move.l a5,4*5(sp) ; / fused - - move.l a6,4*6(sp) - endc - ENDC - setup .size +.size set 8 + movem.l d2-d5/a2-a5,-(sp) + lea (-.size*4+4,sp),a3 + lea .epilogue(pc),a4 + bsr _setup endm - epilogue_7 macro - IFNE VAMP_V4 - ifne SAVE_A5A6 - movem.l (sp)+,d2-d3/a2-a3/a4-a6 - else - movem.l (sp)+,d2-d3/a2-a3/a4 - endc - ELSE +.epilogue move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / + move.l (sp)+,d4 ; \ fused + move.l (sp)+,d5 ; / move.l (sp)+,a2 ; \ fused move.l (sp)+,a3 ; / move.l (sp)+,a4 ; \ fused - ifne SAVE_A5A6 move.l (sp)+,a5 ; / - move.l (sp)+,a6 - endc - ENDC rts endm prologue_11 macro .size set 11 - ifeq SAVE_A5A6 -.size set .size-2 - endc - IFNE VAMP_V4 - ifne SAVE_A5A6 movem.l d2-d7/a2-a6,-(sp) - else - movem.l d2-d7/a2-a4,-(sp) - endc - ELSE - sub.w #4*.size,sp - - move.l d2,4*0(sp) ; \ - move.l d3,4*1(sp) ; / fused - - move.l d4,4*2(sp) ; \ - move.l d5,4*3(sp) ; / fused - - move.l d6,4*4(sp) ; \ - move.l d7,4*5(sp) ; / fused - - move.l a2,4*6(sp) ; \ - move.l a3,4*7(sp) ; / fused - - move.l a4,4*8(sp) ; \ - ifne SAVE_A5A6 - move.l a5,4*9(sp) ; / fused - - move.l a6,4*10(sp) - endc - ENDC - setup .size + lea (-.size*4+4,sp),a3 + lea .epilogue(pc),a4 + bsr _setup endm - epilogue_11 macro - IFNE VAMP_V4 - ifne SAVE_A5A6 - movem.l (sp)+,d2-d7/a2-a6 - else - movem.l (sp)+,d2-d7/a2-a4 - endc - ELSE +.epilogue move.l (sp)+,d2 ; \ fused move.l (sp)+,d3 ; / move.l (sp)+,d4 ; \ fused @@ -1106,21 +704,21 @@ epilogue_11 macro move.l (sp)+,a2 ; \ fused move.l (sp)+,a3 ; / move.l (sp)+,a4 ; \ fused - ifne SAVE_A5A6 move.l (sp)+,a5 ; / move.l (sp)+,a6 - endc - ENDC rts endm *------------------------------------------------------------------------------------ * extern void RenderTile_RT_TRANSPARENT(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -RT_TRANS macro - inline + +_RenderTile_RT_TRANSPARENT + prologue_11 + move.w #32,a6 .L1 - move.l -(a3),d6 ; m = *mask; mask-- + move.l (a3)+,d6 ; m = *mask; mask-- moveq #32,d7 + subq.l #1,a6 moveq #0,d0 ; TODO: remove ? .L2 move.b (a1)+,d0 @@ -1137,48 +735,18 @@ RT_TRANS macro move.l d6,d1 lsl.l d0,d6 sub.l d0,d7 - beq .L4 ; likely to be false most of the times - \1 \2 + beq.b .L4 ; likely to be false most of the times + jsr (a4) move.b (a1)+,d0 bgt.b .L3 ; more likely at this point bra .L22 .L4 - \1 \2 + jsr (a4) .L5 - \3 \4 - sub.w #BUFFER_WIDTH+32,a0 - einline - endm - -_RenderTile_RT_TRANSPARENT - prologue_11 - cmp.l #_RenderLine0_AMMX,a4 - beq _RenderTile_RT_TRANSPARENT_0_AMMX - cmp.l #_RenderLine2_AMMX,a4 - beq _RenderTile_RT_TRANSPARENT_2_AMMX - REPT 32 - RT_TRANS jsr,(a4) - ENDR - epilogue_11 - - XDEF _RenderTile_RT_TRANSPARENT_0_AMMX -_RenderTile_RT_TRANSPARENT_0_AMMX - move.l #32,a4 -.loop - subq.l #1,a4 - RT_TRANS bsr,_RenderLine0_AMMX,tst.l,a4 - bne .loop + tst.l a6 + adda.w #BUFFER_WIDTH-32,a0 + bne .L1 epilogue_11 - - XDEF _RenderTile_RT_TRANSPARENT_2_AMMX -_RenderTile_RT_TRANSPARENT_2_AMMX - move.l #32,a4 -.loop - subq.l #1,a4 - RT_TRANS bsr,_RenderLine2_AMMX,tst.l,a4 - bne .loop - epilogue_11 - *------------------------------------------------------------------------------------ * extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) @@ -1197,9 +765,9 @@ _RenderTile_RT_SQUARE block16 REPT 16 moveq #32,d0 - move.l -(a3),d1 + move.l (a3)+,d1 jsr (a4) - sub.w #BUFFER_WIDTH+32,a0 + add.w #BUFFER_WIDTH-32,a0 ENDR rts @@ -1227,12 +795,12 @@ triangL addq.w #2,a1 ENDC moveq #32-.i,d0 - move.l -(a3),d1 + move.l (a3)+,d1 jsr (a4) IFNE .i .i set .i-2 ENDC - sub.w #BUFFER_WIDTH+32-.i,a0 + add.w #BUFFER_WIDTH-32+.i,a0 ENDR rts @@ -1240,12 +808,12 @@ triangR .i set 30 REPT 16 moveq #32-.i,d0 - move.l -(a3),d1 + move.l (a3)+,d1 jsr (a4) IFNE .i&2 addq.w #2,a1 ENDC - sub.w #BUFFER_WIDTH+32-.i,a0 + add.w #BUFFER_WIDTH-32+.i,a0 .i set .i-2 ENDR rts @@ -1262,11 +830,11 @@ _RenderTile_RT_LTRIANGLE addq.w #2,a1 ENDC moveq #32-.i,d0 - move.l -(a3),d1 + move.l (a3)+,d1 jsr (a4) IFNE .i-30 .i set .i+2 - sub.w #BUFFER_WIDTH+32-.i,a0 + add.w #BUFFER_WIDTH-32+.i,a0 ENDC ENDR epilogue_7 @@ -1279,12 +847,12 @@ _RenderTile_RT_RTRIANGLE .i set 2 REPT 15 moveq #32-.i,d0 - move.l -(a3),d1 + move.l (a3)+,d1 jsr (a4) IFNE .i&2 addq.w #2,a1 ENDC - sub.w #BUFFER_WIDTH+32-.i,a0 + add.w #BUFFER_WIDTH-32+.i,a0 .i set .i+2 ENDR epilogue_7 From 4e2d9f6f5266c758e9f3cdec8017f0a3158522eb Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 2 Jan 2020 11:53:54 +0100 Subject: [PATCH 066/107] works under uae, need to test on real machine --- SourceX/platform/amiga/render68k.asm | 149 ++++++++++++--------------- 1 file changed, 68 insertions(+), 81 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index dc7d49d98e5..0054ef37e70 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -3,10 +3,6 @@ * ----------------------------------------------------------------------------- machine 68080 - section .bss -_epilogue - rs.l 1 - section .text BUFFER_WIDTH set 768 @@ -66,11 +62,10 @@ _RenderLine_NONE rts chk_bounds macro - cmpa.l a5,a0 - bcs.b .chk_bounds - move.l _epilogue,(sp) - rts -.chk_bounds +.ck cmpa.l a5,a0 + bcc _RenderLine_NONE + addq.l #.ok_bounds-.ck,a4 +.ok_bounds endm * ----------------------------------------------------------------------------- @@ -624,52 +619,48 @@ _RenderLine2 * a3 = stack params ptr * a4 = .epilogue _setup - move.l (a3)+,a0 ; \ points to bottom - move.l (a3)+,a1 ; / fused - move.l (a3)+,a2 ; \ fused - move.l (a3)+,a3 ; / - movea.l __ZN3dvl10gpBufStartE,a5 - sub.w #31*4,a3 ; point to start - move.l a4,_epilogue - moveq #0,d3 - cmpa.l __ZN3dvl8gpBufEndE,a0 - bcc.b .setup_drawLine - cmpa.l a5,a0 - bcs _RenderLine2\.chk_bounds-2 - moveq #_RenderLine2\.chk_bounds-_RenderLine2,d3 -.setup_drawLine - sub.w #32*BUFFER_WIDTH,a0 ; point to start + movea.l (a3)+,a0 ; \ points to bottom + movea.l (a3)+,a1 ; / fused + movea.l (a3)+,a2 ; \ fused + movea.l (a3)+,a3 ; / + addq.l #4,a3 ; point to start + cmpa.l __ZN3dvl10gpBufStartE,a0 + bcc.b .ok + move.l a4,(sp) ; tile largely above top of screen + rts ; just goto epilogue +.ok + movea.l __ZN3dvl8gpBufEndE,a5 .ammx tst.b _ac68080_ammx beq.b .m68k lea _RenderLine0_AMMX(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 - beq.b .l1 + beq.b .patch sub.b __ZN3dvl8lightmaxE,d2 lea _RenderLine2_AMMX(pc),a4 - bne.b .l1 + bne.b .patch lea _RenderLine1_AMMX(pc),a4 -.l1 add.w d3,a4 * remove initial comparison so that it now only costs 1 cycle +.patch move.w #$203c,.ammx ; move.l #nnnn,d0 move.w #$7200,.ammx+6 ; moveq #0,d1 - move.w #$4e75,.l1+2 ; #rts + move.w #$4e75,.patch ; #rts rts ; no need to ClearCacheU on apollo! .m68k lea _RenderLine0(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 - beq .l2 + beq.b .done sub.b __ZN3dvl8lightmaxE,d2 lea _RenderLine2(pc),a4 - bne.b .l2 + bne.b .done lea _RenderLine1(pc),a4 -.l2 add.w d3,a4 +.done rts prologue_7 macro .size set 8 movem.l d2-d5/a2-a5,-(sp) - lea (-.size*4+4,sp),a3 + lea (.size*4+4,sp),a3 lea .epilogue(pc),a4 bsr _setup endm @@ -689,7 +680,7 @@ epilogue_7 macro prologue_11 macro .size set 11 movem.l d2-d7/a2-a6,-(sp) - lea (-.size*4+4,sp),a3 + lea (.size*4+4,sp),a3 lea .epilogue(pc),a4 bsr _setup endm @@ -716,7 +707,7 @@ _RenderTile_RT_TRANSPARENT prologue_11 move.w #32,a6 .L1 - move.l (a3)+,d6 ; m = *mask; mask-- + move.l -(a3),d6 ; m = *mask; mask-- moveq #32,d7 subq.l #1,a6 moveq #0,d0 ; TODO: remove ? @@ -744,50 +735,22 @@ _RenderTile_RT_TRANSPARENT jsr (a4) .L5 tst.l a6 - adda.w #BUFFER_WIDTH-32,a0 + sub.w #BUFFER_WIDTH+32,a0 bne .L1 epilogue_11 -*------------------------------------------------------------------------------------ -* extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_SQUARE - prologue_7 - bsr block16 - bsr block16 - epilogue_7 - *------------------------------------------------------------------------------------ - XDEF block16 - XDEF triangL - XDEF triangR - -block16 +block16 macro REPT 16 moveq #32,d0 - move.l (a3)+,d1 + move.l -(a3),d1 jsr (a4) - add.w #BUFFER_WIDTH-32,a0 + sub.w #BUFFER_WIDTH+32,a0 ENDR - rts - -*------------------------------------------------------------------------------------ -* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_LTRAPEZOID - prologue_7 - bsr triangL - bsr block16 - epilogue_7 - -*------------------------------------------------------------------------------------ -* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) -_RenderTile_RT_RTRAPEZOID - prologue_7 - bsr triangR - bsr block16 - epilogue_7 + endm -triangL +triangL macro .i set 30 add.w #.i,a0 REPT 16 @@ -795,34 +758,58 @@ triangL addq.w #2,a1 ENDC moveq #32-.i,d0 - move.l (a3)+,d1 + move.l -(a3),d1 jsr (a4) IFNE .i .i set .i-2 ENDC - add.w #BUFFER_WIDTH-32+.i,a0 + sub.w #BUFFER_WIDTH+32-.i,a0 ENDR - rts + endm -triangR +triangR macro .i set 30 REPT 16 moveq #32-.i,d0 - move.l (a3)+,d1 + move.l -(a3),d1 jsr (a4) IFNE .i&2 addq.w #2,a1 ENDC - add.w #BUFFER_WIDTH-32+.i,a0 + sub.w #BUFFER_WIDTH+32-.i,a0 .i set .i-2 ENDR - rts + endm + +*------------------------------------------------------------------------------------ +* extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_SQUARE + prologue_7 + block16 + block16 + epilogue_7 + +*------------------------------------------------------------------------------------ +* extern void RenderTile_RT_LTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_LTRAPEZOID + prologue_7 + triangL + block16 + epilogue_7 + +*------------------------------------------------------------------------------------ +* extern void RenderTile_RT_RTRAPEZOID(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) +_RenderTile_RT_RTRAPEZOID + prologue_7 + triangR + block16 + epilogue_7 *------------------------------------------------------------------------------------ * extern void RenderTile_RT_LTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_LTRIANGLE prologue_7 - bsr triangL + triangL .i set 2 addq.l #.i,a0 REPT 15 @@ -830,11 +817,11 @@ _RenderTile_RT_LTRIANGLE addq.w #2,a1 ENDC moveq #32-.i,d0 - move.l (a3)+,d1 + move.l -(a3),d1 jsr (a4) IFNE .i-30 .i set .i+2 - add.w #BUFFER_WIDTH-32+.i,a0 + sub.w #BUFFER_WIDTH+32-.i,a0 ENDC ENDR epilogue_7 @@ -843,16 +830,16 @@ _RenderTile_RT_LTRIANGLE * extern void RenderTile_RT_RTRIANGLE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_RTRIANGLE prologue_7 - bsr triangR + triangR .i set 2 REPT 15 moveq #32-.i,d0 - move.l (a3)+,d1 + move.l -(a3),d1 jsr (a4) IFNE .i&2 addq.w #2,a1 ENDC - add.w #BUFFER_WIDTH-32+.i,a0 + sub.w #BUFFER_WIDTH+32-.i,a0 .i set .i+2 ENDR epilogue_7 From 57102297088b06220edbf77d1b137e41c61f0810 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 2 Jan 2020 12:16:54 +0100 Subject: [PATCH 067/107] simplified screen-bounds checking code --- SourceX/platform/amiga/render68k.asm | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 0054ef37e70..2b0558788fd 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -2,7 +2,7 @@ * render68k.asm -- replacement of C code by hand-written asm code by S.Devulder * ----------------------------------------------------------------------------- machine 68080 - + section .text BUFFER_WIDTH set 768 @@ -28,7 +28,7 @@ BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE XREF _ac68080_ammx - + cnop 0,4 bank macro @@ -178,7 +178,7 @@ _RenderLine0_AMMX * other cases move_ macro -; move.\1 (a2,d\2 . b\3),d\4 +; move.\1 (a2,d\2 . b\3),d\4 dc.w %0000000000110010+%0001000000000000*\1+%0000001000000000*\4 dc.w %0000000100001000+%0001000000000000*\2+\3 endm @@ -194,7 +194,7 @@ transform macro rol.l #8,d4 ; p2 2 swap d3 ; p1 d3=CDCDDAABB and.l #$00FF00FF,d2 ; p2 3 d2=00CC00AA - swap d5 ; p1 + swap d5 ; p1 and.l #$00FF00FF,d3 ; p2 4 d3=00DD00BB and.l #$00FF00FF,d4 ; p1 and.l #$00FF00FF,d5 ; p2 5 @@ -214,10 +214,10 @@ transform macro move_ %11,3,3,2 ; p1 4 move.w (a2,d3.b3),d2 move_ %01,3,2,2 ; p1 5 move.b (a2,d3.b2),d2 move_ %11,5,3,4 ; p1 6 move.w (a2,d5.b3),d4 - swap d2 ; p2 6 + swap d2 ; p2 6 move_ %01,5,2,4 ; p1 7 move.b (a2,d5.b2),d4 move_ %11,3,1,2 ; p1 8 move.w (a2,d3.b1),d2 - swap d4 ; p2 8 + swap d4 ; p2 8 move_ %01,3,0,2 ; p1 9 move.b (a2,d3.b0),d2 move_ %11,5,1,4 ; p1 10 move.w (a2,d5.b1),d4 move_ %01,5,0,4 ; p1 11 move.b (a2,d5.b0),d4 @@ -254,7 +254,7 @@ transfAA55_8 macro movep.l d1,\1-8(a0) ; 9 endc ; BYTE_INDEX_MODE endm - + transfAA55 macro inline ifeq BYTE_INDEX_MODE @@ -344,7 +344,7 @@ _RenderLine2_AMMX vperm #$4567CDEF,d2,d4,d2 storem d2,d1,(a0) endm - + move.l d1,d3 ; \ fused addq.l #1,d3 ; / bne .mask @@ -356,7 +356,7 @@ _RenderLine2_AMMX .mask move.l #$AAAAAAAA,d3 eor.l d1,d3 - beq .maskAA + beq .maskAA not.l d3 beq .mask55 .maskXX @@ -615,7 +615,7 @@ _RenderLine2 *------------------------------------------------------------------------------------ xdef _setup - + * a3 = stack params ptr * a4 = .epilogue _setup @@ -656,7 +656,7 @@ _setup lea _RenderLine1(pc),a4 .done rts - + prologue_7 macro .size set 8 movem.l d2-d5/a2-a5,-(sp) @@ -702,7 +702,7 @@ epilogue_11 macro *------------------------------------------------------------------------------------ * extern void RenderTile_RT_TRANSPARENT(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) - + _RenderTile_RT_TRANSPARENT prologue_11 move.w #32,a6 From 9daa5a75520a4c2d3ab607038451bb724db4cd10 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 2 Jan 2020 14:37:28 +0100 Subject: [PATCH 068/107] fixed some transparent tiles not being transparent --- Source/scrollrt.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index a0b1bea4a78..c85713824fe 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -479,17 +479,18 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy, int eflag); static void drawRow(int x, int y, int sx, int sy, int eflag) { +// #undef __mc68000__ #ifdef __mc68000__ // this code is better for gcc BYTE *dst = &gpBuffer[sx + (unsigned short)sy * (unsigned short)BUFFER_WIDTH]; int xy= (unsigned short)x*(unsigned short)MAXDUNY+y; #define xy(T) (&T[0][0]+xy)[0] WORD *mt = &xy(dpiece_defs_map_2).mt[0]; - cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[xy(dTransVal)]); - level_piece_id = xy(dPiece); light_table_index = xy(dLight); + cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[xy(dTransVal)]); + arch_draw_type = 1; if ((level_cel_block = *mt++)) drawUpperScreen(dst); @@ -499,10 +500,8 @@ static void drawRow(int x, int y, int sx, int sy, int eflag) arch_draw_type = 0; for(WORD i = MicroTileLen>>1; --i>0;) { dst -= BUFFER_WIDTH * 32; - level_cel_block = *mt++; - if (level_cel_block != 0) drawUpperScreen(dst); - level_cel_block = *mt++; - if (level_cel_block != 0) drawUpperScreen(dst + 32); + if ((level_cel_block = *mt++)) drawUpperScreen(dst); + if ((level_cel_block = *mt++)) drawUpperScreen(dst + 32); } #else From 12e8af1dac2d83752d66748d8abfce59196f497b Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 2 Jan 2020 17:59:47 +0100 Subject: [PATCH 069/107] improved multithreading in smk_bs_read_1 --- 3rdParty/libsmacker/smk_bitstream.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/3rdParty/libsmacker/smk_bitstream.c b/3rdParty/libsmacker/smk_bitstream.c index b9df45115ad..9ab3b207182 100644 --- a/3rdParty/libsmacker/smk_bitstream.c +++ b/3rdParty/libsmacker/smk_bitstream.c @@ -131,14 +131,15 @@ REGPARM char _smk_bs_read_1(struct smk_bit_t* bs) register unsigned char ret asm("d0"); register struct smk_bit_t* bs_ asm("a0") = bs; __asm__ __volatile__ ( - " move.l (a0),d0 \n" - " lsr.l #1,d0 \n" + " move.l (a0),d1 \n" + " lsr.l #1,d1 \n" " bne.b .result%= \n" CALL_REFILL("%2") - " lsr.l #1,d0 \n" + " move.l d0,d1 \n" + " lsr.l #1,d1 \n" ".result%=: \n" - " move.l d0,(a0) \n" " moveq #0,d0 \n" + " move.l d1,(a0) \n" " addx.l d0,d0 \n" : "=d" (ret) : "a" (bs_), "m"(_smk_refill) : "d1","a1","a0" ); From 2c747288b9364dbe3f7515e6c6893f845afde2ef Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 2 Jan 2020 22:25:32 +0100 Subject: [PATCH 070/107] better handling of selection of RenderLineX functions. Simplified setup code. --- SourceX/platform/amiga/render68k.asm | 101 ++++++++++++++++++--------- 1 file changed, 69 insertions(+), 32 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 2b0558788fd..0af3b9627a4 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -7,6 +7,7 @@ BUFFER_WIDTH set 768 BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 +INLINE_BLOCK16 set 1 ; 1 seem faster, but hard to tell XDEF _RenderTile_RT_SQUARE XDEF _RenderTile_RT_TRANSPARENT @@ -25,7 +26,7 @@ BYTE_INDEX_MODE set 0 ; 1 = experimental index mode on v4 XREF __ZN3dvl10gpBufStartE XREF __ZN3dvl8gpBufEndE - XREF __ZN3dvl8lightmaxE +* XREF __ZN3dvl8lightmaxE XREF __ZN3dvl17light_table_indexE XREF _ac68080_ammx @@ -615,45 +616,46 @@ _RenderLine2 *------------------------------------------------------------------------------------ xdef _setup + +m68k_render + dc.l _RenderLine0 + REPT 14 + dc.l _RenderLine2 + ENDR + dc.l _RenderLine1 + +ammx_render + dc.l _RenderLine0_AMMX + REPT 14 + dc.l _RenderLine2_AMMX + ENDR + dc.l _RenderLine1_AMMX * a3 = stack params ptr * a4 = .epilogue _setup movea.l (a3)+,a0 ; \ points to bottom movea.l (a3)+,a1 ; / fused - movea.l (a3)+,a2 ; \ fused - movea.l (a3)+,a3 ; / - addq.l #4,a3 ; point to start cmpa.l __ZN3dvl10gpBufStartE,a0 bcc.b .ok - move.l a4,(sp) ; tile largely above top of screen - rts ; just goto epilogue +* move.l a4,(sp) ; tile largely above top of screen +* rts ; just goto epilogue + addq.l #4,sp + jmp (a4) .ok - movea.l __ZN3dvl8gpBufEndE,a5 -.ammx - tst.b _ac68080_ammx - beq.b .m68k - lea _RenderLine0_AMMX(pc),a4 move.l __ZN3dvl17light_table_indexE,d2 - beq.b .patch - sub.b __ZN3dvl8lightmaxE,d2 - lea _RenderLine2_AMMX(pc),a4 - bne.b .patch - lea _RenderLine1_AMMX(pc),a4 -* remove initial comparison so that it now only costs 1 cycle +.table + lea m68k_render.l,a4 + movea.l (a3)+,a2 ; \ fused + movea.l (a3)+,a3 ; / + addq.l #4,a3 ; point to start + movea.l __ZN3dvl8gpBufEndE,a5 + move.l (a4,d2.l*4),a4 .patch - move.w #$203c,.ammx ; move.l #nnnn,d0 - move.w #$7200,.ammx+6 ; moveq #0,d1 - move.w #$4e75,.patch ; #rts - rts ; no need to ClearCacheU on apollo! -.m68k - lea _RenderLine0(pc),a4 - move.l __ZN3dvl17light_table_indexE,d2 + tst.b _ac68080_ammx beq.b .done - sub.b __ZN3dvl8lightmaxE,d2 - lea _RenderLine2(pc),a4 - bne.b .done - lea _RenderLine1(pc),a4 + move.l #ammx_render,.table+2 ; change table for ammx + move.w #$4e75,.patch ; #rts .done rts @@ -741,7 +743,7 @@ _RenderTile_RT_TRANSPARENT *------------------------------------------------------------------------------------ -block16 macro +block16_ macro REPT 16 moveq #32,d0 move.l -(a3),d1 @@ -750,7 +752,7 @@ block16 macro ENDR endm -triangL macro +triangL_ macro .i set 30 add.w #.i,a0 REPT 16 @@ -767,7 +769,7 @@ triangL macro ENDR endm -triangR macro +triangR_ macro .i set 30 REPT 16 moveq #32-.i,d0 @@ -780,7 +782,42 @@ triangR macro .i set .i-2 ENDR endm - + + ifeq INLINE_BLOCK16 + +_block16 + block16_ + rts +_triangL + triangL_ + rts +_triangR + triangR_ + rts +block16 macro + bsr _block16 + endm +triangL macro + bsr _triangL + endm +triangR macro + bsr _triangR + endm + + else + +block16 macro + block16_ + endm +triangL macro + triangL_ + endm +triangR macro + triangR_ + endm + + endc + *------------------------------------------------------------------------------------ * extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_SQUARE From 0c5ab353a387fdfd0bf0e5740d450c4839a19230 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 3 Jan 2020 00:00:33 +0100 Subject: [PATCH 071/107] fixed typo in memcpy/ammx resulting in possible mem-override --- SourceX/platform/amiga/memopt.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 6ccbfe069ea..f3542abacad 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -42,7 +42,7 @@ ___wrap_memcpy move.l .dst(sp),d0 ; p1 1 move.l .src(sp),a0 ; p1 2 - add.l .len(sp),d1 ; p1 3 + move.l .len(sp),d1 ; p1 3 movea.l d0,a1 .loop From a38037925aa491acf58039a040f29a98ce777c2c Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 3 Jan 2020 17:08:21 +0100 Subject: [PATCH 072/107] improved scheduling --- SourceX/platform/amiga/render68k.asm | 94 ++++++++++++++++++---------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 0af3b9627a4..039c7ddda9f 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -638,18 +638,15 @@ _setup movea.l (a3)+,a1 ; / fused cmpa.l __ZN3dvl10gpBufStartE,a0 bcc.b .ok -* move.l a4,(sp) ; tile largely above top of screen -* rts ; just goto epilogue - addq.l #4,sp - jmp (a4) -.ok - move.l __ZN3dvl17light_table_indexE,d2 + addq.l #4,sp ; tile largely above top of screen + jmp (a4) ; just goto epilogue +.ok move.l __ZN3dvl17light_table_indexE,d2 .table lea m68k_render.l,a4 movea.l (a3)+,a2 ; \ fused movea.l (a3)+,a3 ; / - addq.l #4,a3 ; point to start movea.l __ZN3dvl8gpBufEndE,a5 + addq.l #4,a3 ; point to start move.l (a4,d2.l*4),a4 .patch tst.b _ac68080_ammx @@ -707,38 +704,69 @@ epilogue_11 macro _RenderTile_RT_TRANSPARENT prologue_11 - move.w #32,a6 -.L1 - move.l -(a3),d6 ; m = *mask; mask-- - moveq #32,d7 - subq.l #1,a6 - moveq #0,d0 ; TODO: remove ? -.L2 - move.b (a1)+,d0 - bgt.b .L3 + move.w #32,a6 ; p1 + moveq #0,d0 ; p2 +.L1 move.l -(a3),d6 ; p1 + subq.l #1,a6 ; p2 + moveq #32,d7 ; p1 + move.b (a1)+,d0 ; p2 + bgt .L4 ; p1 + bra .L3 ; p2 +.L2 move.l d6,d1 ; p2 + lsl.l d0,d6 ; p1 + jsr (a4) ; p1 + move.b (a1)+,d0 ; p1 + bgt .L4 ; p1 +.L3 add.b d0,d7 ; p2 + beq .L6 ; p1 + neg.b d0 ; p2 + adda.l d0,a0 ; p1 + lsl.l d0,d6 ; p2 + move.b (a1)+,d0 ; p1 + ble .L3 ; p1 +.L4 sub.b d0,d7 ; p2 + bne .L2 ; p1 + move.l d6,d1 ; p2 + jsr (a4) ; p1 + sub.w #BUFFER_WIDTH+32,a0 ; p1 + tst.l a6 ; p2 + bne .L1 ; p1 + epilogue_11 +.L6 suba.w #BUFFER_WIDTH+32-256,a0 ; p2 + tst.l a6 ; p1 + suba.w d0,a0 ; p2 + bne .L1 ; p1 + bra .epilogue ; p2 + +_RenderTile_RT_TRANSPARENTorig + prologue_11 + move.w #32,a6 ; p1 + moveq #0,d0 ; p2 +.L1 move.l -(a3),d6 ; p1 m = *mask; mask-- + subq.l #1,a6 ; p2 + moveq #32,d7 ; p1 +.L2 move.b (a1)+,d0 ; p2 + bgt.b .L3 ; p1 .L22 - neg.b d0 ; p1 + neg.b d0 ; p2 lsl.l d0,d6 ; p1 sub.l d0,d7 ; p2 adda.l d0,a0 ; p1 doesnt affect the flags - beq.b .L5 ; p2 likely be false + beq.b .L5 ; p1 likely be false move.b (a1)+,d0 ; p1 ble.b .L22 ; p1 more likely to be false at this point -.L3 - move.l d6,d1 - lsl.l d0,d6 - sub.l d0,d7 - beq.b .L4 ; likely to be false most of the times - jsr (a4) - move.b (a1)+,d0 - bgt.b .L3 ; more likely at this point - bra .L22 -.L4 - jsr (a4) -.L5 - tst.l a6 - sub.w #BUFFER_WIDTH+32,a0 - bne .L1 +.L3 move.l d6,d1 ; p1 + lsl.l d0,d6 ; p2 + sub.l d0,d7 ; p1 + beq.b .L4 ; p1 + jsr (a4) ; p1 + move.b (a1)+,d0 ; p1 + bgt.b .L3 ; p1 + bra .L22 ; p2 +.L4 jsr (a4) ; p1 +.L5 tst.l a6 ; p1 + sub.w #BUFFER_WIDTH+32,a0 ; p2 + bne .L1 ; p1 epilogue_11 *------------------------------------------------------------------------------------ From 4c8d5465bc8e0b36312aa56b220b1dd57eb8199d Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 3 Jan 2020 18:17:15 +0100 Subject: [PATCH 073/107] now uses a 5sec basetime to get a more stable & accurate fps --- Source/scrollrt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index c85713824fe..4988d014a2d 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1093,7 +1093,7 @@ static void DrawFPS() frameend++; tc = GetTickCount(); frames = tc - framestart; - if (tc - framestart >= 1000) { + if (tc - framestart >= 1000*5) { framestart = tc; framerate = (1000 * frameend + frames/2) / frames; frameend = 0; From 3bbbc2edf00a0d03ec4ea402586506640d26b014 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 3 Jan 2020 18:18:24 +0100 Subject: [PATCH 074/107] improved end of mask handling --- SourceX/platform/amiga/render68k.asm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 039c7ddda9f..db8c274254e 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -131,7 +131,8 @@ _RenderLine1_AMMX storem d2,d1,(a0)+ endm .m0 macro - rol_d1_mask + bfclr d1{d0:8} + rol.l #8,d1 storem d2,d1,(a0) endm @@ -163,8 +164,9 @@ _RenderLine0_AMMX storem d2,d1,(a0)+ endm .m0 macro - rol_d1_mask load (a1),d2 + bfclr d1{d0:8} + rol.l #8,d1 storem d2,d1,(a0) endm @@ -338,16 +340,17 @@ _RenderLine2_AMMX storem d2,d1,(a0)+ endm .m0 macro + bfclr d1{d0:8} move.l (a1),d3 ; F(used) d3=AABBCCDD move.l 4(a1),d5 ; F 1 - rol_d1_mask transform vperm #$4567CDEF,d2,d4,d2 + rol.l #8,d1 storem d2,d1,(a0) endm - move.l d1,d3 ; \ fused - addq.l #1,d3 ; / + move.l d1,d3 ; \ fused + addq.l #1,d3 ; / bne .mask binAMMX .n8,.n0,%11 .maskAA From c26c9fcd60d55d85efa89d1c4217519a26a26849 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 3 Jan 2020 18:18:38 +0100 Subject: [PATCH 075/107] improved end of mask handling --- SourceX/platform/amiga/render68k.asm | 6 ------ 1 file changed, 6 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index db8c274254e..dc9e8a93b97 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -72,12 +72,6 @@ chk_bounds macro * ----------------------------------------------------------------------------- * AMMX version -* final extraction of a mask -rol_d1_mask macro - bfclr d1{d0:8} - rol.l #8,d1 - endm - * binary search from 32 up to 7 binAMMX macro inline From 854146e16c0bf6e56b049a3993f629bb88044682 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 6 Jan 2020 22:47:53 +0100 Subject: [PATCH 076/107] possibly fixed progress without background --- Source/scrollrt.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 4988d014a2d..c5280e4aa56 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1198,11 +1198,14 @@ void scrollrt_draw_game_screen(BOOL draw_cursor) DrawMain(hgt, 0, 0, 0, 0, 0); - if (draw_cursor) { #ifdef __AMIGA__ + if(ac68080_saga) { lock_buf(0); unlock_buf(0); // forces flip before cursor restore display + } #endif + + if (draw_cursor) { lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); From e57b0c2e351107158b85f55308b178cd140f8934 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 12 Jan 2020 10:36:30 +0100 Subject: [PATCH 077/107] code reorg for m68k --- 3rdParty/libsmacker/smacker.c | 82 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/3rdParty/libsmacker/smacker.c b/3rdParty/libsmacker/smacker.c index d7ac0831bee..66130ad8aaf 100644 --- a/3rdParty/libsmacker/smacker.c +++ b/3rdParty/libsmacker/smacker.c @@ -864,9 +864,14 @@ static char smk_render_video(struct smk_video_t* s, unsigned char* p, unsigned i long unpack; /* unpack, broken into pieces */ - unsigned char type; - unsigned char blocklen; - unsigned char typedata; +#ifdef __mc68000__ + unsigned long +#else + unsigned char +#endif + type, + blocklen, + typedata; char bit; const unsigned short sizetable[64] = { @@ -901,9 +906,15 @@ static char smk_render_video(struct smk_video_t* s, unsigned char* p, unsigned i { smk_huff16_lookup(bs,s->tree[SMK_TREE_TYPE],unpack); +#ifdef __mc68000__ + type = (unpack & 0x0003); + blocklen = ((unpack & 0x00FF) >> 2); + typedata = ((unpack>>8)&255)*0x1010101; +#else type = ((unpack & 0x0003)); blocklen = ((unpack & 0x00FC) >> 2); typedata = ((unpack & 0xFF00) >> 8); +#endif /* support for v4 full-blocks */ if (type == 1 && s->v == '4') @@ -921,45 +932,33 @@ static char smk_render_video(struct smk_video_t* s, unsigned char* p, unsigned i } } - for (j = 0; (j < sizetable[blocklen]) && (row < s->h); j ++) + for (j = sizetable[blocklen]; j && (row < s->h); --j) { skip = (row * s->w) + col; switch(type) { case 0: smk_huff16_lookup(bs,s->tree[SMK_TREE_MCLR],unpack); - s1 = (unpack & 0xFF00) >> 8; - s2 = (unpack & 0x00FF); + s2 = unpack; s1 = unpack>>8; smk_huff16_lookup(bs,s->tree[SMK_TREE_MMAP],unpack); - - temp = 0x01; - for (k = 0; k < 4; k ++) - { - for (i = 0; i < 4; i ++) - { - if (unpack & temp) - { - t[skip + i] = s1; - } - else - { - t[skip + i] = s2; - } - temp = temp << 1; - } + for(k=4; k; --k) { + t[skip + 0] = (unpack & 1) ? s1 : s2; + t[skip + 1] = (unpack & 2) ? s1 : s2; + t[skip + 2] = (unpack & 4) ? s1 : s2; + t[skip + 3] = (unpack & 8) ? s1 : s2; + unpack>>=4; skip += s->w; } break; - case 1: /* FULL BLOCK */ - for (k = 0; k < 4; k ++) + for (k = 4; k; --k) { smk_huff16_lookup(bs,s->tree[SMK_TREE_FULL],unpack); - t[skip + 3] = ((unpack & 0xFF00) >> 8); - t[skip + 2] = (unpack & 0x00FF); + t[skip + 2] = unpack; + t[skip + 3] = unpack>>8; smk_huff16_lookup(bs,s->tree[SMK_TREE_FULL],unpack); - t[skip + 1] = ((unpack & 0xFF00) >> 8); - t[skip] = (unpack & 0x00FF); + t[skip + 0] = unpack; + t[skip + 1] = unpack>>8; skip += s->w; } break; @@ -977,6 +976,12 @@ static char smk_render_video(struct smk_video_t* s, unsigned char* p, unsigned i } */ break; case 3: /* SOLID BLOCK */ +#ifdef __mc68000__ + *(int*)&t[skip] = typedata; skip += s->w; + *(int*)&t[skip] = typedata; skip += s->w; + *(int*)&t[skip] = typedata; skip += s->w; + *(int*)&t[skip] = typedata; +#else memset(&t[skip],typedata,4); skip += s->w; memset(&t[skip],typedata,4); @@ -984,32 +989,29 @@ static char smk_render_video(struct smk_video_t* s, unsigned char* p, unsigned i memset(&t[skip],typedata,4); skip += s->w; memset(&t[skip],typedata,4); +#endif break; case 4: /* V4 DOUBLE BLOCK */ - for (k = 0; k < 2; k ++) + for (k = 2; k ; --k) { smk_huff16_lookup(bs,s->tree[SMK_TREE_FULL],unpack); for (i = 0; i < 2; i ++) { - memset(&t[skip + 2],(unpack & 0xFF00) >> 8,2); - memset(&t[skip],(unpack & 0x00FF),2); + t[skip+0] = t[skip+1] = unpack; + t[skip+2] = t[skip+3] = unpack>>8; skip += s->w; } } break; case 5: /* V4 HALF BLOCK */ - for (k = 0; k < 2; k ++) + for (k = 2; k; --k) { smk_huff16_lookup(bs,s->tree[SMK_TREE_FULL],unpack); - t[skip + 3] = ((unpack & 0xFF00) >> 8); - t[skip + 2] = (unpack & 0x00FF); - t[skip + s->w + 3] = ((unpack & 0xFF00) >> 8); - t[skip + s->w + 2] = (unpack & 0x00FF); + t[skip + s->w + 2] = t[skip + 2] = unpack; + t[skip + s->w + 3] = t[skip + 3] = unpack>>8; smk_huff16_lookup(bs,s->tree[SMK_TREE_FULL],unpack); - t[skip + 1] = ((unpack & 0xFF00) >> 8); - t[skip] = (unpack & 0x00FF); - t[skip + s->w + 1] = ((unpack & 0xFF00) >> 8); - t[skip + s->w] = (unpack & 0x00FF); + t[skip + s->w + 0] = t[skip + 0] = unpack; + t[skip + s->w + 1] = t[skip + 1] = unpack>>8; skip += (s->w << 1); } break; From b6685e10fc015a869439cdf9aaa5724bf3ed131a Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 12 Jan 2020 10:46:02 +0100 Subject: [PATCH 078/107] removed valid flag now gcc has been fixed --- 3rdParty/Storm/Source/storm.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/3rdParty/Storm/Source/storm.h b/3rdParty/Storm/Source/storm.h index 87104bc0210..d6dc79b397f 100644 --- a/3rdParty/Storm/Source/storm.h +++ b/3rdParty/Storm/Source/storm.h @@ -55,37 +55,22 @@ typedef struct _WSIZE struct CCritSect { CRITICAL_SECTION m_critsect; -#ifdef __AMIGA__ - bool valid; -#endif CCritSect() { InitializeCriticalSection(&m_critsect); -#ifdef __AMIGA__ - valid = true; -#endif } ~CCritSect() { -#ifdef __AMIGA__ - valid = false; -#endif DeleteCriticalSection(&m_critsect); } void Enter() { -#ifdef __AMIGA__ - if(valid) -#endif EnterCriticalSection(&m_critsect); } void Leave() { -#ifdef __AMIGA__ - if(valid) -#endif LeaveCriticalSection(&m_critsect); } }; From 94c61524c0ca0aeb1736d3e521edf78d05491fc0 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 12 Jan 2020 10:46:36 +0100 Subject: [PATCH 079/107] lock/unlock earlier only when running saga --- Source/scrollrt.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index c5280e4aa56..c43f7bb607f 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1201,7 +1201,7 @@ void scrollrt_draw_game_screen(BOOL draw_cursor) #ifdef __AMIGA__ if(ac68080_saga) { lock_buf(0); - unlock_buf(0); // forces flip before cursor restore display + unlock_buf(0); // forces flip before cursor restore display when in saga mode } #endif @@ -1270,8 +1270,10 @@ void DrawAndBlit() DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag); #ifdef __AMIGA__ - lock_buf(0); - unlock_buf(0); // forces flip before cursor restore display + if(ac68080_saga) { + lock_buf(0); + unlock_buf(0); // forces flip before cursor restore display when in saga mode + } #endif lock_buf(0); From 6069c4baf93c7e374e165ccdb67d9fb4a480ba2e Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 12 Jan 2020 10:58:21 +0100 Subject: [PATCH 080/107] // change the palette the closest to screen wap, otherwise since decodign frames // takes time, we see the palette change on the previous image typically resutling // in white spots here and there --- SourceX/storm/storm.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index caf2eb96462..77b378fa070 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -628,8 +628,15 @@ BOOL SVidLoadNextFrame() BOOL SVidPlayContinue(void) { +#ifdef __AMIGA__ + static SDL_Color colors[256]; + static unsigned char palette_changed = 0; +#endif + if (smk_palette_updated(SVidSMK)) { +#ifndef __AMIGA__ SDL_Color colors[256]; +#endif const unsigned char *palette_data = smk_get_palette(SVidSMK); for (int i = 0; i < 256; i++) { @@ -647,10 +654,14 @@ BOOL SVidPlayContinue(void) } memcpy(logical_palette, orig_palette, 1024); +#ifdef __AMIGA__ + palette_changed = 255; +#else if (SDLC_SetSurfaceAndPaletteColors(SVidSurface, SVidPalette, colors, 0, 256) <= -1) { SDL_Log(SDL_GetError()); return false; } +#endif } if (SDL_GetTicks() * 1000 >= SVidFrameEnd) { @@ -731,6 +742,16 @@ BOOL SVidPlayContinue(void) SDL_FreeSurface(tmp); } +#ifdef __AMIGA__ + // change the palette the closest to screen wap, otherwise since decodign frames + // takes time, we see the palette change on the previous image typically resutling + // in white spots here and there + if (palette_changed + && SDLC_SetSurfaceAndPaletteColors(SVidSurface, SVidPalette, colors, 0, 256) <= -1) { + SDL_Log(SDL_GetError()); + return false; + } +#endif bufferUpdated = true; RenderPresent(); From 5d9ebb5c7a3ccff9a9b4168b51d5eb37100a5a9f Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 17 Jan 2020 23:08:04 +0100 Subject: [PATCH 081/107] reintroduced valid-flag --- 3rdParty/Storm/Source/storm.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/3rdParty/Storm/Source/storm.h b/3rdParty/Storm/Source/storm.h index d6dc79b397f..3f3f8dca1e0 100644 --- a/3rdParty/Storm/Source/storm.h +++ b/3rdParty/Storm/Source/storm.h @@ -55,22 +55,27 @@ typedef struct _WSIZE struct CCritSect { CRITICAL_SECTION m_critsect; + bool valid; CCritSect() { + valid = true; InitializeCriticalSection(&m_critsect); } ~CCritSect() { + valid = false; DeleteCriticalSection(&m_critsect); } void Enter() { + if(valid) EnterCriticalSection(&m_critsect); } void Leave() { + if(valid) LeaveCriticalSection(&m_critsect); } }; From 8809b2a4a443ed2560ce184f9cdee90c46f9a674 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 17 Jan 2020 23:18:25 +0100 Subject: [PATCH 082/107] fixed savefile. --- Source/encrypt.cpp | 11 +++++--- Source/loadsave.cpp | 28 ++++++++++++++----- Source/mpqapi.cpp | 19 +++++++++++-- Source/pack.cpp | 66 +++++++++++++++++++++++---------------------- Source/pfile.cpp | 4 +-- Source/sha.cpp | 5 ++-- 6 files changed, 85 insertions(+), 48 deletions(-) diff --git a/Source/encrypt.cpp b/Source/encrypt.cpp index bc4d0b76dd7..6a90ad6004e 100644 --- a/Source/encrypt.cpp +++ b/Source/encrypt.cpp @@ -13,9 +13,11 @@ void Decrypt(void *block, DWORD size, DWORD key) castBlock = (DWORD *)block; seed = 0xEEEEEEEE; for (i = 0; i < (size >> 2); i++) { + DWORD t = SwapLE32(*castBlock); seed += hashtable[0x400 + (key & 0xFF)]; - *castBlock ^= seed + key; - seed += *castBlock + (seed << 5) + 3; + t ^= seed + key; + *castBlock = t; + seed += t + (seed << 5) + 3; key = ((~key << 0x15) + 0x11111111) | (key >> 0x0B); castBlock++; } @@ -29,9 +31,10 @@ void Encrypt(void *block, DWORD size, DWORD key) castBlock = (DWORD *)block; seed = 0xEEEEEEEE; for (i = 0; i < (size >> 2); i++) { - ch = *castBlock; + DWORD t = ch = *castBlock; seed += hashtable[0x400 + (key & 0xFF)]; - *castBlock ^= seed + key; + t ^= seed + key; + *castBlock = SwapLE32(t); seed += ch + (seed << 5) + 3; key = ((~key << 0x15) + 0x11111111) | (key >> 0x0B); castBlock++; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index b2032df3cb0..515d41674da 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -215,32 +215,48 @@ void CopyBytes(const void *src, const int n, void *dst) void CopyChar(const void *src, void *dst) { - CopyBytes(src, 1, dst); + *(char*)dst = *(char*)src; + tbuff += 1; } void CopyShort(const void *src, void *dst) { - CopyBytes(src, 2, dst); + *(unsigned short*)dst = SwapLE16(*(unsigned short*)src); + tbuff += 2; } void CopyShorts(const void *src, const int n, void *dst) { - CopyBytes(src, 2 * n, dst); + unsigned short *s=src, *d=dst; + int i=n; + tbuff += 2*n; + while(i) { + *d = SwapLE16(*s); + ++d; ++s; --i; + } } void CopyInt(const void *src, void *dst) { - CopyBytes(src, 4, dst); + *(unsigned int*)dst = SwapLE32(*(unsigned int*)src); + tbuff += 4; } void CopyInts(const void *src, const int n, void *dst) { - CopyBytes(src, 4 * n, dst); + unsigned int *s=src, *d=dst; + int i=n; + tbuff += 4*n; + while(i) { + *d = SwapLE32(*s); + ++d; ++s; --i; + } } void CopyInt64(const void *src, void *dst) { - CopyBytes(src, 8, dst); + *(unsigned long long*)dst = SDL_SwapLE64(*(unsigned long long*)src); + tbuff += 8; } void LoadPlayer(int i) diff --git a/Source/mpqapi.cpp b/Source/mpqapi.cpp index 51d542de13d..ac11a4ca28b 100644 --- a/Source/mpqapi.cpp +++ b/Source/mpqapi.cpp @@ -231,7 +231,7 @@ BOOL mpqapi_write_file_contents(const char *pszName, const BYTE *pbData, DWORD d } destsize += nNumberOfBytesToWrite; } - sectoroffsettable[j] = destsize; + sectoroffsettable[j] = SwapLE32(destsize); if (!WriteFile(sghArchive, mpq_buf, len, &len, NULL)) { goto on_error; } @@ -243,7 +243,7 @@ BOOL mpqapi_write_file_contents(const char *pszName, const BYTE *pbData, DWORD d destsize += len; } - sectoroffsettable[j] = destsize; + sectoroffsettable[j] = SwapLE32(destsize); if (SetFilePointer(sghArchive, -destsize, NULL, FILE_CURRENT) == (DWORD)-1) { goto on_error; } @@ -376,6 +376,20 @@ BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar) return FALSE; } +static BOOL byteSwapHdr(_FILEHEADER *pHdr) +{ + pHdr->signature = SDL_SwapLE32(pHdr->signature); + pHdr->headersize = SDL_SwapLE32(pHdr->headersize); + pHdr->filesize = SDL_SwapLE32(pHdr->filesize); + pHdr->version = SDL_SwapLE16(pHdr->version); + pHdr->sectorsizeid = SDL_SwapLE16(pHdr->sectorsizeid); + pHdr->hashoffset = SDL_SwapLE32(pHdr->hashoffset); + pHdr->blockoffset = SDL_SwapLE32(pHdr->blockoffset); + pHdr->hashcount = SDL_SwapLE32(pHdr->hashcount); + pHdr->blockcount = SDL_SwapLE32(pHdr->blockcount); + return false; +} + BOOL ParseMPQHeader(_FILEHEADER *pHdr, DWORD *pdwNextFileStart) { DWORD size; @@ -387,6 +401,7 @@ BOOL ParseMPQHeader(_FILEHEADER *pHdr, DWORD *pdwNextFileStart) if (size == -1 || size < sizeof(*pHdr) || !ReadFile(sghArchive, pHdr, sizeof(*pHdr), &NumberOfBytesRead, NULL) + || byteSwapHdr(pHdr) || NumberOfBytesRead != 104 || pHdr->signature != '\x1AQPM' || pHdr->headersize != 32 diff --git a/Source/pack.cpp b/Source/pack.cpp index ddd0c167737..ec94db91c23 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -7,27 +7,27 @@ static void PackItem(PkItemStruct *id, ItemStruct *is) if (is->_itype == -1) { id->idx = 0xFFFF; } else { - id->idx = is->IDidx; + id->idx = SwapLE16(is->IDidx); if (is->IDidx == IDI_EAR) { id->iCreateInfo = is->_iName[8] | (is->_iName[7] << 8); - id->iSeed = is->_iName[12] | ((is->_iName[11] | ((is->_iName[10] | (is->_iName[9] << 8)) << 8)) << 8); + id->iSeed = SwapLE32(is->_iName[12] | ((is->_iName[11] | ((is->_iName[10] | (is->_iName[9] << 8)) << 8)) << 8)); id->bId = is->_iName[13]; id->bDur = is->_iName[14]; id->bMDur = is->_iName[15]; id->bCh = is->_iName[16]; id->bMCh = is->_iName[17]; - id->wValue = is->_ivalue | (is->_iName[18] << 8) | ((is->_iCurs - 19) << 6); - id->dwBuff = is->_iName[22] | ((is->_iName[21] | ((is->_iName[20] | (is->_iName[19] << 8)) << 8)) << 8); + id->wValue = SwapLE16(is->_ivalue | (is->_iName[18] << 8) | ((is->_iCurs - 19) << 6)); + id->dwBuff = SwapLE32(is->_iName[22] | ((is->_iName[21] | ((is->_iName[20] | (is->_iName[19] << 8)) << 8)) << 8)); } else { - id->iSeed = is->_iSeed; - id->iCreateInfo = is->_iCreateInfo; + id->iSeed = SwapLE32(is->_iSeed); + id->iCreateInfo = SwapLE16(is->_iCreateInfo); id->bId = is->_iIdentified + 2 * is->_iMagical; id->bDur = is->_iDurability; id->bMDur = is->_iMaxDur; id->bCh = is->_iCharges; id->bMCh = is->_iMaxCharges; if (is->IDidx == IDI_GOLD) - id->wValue = is->_ivalue; + id->wValue = SwapLE16(is->_ivalue); } } } @@ -57,13 +57,13 @@ void PackPlayer(PkPlayerStruct *pPack, int pnum, BOOL manashield) pPack->pBaseVit = pPlayer->_pBaseVit; pPack->pLevel = pPlayer->_pLevel; pPack->pStatPts = pPlayer->_pStatPts; - pPack->pExperience = pPlayer->_pExperience; - pPack->pGold = pPlayer->_pGold; - pPack->pHPBase = pPlayer->_pHPBase; - pPack->pMaxHPBase = pPlayer->_pMaxHPBase; - pPack->pManaBase = pPlayer->_pManaBase; - pPack->pMaxManaBase = pPlayer->_pMaxManaBase; - pPack->pMemSpells = pPlayer->_pMemSpells; + pPack->pExperience = SwapLE32(pPlayer->_pExperience); + pPack->pGold = SwapLE32(pPlayer->_pGold); + pPack->pHPBase = SwapLE32(pPlayer->_pHPBase); + pPack->pMaxHPBase = SwapLE32(pPlayer->_pMaxHPBase); + pPack->pManaBase = SwapLE32(pPlayer->_pManaBase); + pPack->pMaxManaBase = SwapLE32(pPlayer->_pMaxManaBase); + pPack->pMemSpells = SDL_SwapLE64(pPlayer->_pMemSpells); for (i = 0; i < MAX_SPELLS; i++) pPack->pSplLvl[i] = pPlayer->_pSplLvl[i]; @@ -99,10 +99,10 @@ void PackPlayer(PkPlayerStruct *pPack, int pnum, BOOL manashield) pi++; } - pPack->pDiabloKillLevel = pPlayer->pDiabloKillLevel; + pPack->pDiabloKillLevel = SwapLE32(pPlayer->pDiabloKillLevel); if (gbMaxPlayers == 1 || manashield) - pPack->pManaShield = pPlayer->pManaShield; + pPack->pManaShield = SwapLE32(pPlayer->pManaShield); else pPack->pManaShield = FALSE; } @@ -111,23 +111,25 @@ void PackPlayer(PkPlayerStruct *pPack, int pnum, BOOL manashield) // find real name reference below, possibly [sizeof(item[])/sizeof(ItemStruct)] static void UnPackItem(PkItemStruct *is, ItemStruct *id) { - if (is->idx == 0xFFFF) { + WORD idx = SwapLE16(is->idx); + + if (idx == 0xFFFF) { id->_itype = -1; } else { - if (is->idx == IDI_EAR) { + if (idx == IDI_EAR) { RecreateEar( MAXITEMS, - is->iCreateInfo, - is->iSeed, + SwapLE16(is->iCreateInfo), + SwapLE32(is->iSeed), is->bId, is->bDur, is->bMDur, is->bCh, is->bMCh, - is->wValue, - is->dwBuff); + SwapLE16(is->wValue), + SwapLE32(is->dwBuff)); } else { - RecreateItem(MAXITEMS, is->idx, is->iCreateInfo, is->iSeed, is->wValue); + RecreateItem(MAXITEMS, idx, SwapLE16(is->iCreateInfo), SwapLE32(is->iSeed), SwapLE32(is->wValue)); item[MAXITEMS]._iMagical = is->bId >> 1; item[MAXITEMS]._iIdentified = is->bId & 1; item[MAXITEMS]._iDurability = is->bDur; @@ -188,17 +190,17 @@ void UnPackPlayer(PkPlayerStruct *pPack, int pnum, BOOL killok) pPlayer->_pVitality = pPack->pBaseVit; pPlayer->_pLevel = pPack->pLevel; pPlayer->_pStatPts = pPack->pStatPts; - pPlayer->_pExperience = pPack->pExperience; - pPlayer->_pGold = pPack->pGold; - pPlayer->_pMaxHPBase = pPack->pMaxHPBase; - pPlayer->_pHPBase = pPack->pHPBase; + pPlayer->_pExperience = SwapLE32(pPack->pExperience); + pPlayer->_pGold = SwapLE32(pPack->pGold); + pPlayer->_pMaxHPBase = SwapLE32(pPack->pMaxHPBase); + pPlayer->_pHPBase = SwapLE32(pPack->pHPBase); if (!killok) if ((int)(pPlayer->_pHPBase & 0xFFFFFFC0) < 64) pPlayer->_pHPBase = 64; - pPlayer->_pMaxManaBase = pPack->pMaxManaBase; - pPlayer->_pManaBase = pPack->pManaBase; - pPlayer->_pMemSpells = pPack->pMemSpells; + pPlayer->_pMaxManaBase = SwapLE32(pPack->pMaxManaBase); + pPlayer->_pManaBase = SwapLE32(pPack->pManaBase); + pPlayer->_pMemSpells = SDL_SwapLE64(pPack->pMemSpells); for (i = 0; i < MAX_SPELLS; i++) pPlayer->_pSplLvl[i] = pPack->pSplLvl[i]; @@ -245,9 +247,9 @@ void UnPackPlayer(PkPlayerStruct *pPack, int pnum, BOOL killok) pPlayer->pTownWarps = 0; pPlayer->pDungMsgs = 0; pPlayer->pLvlLoad = 0; - pPlayer->pDiabloKillLevel = pPack->pDiabloKillLevel; + pPlayer->pDiabloKillLevel = SwapLE32(pPack->pDiabloKillLevel); pPlayer->pBattleNet = pPack->pBattleNet; - pPlayer->pManaShield = pPack->pManaShield; + pPlayer->pManaShield = SwapLE32(pPack->pManaShield); } DEVILUTION_END_NAMESPACE diff --git a/Source/pfile.cpp b/Source/pfile.cpp index 197984e17e8..3c92d813f38 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -102,9 +102,9 @@ BOOL pfile_create_player_description(char *dst, DWORD len) _uiheroinfo uihero; myplr = 0; -#if !defined(__BIG_ENDIAN__) +//#if !defined(__BIG_ENDIAN__) pfile_read_player_from_save(); -#endif +//#endif game_2_ui_player(plr, &uihero, gbValidSaveFile); UiSetupPlayerInfo(gszHero, &uihero, GAME_ID); diff --git a/Source/sha.cpp b/Source/sha.cpp index e6b57c25d49..b19f3d1e220 100644 --- a/Source/sha.cpp +++ b/Source/sha.cpp @@ -40,7 +40,7 @@ void SHA1Result(int n, char Message_Digest[SHA1HashSize]) Message_Digest_Block = (DWORD *)Message_Digest; if (Message_Digest) { for (i = 0; i < 5; i++) { - *Message_Digest_Block = sgSHA1[n].state[i]; + *Message_Digest_Block = SwapLE32(sgSHA1[n].state[i]); Message_Digest_Block++; } } @@ -79,7 +79,8 @@ void SHA1ProcessMessageBlock(SHA1Context *context) DWORD *buf = (DWORD *)context->buffer; for (i = 0; i < 16; i++) - W[i] = buf[i]; + W[i] = SwapLE32(buf[i]); + for (i = 16; i < 80; i++) { W[i] = W[i - 16] ^ W[i - 14] ^ W[i - 8] ^ W[i - 3]; From cb508952a095d0a843621b60ed798046fc3afc96 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 18 Jan 2020 00:03:33 +0100 Subject: [PATCH 083/107] fixed Abort() when dtartign mutliplayer. --- structs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/structs.h b/structs.h index a624d24a9a1..e16ccf0d882 100644 --- a/structs.h +++ b/structs.h @@ -1206,6 +1206,7 @@ typedef struct DeadStruct { typedef struct _gamedata { int dwSeed; BYTE bDiff; + BYTE __pad[3]; // sam : added adding so that sizeof()==8 and not 6 on bigendian machines } _gamedata; typedef struct _uidefaultstats { From 75b82ffa250b3f0b43ea325a94764c1c1b115574 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 18 Jan 2020 11:47:46 +0100 Subject: [PATCH 084/107] fixed gold at 5000 --- Source/pack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/pack.cpp b/Source/pack.cpp index ec94db91c23..1c69ca61dfc 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -129,7 +129,7 @@ static void UnPackItem(PkItemStruct *is, ItemStruct *id) SwapLE16(is->wValue), SwapLE32(is->dwBuff)); } else { - RecreateItem(MAXITEMS, idx, SwapLE16(is->iCreateInfo), SwapLE32(is->iSeed), SwapLE32(is->wValue)); + RecreateItem(MAXITEMS, idx, SwapLE16(is->iCreateInfo), SwapLE32(is->iSeed), SwapLE16(is->wValue)); item[MAXITEMS]._iMagical = is->bId >> 1; item[MAXITEMS]._iIdentified = is->bId & 1; item[MAXITEMS]._iDurability = is->bDur; From 5464f567e87dbc8424fdf433a54b38f4425189aa Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 18 Jan 2020 23:51:36 +0100 Subject: [PATCH 085/107] fixed right side of pillars being displayed at full intensity in dungeons --- SourceX/platform/amiga/render68k.asm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index dc9e8a93b97..70cb125d135 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -299,13 +299,17 @@ transfAA55 macro ifeq \1 tst.b d0 beq.b .bb0 - move.b (a1)+,(a0)+ + move.b (a1)+,d2 ; 1 +; 2 bubbles + move.b (a2,d2.w),d1 ; 4 + move.b d1,(a0)+ ; 5 .bb0 + rts else add.w d0,a0 add.w d0,a1 - endc rts + endc einline endm From 5974e965d505196e2e4d956e7dfbc7234c42e988 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sun, 19 Jan 2020 12:17:18 +0100 Subject: [PATCH 086/107] fixed endianess issue in SetMapMonsters (which created enforcer hits on the amiga) --- Source/monster.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/monster.cpp b/Source/monster.cpp index e22769a5b3e..fe61c03a3cf 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -1042,9 +1042,9 @@ void SetMapMonsters(BYTE *pMap, int startx, int starty) PlaceUniqueMonst(UMT_BLACKJADE, 0, 0); } lm = (WORD *)pMap; - rw = *lm; + rw = SwapLE16(*lm); lm++; - rh = *lm; + rh = SwapLE16(*lm); lm += (rw * rh + 1); rw = rw << 1; rh = rh << 1; @@ -1053,7 +1053,7 @@ void SetMapMonsters(BYTE *pMap, int startx, int starty) for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm) { - mtype = AddMonsterType(MonstConvTbl[(*lm) - 1], 2); + mtype = AddMonsterType(MonstConvTbl[SwapLE16(*lm) - 1], 2); PlaceMonster(nummonsters++, mtype, i + startx + 16, j + starty + 16); } lm++; From e1bae9e3120eab9bf02c93298840bd9c0ee5d7e2 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 22 Jan 2020 23:12:59 +0100 Subject: [PATCH 087/107] removed the 'valid' flag --- 3rdParty/Storm/Source/storm.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/3rdParty/Storm/Source/storm.h b/3rdParty/Storm/Source/storm.h index 3f3f8dca1e0..d6dc79b397f 100644 --- a/3rdParty/Storm/Source/storm.h +++ b/3rdParty/Storm/Source/storm.h @@ -55,27 +55,22 @@ typedef struct _WSIZE struct CCritSect { CRITICAL_SECTION m_critsect; - bool valid; CCritSect() { - valid = true; InitializeCriticalSection(&m_critsect); } ~CCritSect() { - valid = false; DeleteCriticalSection(&m_critsect); } void Enter() { - if(valid) EnterCriticalSection(&m_critsect); } void Leave() { - if(valid) LeaveCriticalSection(&m_critsect); } }; From c42cdceb63ec261743750a88e2462664fc6a56fc Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 27 Jan 2020 01:14:51 +0100 Subject: [PATCH 088/107] now uses dlmalloc/dlfree on the global level. This might help finding the out-of-mem issue. --- CMake/amiga/m68k-amigaos.cmake | 8 ++++-- SourceX/platform/amiga/ac68080_support.c | 33 +++++++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 5cd1a39f7de..06b5c084b47 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -2,7 +2,7 @@ set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR m68k) # CPU -set(M68K_CPU_TYPES "68000" "68010" "68020" "68040" "68060") +set(M68K_CPU_TYPES "68000" "68010" "68020" "68040" "68060" "68080") set(M68K_CPU "68000" CACHE STRING "Target CPU model") set_property(CACHE M68K_CPU PROPERTY STRINGS ${M68K_CPU_TYPES}) @@ -72,7 +72,11 @@ set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSD foreach(_wrapped memcpy memset - memcmp) + memcmp + malloc + free + realloc + calloc) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=${_wrapped}") endforeach(_wrapped) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 25b27bfc629..63026af77cf 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -100,9 +100,17 @@ size_t __stack = MINSTACK; /* ixemul, vbcc */ #define USE_DL_PREFIX #define SANITY_CHK 0 - +#define DO_WRAPPERS 1 + +#ifdef DO_WRAPPERS +#define lower_malloc __real_malloc +#define lower_free __real_free +extern void *lower_malloc(size_t); +extern void lower_free(void *); +#else #define lower_malloc malloc #define lower_free free +#endif #define HAVE_MORECORE 0 @@ -127,6 +135,10 @@ static void* MMAP(size_t len) } printf("MMAP(%d) = %p\n", len, p); #endif + if(!p) { + printf("Out of memory (%d bytes requested).\n", len+4); + dlmalloc_stats(); + } return p; } @@ -150,6 +162,25 @@ static int MUNMAP(void *p, size_t len) #include "malloc.c" +#ifdef DO_WRAPPERS +void *__wrap_malloc(size_t size) +{ + return dlmalloc(size); +} +void __wrap_free(void *ptr) +{ + dlfree(ptr); +} +void *__wrap_realloc(void *ptr, size_t size) +{ + return dlrealloc(ptr, size); +} +void *__wrap_calloc(size_t num, size_t size) +{ + return dlcalloc(num,size); +} +#endif + /*****************************************************************************/ static void stop(void) From 1f53f3daefccc980c251d6751faf46f41c1d3768 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 29 Jan 2020 23:54:14 +0100 Subject: [PATCH 089/107] mertged with upstream --- .gitignore | 3 +- 3rdParty/Storm/Source/storm.h | 64 +++-- CMake/amiga/m68k-amigaos.cmake | 6 +- CMake/gkd350h_defs.cmake | 49 ++++ CMake/mingwcc.cmake | 1 + CMake/retrofw_defs.cmake | 3 +- CMakeLists.txt | 30 +- DiabloUI/diabloui.h | 60 ++-- Packaging/OpenDingux/build-retrofw.sh | 4 - Packaging/OpenDingux/build-rg350.sh | 4 - Packaging/OpenDingux/build.sh | 74 +++-- Packaging/OpenDingux/buildroot_rs90_defconfig | 14 - .../OpenDingux/devilutionx-retrofw.man.txt | 33 ++- Packaging/OpenDingux/gkd350h.desktop | 11 + Packaging/OpenDingux/manual-gkd350h.txt | 33 +++ Packaging/OpenDingux/manual-rg350.txt | 31 +++ Packaging/OpenDingux/package-ipk.sh | 14 +- Packaging/OpenDingux/package-opk.sh | 32 +-- Packaging/OpenDingux/readme.gcw0.txt | 26 -- ...efconfig => retrofw_devilutionx_defconfig} | 0 Packaging/OpenDingux/rg350.desktop | 12 + ..._defconfig => rg350_devilutionx_defconfig} | 0 Packaging/amiga/prep.sh | 25 +- Packaging/debian/changelog | 48 +++- Packaging/debian/control | 10 +- Packaging/debian/devilutionx.install | 10 - Packaging/debian/rules | 35 ++- Packaging/fedora/devilutionx.desktop | 2 + Packaging/nix/README.txt | 13 +- Packaging/pi/README.txt | 17 +- Packaging/switch/readme-switch.md | 41 --- Packaging/switch/readme.txt | 47 ++++ Packaging/windows/README.txt | 11 +- Packaging/windows/devilutionx.rc | 1 + Packaging/windows/icon.ico | Bin 0 -> 766 bytes README.md | 133 ++++----- Source/appfat.cpp | 6 +- Source/appfat.h | 8 +- Source/automap.cpp | 30 +- Source/capture.cpp | 96 +++---- Source/control.cpp | 16 +- Source/control.h | 2 +- Source/diablo.cpp | 263 ++++++++---------- Source/diablo.h | 11 +- Source/drlg_l2.cpp | 1 - Source/drlg_l3.cpp | 1 - Source/dthread.cpp | 2 +- Source/dthread.h | 2 +- Source/effects.cpp | 6 +- Source/effects.h | 2 +- Source/encrypt.cpp | 4 +- Source/encrypt.h | 4 +- Source/engine.cpp | 2 +- Source/engine.h | 8 +- Source/help.cpp | 4 +- Source/init.cpp | 2 +- Source/init.h | 2 +- Source/inv.cpp | 12 +- Source/items.cpp | 28 +- Source/lighting.cpp | 4 +- Source/loadsave.cpp | 39 +-- Source/mainmenu.cpp | 6 +- Source/mainmenu.h | 4 +- Source/missiles.cpp | 108 +++---- Source/monstdat.cpp | 2 +- Source/monster.cpp | 30 +- Source/monster.h | 1 + Source/movie.cpp | 10 +- Source/movie.h | 2 +- Source/mpqapi.cpp | 24 +- Source/mpqapi.h | 5 +- Source/msg.cpp | 10 +- Source/msg.h | 2 +- Source/multi.cpp | 6 +- Source/multi.h | 4 +- Source/nthread.cpp | 2 +- Source/nthread.h | 2 +- Source/objects.cpp | 64 ++--- Source/palette.cpp | 2 +- Source/pfile.cpp | 43 +-- Source/pfile.h | 14 +- Source/player.cpp | 2 +- Source/plrmsg.cpp | 2 +- Source/plrmsg.h | 2 +- Source/render.cpp | 2 +- Source/scrollrt.cpp | 10 +- Source/stores.cpp | 12 +- Source/themes.cpp | 4 +- Source/trigs.cpp | 18 +- SourceS/file_util.h | 23 ++ SourceS/miniwin.h | 1 - SourceS/miniwin/com.h | 7 +- SourceS/miniwin/com_macro.h | 12 - SourceS/miniwin/misc.h | 83 ++---- SourceS/miniwin/misc_macro.h | 9 +- SourceS/miniwin/popdecl.inc | 7 - SourceS/miniwin/pushdecl.inc | 24 -- SourceS/miniwin/thread.h | 8 +- SourceS/sdl_compat.h | 10 +- SourceX/DiabloUI/credits.cpp | 1 - SourceX/DiabloUI/diabloui.cpp | 91 ++++-- SourceX/DiabloUI/diabloui.h | 1 + SourceX/DiabloUI/dialogs.cpp | 45 +-- SourceX/DiabloUI/fonts.cpp | 4 +- SourceX/DiabloUI/mainmenu.cpp | 43 +-- SourceX/DiabloUI/progress.cpp | 19 +- SourceX/DiabloUI/selgame.cpp | 57 +++- SourceX/DiabloUI/selhero.cpp | 77 +++-- SourceX/DiabloUI/selok.cpp | 86 ++++++ SourceX/DiabloUI/selok.h | 11 + SourceX/DiabloUI/selyesno.cpp | 31 +-- SourceX/DiabloUI/selyesno.h | 2 +- SourceX/controls/README.md | 2 +- SourceX/controls/controller_buttons.h | 8 + SourceX/controls/controller_motion.cpp | 28 +- SourceX/controls/devices/kbcontroller.cpp | 75 +---- SourceX/controls/game_controls.cpp | 206 +++++++++++--- SourceX/controls/game_controls.h | 5 + SourceX/controls/modifier_hints.cpp | 137 +++++++++ SourceX/controls/modifier_hints.h | 7 + SourceX/controls/plrctrls.cpp | 102 ++++--- SourceX/controls/plrctrls.h | 3 + SourceX/dvlnet/abstract_net.h | 5 + SourceX/dvlnet/frame_queue.h | 5 + SourceX/dvlnet/packet.h | 15 +- SourceX/dvlnet/tcp_client.cpp | 12 +- SourceX/dvlnet/tcp_server.cpp | 1 + SourceX/dvlnet/tcp_server.h | 5 + SourceX/dvlnet/udp_p2p.cpp | 15 +- SourceX/dx.cpp | 11 +- SourceX/main.cpp | 17 +- SourceX/miniwin/ddraw.h | 1 - SourceX/miniwin/dsound.cpp | 9 +- SourceX/miniwin/dsound.h | 2 +- SourceX/miniwin/misc.cpp | 90 +++--- SourceX/miniwin/misc_io.cpp | 40 +-- SourceX/miniwin/misc_msg.cpp | 78 +++++- SourceX/miniwin/thread.cpp | 6 - SourceX/sound.cpp | 12 +- SourceX/storm/storm.cpp | 22 +- defs.h | 9 +- structs.h | 2 +- types.h | 20 -- 143 files changed, 1971 insertions(+), 1476 deletions(-) create mode 100644 CMake/gkd350h_defs.cmake delete mode 100755 Packaging/OpenDingux/build-retrofw.sh delete mode 100755 Packaging/OpenDingux/build-rg350.sh delete mode 100644 Packaging/OpenDingux/buildroot_rs90_defconfig create mode 100644 Packaging/OpenDingux/gkd350h.desktop create mode 100644 Packaging/OpenDingux/manual-gkd350h.txt create mode 100644 Packaging/OpenDingux/manual-rg350.txt delete mode 100644 Packaging/OpenDingux/readme.gcw0.txt rename Packaging/OpenDingux/{buildroot_retrofw_defconfig => retrofw_devilutionx_defconfig} (100%) create mode 100644 Packaging/OpenDingux/rg350.desktop rename Packaging/OpenDingux/{buildroot_rg350_defconfig => rg350_devilutionx_defconfig} (100%) delete mode 100644 Packaging/debian/devilutionx.install delete mode 100644 Packaging/switch/readme-switch.md create mode 100644 Packaging/switch/readme.txt create mode 100644 Packaging/windows/devilutionx.rc create mode 100644 Packaging/windows/icon.ico create mode 100644 SourceS/file_util.h delete mode 100644 SourceS/miniwin/com_macro.h delete mode 100644 SourceS/miniwin/popdecl.inc delete mode 100644 SourceS/miniwin/pushdecl.inc create mode 100644 SourceX/DiabloUI/selok.cpp create mode 100644 SourceX/DiabloUI/selok.h create mode 100644 SourceX/controls/modifier_hints.cpp create mode 100644 SourceX/controls/modifier_hints.h diff --git a/.gitignore b/.gitignore index fedca48b275..a0fb0136bd8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,7 @@ devilution-comparer comparer-config.toml #ignore cmake cache -/build/ -/build32/ +/build-*/ .vscode/tasks.json # ELF object file. diff --git a/3rdParty/Storm/Source/storm.h b/3rdParty/Storm/Source/storm.h index d6dc79b397f..ed1c5b5221c 100644 --- a/3rdParty/Storm/Source/storm.h +++ b/3rdParty/Storm/Source/storm.h @@ -3,15 +3,17 @@ #ifndef __BLIZZARD_STORM_HEADER #define __BLIZZARD_STORM_HEADER -#include "miniwin/pushdecl.inc" #include +#include namespace dvl { +extern std::string basePath; + // Note to self: Linker error => forgot a return value in cpp // Storm API definition #ifndef STORMAPI -#define STORMAPI __stdcall +#define STORMAPI #endif #ifndef __STORM_SMAX @@ -456,8 +458,6 @@ SNetSetGameMode( #define SNMakeGamePublic() SNetSetGameMode( (DWORD mode, SNetGetGameInfo(GAMEINFO_MODEFLAGS, &mode, 4), mode), true) -BOOL STORMAPI SNetEnumGamesEx(int a1, int a2, int (__fastcall *callback)(DWORD, DWORD, DWORD), int *hintnextcall); - BOOL STORMAPI SNetDisconnectAll(DWORD flags); BOOL STORMAPI SNetCreateLadderGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString, DWORD dwGameType, DWORD dwGameLadderType, DWORD dwGameModeFlags, char *GameTemplateData, int GameTemplateSize, int playerCount, char *creatorName, char *a11, int *playerID); @@ -1181,8 +1181,7 @@ void STORMAPI SRgn529i(int handle, int a2, int a3); * * Returns TRUE if the user chose to continue execution, FALSE otherwise. */ -BOOL __cdecl -SErrDisplayErrorFmt( +BOOL SErrDisplayErrorFmt( DWORD dwErrMsg, const char *logfilename, int logline, @@ -1235,7 +1234,7 @@ char *STORMAPI SStrChrR(const char *string, char c); * * Returns the number of characters written. */ -unsigned int __cdecl +unsigned int SStrVPrintf( char *dest, unsigned int size, @@ -1252,37 +1251,36 @@ int STORMAPI SBigPowMod(void *buffer1, void *buffer2, int a3, int a4); int STORMAPI SBigToBinaryBuffer(void *buffer, int length, int a3, int a4); -void __stdcall SDrawMessageBox(char *,char *,int); -void __cdecl SDrawDestroy(void); -BOOLEAN __cdecl StormDestroy(void); -BOOL __stdcall SFileSetBasePath(char *); -void __cdecl SDrawRealizePalette(void); -BOOL __cdecl SVidPlayContinue(void); -BOOL __stdcall SNetGetOwnerTurnsWaiting(DWORD *); -BOOL __stdcall SNetUnregisterEventHandler(int,SEVTHANDLER); -BOOL __stdcall SNetRegisterEventHandler(int,SEVTHANDLER); -BOOLEAN __stdcall SNetSetBasePlayer(int); -int __stdcall SNetInitializeProvider(unsigned long,struct _SNETPROGRAMDATA *,struct _SNETPLAYERDATA *,struct _SNETUIDATA *,struct _SNETVERSIONDATA *); -int __stdcall SNetGetProviderCaps(struct _SNETCAPS *); -int __stdcall SFileSetFilePointer(HANDLE,int,HANDLE,int); -void __stdcall SDrawClearSurface(int a1); -BOOL __stdcall SDlgSetBitmapI(HWND hWnd, int a2, char *src, int mask1, int flags, void *pBuff, int a7, int width, int height, int mask2); -void __stdcall SDlgBeginPaint(HWND hWnd, char *a2); -void __stdcall SDlgEndPaint(HWND hWnd, char *a2); -void __stdcall SDlgSetSystemCursor(BYTE *a1, BYTE *a2, int *a3, int a4); -void __stdcall SDlgSetCursor(HWND hWnd, HCURSOR a2, int a3, int *a4); -BOOL __stdcall SDlgSetTimer(int a1, int a2, int a3, void (__stdcall *a4)(int, int, int, int)); -BOOL __stdcall SDlgKillTimer(int a1, int a2); -BOOL __stdcall SDlgDrawBitmap(HWND hWnd, int a2, int a3, int a4, int a5, int a6, int a7); -BOOL __stdcall SDlgDialogBoxParam(HINSTANCE hInst, char *szDialog, int hWnd, WNDPROC func, int selhero_is_good); -BOOL __stdcall SGdiTextOut(void *pBuffer, int x, int y, int mask, char *str, int len); -BOOL __stdcall SFileEnableDirectAccess(BOOL enable); +void SDrawMessageBox(char *, char *, int); +void SDrawDestroy(void); +BOOLEAN StormDestroy(void); +BOOL SFileSetBasePath(char *); +void SDrawRealizePalette(void); +BOOL SVidPlayContinue(void); +BOOL SNetGetOwnerTurnsWaiting(DWORD *); +BOOL SNetUnregisterEventHandler(int, SEVTHANDLER); +BOOL SNetRegisterEventHandler(int, SEVTHANDLER); +BOOLEAN SNetSetBasePlayer(int); +int SNetInitializeProvider(unsigned long, struct _SNETPROGRAMDATA *, struct _SNETPLAYERDATA *, struct _SNETUIDATA *, struct _SNETVERSIONDATA *); +int SNetGetProviderCaps(struct _SNETCAPS *); +int SFileSetFilePointer(HANDLE, int, HANDLE, int); +void SDrawClearSurface(int a1); +BOOL SDlgSetBitmapI(HWND hWnd, int a2, char *src, int mask1, int flags, void *pBuff, int a7, int width, int height, int mask2); +void SDlgBeginPaint(HWND hWnd, char *a2); +void SDlgEndPaint(HWND hWnd, char *a2); +void SDlgSetSystemCursor(BYTE *a1, BYTE *a2, int *a3, int a4); +void SDlgSetCursor(HWND hWnd, HCURSOR a2, int a3, int *a4); +BOOL SDlgSetTimer(int a1, int a2, int a3, void (*a4)(int, int, int, int)); +BOOL SDlgKillTimer(int a1, int a2); +BOOL SDlgDrawBitmap(HWND hWnd, int a2, int a3, int a4, int a5, int a6, int a7); +BOOL SDlgDialogBoxParam(HINSTANCE hInst, char *szDialog, int hWnd, WNDPROC func, int selhero_is_good); +BOOL SGdiTextOut(void *pBuffer, int x, int y, int mask, char *str, int len); +BOOL SFileEnableDirectAccess(BOOL enable); #if defined(__GNUC__) || defined(__cplusplus) } #endif } -#include "miniwin/popdecl.inc" #endif diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 06b5c084b47..b0338e79fcd 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -3,7 +3,7 @@ set(CMAKE_SYSTEM_PROCESSOR m68k) # CPU set(M68K_CPU_TYPES "68000" "68010" "68020" "68040" "68060" "68080") -set(M68K_CPU "68000" CACHE STRING "Target CPU model") +set(M68K_CPU "68080" CACHE STRING "Target CPU model") set_property(CACHE M68K_CPU PROPERTY STRINGS ${M68K_CPU_TYPES}) # FPU @@ -57,7 +57,7 @@ if(PROFILE) else() set(FLAGS_COMMON "-fomit-frame-pointer") endif() -set(FLAGS_COMMON "${FLAGS_COMMON} -m${M68K_CPU} -m${M68K_FPU}-float -Dfbbb=abcdefghi -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -g -noixemul") +set(FLAGS_COMMON "${FLAGS_COMMON} -m${M68K_CPU} -m${M68K_FPU}-float -Ofast -ffast-math -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt -fregmove -ffast-math -fsingle-precision-constant -fmodulo-sched -fmodulo-sched-allow-regmoves -flive-range-shrinkage -fsched-pressure -fsched-spec-load -fsched-verbose=2 -w -fpermissive -g -noixemul") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_COMMON}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_COMMON} -D__BIG_ENDIAN__ -D__AMIGA__ -fpermissive") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -quiet -x -m${M68K_CPU} -nowarn=24 -Fhunk -I${M68K_TOOLCHAIN_PATH}/m68k-amigaos/sys-include ") @@ -66,7 +66,7 @@ set(BUILD_SHARED_LIBS OFF) unset(FLAGS_COMMON) # Linker configuration -set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lft2 -lz -noixemul") +set(CMAKE_EXE_LINKER_FLAGS "-lpthread -lSDL_mixer -Wl,--whole-archive -lSDL -lSDL_ttf -lpng16 -Wl,--no-whole-archive -lfreetype -lzlib -noixemul") # wrapper - replace gcc functions by our own foreach(_wrapped diff --git a/CMake/gkd350h_defs.cmake b/CMake/gkd350h_defs.cmake new file mode 100644 index 00000000000..b1780ad2874 --- /dev/null +++ b/CMake/gkd350h_defs.cmake @@ -0,0 +1,49 @@ +set(NONET ON) +set(USE_SDL1 ON) + +# GKD350h IPU scaler is broken at the moment +set(SDL1_VIDEO_MODE_WIDTH 320) +set(SDL1_VIDEO_MODE_HEIGHT 240) + +set(SDL1_VIDEO_MODE_BPP 16) +set(PREFILL_PLAYER_NAME ON) + +# In joystick mode, GKD350h reports D-Pad as left stick, +# so we have to use keyboard mode instead. + +set(HAS_KBCTRL 1) +set(KBCTRL_BUTTON_DPAD_LEFT SDLK_LEFT) +set(KBCTRL_BUTTON_DPAD_RIGHT SDLK_RIGHT) +set(KBCTRL_BUTTON_DPAD_UP SDLK_UP) +set(KBCTRL_BUTTON_DPAD_DOWN SDLK_DOWN) +set(KBCTRL_BUTTON_B SDLK_LCTRL) +set(KBCTRL_BUTTON_A SDLK_LALT) +set(KBCTRL_BUTTON_Y SDLK_SPACE) +set(KBCTRL_BUTTON_X SDLK_LSHIFT) +set(KBCTRL_BUTTON_RIGHTSHOULDER SDLK_BACKSPACE) +set(KBCTRL_BUTTON_LEFTSHOULDER SDLK_TAB) + +# We swap Select and Start because Start + D-Pad is overtaken by the kernel. +set(KBCTRL_BUTTON_START SDLK_ESCAPE) # Select +set(KBCTRL_BUTTON_BACK SDLK_RETURN) # Start + +set(JOY_AXIS_LEFTX 0) +set(JOY_AXIS_LEFTY 1) + +# Unused joystick mappings (kept here for future reference). +set(JOY_HAT_DPAD_UP_HAT 0) +set(JOY_HAT_DPAD_UP 1) +set(JOY_HAT_DPAD_DOWN_HAT 0) +set(JOY_HAT_DPAD_DOWN 4) +set(JOY_HAT_DPAD_LEFT_HAT 0) +set(JOY_HAT_DPAD_LEFT 8) +set(JOY_HAT_DPAD_RIGHT_HAT 0) +set(JOY_HAT_DPAD_RIGHT 2) +set(JOY_BUTTON_A 0) +set(JOY_BUTTON_B 1) +set(JOY_BUTTON_Y 2) +set(JOY_BUTTON_X 3) +set(JOY_BUTTON_RIGHTSHOULDER 7) +set(JOY_BUTTON_LEFTSHOULDER 6) +set(JOY_BUTTON_START 5) +set(JOY_BUTTON_BACK 4) diff --git a/CMake/mingwcc.cmake b/CMake/mingwcc.cmake index e3349b47370..24e2df5250c 100644 --- a/CMake/mingwcc.cmake +++ b/CMake/mingwcc.cmake @@ -9,6 +9,7 @@ list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "${CROSS_PREFIX}/i686-w64-min SET(CMAKE_C_COMPILER "i686-w64-mingw32-gcc") SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-g++") +set(CMAKE_RC_COMPILER "i686-w64-mingw32-windres") SET(CMAKE_FIND_ROOT_PATH "${CROSS_PREFIX}/i686-w64-mingw32" "${CROSS_PREFIX}/i686-w64-mingw32/i686-w64-mingw32") diff --git a/CMake/retrofw_defs.cmake b/CMake/retrofw_defs.cmake index 08e0d422289..3ffa2d1177b 100644 --- a/CMake/retrofw_defs.cmake +++ b/CMake/retrofw_defs.cmake @@ -2,6 +2,7 @@ set(NONET ON) set(USE_SDL1 ON) set(PREFILL_PLAYER_NAME ON) set(HAS_KBCTRL 1) +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(KBCTRL_BUTTON_DPAD_LEFT SDLK_LEFT) set(KBCTRL_BUTTON_DPAD_RIGHT SDLK_RIGHT) set(KBCTRL_BUTTON_DPAD_UP SDLK_UP) @@ -14,5 +15,5 @@ set(KBCTRL_BUTTON_RIGHTSHOULDER SDLK_BACKSPACE) set(KBCTRL_BUTTON_LEFTSHOULDER SDLK_TAB) set(KBCTRL_BUTTON_START SDLK_RETURN) set(KBCTRL_BUTTON_LEFTSTICK SDLK_END) # Suspend -set(KBCTRL_MODIFIER_KEY SDLK_ESCAPE) # Select +set(KBCTRL_BUTTON_BACK SDLK_ESCAPE) # Select set(KBCTRL_IGNORE_1 SDLK_3) # Backlight diff --git a/CMakeLists.txt b/CMakeLists.txt index ee0a2325327..300f0b07c9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,16 @@ if(NIGHTLY_BUILD) set(FASTER OFF) endif() +include(CMake/git.cmake) +get_git_tag(GIT_TAG) +if(NOT CMAKE_BUILD_TYPE MATCHES "Release") + get_git_commit_hash(GIT_COMMIT_HASH) +endif() + +project(DevilutionX + VERSION ${GIT_TAG} + LANGUAGES C CXX) + if(LTO) # Use LTO on compilers where it is supported. include(CheckIPOSupported) @@ -77,6 +87,10 @@ if(RG350) include(rg350_defs) endif() +if (GKD350H) + include(gkd350h_defs) +endif() + if(RETROFW) include(retrofw_defs) endif() @@ -251,6 +265,7 @@ set(devilutionx_SRCS SourceX/controls/controller_motion.cpp SourceX/controls/game_controls.cpp SourceX/controls/menu_controls.cpp + SourceX/controls/modifier_hints.cpp SourceX/controls/plrctrls.cpp SourceX/controls/touch.cpp SourceX/miniwin/ddraw.cpp @@ -286,13 +301,15 @@ set(devilutionx_SRCS SourceX/DiabloUI/selgame.cpp SourceX/DiabloUI/selhero.cpp SourceX/DiabloUI/selyesno.cpp + SourceX/DiabloUI/selok.cpp SourceX/DiabloUI/text_draw.cpp SourceX/DiabloUI/text.cpp SourceX/DiabloUI/title.cpp SourceX/DiabloUI/ttf_render_wrapped.cpp SourceX/main.cpp - ./Packaging/macOS/AppIcon.icns - ./Packaging/resources/CharisSILB.ttf) + Packaging/macOS/AppIcon.icns + Packaging/resources/CharisSILB.ttf + Packaging/windows/devilutionx.rc) if(NOT NONET) list(APPEND devilutionx_SRCS @@ -318,7 +335,7 @@ if(AMIGA) SourceX/platform/amiga/ac68080_support.c) endif() -add_executable(${BIN_TARGET} MACOSX_BUNDLE ${devilutionx_SRCS}) +add_executable(${BIN_TARGET} WIN32 MACOSX_BUNDLE ${devilutionx_SRCS}) configure_file(SourceS/config.h.in config.h @ONLY) target_include_directories(devilution PUBLIC Source SourceS ${CMAKE_CURRENT_BINARY_DIR}) @@ -364,6 +381,8 @@ endforeach(def_name) foreach( def_name TTF_FONT_PATH + SDL1_VIDEO_MODE_WIDTH + SDL1_VIDEO_MODE_HEIGHT SDL1_VIDEO_MODE_BPP SDL1_VIDEO_MODE_FLAGS HAS_KBCTRL @@ -381,7 +400,6 @@ foreach( KBCTRL_BUTTON_LEFTSHOULDER KBCTRL_BUTTON_START KBCTRL_BUTTON_BACK - KBCTRL_MODIFIER_KEY KBCTRL_IGNORE_1 JOY_AXIS_LEFTX JOY_AXIS_LEFTY @@ -552,7 +570,3 @@ if(SWITCH) include(nx-utils) build_switch_binaries(${BIN_TARGET}) endif() - -if(RETROFW OR RG350) - set_target_properties(${BIN_TARGET} PROPERTIES OUTPUT_NAME "devilutionx.dge") -endif() diff --git a/DiabloUI/diabloui.h b/DiabloUI/diabloui.h index d2a385e9d32..efae492f5f8 100644 --- a/DiabloUI/diabloui.h +++ b/DiabloUI/diabloui.h @@ -2,7 +2,6 @@ #ifndef __DIABLOUI_H__ #define __DIABLOUI_H__ -#include "miniwin/pushdecl.inc" namespace dvl { //#if defined(__GNUC__) || defined(__cplusplus) @@ -28,42 +27,41 @@ struct ProfFntStruct { int field_8; }; -void __stdcall UiDestroy(); +void UiDestroy(); void UiTitleDialog(); -void __stdcall UiSetSpawned(BOOL bSpawned); -void __stdcall UiInitialize(); -BOOL __stdcall UiCopyProtError(int *pdwResult); -void __stdcall UiAppActivate(BOOL bActive); -BOOL __fastcall UiValidPlayerName(char *name); /* check __stdcall */ -BOOL __stdcall UiSelHeroMultDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, BOOL *hero_is_created, char *name); -BOOL __stdcall UiSelHeroSingDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)), BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, char *name, int *difficulty); -BOOL __stdcall UiCreditsDialog(int a1); -BOOL __stdcall UiMainMenuDialog(char *name, int *pdwResult, void(__stdcall *fnSound)(char *file), int attractTimeOut); -BOOL __stdcall UiProgressDialog(HWND window, char *msg, int enable, int(*fnfunc)(), int rate); -int __stdcall UiProfileGetString(); -void __cdecl UiProfileCallback(); -void __cdecl UiProfileDraw(); -BOOL __stdcall UiCategoryCallback(int a1, int a2, int a3, int a4, int a5, DWORD *a6, DWORD *a7); -BOOL __stdcall UiGetDataCallback(int game_type, int data_code, void *a3, int a4, int a5); -BOOL __stdcall UiAuthCallback(int a1, char *a2, char *a3, char a4, char *a5, LPSTR lpBuffer, int cchBufferMax); -BOOL __stdcall UiSoundCallback(int a1, int type, int a3); -void __stdcall UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType); -BOOL __stdcall UiDrawDescCallback(int game_type, COLORREF color, LPCSTR lpString, char *a4, int a5, UINT align, time_t a7, HDC *a8); -BOOL __stdcall UiCreateGameCallback(int a1, int a2, int a3, int a4, int a5, int a6); -BOOL __stdcall UiArtCallback(int game_type, unsigned int art_code, PALETTEENTRY *pPalette, BYTE *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp); -int __stdcall UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *a6); -int __stdcall UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *type); -BOOL __stdcall UiCreatePlayerDescription(_uiheroinfo *info, DWORD mode, char *desc); -void __stdcall UiSetupPlayerInfo(char *infostr, _uiheroinfo *pInfo, DWORD type); -void __stdcall UiCreateGameCriteria(_uiheroinfo *pInfo, char *str); -BOOL __stdcall UiGetDefaultStats(int pclass, _uidefaultstats *pStats); -BOOL __stdcall UiBetaDisclaimer(int a1); +void UiSetSpawned(BOOL bSpawned); +void UiInitialize(); +BOOL UiCopyProtError(int *pdwResult); +void UiAppActivate(BOOL bActive); +BOOL UiValidPlayerName(char *name); /* check */ +BOOL UiSelHeroMultDialog(BOOL (*fninfo)(BOOL (*fninfofunc)(_uiheroinfo *)), BOOL (*fncreate)(_uiheroinfo *), BOOL (*fnremove)(_uiheroinfo *), BOOL (*fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, BOOL *hero_is_created, char *name); +BOOL UiSelHeroSingDialog(BOOL (*fninfo)(BOOL (*fninfofunc)(_uiheroinfo *)), BOOL (*fncreate)(_uiheroinfo *), BOOL (*fnremove)(_uiheroinfo *), BOOL (*fnstats)(unsigned int, _uidefaultstats *), int *dlgresult, char *name, int *difficulty); +BOOL UiCreditsDialog(int a1); +BOOL UiMainMenuDialog(char *name, int *pdwResult, void (*fnSound)(char *file), int attractTimeOut); +BOOL UiProgressDialog(HWND window, char *msg, int enable, int (*fnfunc)(), int rate); +int UiProfileGetString(); +void UiProfileCallback(); +void UiProfileDraw(); +BOOL UiCategoryCallback(int a1, int a2, int a3, int a4, int a5, DWORD *a6, DWORD *a7); +BOOL UiGetDataCallback(int game_type, int data_code, void *a3, int a4, int a5); +BOOL UiAuthCallback(int a1, char *a2, char *a3, char a4, char *a5, LPSTR lpBuffer, int cchBufferMax); +BOOL UiSoundCallback(int a1, int type, int a3); +void UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType); +BOOL UiDrawDescCallback(int game_type, COLORREF color, LPCSTR lpString, char *a4, int a5, UINT align, time_t a7, HDC *a8); +BOOL UiCreateGameCallback(int a1, int a2, int a3, int a4, int a5, int a6); +BOOL UiArtCallback(int game_type, unsigned int art_code, PALETTEENTRY *pPalette, BYTE *pBuffer, DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp); +int UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *a6); +int UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info, _SNETVERSIONDATA *file_info, int *type); +BOOL UiCreatePlayerDescription(_uiheroinfo *info, DWORD mode, char *desc); +void UiSetupPlayerInfo(char *infostr, _uiheroinfo *pInfo, DWORD type); +void UiCreateGameCriteria(_uiheroinfo *pInfo, char *str); +BOOL UiGetDefaultStats(int pclass, _uidefaultstats *pStats); +BOOL UiBetaDisclaimer(int a1); //#if defined(__GNUC__) || defined(__cplusplus) //} //#endif } -#include "miniwin/popdecl.inc" #endif /* __DIABLOUI_H__ */ diff --git a/Packaging/OpenDingux/build-retrofw.sh b/Packaging/OpenDingux/build-retrofw.sh deleted file mode 100755 index 7036e8a476d..00000000000 --- a/Packaging/OpenDingux/build-retrofw.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -declare -r DIR="$(dirname "${BASH_SOURCE[0]}")" -"${DIR}/build.sh" retrofw diff --git a/Packaging/OpenDingux/build-rg350.sh b/Packaging/OpenDingux/build-rg350.sh deleted file mode 100755 index fa6c99751ba..00000000000 --- a/Packaging/OpenDingux/build-rg350.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -declare -r DIR="$(dirname "${BASH_SOURCE[0]}")" -"${DIR}/build.sh" rg350 diff --git a/Packaging/OpenDingux/build.sh b/Packaging/OpenDingux/build.sh index ae7bd4262d7..c32ebfd138a 100755 --- a/Packaging/OpenDingux/build.sh +++ b/Packaging/OpenDingux/build.sh @@ -4,7 +4,7 @@ set -euo pipefail usage() { echo "Usage: build.sh [target]" - echo " target: target architecture. Either rg350 or retrofw" + echo " target: target architecture: rg350, gkd350h, or retrofw" } if [[ $# -ne 1 ]]; then @@ -13,27 +13,40 @@ if [[ $# -ne 1 ]]; then exit 1 fi -if [[ "$1" != "rg350" ]] && [[ "$1" != "retrofw" ]]; then +if [[ $1 != rg350 ]] && [[ $1 != retrofw ]] && [[ $1 != gkd350h ]]; then echo "Error: invalid target" usage exit 1 fi +cd "$(dirname "${BASH_SOURCE[0]}")/../.." + declare -r TARGET="${1}" -echo "Building for target: ${TARGET}" +declare -r BUILD_DIR="build-${TARGET}" -declare -r DIR="$(dirname "${BASH_SOURCE[0]}")" -cd "$DIR" -declare -r ABSDIR="$(pwd)" +declare -rA BUILDROOT_REPOS=( + [retrofw]=https://github.com/retrofw/buildroot.git + [rg350]=https://github.com/tonyjih/RG350_buildroot.git +) -if [[ "$TARGET" == "retrofw" ]]; then - declare -r BUILDROOT_VER=buildroot-2018.02.9 - declare -r BUILDROOT_ARCHIVE="$HOME/${BUILDROOT_VER}.tar.gz" -fi +declare BUILDROOT_DEFCONFIG +declare BUILDROOT_REPO -BUILDROOT="${BUILDROOT:-$HOME/buildroot-${TARGET}-devilutionx}" +set_buildroot_vars() { + BUILDROOT_DEFCONFIG="$1_devilutionx_defconfig" + BUILDROOT_REPO="${BUILDROOT_REPOS[$1]}" + BUILDROOT="${BUILDROOT:-$HOME/buildroot-$1-devilutionx}" +} + +# Use the rg350 buildroot for gkd350h because gkd350h buildroot is not open-source. +if [[ $TARGET == gkd350h ]]; then + set_buildroot_vars rg350 +else + set_buildroot_vars "$TARGET" +fi main() { + >&2 echo "Building for target ${TARGET} in ${BUILD_DIR}" set -x prepare_buildroot make_buildroot @@ -45,41 +58,22 @@ prepare_buildroot() { if [[ -d $BUILDROOT ]]; then return fi - if [[ "$TARGET" == "rg350" ]]; then - git clone --depth=1 https://github.com/tonyjih/RG350_buildroot.git "$BUILDROOT" - else # retrofw - if [[ ! -f $BUILDROOT_ARCHIVE ]]; then - \curl https://buildroot.org/downloads/${BUILDROOT_VER}.tar.gz -o "$BUILDROOT_ARCHIVE" - fi - tar xf "$BUILDROOT_ARCHIVE" -C "$(dirname "$BUILDROOT_ARCHIVE")" - mv "${BUILDROOT_ARCHIVE%.tar.gz}" "$BUILDROOT" - fi + git clone --depth=1 "${BUILDROOT_REPOS[$TARGET]}" "$BUILDROOT" } make_buildroot() { - cp buildroot_${TARGET}_defconfig "$BUILDROOT/configs/${TARGET}_devilutionx_defconfig" + cp "Packaging/OpenDingux/$BUILDROOT_DEFCONFIG" "$BUILDROOT/configs/" cd "$BUILDROOT" - make ${TARGET}_devilutionx_defconfig - if [[ "$TARGET" == "rg350" ]]; then - BR2_JLEVEL=0 make - else - BR2_JLEVEL=0 make toolchain libzip sdl sdl_mixer sdl_ttf - fi + make "$BUILDROOT_DEFCONFIG" + BR2_JLEVEL=0 make toolchain libzip sdl sdl_mixer sdl_ttf cd - } build() { - mkdir -p ../../build - cd ../../build + mkdir -p "$BUILD_DIR" + cd "$BUILD_DIR" rm -f CMakeCache.txt - - local -a defs=(-DBINARY_RELEASE=ON) - if [[ "$TARGET" == "rg350" ]]; then - defs+=(-DRG350=ON) - else # retrofw - defs+=(-DRETROFW=ON) - fi - cmake .. ${defs[@]} \ + cmake .. -DBINARY_RELEASE=ON "-D${TARGET^^}=ON" \ -DCMAKE_TOOLCHAIN_FILE="$BUILDROOT/output/host/usr/share/buildroot/toolchainfile.cmake" make -j $(getconf _NPROCESSORS_ONLN) cd - @@ -87,9 +81,11 @@ build() { package() { if [[ "$TARGET" == "retrofw" ]]; then - ./package-ipk.sh ../../build/devilutionx-retrofw.ipk + Packaging/OpenDingux/package-ipk.sh "${PWD}/${BUILD_DIR}/devilutionx-${TARGET}.ipk" else - ./package-opk.sh ../../build/devilutionx-${TARGET}.opk + Packaging/OpenDingux/package-opk.sh "${PWD}/${BUILD_DIR}/devilutionx-${TARGET}.opk" \ + "${PWD}/Packaging/OpenDingux/${TARGET}.desktop" \ + "${PWD}/Packaging/OpenDingux/manual-${TARGET}.txt" fi } diff --git a/Packaging/OpenDingux/buildroot_rs90_defconfig b/Packaging/OpenDingux/buildroot_rs90_defconfig deleted file mode 100644 index b978eccfbd1..00000000000 --- a/Packaging/OpenDingux/buildroot_rs90_defconfig +++ /dev/null @@ -1,14 +0,0 @@ -BR2_mipsel=y -# BR2_MIPS_SOFT_FLOAT is not set -BR2_OPTIMIZE_2=y -BR2_TOOLCHAIN_BUILDROOT_MUSL=y -BR2_KERNEL_HEADERS_4_20=y -BR2_BINUTILS_VERSION_2_31_X=y -BR2_GCC_VERSION_8_X=y -BR2_TOOLCHAIN_BUILDROOT_CXX=y -BR2_GCC_ENABLE_LTO=y -BR2_PACKAGE_SDL=y -BR2_PACKAGE_SDL_MIXER=y -BR2_PACKAGE_SDL_TTF=y -BR2_PACKAGE_LIBZIP=y -BR2_PACKAGE_LIBSODIUM=y diff --git a/Packaging/OpenDingux/devilutionx-retrofw.man.txt b/Packaging/OpenDingux/devilutionx-retrofw.man.txt index d930cd5d18a..8750492085a 100644 --- a/Packaging/OpenDingux/devilutionx-retrofw.man.txt +++ b/Packaging/OpenDingux/devilutionx-retrofw.man.txt @@ -1,4 +1,4 @@ -Copy diabdat.mpq from your CD, or GoG install folder to: +Copy diabdat.mpq from your CD (or GoG install folder) to: /home/retrofw/.local/share/diasurgical/diabdat.mpq Game saves and diablo.ini are located at: @@ -6,16 +6,21 @@ Game saves and diablo.ini are located at: Controls: - D-pad: move hero -- A: attack nearby enemies, talk to towns people and merchants, pickup & drop items in inventory, OK while in main menu -- B: Select spell, cancel while in main menu -- X: pickup gold, potions & equipment from ground, open chests and doors that are nearby, use item when in inventory (useful to read books etc.) -- Y: cast spell, go to previous screen when talking to people and in shops, delete character while in main menu -- R1: Drink health potion -- L1: Drink mana potion -- Select + R1: inventory -- Select + R2: character -- Select + D-pad: Move map/cursor -- Select + A: Left click -- Select + Y: Quest log -- Suspend: Map -- Start: game Menu, skip intro +- A: attack nearby enemies, talk to townspeople and merchants, pickup/place items in the inventory, OK while in main menu +- B: select spell, back while in menus +- X: pickup items, open nearby chests and doors, use item in the inventory +- Y: cast spell, delete character while in main menu +- R1: use mana potion from belt +- L1: use health item from belt +- Start + Up: game menu +- Start + Left: character info +- Start + Right: inventory +- Start + Down: map +- Start + Y: Quest log +- Start + B: Spell book +- Select + A/B/X/Y: hot spell +- Select + D-pad: move map/cursor +- Select + L1: left mouse click +- Select + R1: right mouse click +- Start + Select: game menu +- Suspend: map diff --git a/Packaging/OpenDingux/gkd350h.desktop b/Packaging/OpenDingux/gkd350h.desktop new file mode 100644 index 00000000000..1fa04dff65c --- /dev/null +++ b/Packaging/OpenDingux/gkd350h.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=DevilutionX +Comment=A port of DevilutionX for GKD350h. +Exec=devilutionx +Terminal=false +Type=Application +StartupNotify=true +Icon=Diablo_32 +Categories=games; +X-OD-Manual=readme.gcw0.txt +X-OD-NeedsDownscaling=true diff --git a/Packaging/OpenDingux/manual-gkd350h.txt b/Packaging/OpenDingux/manual-gkd350h.txt new file mode 100644 index 00000000000..742b1e644ae --- /dev/null +++ b/Packaging/OpenDingux/manual-gkd350h.txt @@ -0,0 +1,33 @@ +Copy diabdat.mpq from your CD (or GoG install folder) to: +/usr/local/home/.local/share/diasurgical/devilution/diabdat.mpq + +diabdat.mpq filename must be lowercase. + +Game saves and diablo.ini are located at: +/usr/local/home/.local/share/diasurgical/devilution/ + +Controls: + +- Joystick / D-Pad: move hero +- Right analog: simulate mouse +- **○** circle: attack nearby enemies, talk to townspeople and merchants, pickup/place items in the inventory, OK while in main menu +- **×** cross: select spell, back while in menus +- **△** triangle: pickup items, open nearby chests and doors, use item in the inventory +- **□** square: cast spell, delete character while in main menu +- L: use health item from belt +- R: use mana potion from belt +- Select + ↑ up: game menu +- Select + ↠left: character info +- Select + → right: inventory +- Select + ↓ down: map +- Select + **□** square: Quest log +- Select + **×** cross: Spell book +- Start + **△○×□**: Quick spell hotkeys + +Known issues/quirks: + +* Start and Select are swapped in this version because Start + D-Pad controls backlight on the GKD350h. +* There is nothing to map mouse emulation to in this version because of this but it isn't necessary to play the game. Unfortunately, this also means that you can't move the automap. +* This version looks uglier than on RG350 because it uses software scaling beacuse the IPU on the GKD350h doesn't work. + +Source: https://github.com/diasurgical/devilutionX/ diff --git a/Packaging/OpenDingux/manual-rg350.txt b/Packaging/OpenDingux/manual-rg350.txt new file mode 100644 index 00000000000..336be84baed --- /dev/null +++ b/Packaging/OpenDingux/manual-rg350.txt @@ -0,0 +1,31 @@ +Copy diabdat.mpq from your CD (or GoG install folder) to: +/media/home/.local/share/diasurgical/devilution/diabdat.mpq + +diabdat.mpq filename must be lowercase. + +Game saves and diablo.ini are located at: +/media/home/.local/share/diasurgical/devilution/ + +Controls: + +- Left analog or D-Pad: move hero +- A: attack nearby enemies, talk to townspeople and merchants, pickup/place items in the inventory, OK while in main menu +- B: select spell, back while in menus +- X: pickup items, open nearby chests and doors, use item in the inventory +- Y: cast spell, delete character while in main menu +- L1: use health item from belt +- R1: use mana potion from belt +- L2 or Start + Left: character sheet +- R2 or Start + Right: inventory +- Left analog click or Start + Down: toggle automap +- Start + Up or Start + Select: game menu +- Start + Left: character info +- Start + Right: inventory +- Select + A/B/X/Y: Spell hotkeys +- Right analog: move automap or simulate mouse +- Right analog click or Select + L1: left mouse click +- Select + Right analog click or Select + R1: right mouse click +- Select + L2 or Start + Y: quest log +- Select + R2 or Start + B: spell book + +Source: https://github.com/diasurgical/devilutionX/ diff --git a/Packaging/OpenDingux/package-ipk.sh b/Packaging/OpenDingux/package-ipk.sh index 5b6799c7b7a..66a79fff434 100755 --- a/Packaging/OpenDingux/package-ipk.sh +++ b/Packaging/OpenDingux/package-ipk.sh @@ -4,8 +4,13 @@ set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" -readonly OUT="${1:-../../build/devilutionx.ipk}" -readonly IN="${2:-../../build/devilutionx.dge}" +if [[ -z "$1" ]]; then + echo "Error: output path is required" + exit 1 +fi + +readonly OUT="$1" +readonly IN="${2:-$(dirname "$OUT")/devilutionx}" readonly PKG_TARGET=devilutionx readonly TMP="tmp/${PKG_TARGET}" @@ -27,7 +32,7 @@ mkdir -p "${TMP}" # data.tar.gz mkdir -p "${TMP}/root/${PKG_INSTALL_DIR}" "${TMP}/root/${PKG_LOCAL_DIR}" -cp "$IN" "${TMP}/root/${PKG_INSTALL_DIR}/${PKG_TARGET}.dge" +cp "$IN" "${TMP}/root/${PKG_INSTALL_DIR}/${PKG_TARGET}" cp ../resources/Diablo_32.png "${TMP}/root/${PKG_INSTALL_DIR}/devilutionx.png" cp ../resources/CharisSILB.ttf ../resources/LICENSE.CharisSILB.txt "${TMP}/root/${PKG_INSTALL_DIR}" cp devilutionx-retrofw.man.txt "${TMP}/root/${PKG_INSTALL_DIR}/devilutionx.man.txt" @@ -36,7 +41,7 @@ mkdir -p "${TMP}/root/$(dirname "$PKG_MENU_LNK_OUT")" printf "%s\n" \ "title=DevilutionX" \ "description=$(pkg_control_get Description)" \ - "exec=/${PKG_INSTALL_DIR}/${PKG_TARGET}.dge" \ + "exec=/${PKG_INSTALL_DIR}/${PKG_TARGET}" \ > "${TMP}/root/${PKG_MENU_LNK_OUT}" tar --owner=0 --group=0 -czvf "${TMP}/data.tar.gz" -C "${TMP}/root/" . @@ -49,6 +54,7 @@ printf "%s\n" \ tar --owner=0 --group=0 -czvf "${TMP}/control.tar.gz" -C "${TMP}/" control conffiles printf '2.0\n' > "${TMP}/debian-binary" +rm -f "$OUT" ar r "$OUT" \ "${TMP}/control.tar.gz" \ "${TMP}/data.tar.gz" \ diff --git a/Packaging/OpenDingux/package-opk.sh b/Packaging/OpenDingux/package-opk.sh index 4fd020f10c5..eef6bac68a4 100755 --- a/Packaging/OpenDingux/package-opk.sh +++ b/Packaging/OpenDingux/package-opk.sh @@ -2,38 +2,34 @@ cd "$(dirname "${BASH_SOURCE[0]}")" -readonly OUT="${1:-../../build/devilutionx.opk}" -readonly IN="${2:-../../build/devilutionx.dge}" +if [[ -z "$1" ]]; then + echo "Error: output path is required" + exit 1 +fi + +readonly OUT="$1" +readonly DESKTOP_FILE="$2" +readonly README_FILE="$2" + +readonly IN="$(dirname "$OUT")/devilutionx" readonly TMP="tmp/opk" echo 1>&2 Packaging ${OUT}... # To run with SDL2 controller mappings for RG350: -# Exec=env SDL_GAMECONTROLLERCONFIG=190000006c696e6b6465762064657600,RG350,platform:Linux,x:b3,a:b0,b:b1,y:b2,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, ./devilutionx.dge +# Exec=env SDL_GAMECONTROLLERCONFIG=190000006c696e6b6465762064657600,RG350,platform:Linux,x:b3,a:b0,b:b1,y:b2,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, ./devilutionx # # We use SDL1 instead as it's ~3x faster, likely because with SDL1 scaling is done in hardware. set -x rm -rf "${TMP}" mkdir -p "${TMP}" -cat > "${TMP}/default.gcw0.desktop" < Thu, 02 Jan 2019 21:35:11 +0200 + devilutionx (0.5.0.3) UNRELEASED; urgency=medium * Hardcoded font path fix @@ -10,11 +50,3 @@ devilutionx (0.5.0.2) UNRELEASED; urgency=medium Missing font hotfix * - -- root Sat, 05 Oct 2019 12:04:39 +0000 - -devilutionx (0.4.0) bionic; urgency=medium - - [ Vítězslav Dvořák ] - * Non-maintainer upload. - - -- Vítězslav Dvořák Fri, 28 Jun 2019 22:55:11 +0200 diff --git a/Packaging/debian/control b/Packaging/debian/control index 5d15036da42..6d077ea9861 100644 --- a/Packaging/debian/control +++ b/Packaging/debian/control @@ -3,8 +3,13 @@ Section: contrib/games Priority: optional Maintainer: Debian Games Team Build-Depends: - debhelper (>= 9), - cmake, g++, libsdl2-mixer-dev, libsdl2-ttf-dev, libsodium-dev + debhelper (>= 9), + cmake, + g++, + gettext, + libsdl2-mixer-dev, + libsdl2-ttf-dev, + libsodium-dev Standards-Version: 4.3.0 Homepage: https://github.com/diasurgical/devilutionX Vcs-Git: git://git@github.com:diasurgical/devilutionX.git @@ -22,6 +27,7 @@ Description: Diablo build for modern operating systems Package: diablo-data Architecture: all +Multi-Arch: foreign Depends: ${shlibs:Depends}, ${misc:Depends}, diff --git a/Packaging/debian/devilutionx.install b/Packaging/debian/devilutionx.install deleted file mode 100644 index dfa2aae2d11..00000000000 --- a/Packaging/debian/devilutionx.install +++ /dev/null @@ -1,10 +0,0 @@ -Packaging/fedora/devilutionx.desktop usr/share/applications/ -obj-x86_64-linux-gnu/devilutionx usr/share/games/diablo/ -Packaging/resources/Diablo_48.png usr/share/icons/hicolor/48x48/apps -Packaging/resources/Diablo_32.png usr/share/icons/hicolor/32x32/apps -Packaging/resources/16.png usr/share/icons/hicolor/16x16/apps -Packaging/resources/CharisSILB.ttf usr/share/fonts/truetype -Packaging/resources/16.png usr/share/icons/hicolor/16x16/apps/ -Packaging/resources/Diablo_32.png usr/share/icons/hicolor/32x32/apps/ -Packaging/resources/Diablo_48.png usr/share/icons/hicolor/48x48/apps/ - diff --git a/Packaging/debian/rules b/Packaging/debian/rules index b0e861e2029..2b454f3bc1c 100755 --- a/Packaging/debian/rules +++ b/Packaging/debian/rules @@ -2,30 +2,35 @@ # -*- makefile -*- # Uncomment this to turn on verbose mode. -export DH_VERBOSE=1 +#export DH_VERBOSE=1 export COMPILE_FLAGS="-O0" - -export DH_VERBOSE = 1 export DEB_BUILD_MAINT_OPTIONS = hardening=-all export DEB_CFLAGS_MAINT_APPEND = -Wno-error export DEB_LDFLAGS_MAINT_APPEND = -Wno-error export CXXFLAGS="-DTTF_FONT_PATH=\"/usr/share/fonts/truetype/CharisSILB.ttf\"" +DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) %: - dh $@ --buildsystem=cmake + dh $@ --buildsystem=cmake --builddirectory=obj-${DEB_HOST_MULTIARCH} -#override_dh_auto_clean: -# dh_auto_clean -#override_dh_auto_configure: -# dh_auto_configure -O--buildsystem=cmake -- -DDESTDIR=/usr/games -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=None -DCMAKE_INSTALL_SYSCONFDIR=/etc -DCMAKE_INSTALL_LOCALSTATEDIR=/var +override_dh_auto_configure: + dh_auto_configure -- -DNIGHTLY_BUILD=ON #-DSPAWN=ON override_dh_auto_install: - mkdir -p debian/diablo-data/usr/share/games/diablo/ + install -pdm755 debian/diablo-data/usr/share/games/diablo/ test -f "../diabdat.mpq" && cp ../diabdat.mpq debian/diablo-data/usr/share/games/diablo/ || true dh_auto_install - mkdir -p debian/devilutionx/usr/share/icons/hicolor/16x16/apps/ - mkdir -p debian/devilutionx/usr/share/icons/hicolor/32x32/apps/ - mkdir -p debian/devilutionx/usr/share/icons/hicolor/48x48/apps/ - cp Packaging/resources/16.png debian/devilutionx/usr/share/icons/hicolor/16x16/apps/diablo.png - cp Packaging/resources/Diablo_32.png debian/devilutionx/usr/share/icons/hicolor/32x32/apps/diablo.png - cp Packaging/resources/Diablo_48.png debian/devilutionx/usr/share/icons/hicolor/48x48/apps/diablo.png + install -pdm755 debian/devilutionx/usr/share/icons/hicolor/48x48/apps/ + install -pdm755 debian/devilutionx/usr/share/applications/ + install -pdm755 debian/devilutionx/usr/share/fonts/truetype/ + install -pdm755 debian/devilutionx/usr/share/icons/hicolor/16x16/apps/ + install -pdm755 debian/devilutionx/usr/share/icons/hicolor/32x32/apps/ + install -pdm755 debian/devilutionx/usr/share/icons/hicolor/48x48/apps/ + install -pdm755 debian/devilutionx/usr/share/games/diablo/ + install -Dm664 Packaging/resources/16.png debian/devilutionx/usr/share/icons/hicolor/16x16/apps/devilutionx.png + install -Dm664 Packaging/resources/Diablo_32.png debian/devilutionx/usr/share/icons/hicolor/32x32/apps/devilutionx.png + install -Dm664 Packaging/resources/Diablo_48.png debian/devilutionx/usr/share/icons/hicolor/48x48/apps/devilutionx.png + install -Dm664 Packaging/fedora/devilutionx.desktop debian/devilutionx/usr/share/applications/ + install -Dm664 Packaging/resources/CharisSILB.ttf debian/devilutionx/usr/share/fonts/truetype/ + install -Dm755 obj-${DEB_HOST_MULTIARCH}/devilutionx debian/devilutionx/usr/share/games/diablo/ + diff --git a/Packaging/fedora/devilutionx.desktop b/Packaging/fedora/devilutionx.desktop index 6e583ba61bc..1091c22a673 100644 --- a/Packaging/fedora/devilutionx.desktop +++ b/Packaging/fedora/devilutionx.desktop @@ -2,6 +2,8 @@ Name=devilutionX GenericName=DevilutionX Comment=Play Diablo I on Linux +Comment[da]=Spil Diablo I på Linux +Comment[hr]=Igrajte Diablo I na Linuxu Exec=devilutionx Icon=devilutionx.png Terminal=false diff --git a/Packaging/nix/README.txt b/Packaging/nix/README.txt index ee91766021f..f93e1e8438d 100644 --- a/Packaging/nix/README.txt +++ b/Packaging/nix/README.txt @@ -5,14 +5,13 @@ Discord: https://discord.gg/aQBQdDe GitHub: https://github.com/diasurgical/devilutionX # How To Install: - - Extract the files in the zip. + - Extract the files in the archive. - Install libsdl2 libsdl2-mixer libsdl2-ttf - - Copy diabdat.mpq from your CD, or GoG install folder, to the DevilutionX install folder; Make sure it is all lowercase. + - Copy diabdat.mpq from your CD (or GoG install folder) to the DevilutionX install folder. Make sure it is all lowercase. - Run ./devilutionx # Multiplayer - - TCP/IP only requires the host to expose port 6112 - - UPD/IP requires that all players expose port 6112 (currently disabled) + - TCP/IP requires the host to expose port 6112. All games are encrypted and password protected. @@ -26,8 +25,8 @@ The configurations and save games are located in: # Legal This software is being released to the Public Domain. No assets of Diablo are being provided. You must own a copy of Diablo and have access to the assets beforehand in order to use this software. -Battle.net(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Battle.net® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -Diablo(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Diablo® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -This software is in no way associated with or endorsed by Blizzard Entertainment(R). +This software is in no way associated with or endorsed by Blizzard Entertainment®. diff --git a/Packaging/pi/README.txt b/Packaging/pi/README.txt index 96916ea17fb..73ba98a07e0 100644 --- a/Packaging/pi/README.txt +++ b/Packaging/pi/README.txt @@ -5,19 +5,18 @@ Discord: https://discord.gg/aQBQdDe GitHub: https://github.com/diasurgical/devilutionX # How To Install: - - Extract the files in the zip. + - Extract the files in the archive. - Install libsdl2 libsdl2-mixer libsdl2-ttf - - Copy diabdat.mpq from your CD, or GoG install folder, to the DevilutionX install folder; Make sure it is all lowercase. + - Copy diabdat.mpq from your CD (or GoG install folder) to the DevilutionX install folder. Make sure it is all lowercase. - Run ./devilutionx # Raspberry Pi performance - - This build is compiled for Raspbian Buster + - This build is compiled for Raspbian Stretch - For the best experience set upscale=0 in diablo.ini and set the system resolution to 640x480 - - Alternatly you can enable experimental GL-drivers via raspi-config for upscaling support + - Alternately you can enable experimental GL-drivers via raspi-config for upscaling support # Multiplayer - - TCP/IP only requires the host to expose port 6112 - - UPD/IP requires that all players expose port 6112 (currently disabled) + - TCP/IP requires the host to expose port 6112. All games are encrypted and password protected. @@ -31,8 +30,8 @@ The configurations and save games are located in: # Legal This software is being released to the Public Domain. No assets of Diablo are being provided. You must own a copy of Diablo and have access to the assets beforehand in order to use this software. -Battle.net(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Battle.net® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -Diablo(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Diablo® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -This software is in no way associated with or endorsed by Blizzard Entertainment(R). +This software is in no way associated with or endorsed by Blizzard Entertainment®. diff --git a/Packaging/switch/readme-switch.md b/Packaging/switch/readme-switch.md deleted file mode 100644 index 2c9dfc03ab0..00000000000 --- a/Packaging/switch/readme-switch.md +++ /dev/null @@ -1,41 +0,0 @@ -# Nintendo Switch Port of DevilutionX (Diablo) - -### How To Play: -- Put `devilutionx.nro` in into `/switch/devilutionx` -- Copy `DIABDAT.MPQ` from the original Diablo game disc or GOG version into `/switch/devilutionx` -- Launch `devilutionx.nro` (do not use album to launch, see the note below) -- *Note:* Hold R on any installed game and launch it. Do not use album to launch. If you use album, the homebrew only has very little memory available, and the touch keyboard doesn't work. This is true for all homebrew, not just Diablo-NX. - -### Joycon Controls - -- Left analog : move hero -- Right analog : simulate mouse -- A : attack nearby enemies, talk to towns people and merchants, pickup & drop items in inventory, OK while in main menu -- X : pickup gold, potions & equipment from ground, open chests and doors that are nearby, use item when in inventory (useful to read books etc.) -- Y : cast spell, go to previous screen when talking to people and in shops, delete character while in main menu -- B : Select spell, cancel while in main menu -- R : drink mana potion -- L : drink health potion -- ZR : inventory -- ZL : character -- Minus + Y : quest log -- Right analog click : left mouse click -- Left analog click : automap -- Plus : game Menu, skip intro - -### Touch Controls - -- Single finger drag : move the mouse pointer (pointer jumps to finger) -- Single short tap : left mouse click -- Single short tap while holding a second finger down : right mouse click -- Dual finger drag : drag'n'drop (left mouse button is held down) -- Three finger drag : drag'n'drop (right mouse button is held down) - -### Credits - -- Initial Switch Port by [MVG](https://github.com/lantus) in 2019 -- Controller code by [Jacob Fliss](https://github.com/erfg12) -- Control improvements and bug fixes by [rsn8887](https://github.com/rsn8887) in 2019 -- [AJenbo](https://github.com/AJenbo) for upstreaming Switch code and many code fixes - -And a special thanks to all the support and people who work on Devilution to make it possible! <3 diff --git a/Packaging/switch/readme.txt b/Packaging/switch/readme.txt new file mode 100644 index 00000000000..8c1766feeaf --- /dev/null +++ b/Packaging/switch/readme.txt @@ -0,0 +1,47 @@ +# Nintendo Switch Port of DevilutionX (Diablo) + +# How To Install: + - Put `devilutionx.nro` and `CharisSILB.ttf` in into `/switch/devilutionx` + - Copy diabdat.mpq from your CD (or GoG install folder) to `/switch/devilutionx`. Make sure it is all lowercase. + - Launch `devilutionx.nro`. (Do not use album to launch; see the note below.) + - *Note:* Hold R on any installed game and launch it. Do not use album to launch. If you use album, the homebrew will only have a small amount memory available, and the touch keyboard won't work. This is true for all homebrew, not just DevilutionX. + +# Joycon Controls +- Left analog or D-Pad: move hero +- A: attack nearby enemies, talk to townspeople and merchants, pickup/place items in the inventory, OK while in main menu +- B: select spell, back while in menus +- X: pickup items, open nearby chests and doors, use item in the inventory +- Y: cast spell, delete character while in main menu +- L: use health item from belt +- R: use mana potion from belt +- ZL or Start + Left: character sheet +- ZR or Start + Right: inventory +- Left analog click or Start + Down: toggle automap +- Start + Up or Start + Select: game menu +- Start + Left: character info +- Start + Right: inventory +- Select + A/B/X/Y: Spell hotkeys +- Right analog: move automap or simulate mouse +- Right analog click or Select + L: left mouse click +- Select + Right analog click or Select + R: right mouse click +- Select + ZL or Start + Y: quest log +- Select + ZR or Start + B: spell book + +# Touch Controls + - Single finger drag: move the mouse pointer (pointer jumps to finger) + - Single short tap: left mouse click + - Single short tap while holding a second finger down: right mouse click + - Dual finger drag: drag'n'drop (left mouse button is held down) + - Three finger drag: drag'n'drop (right mouse button is held down) + +# Credits + - See list of contributors https://github.com/diasurgical/devilutionX/graphs/contributors + +# Legal +This software is being released to the Public Domain. No assets of Diablo are being provided. You must own a copy of Diablo and have access to the assets beforehand in order to use this software. + +Battle.net® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. + +Diablo® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. + +This software is in no way associated with or endorsed by Blizzard Entertainment®. diff --git a/Packaging/windows/README.txt b/Packaging/windows/README.txt index cbb3b0690aa..9f9adda419a 100644 --- a/Packaging/windows/README.txt +++ b/Packaging/windows/README.txt @@ -6,12 +6,11 @@ GitHub: https://github.com/diasurgical/devilutionX # How To Install: - Extract the files in the zip - - Copy diabdat.mpq from your CD, or GoG install folder, to the DevilutionX install folder. + - Copy diabdat.mpq from your CD (or GoG install folder) to the DevilutionX install folder. - Run devilutionx.exe # Multiplayer - - TCP/IP only requires the host to expose port 6112 - - UPD/IP requires that all players expose port 6112 (currently disabled) + - TCP/IP requires the host to expose port 6112. All games are encrypted and password protected. @@ -25,8 +24,8 @@ C:\Users\[username]\AppData\Roaming\diasurgical\devilution # Legal This software is being released to the Public Domain. No assets of Diablo are being provided. You must own a copy of Diablo and have access to the assets beforehand in order to use this software. -Battle.net(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Battle.net® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -Diablo(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Diablo® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -This software is in no way associated with or endorsed by Blizzard Entertainment(R). +This software is in no way associated with or endorsed by Blizzard Entertainment®. diff --git a/Packaging/windows/devilutionx.rc b/Packaging/windows/devilutionx.rc new file mode 100644 index 00000000000..46a5a428b60 --- /dev/null +++ b/Packaging/windows/devilutionx.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "icon.ico" diff --git a/Packaging/windows/icon.ico b/Packaging/windows/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3fec6d7d0f623ba9e7c1bfa35b234b86a3899dee GIT binary patch literal 766 zcmaiyJ#ND=427R76&>rMKxe~KM**UD1ETfWewrVSnB!}u=4~gx`OFFPJ~<-mJh@za&o=AaTJZQN@t?awM67ZS$Fxe z(rfYMSgPG5W}uY6r+Bf9=1# LU2i!zJ8FLc1K(6q literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 7992c79337f..9579b523949 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,15 @@ Nightly builds | Platform ![Discord Channel](https://avatars3.githubusercontent.com/u/1965106?s=16&v=4) [Discord Chat Channel](https://discord.gg/aQBQdDe) # How To Play: - - Copy diabdat.mpq from your CD, or GoG install folder, to the DevilutionX install folder or data folder; make sure it is all lowercase. The DeviliutionX install is the one that contains the DevilutionX executable. The data folder path may differ depending on OS version and security setting, but will normally be as following: + - Download [the latest DevilutionX release](https://github.com/diasurgical/devilutionX/releases), or build from source + - Copy diabdat.mpq from your CD or GoG installation (or [extract it from the GoG installer](https://github.com/diasurgical/devilutionX/wiki/Extracting-the-DIABDAT.MPQ-from-the-GoG-installer)) to the DevilutionX install folder or data folder; make sure it is all lowercase. The DeviliutionX install folder is the one that contains the DevilutionX executable. The data folder path may differ depending on OS version and security settings, but will normally be as follows: - macOS `~/Library/Application Support/diasurgical/devilution` - Linux `~/.local/share/diasurgical/devilution/` - - Windows `C:\Users[username]\AppData\Roaming\diasurgical\devilution` - - [Download DevilutionX](https://github.com/diasurgical/devilutionX/releases), or build from source - - Install [SDL2](https://www.libsdl.org/download-2.0.php) (including [SDL2_mixer](https://www.libsdl.org/projects/SDL_mixer/) and [SDL2_ttf](https://www.libsdl.org/projects/SDL_ttf/)) + - Windows `C:\Users\[username]\AppData\Roaming\diasurgical\devilution` + - Install [SDL2](https://www.libsdl.org/download-2.0.php), [SDL2_mixer](https://www.libsdl.org/projects/SDL_mixer/) and [SDL2_ttf](https://www.libsdl.org/projects/SDL_ttf/) (included in macOS and Windows releases): + - Ubuntu/Debian/Rasbian `sudo apt-get install libsdl2-ttf-2.0-0 libsdl2-mixer-2.0-0` - Run `./devilutionx` -Please keep in mind that this is still being worked on and is missing parts of UI and some minor bugs, see [milestone 1](https://github.com/diasurgical/devilutionX/milestone/1) for a full list of known issues. - # Building from Source
Linux @@ -35,7 +34,7 @@ sudo dnf install cmake glibc-devel SDL2-devel SDL2_ttf-devel SDL2_mixer-devel li ``` cd build cmake .. -cmake --build . -j $(nproc) +make -j$(nproc) ```
@@ -91,7 +90,7 @@ sudo apt-get install cmake gcc-mingw-w64-i686 g++-mingw-w64-i686 ``` cd build cmake -DCMAKE_TOOLCHAIN_FILE=../CMake/mingwcc.cmake .. -cmake --build . -j $(nproc) +make -j$(nproc) ```
Windows via Visual Studio @@ -188,42 +187,40 @@ The build script does the following: 1. Downloads and configures the buildroot if necessary. 2. Builds the executable (using CMake). -3. Packages the executable and all related resources into an `.ipk` package. +3. Packages the executable and all related resources into an `.ipk` or `.opk` package. -The buildroot uses ~4 GiB of disk space and can take almost an hour to build. +The buildroot uses ~2.5 GiB of disk space and can take 20 minutes to build. For OpenDingux builds `mksquashfs` needs to be installed. -### RetroFW (RS97, RG300, LDK) - -The RetroFW build uses the buildroot at `$HOME/buildroot-2018.02.9-retrofw`. +To build, run the following command ~~~ bash -Packaging/OpenDingux/build-retrofw.sh +Packaging/OpenDingux/build.sh ~~~ -### OpenDingux (RG350, GCW0) +Replace `` with one of: `retrofw`, `rg350`, or `gkd350h`. -This OpenDingux build uses the buildroot at `$HOME/buildroot-rg350-devilutionx`. - -~~~ bash -Packaging/OpenDingux/build-rg350.sh -~~~ +This prepares and uses the buildroot at `$HOME/buildroot-$PLATFORM-devilutionx`.
-## CMake arguments +
CMake build options + ### General -The default build type is `Debug`. This can be changed with `-DBINARY_RELEASE=ON`. Independently of this, the debug mode of the Diablo engine is always enabled by default. It can be disabled with `-DDEBUG=OFF`. Finally, in debug builds the address sanitizer is enabled by default. This can be disabled with `-DASAN=OFF`. -You can also generate 32bit builds on 64bit platforms by setting `-DCMAKE_TOOLCHAIN_FILE=../CMake/32bit.cmake` (remember to use the `linux32` command if on Linux). -Network support can be disabled using `-DNONET=ON`, this also removes the need for the ASIO and Sodium dependencies. -You can compile the shareware version with `-DSPAWN=ON` this will allow you to try the game using spawn.mpq from the original shareware which can still be [downloaded](http://ftp.blizzard.com/pub/demos/diablosw.exe) for free. +- `-DBINARY_RELEASE=ON` changed build type to release and optimize for distribution. +- `-DNONET=ON` disable network support, this also removes the need for the ASIO and Sodium. +- `-DUSE_SDL1=ON` build for SDL v1 instead of v2, not all features are supported under SDL v1, notably upscaling. +- `-DSPAWN=ON` build the shareware version, using spawn.mpq from the original shareware; which can still be [downloaded](http://ftp.blizzard.com/pub/demos/diablosw.exe) for free. +- `-DCMAKE_TOOLCHAIN_FILE=../CMake/32bit.cmake` generate 32bit builds on 64bit platforms (remember to use the `linux32` command if on Linux). +- `-DCROSS_PREFIX=/path/to/prefix` set the path to the `i686-w64-mingw32` directory. + +### Debug builds +- `-DDEBUG=OFF` disable debug mode of the Diablo engine. +- `-DASAN=OFF` disable address sanitizer. +- `-DUBSAN=OFF` disable undefined behavior sanitizer. -### mingw32 -Use `-DCROSS_PREFIX=/path/to/prefix` if the `i686-w64-mingw32` directory is not in `/usr`. -### Use SDL v1 instead of SDL v2. -Pass `-DUSE_SDL1=ON` to build with SDL v1 instead of v2. -Note that some features are not yet supported in SDL v1, notably upscaling, and fullscreen. +
# Multiplayer - TCP/IP only requires the host to expose port 6112 @@ -237,20 +234,25 @@ DevilutionX supports gamepad controls. Default controller mappings (A/B/X/Y as in Nintendo layout, so the rightmost button is attack): -- Left analog / DPad: move hero -- Right analog: simulate mouse -- A: attack nearby enemies, talk to towns people and merchants, pickup & place items in the inventory, OK while in main menu -- B: Select spell, cancel while in main menu -- X: pickup gold, potions & equipment from ground, open chests and doors that are nearby, use item when in inventory (useful to read books etc.) -- Y: cast spell, go to previous screen when talking to people and in shops, delete character while in main menu -- R1: use mana potion from belt +- Left analog or D-Pad: move hero +- A: attack nearby enemies, talk to townspeople and merchants, pickup/place items in the inventory, OK while in main menu +- B: select spell, back while in menus +- X: pickup items, open nearby chests and doors, use item in the inventory +- Y: cast spell, delete character while in main menu - L1: use health item from belt -- R2: inventory -- L2: character sheet -- Left analog click: toggle automap -- Right analog click: left mouse click -- Select: quest log -- Start: game Menu, skip intro +- R1: use mana potion from belt +- L2 or Start + Left: character sheet +- R2 or Start + Right: inventory +- Left analog click or Start + Down: toggle automap +- Start + Up or Start + Select: game menu +- Start + Left: character info +- Start + Right: inventory +- Select + A/B/X/Y: Spell hotkeys +- Right analog: move automap or simulate mouse +- Right analog click or Select + L1: left mouse click +- Select + Right analog click or Select + R1: right mouse click +- Select + L2 or Start + Y: quest log +- Select + R2 or Start + B: spell book For now, they can be re-mapped by changing `SourceX/controls` or by setting the `SDL_GAMECONTROLLERCONFIG` environment variable (see @@ -259,48 +261,35 @@ variable (see # Contributing [Guidelines](docs/CONTRIBUTING.md) -# Modding -Below are a few examples of some simple improvements made to the game. It is planned in the future to create tools for designing dungeons and graphics. - -![Screenshot 1: Monster lifebar+items](https://github.com/diasurgical/scalpel/blob/master/screens/mod1.png) - -![Screenshot 2: New trade screen](https://github.com/diasurgical/scalpel/blob/master/screens/mod2.png) - # F.A.Q. -
Click to reveal - > Wow, does this mean I can download and play Diablo for free now? -No, you'll need access to the data from the original game. If you don't have an original CD then you can [buy Diablo from GoG.com](https://www.gog.com/game/diablo). Alternatively you can also use `spawn.mpq` from the [http://ftp.blizzard.com/pub/demos/diablosw.exe](shareware) version and compile the with the SPAWN flag defined. -> Cool, so I fired your mod up, but there's no 1080p or new features? +No, you'll need access to the data from the original game. If you don't have an original CD then you can [buy Diablo from GoG.com](https://www.gog.com/game/diablo). Alternately you can use `spawn.mpq` from the [http://ftp.blizzard.com/pub/demos/diablosw.exe](shareware) version and compile the with the SPAWN flag defined. +> What game changes does DevilutionX provide + +DevilutionX's main focus is to make the game work on multiple platforms. An additional goal is to make the engine mod friendly. As such, there are no changes to gameplay, but we will be making some enhancments to the engine itself. For example, the engine now has upscaling, unlocked fps, controller support, and multiplayer via TCP. +> Is 1080p supported? -We're working on it. +Currently the game simply scales the original 640x480 to best fit, but we are working on widescreen support. > What about Hellfire? -Hellfire was a bit of a flop on the developer's part. Support may come in the future once the base game is finished. +Hellfire is being worked on and is mostly done, though not fully playable at the moment. +> Does it work with Battle.net? + +Battle.net is a service provided by Blizzard. We are not associated with them, so we have not worked on intergrating with their service.
# Credits -- Reverse engineered by GalaXyHaXz in 2018 -- [sanctuary](https://github.com/sanctuary) - extensively documenting Diablo's game engine -- [BWAPI Team](https://github.com/bwapi) - providing library API to work with Storm -- [Ladislav Zezula](https://github.com/ladislav-zezula) - reversing PKWARE library, further documenting Storm -- [fearedbliss](https://github.com/fearedbliss) - being awe-inspiring -- Diablodin - providing additional info about the PSX release -- Climax Studios & Sony - secretly helping with their undercover QA :P -- Blizzard North - wait, this was a typo! -- Depression - reason to waste four months of my life doing this ;) - -And a special thanks to all the support and people who work on this project to make it possible! <3 +- The original Devilution project [Devilution](https://github.com/diasurgical/devilution#credits) +- [Everyone](https://github.com/diasurgical/devilutionX/graphs/contributors) who worked on Devilution/DevilutionX +- And a thanks to all who support the project, report bugs and help spread the word <3 # Changelog [From the beginning until release](docs/CHANGELOG.md) # Legal -Devilution is released to the Public Domain. The documentation and function provided by Devilution may only be utilized with assets provided by ownership of Diablo. - -Battle.net(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +DevilutionX is released to the Public Domain. The documentation and functionality provided by Devilution may only be utilized with assets provided by ownership of Diablo. -Diablo(R) - Copyright (C) 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. +Diablo® - Copyright © 1996 Blizzard Entertainment, Inc. All rights reserved. Diablo and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries. -Devilution and any of its' maintainers are in no way associated with or endorsed by Blizzard Entertainment(R). +Devilution and any of its maintainers are in no way associated with or endorsed by Blizzard Entertainment®. diff --git a/Source/appfat.cpp b/Source/appfat.cpp index 6bd9a99f47b..42c1f8fad46 100644 --- a/Source/appfat.cpp +++ b/Source/appfat.cpp @@ -8,7 +8,7 @@ char sz_error_buf[256]; BOOL terminating; int cleanup_thread_id; -void __cdecl app_fatal(const char *pszFmt, ...) +void app_fatal(const char *pszFmt, ...) { va_list va; @@ -48,7 +48,7 @@ void FreeDlg() SNetDestroy(); } -void __cdecl DrawDlg(char *pszFmt, ...) +void DrawDlg(char *pszFmt, ...) { char text[256]; va_list arglist; @@ -93,7 +93,7 @@ void FileErrDlg(const char *error) 1024, "Unable to open a required file.\n" "\n" - "Verify that the MD5 of diabdat.mpq matches on of the following values\n" + "Verify that the MD5 of diabdat.mpq matches one of the following values\n" "011bc6518e6166206231080a4440b373\n" "68f049866b44688a7af65ba766bef75a\n" "\n" diff --git a/Source/appfat.h b/Source/appfat.h index fe41a1a1526..08ee8337325 100644 --- a/Source/appfat.h +++ b/Source/appfat.h @@ -7,15 +7,12 @@ extern BOOL terminating; extern int cleanup_thread_id; void TriggerBreak(); -#ifdef _DEBUG -LONG __stdcall BreakFilter(PEXCEPTION_POINTERS pExc); -#endif char *GetErrorStr(DWORD error_code); #define TraceLastError SDL_GetError -void __cdecl app_fatal(const char *pszFmt, ...); +void app_fatal(const char *pszFmt, ...); void MsgBox(const char *pszFmt, va_list va); void FreeDlg(); -void __cdecl DrawDlg(char *pszFmt, ...); +void DrawDlg(char *pszFmt, ...); #ifdef _DEBUG void assert_fail(int nLineNo, const char *pszFile, const char *pszFail); #endif @@ -23,7 +20,6 @@ void DDErrMsg(DWORD error_code, int log_line_nr, char *log_file_path); void DSErrMsg(DWORD error_code, int log_line_nr, char *log_file_path); void center_window(HWND hDlg); void ErrDlg(const char *title, const char *error, char *log_file_path, int log_line_nr); -BOOL __stdcall FuncDlg(HWND hDlg, UINT uMsg, WPARAM wParam, char *text); void TextDlg(HWND hDlg, char *text); void FileErrDlg(const char *error); void DiskFreeDlg(char *error); diff --git a/Source/automap.cpp b/Source/automap.cpp index 4a7685166ba..311871bc6f3 100644 --- a/Source/automap.cpp +++ b/Source/automap.cpp @@ -588,52 +588,52 @@ void SetAutomapView(int x, int y) case 2: if (solid) { if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007) - automapview[xx][yy + 1] = 1; + automapview[xx][yy + 1] = TRUE; } else if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) { - automapview[xx - 1][yy] = 1; + automapview[xx - 1][yy] = TRUE; } break; case 3: if (solid) { if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007) - automapview[xx + 1][yy] = 1; + automapview[xx + 1][yy] = TRUE; } else if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) { - automapview[xx][yy - 1] = 1; + automapview[xx][yy - 1] = TRUE; } break; case 4: if (solid) { if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007) - automapview[xx][yy + 1] = 1; + automapview[xx][yy + 1] = TRUE; if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007) - automapview[xx + 1][yy] = 1; + automapview[xx + 1][yy] = TRUE; } else { if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) - automapview[xx - 1][yy] = 1; + automapview[xx - 1][yy] = TRUE; if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) - automapview[xx][yy - 1] = 1; + automapview[xx][yy - 1] = TRUE; if (GetAutomapType(xx - 1, yy - 1, FALSE) & 0x4000) - automapview[xx - 1][yy - 1] = 1; + automapview[xx - 1][yy - 1] = TRUE; } break; case 5: if (solid) { if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) - automapview[xx][yy - 1] = 1; + automapview[xx][yy - 1] = TRUE; if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007) - automapview[xx][yy + 1] = 1; + automapview[xx][yy + 1] = TRUE; } else if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) { - automapview[xx - 1][yy] = 1; + automapview[xx - 1][yy] = TRUE; } break; case 6: if (solid) { if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) - automapview[xx - 1][yy] = 1; + automapview[xx - 1][yy] = TRUE; if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007) - automapview[xx + 1][yy] = 1; + automapview[xx + 1][yy] = TRUE; } else if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) { - automapview[xx][yy - 1] = 1; + automapview[xx][yy - 1] = TRUE; } break; } diff --git a/Source/capture.cpp b/Source/capture.cpp index b6a4d4809ff..be4fc6cda68 100644 --- a/Source/capture.cpp +++ b/Source/capture.cpp @@ -1,9 +1,12 @@ +#include + #include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" +#include "file_util.h" DEVILUTION_BEGIN_NAMESPACE -static BOOL CaptureHdr(HANDLE hFile, short width, short height) +static BOOL CaptureHdr(short width, short height, std::ofstream *out) { DWORD lpNumBytes; PCXHEADER Buffer; @@ -13,19 +16,19 @@ static BOOL CaptureHdr(HANDLE hFile, short width, short height) Buffer.Version = 5; Buffer.Encoding = 1; Buffer.BitsPerPixel = 8; - Buffer.Xmax = width - 1; - Buffer.Ymax = height - 1; - Buffer.HDpi = width; - Buffer.VDpi = height; + Buffer.Xmax = SDL_SwapLE16(width - 1); + Buffer.Ymax = SDL_SwapLE16(height - 1); + Buffer.HDpi = SDL_SwapLE16(width); + Buffer.VDpi = SDL_SwapLE16(height); Buffer.NPlanes = 1; - Buffer.BytesPerLine = width; + Buffer.BytesPerLine = SDL_SwapLE16(width); - return WriteFile(hFile, &Buffer, sizeof(Buffer), &lpNumBytes, NULL) && lpNumBytes == sizeof(Buffer); + out->write(reinterpret_cast(&Buffer), sizeof(Buffer)); + return !out->fail(); } -static BOOL CapturePal(HANDLE hFile, PALETTEENTRY *palette) +static BOOL CapturePal(PALETTEENTRY *palette, std::ofstream *out) { - DWORD NumberOfBytesWritten; BYTE pcx_palette[769]; int i; @@ -36,7 +39,8 @@ static BOOL CapturePal(HANDLE hFile, PALETTEENTRY *palette) pcx_palette[1 + 3 * i + 2] = palette[i].peBlue; } - return WriteFile(hFile, pcx_palette, 769, &NumberOfBytesWritten, 0) && NumberOfBytesWritten == 769; + out->write(reinterpret_cast(pcx_palette), sizeof(pcx_palette)); + return !out->fail(); } static BYTE *CaptureEnc(BYTE *src, BYTE *dst, int width) @@ -73,7 +77,7 @@ static BYTE *CaptureEnc(BYTE *src, BYTE *dst, int width) return dst; } -static BOOL CapturePix(HANDLE hFile, WORD width, WORD height, WORD stride, BYTE *pixels) +static bool CapturePix(WORD width, WORD height, WORD stride, BYTE *pixels, std::ofstream *out) { int writeSize; DWORD lpNumBytes; @@ -84,32 +88,27 @@ static BOOL CapturePix(HANDLE hFile, WORD width, WORD height, WORD stride, BYTE pBufferEnd = CaptureEnc(pixels, pBuffer, width); pixels += stride; writeSize = pBufferEnd - pBuffer; - if (!(WriteFile(hFile, pBuffer, writeSize, &lpNumBytes, 0) && lpNumBytes == writeSize)) { - return FALSE; - } + out->write(reinterpret_cast(pBuffer), writeSize); + if (out->fail()) return false; } mem_free_dbg(pBuffer); - return TRUE; + return true; } -static HANDLE CaptureFile(char *dst_path) +// Returns a pointer because in GCC < 5 ofstream itself is not moveable due to a bug. +static std::ofstream *CaptureFile(char *dst_path) { char path[MAX_PATH]; - GetPrefPath(dst_path, MAX_PATH); + GetPrefPath(path, MAX_PATH); for (int i = 0; i <= 99; i++) { snprintf(dst_path, MAX_PATH, "%sscreen%02d.PCX", path, i); - FILE *file = fopen(dst_path, "r"); - - if (file == NULL) { - return CreateFile(dst_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - } - - fclose(file); + if (!FileExists(dst_path)) + return new std::ofstream(dst_path, std::ios::binary | std::ios::trunc); } - return INVALID_HANDLE_VALUE; + return nullptr; } static void RedPalette(PALETTEENTRY *pal) @@ -129,34 +128,37 @@ static void RedPalette(PALETTEENTRY *pal) void CaptureScreen() { - HANDLE hObject; PALETTEENTRY palette[256]; char FileName[MAX_PATH]; BOOL success; - hObject = CaptureFile(FileName); - if (hObject != INVALID_HANDLE_VALUE) { - DrawAndBlit(); - PaletteGetEntries(256, palette); - RedPalette(palette); - - lock_buf(2); - success = CaptureHdr(hObject, SCREEN_WIDTH, SCREEN_HEIGHT); - if (success) { - success = CapturePix(hObject, SCREEN_WIDTH, SCREEN_HEIGHT, BUFFER_WIDTH, &gpBuffer[SCREENXY(0, 0)]); - } - if (success) { - success = CapturePal(hObject, palette); - } - unlock_buf(2); - CloseHandle(hObject); - - if (!success) - DeleteFile(FileName); + std::ofstream *out = CaptureFile(FileName); + if (out == nullptr) return; + DrawAndBlit(); + PaletteGetEntries(256, palette); + RedPalette(palette); - Sleep(300); - PaletteGetEntries(256, palette); + lock_buf(2); + success = CaptureHdr(SCREEN_WIDTH, SCREEN_HEIGHT, out); + if (success) { + success = CapturePix(SCREEN_WIDTH, SCREEN_HEIGHT, BUFFER_WIDTH, &gpBuffer[SCREENXY(0, 0)], out); } + if (success) { + success = CapturePal(palette, out); + } + unlock_buf(2); + out->close(); + + if (!success) { + SDL_Log("Failed to save screenshot at %s", FileName); + DeleteFile(FileName); + } else { + SDL_Log("Screenshot saved at %s", FileName); + } + + Sleep(300); + PaletteGetEntries(256, palette); + delete out; } DEVILUTION_END_NAMESPACE diff --git a/Source/control.cpp b/Source/control.cpp index dd51ec9b78b..53e22842245 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -759,7 +759,7 @@ void InitControlPan() pPanelButtons = LoadFileInMem("CtrlPan\\Panel8bu.CEL", NULL); for (i = 0; i < sizeof(panbtn) / sizeof(panbtn[0]); i++) panbtn[i] = 0; - panbtndown = 0; + panbtndown = FALSE; if (gbMaxPlayers == 1) numpanbtns = 6; else @@ -935,7 +935,7 @@ void DoAutoMap() if (!automapflag) StartAutomap(); else - automapflag = 0; + automapflag = FALSE; } else { InitDiabloMsg(EMSG_NO_AUTOMAP_IN_TOWN); } @@ -1095,7 +1095,7 @@ void CheckBtnUp() } break; case PANBTN_SPELLBOOK: - invflag = 0; + invflag = FALSE; if (dropGoldFlag) { dropGoldFlag = FALSE; dropGoldValue = 0; @@ -1230,7 +1230,7 @@ void control_draw_info_str() yo = 0; lo = 1; if (infostr[0]) { - control_print_info_str(0, infostr, 1, pnumlines); + control_print_info_str(0, infostr, TRUE, pnumlines); yo = 1; lo = 0; } @@ -1274,7 +1274,7 @@ void control_print_info_str(int y, char *str, BOOL center, int lines) } } -void PrintGameStr(int x, int y, char *str, int color) +void PrintGameStr(int x, int y, const char *str, int color) { BYTE c; int sx, sy; @@ -1924,13 +1924,13 @@ void control_drop_gold(char vkey) } memset(input, 0, sizeof(input)); - _itoa(dropGoldValue, input, 10); + snprintf(input, sizeof(input), "%d", dropGoldValue); if (vkey == VK_RETURN) { if (dropGoldValue > 0) control_remove_gold(myplr, initialDropGoldIndex); - dropGoldFlag = 0; + dropGoldFlag = FALSE; } else if (vkey == VK_ESCAPE) { - dropGoldFlag = 0; + dropGoldFlag = FALSE; dropGoldValue = 0; } else if (vkey == VK_BACK) { input[strlen(input) - 1] = '\0'; diff --git a/Source/control.h b/Source/control.h index ef91a8b33d8..acc494a8099 100644 --- a/Source/control.h +++ b/Source/control.h @@ -85,7 +85,7 @@ BOOL control_WriteStringToBuffer(BYTE *str); void DrawInfoBox(); void control_draw_info_str(); void control_print_info_str(int y, char *str, BOOL center, int lines); -void PrintGameStr(int x, int y, char *str, int color); +void PrintGameStr(int x, int y, const char *str, int color); void DrawChr(); #define ADD_PlrStringXY(x, y, width, pszStr, col) MY_PlrStringXY(x, y, width, pszStr, col, 1) void MY_PlrStringXY(int x, int y, int width, char *pszStr, char col, int base); diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 0acd80d896d..8ee962626fc 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -1,6 +1,7 @@ #include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" +#include DEVILUTION_BEGIN_NAMESPACE @@ -38,8 +39,8 @@ int color_cycle_timer; /* rdata */ BOOL fullscreen = TRUE; -#ifdef _DEBUG int showintrodebug = 1; +#ifdef _DEBUG int questdebug = -1; int debug_mode_key_s; int debug_mode_key_w; @@ -226,7 +227,7 @@ void start_game(unsigned int uMsg) InitLevelCursor(); sgnTimeoutCurs = 0; sgbMouseDown = 0; - track_repeat_walk(0); + track_repeat_walk(FALSE); } void free_game() @@ -249,7 +250,7 @@ void free_game() FreeGameMem(); } -void diablo_init(LPSTR lpCmdLine) +void diablo_init() { init_create_window(); @@ -269,7 +270,6 @@ void diablo_init(LPSTR lpCmdLine) InitHash(); diablo_init_screen(); - diablo_parse_flags(lpCmdLine); snd_init(NULL); atexit(sound_cleanup); @@ -279,10 +279,8 @@ void diablo_init(LPSTR lpCmdLine) void diablo_splash() { -#ifdef _DEBUG if (!showintrodebug) return; -#endif play_movie("gendata\\logo.smk", TRUE); #ifndef SPAWN @@ -294,154 +292,112 @@ void diablo_splash() UiTitleDialog(); } -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +int DiabloMain(int argc, char **argv) { - diablo_init(lpCmdLine); + diablo_parse_flags(argc, argv); + diablo_init(); diablo_splash(); mainmenu_loop(); return 0; } -void diablo_parse_flags(char *args) +static void print_help_and_exit() { - char c; + printf("Options:\n"); + printf(" %-20s %-30s\n", "-h, --help", "Print this message and exit"); + printf(" %-20s %-30s\n", "--version", "Print the version and exit"); + printf(" %-20s %-30s\n", "--data-dir", "Specify the folder of diabdat.mpq"); + printf(" %-20s %-30s\n", "-n", "Skip startup videos"); + printf(" %-20s %-30s\n", "-f", "Display frames per second"); + printf(" %-20s %-30s\n", "-x", "Run in windowed mode"); #ifdef _DEBUG - int i; + printf("\nDebug options:\n"); + printf(" %-20s %-30s\n", "-d", "Increaased item drops"); + printf(" %-20s %-30s\n", "-w", "Enable cheats"); + printf(" %-20s %-30s\n", "-$", "Enable god mode"); + printf(" %-20s %-30s\n", "-^", "Enable god mode and debug tools"); + //printf(" %-20s %-30s\n", "-b", "Enable item drop log"); + printf(" %-20s %-30s\n", "-v", "Highlight visibility"); + printf(" %-20s %-30s\n", "-i", "Ignore network timeout"); + //printf(" %-20s %-30s\n", "-j <##>", "Init trigger at level"); + printf(" %-20s %-30s\n", "-l <##> <##>", "Start in level as type"); + printf(" %-20s %-30s\n", "-m <##>", "Add debug monster, up to 10 allowed"); + printf(" %-20s %-30s\n", "-q <#>", "Force a certain quest"); + printf(" %-20s %-30s\n", "-r <##########>", "Set map seed"); + printf(" %-20s %-30s\n", "-t <##>", "Set current quest level"); #endif + printf("\nReport bugs at https://github.com/diasurgical/devilutionX/\n"); + exit(0); +} - while (*args != '\0') { - while (isspace(*args)) { - args++; - } - { - c = tolower(*args); - args++; - switch (c) { -#ifdef _DEBUG - case '^': - debug_mode_key_inverted_v = 1; - break; - case '$': - debug_mode_dollar_sign = 1; - break; - case 'b': - /* - debug_mode_key_b = 1; - */ - break; - case 'd': - showintrodebug = 0; - debug_mode_key_d = 1; - break; +void diablo_parse_flags(int argc, char **argv) +{ + for (int i = 1; i < argc; i++) { + if (strcasecmp("-h", argv[i]) == 0 || strcasecmp("--help", argv[i]) == 0) { + print_help_and_exit(); + } else if (strcasecmp("--version", argv[i]) == 0) { + printf("%s v%s\n", PROJECT_NAME, PROJECT_VERSION); + exit(0); + } else if (strcasecmp("--data-dir", argv[i]) == 0) { + basePath = argv[++i]; +#ifdef _WIN32 + if (basePath.back() != '\\') + basePath += '\\'; +#else + if (basePath.back() != '/') + basePath += '/'; #endif - case 'f': - EnableFrameCount(); - break; + } else if (strcasecmp("-n", argv[i]) == 0) { + showintrodebug = 0; + } else if (strcasecmp("-f", argv[i]) == 0) { + EnableFrameCount(); + } else if (strcasecmp("-x", argv[i]) == 0) { + fullscreen = FALSE; #ifdef _DEBUG - case 'i': - debug_mode_key_i = 1; - break; - case 'j': - /* - while(isspace(*args)) { - args++; - } - i = 0; - while(isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - debug_mode_key_J_trigger = i; - */ - break; - case 'l': - setlevel = FALSE; - leveldebug = TRUE; - while (isspace(*args)) { - args++; - } - i = 0; - while (isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - leveltype = i; - while (isspace(*args)) { - args++; - } - i = 0; - while (isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - currlevel = i; - plr[0].plrlevel = i; - break; - case 'm': - monstdebug = TRUE; - while (isspace(*args)) { - args++; - } - i = 0; - while (isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - DebugMonsters[debugmonsttypes++] = i; - break; - case 'n': - showintrodebug = 0; - break; - case 'q': - while (isspace(*args)) { - args++; - } - i = 0; - while (isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - questdebug = i; - break; - case 'r': - while (isspace(*args)) { - args++; - } - i = 0; - while (isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - setseed = i; - break; - case 's': - debug_mode_key_s = 1; - break; - case 't': - leveldebug = TRUE; - setlevel = TRUE; - while (isspace(*args)) { - args++; - } - i = 0; - while (isdigit(*args)) { - i = *args + 10 * i - '0'; - args++; - } - setlvlnum = i; - break; - case 'v': - visiondebug = TRUE; - break; - case 'w': - debug_mode_key_w = 1; - break; - case 'x': - fullscreen = FALSE; - break; + } else if (strcasecmp("-^", argv[i]) == 0) { + debug_mode_key_inverted_v = 1; + } else if (strcasecmp("-$", argv[i]) == 0) { + debug_mode_dollar_sign = 1; + /* + } else if (strcasecmp("-b", argv[i]) == 0) { + debug_mode_key_b = 1; + */ + } else if (strcasecmp("-d", argv[i]) == 0) { + debug_mode_key_d = 1; + } else if (strcasecmp("-i", argv[i]) == 0) { + debug_mode_key_i = 1; + /* + } else if (strcasecmp("-j", argv[i]) == 0) { + debug_mode_key_J_trigger = argv[++i]; + */ + } else if (strcasecmp("-l", argv[i]) == 0) { + setlevel = FALSE; + leveldebug = TRUE; + leveltype = SDL_atoi(argv[++i]); + currlevel = SDL_atoi(argv[++i]); + plr[0].plrlevel = currlevel; + } else if (strcasecmp("-m", argv[i]) == 0) { + monstdebug = TRUE; + DebugMonsters[debugmonsttypes++] = SDL_atoi(argv[++i]); + } else if (strcasecmp("-q", argv[i]) == 0) { + questdebug = SDL_atoi(argv[++i]); + } else if (strcasecmp("-r", argv[i]) == 0) { + setseed = SDL_atoi(argv[++i]); + } else if (strcasecmp("-s", argv[i]) == 0) { + debug_mode_key_s = 1; + } else if (strcasecmp("-t", argv[i]) == 0) { + leveldebug = TRUE; + setlevel = TRUE; + setlvlnum = SDL_atoi(argv[++i]); + } else if (strcasecmp("-v", argv[i]) == 0) { + visiondebug = TRUE; + } else if (strcasecmp("-w", argv[i]) == 0) { + debug_mode_key_w = 1; #endif - } + } else { + printf("unrecognized option '%s'\n", argv[i]); + print_help_and_exit(); } } } @@ -452,6 +408,8 @@ void diablo_init_screen() MouseX = SCREEN_WIDTH / 2; MouseY = SCREEN_HEIGHT / 2; + if (!sgbControllerActive) + SetCursorPos(MouseX, MouseY); ScrollInfo._sdx = 0; ScrollInfo._sdy = 0; ScrollInfo._sxoff = 0; @@ -503,7 +461,7 @@ BOOL PressEscKey() return rv; } -LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +LRESULT DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_KEYDOWN: @@ -512,6 +470,8 @@ LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM case WM_SYSKEYDOWN: case WM_SYSCOMMAND: case WM_MOUSEMOVE: + MouseX = (short)LOWORD(lParam); + MouseY = (short)HIWORD(lParam); return 0; case WM_LBUTTONDOWN: if (sgbMouseDown == 0) { @@ -542,7 +502,7 @@ LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM return MainWndProc(hWnd, uMsg, wParam, lParam); } -LRESULT CALLBACK GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +LRESULT GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_KEYDOWN: @@ -892,7 +852,7 @@ void PressKey(int vkey) } if (vkey == VK_ESCAPE) { if (!PressEscKey()) { - track_repeat_walk(0); + track_repeat_walk(FALSE); gamemenu_previous(); } return; @@ -924,7 +884,7 @@ void PressKey(int vkey) ClearPanel(); AddPanelString("No help available", TRUE); /// BUGFIX: message isn't displayed AddPanelString("while in stores", TRUE); - track_repeat_walk(0); + track_repeat_walk(FALSE); } else { invflag = 0; chrflag = FALSE; @@ -935,7 +895,7 @@ void PressKey(int vkey) sfx_stop(); } questlog = FALSE; - automapflag = 0; + automapflag = FALSE; msgdelay = 0; gamemenu_off(); DisplayHelp(); @@ -1044,7 +1004,7 @@ void PressKey(int vkey) SetCursorPos(MouseX - 160, MouseY); } helpflag = 0; - invflag = 0; + invflag = FALSE; chrflag = FALSE; sbookflag = FALSE; spselflag = 0; @@ -1053,7 +1013,7 @@ void PressKey(int vkey) sfx_stop(); } questlog = FALSE; - automapflag = 0; + automapflag = FALSE; msgdelay = 0; gamemenu_off(); doom_close(); @@ -1068,7 +1028,7 @@ void diablo_pause_game() } else { PauseMode = 2; FreeMonsterSnd(); - track_repeat_walk(0); + track_repeat_walk(FALSE); } force_redraw = 255; } @@ -1155,19 +1115,19 @@ void PressChar(int vkey) case 'S': case 's': if (!stextflag) { - invflag = 0; + invflag = FALSE; if (!spselflag) { DoSpeedBook(); } else { spselflag = 0; } - track_repeat_walk(0); + track_repeat_walk(FALSE); } return; case 'B': case 'b': if (!stextflag) { - invflag = 0; + invflag = FALSE; sbookflag = !sbookflag; } return; @@ -1683,7 +1643,6 @@ void game_loop(BOOL bStartup) } } - // Controller support: extern void plrctrls_after_game_logic(); diff --git a/Source/diablo.h b/Source/diablo.h index b5b05a718c1..aee94eac4c4 100644 --- a/Source/diablo.h +++ b/Source/diablo.h @@ -125,13 +125,13 @@ BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer); void run_game_loop(unsigned int uMsg); void start_game(unsigned int uMsg); void free_game(); -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); -void diablo_parse_flags(char *args); +int DiabloMain(int argc, char **argv); +void diablo_parse_flags(int argc, char **argv); void diablo_init_screen(); void diablo_reload_process(HINSTANCE hInstance); BOOL PressEscKey(); -LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +LRESULT DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +LRESULT GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL LeftMouseDown(int wParam); BOOL LeftMouseCmd(BOOL bShift); BOOL TryIconCurs(); @@ -158,8 +158,8 @@ void diablo_color_cyc_logic(); /* rdata */ extern BOOL fullscreen; -#ifdef _DEBUG extern int showintrodebug; +#ifdef _DEBUG extern int questdebug; extern int debug_mode_key_s; extern int debug_mode_key_w; @@ -180,7 +180,6 @@ extern BOOL FriendlyMode; extern char *spszMsgTbl[4]; extern char *spszMsgHotKeyTbl[4]; -#include "miniwin/popdecl.inc" DEVILUTION_END_NAMESPACE #endif /* __DIABLO_H__ */ diff --git a/Source/drlg_l2.cpp b/Source/drlg_l2.cpp index c9a16a83988..8ad90762d17 100644 --- a/Source/drlg_l2.cpp +++ b/Source/drlg_l2.cpp @@ -1,6 +1,5 @@ #ifndef SPAWN -#include #include #include "diablo.h" diff --git a/Source/drlg_l3.cpp b/Source/drlg_l3.cpp index 3475d8c9718..16afb736efb 100644 --- a/Source/drlg_l3.cpp +++ b/Source/drlg_l3.cpp @@ -1,6 +1,5 @@ #ifndef SPAWN -#include #include #include "diablo.h" diff --git a/Source/dthread.cpp b/Source/dthread.cpp index 06cae9b1a70..21a81bee663 100644 --- a/Source/dthread.cpp +++ b/Source/dthread.cpp @@ -73,7 +73,7 @@ void dthread_start() } } -unsigned int __stdcall dthread_handler(void *) +unsigned int dthread_handler(void *) { const char *error_buf; TMegaPkt *pkt; diff --git a/Source/dthread.h b/Source/dthread.h index 4ad5d3fb687..74c2f416b12 100644 --- a/Source/dthread.h +++ b/Source/dthread.h @@ -8,7 +8,7 @@ extern BOOLEAN dthread_running; void dthread_remove_player(int pnum); void dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen); void dthread_start(); -unsigned int __stdcall dthread_handler(void *); +unsigned int dthread_handler(void *); void dthread_cleanup(); /* data */ diff --git a/Source/effects.cpp b/Source/effects.cpp index b6382494776..c6346cfb165 100644 --- a/Source/effects.cpp +++ b/Source/effects.cpp @@ -1029,7 +1029,7 @@ BOOL calc_snd_position(int x, int y, int *plVolume, int *plPan) void PlaySFX(int psfx) { psfx = RndSFX(psfx); - PlaySFX_priv(&sgSFX[psfx], 0, 0, 0); + PlaySFX_priv(&sgSFX[psfx], FALSE, 0, 0); } void PlaySFX_priv(TSFX *pSFX, BOOL loc, int x, int y) @@ -1137,7 +1137,7 @@ void PlaySfxLoc(int psfx, int x, int y) pSnd->start_tc = 0; } - PlaySFX_priv(&sgSFX[psfx], 1, x, y); + PlaySFX_priv(&sgSFX[psfx], TRUE, x, y); } void FreeMonsterSnd() @@ -1233,7 +1233,7 @@ void sound_init() priv_sound_init(SFX_UI); } -void __stdcall effects_play_sound(char *snd_file) +void effects_play_sound(char *snd_file) { DWORD i; diff --git a/Source/effects.h b/Source/effects.h index 8ed845e6967..988f80e8361 100644 --- a/Source/effects.h +++ b/Source/effects.h @@ -26,7 +26,7 @@ void effects_cleanup_sfx(); void stream_update(); void priv_sound_init(BYTE bLoadMask); void sound_init(); -void __stdcall effects_play_sound(char *snd_file); +void effects_play_sound(char *snd_file); /* rdata */ diff --git a/Source/encrypt.cpp b/Source/encrypt.cpp index 6a90ad6004e..ecd0c61665f 100644 --- a/Source/encrypt.cpp +++ b/Source/encrypt.cpp @@ -111,7 +111,7 @@ int PkwareCompress(void *buf, int size) return size; } -unsigned int __cdecl PkwareBufferRead(char *buf, unsigned int *size, void *param) +unsigned int PkwareBufferRead(char *buf, unsigned int *size, void *param) { TDataInfo *pInfo; DWORD sSize; @@ -130,7 +130,7 @@ unsigned int __cdecl PkwareBufferRead(char *buf, unsigned int *size, void *param return sSize; } -void __cdecl PkwareBufferWrite(char *buf, unsigned int *size, void *param) +void PkwareBufferWrite(char *buf, unsigned int *size, void *param) { TDataInfo *pInfo; diff --git a/Source/encrypt.h b/Source/encrypt.h index 0d76b0f8557..80c0c9d2122 100644 --- a/Source/encrypt.h +++ b/Source/encrypt.h @@ -9,8 +9,8 @@ void Encrypt(void *block, DWORD size, DWORD key); DWORD Hash(const char *s, int type); void InitHash(); int PkwareCompress(void *buf, int size); -unsigned int __cdecl PkwareBufferRead(char *buf, unsigned int *size, void *param); -void __cdecl PkwareBufferWrite(char *buf, unsigned int *size, void *param); +unsigned int PkwareBufferRead(char *buf, unsigned int *size, void *param); +void PkwareBufferWrite(char *buf, unsigned int *size, void *param); void PkwareDecompress(void *param, int recv_size, int dwMaxBytes); #endif /* __ENCRYPT_H__ */ diff --git a/Source/engine.cpp b/Source/engine.cpp index f423abc25a5..f73a7358df4 100644 --- a/Source/engine.cpp +++ b/Source/engine.cpp @@ -1203,7 +1203,7 @@ void Cl2DrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) void PlayInGameMovie(char *pszMovie) { PaletteFadeOut(8); - play_movie(pszMovie, 0); + play_movie(pszMovie, FALSE); ClearScreenBuffer(); force_redraw = 255; scrollrt_draw_game_screen(1); diff --git a/Source/engine.h b/Source/engine.h index 087ad1d85a2..3255c778194 100644 --- a/Source/engine.h +++ b/Source/engine.h @@ -20,15 +20,13 @@ inline BYTE *CelGetFrameStart(BYTE *pCelBuff, int nCel) return pCelBuff + SwapLE32(pFrameTable[nCel]); } +#define LOAD_LE32(b) (((DWORD)(b)[3] << 24) | ((DWORD)(b)[2] << 16) | ((DWORD)(b)[1] << 8) | (DWORD)(b)[0]) inline BYTE *CelGetFrame(BYTE *pCelBuff, int nCel, int *nDataSize) { - DWORD *pFrameTable; DWORD nCellStart; - pFrameTable = (DWORD *)pCelBuff; - nCellStart = SwapLE32(pFrameTable[nCel]); - *nDataSize = SwapLE32(pFrameTable[nCel + 1]) - nCellStart; - + nCellStart = LOAD_LE32(&pCelBuff[nCel * 4]); + *nDataSize = LOAD_LE32(&pCelBuff[(nCel+1) * 4]) - nCellStart; return pCelBuff + nCellStart; } diff --git a/Source/help.cpp b/Source/help.cpp index 4002cf027a0..be65dc4816d 100644 --- a/Source/help.cpp +++ b/Source/help.cpp @@ -452,7 +452,7 @@ void DrawHelp() DrawSTextHelp(); DrawQTextBack(); - PrintSString(0, 2, 1, "Diablo Help", COL_GOLD, 0); + PrintSString(0, 2, TRUE, "Diablo Help", COL_GOLD, 0); DrawSLine(5); s = gszHelpText; @@ -530,7 +530,7 @@ void DrawHelp() } } - PrintSString(0, 23, 1, "Press ESC to end or the arrow keys to scroll.", COL_GOLD, 0); + PrintSString(0, 23, TRUE, "Press ESC to end or the arrow keys to scroll.", COL_GOLD, 0); } void DrawHelpLine(int always_0, int help_line_nr, char *text, char color) diff --git a/Source/init.cpp b/Source/init.cpp index 939e0664c8d..f38b35345ad 100644 --- a/Source/init.cpp +++ b/Source/init.cpp @@ -114,7 +114,7 @@ void init_get_file_info() snprintf(gszVersionNumber, MAX_PATH, "version %s", PROJECT_VERSION); } -LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +LRESULT MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_ERASEBKGND: diff --git a/Source/init.h b/Source/init.h index 7f900d51e44..5f3a4e11489 100644 --- a/Source/init.h +++ b/Source/init.h @@ -19,7 +19,7 @@ void init_create_window(); void init_archives(); HANDLE init_test_access(char *mpq_path, char *mpq_name, char *reg_loc, int flags, int fs); void init_get_file_info(); -LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void init_activate_window(HWND hWnd, BOOL bActive); WNDPROC SetWindowProc(WNDPROC NewProc); diff --git a/Source/inv.cpp b/Source/inv.cpp index 3323373d9c2..647244f37dd 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -107,7 +107,7 @@ void InitInv() #endif } - invflag = 0; + invflag = FALSE; drawsbarflag = FALSE; } @@ -810,7 +810,7 @@ void CheckInvPaste(int pnum, int mx, int my) } break; case ILOC_AMULET: - NetSendCmdChItem(0, INVLOC_AMULET); + NetSendCmdChItem(FALSE, INVLOC_AMULET); if (plr[pnum].InvBody[INVLOC_AMULET]._itype == ITYPE_NONE) plr[pnum].InvBody[INVLOC_AMULET] = plr[pnum].HoldItem; else @@ -1046,7 +1046,7 @@ void CheckInvPaste(int pnum, int mx, int my) if (plr[pnum].HoldItem._itype == 11) plr[pnum]._pGold = CalculateGold(pnum); } - drawsbarflag = 1; + drawsbarflag = TRUE; break; } CalcPlrInv(pnum, TRUE); @@ -1606,7 +1606,7 @@ void AutoGetItem(int pnum, int ii) } } plr[pnum].HoldItem = item[ii]; - RespawnItem(ii, 1); + RespawnItem(ii, TRUE); NetSendCmdPItem(TRUE, CMD_RESPAWNITEM, item[ii]._ix, item[ii]._iy); plr[pnum].HoldItem._itype = ITYPE_NONE; } @@ -1806,7 +1806,7 @@ int InvPutItem(int pnum, int x, int y) item[ii] = plr[pnum].HoldItem; item[ii]._ix = x; item[ii]._iy = y; - RespawnItem(ii, 1); + RespawnItem(ii, TRUE); numitems++; SetCursor_(CURSOR_HAND); return ii; @@ -1885,7 +1885,7 @@ int SyncPutItem(int pnum, int x, int y, int idx, WORD icreateinfo, int iseed, in item[ii]._ix = x; item[ii]._iy = y; - RespawnItem(ii, 1); + RespawnItem(ii, TRUE); numitems++; return ii; } diff --git a/Source/items.cpp b/Source/items.cpp index b4ea94e6c03..9af554e94ee 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -2071,7 +2071,7 @@ void SetupAllItems(int ii, int idx, int iseed, int lvl, int uper, int onlygood, iblvl = lvl + 4; if (iblvl != -1) { uid = CheckUnique(ii, iblvl, uper, recreate); - if (uid == -1) { + if (uid == UITYPE_INVALID) { GetItemBonus(ii, idx, iblvl >> 1, iblvl, onlygood); } else { GetUniqueItem(ii, uid); @@ -2968,30 +2968,30 @@ void DrawUniqueInfo() if ((!chrflag && !questlog) || SCREEN_WIDTH >= SPANEL_WIDTH * 3) { uid = curruitem._iUid; DrawUTextBack(); - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, 2, 1, UniqueItemList[uid].UIName, 3); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, 2, TRUE, UniqueItemList[uid].UIName, 3); DrawULine(5); PrintItemPower(UniqueItemList[uid].UIPower1, &curruitem); y = 6 - UniqueItemList[uid].UINumPL + 8; - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y, 1, tempstr, 0); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y, TRUE, tempstr, 0); if (UniqueItemList[uid].UINumPL > 1) { PrintItemPower(UniqueItemList[uid].UIPower2, &curruitem); - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 2, 1, tempstr, 0); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 2, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 2) { PrintItemPower(UniqueItemList[uid].UIPower3, &curruitem); - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 4, 1, tempstr, 0); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 4, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 3) { PrintItemPower(UniqueItemList[uid].UIPower4, &curruitem); - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 6, 1, tempstr, 0); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 6, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 4) { PrintItemPower(UniqueItemList[uid].UIPower5, &curruitem); - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 8, 1, tempstr, 0); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 8, TRUE, tempstr, 0); } if (UniqueItemList[uid].UINumPL > 5) { PrintItemPower(UniqueItemList[uid].UIPower6, &curruitem); - PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 10, 1, tempstr, 0); + PrintUString(0 + RIGHT_PANEL - SPANEL_WIDTH, y + 10, TRUE, tempstr, 0); } } } @@ -3451,7 +3451,7 @@ void SpawnOnePremium(int i, int plvl) SetRndSeed(item[0]._iSeed); itype = RndPremiumItem(plvl >> 2, plvl) - 1; GetItemAttrs(0, itype, plvl); - GetItemBonus(0, itype, plvl >> 1, plvl, 1); + GetItemBonus(0, itype, plvl >> 1, plvl, TRUE); } while (item[0]._iIvalue > SMITH_MAX_PREMIUM_VALUE); premiumitem[i] = item[0]; premiumitem[i]._iCreateInfo = plvl | 0x800; @@ -3597,7 +3597,7 @@ void SpawnWitch(int lvl) if (maxlvl == -1 && item[0]._iMiscId == IMISC_STAFF) maxlvl = 2 * lvl; if (maxlvl != -1) - GetItemBonus(0, idata, maxlvl >> 1, maxlvl, 1); + GetItemBonus(0, idata, maxlvl >> 1, maxlvl, TRUE); } while (item[0]._iIvalue > 140000); witchitem[i] = item[0]; witchitem[i]._iCreateInfo = lvl | 0x2000; @@ -3638,7 +3638,7 @@ void SpawnBoy(int lvl) SetRndSeed(item[0]._iSeed); itype = RndBoyItem(lvl) - 1; GetItemAttrs(0, itype, lvl); - GetItemBonus(0, itype, lvl, 2 * lvl, 1); + GetItemBonus(0, itype, lvl, 2 * lvl, TRUE); } while (item[0]._iIvalue > 90000); boyitem = item[0]; boyitem._iCreateInfo = lvl | 0x1000; @@ -3800,7 +3800,7 @@ void RecreatePremiumItem(int ii, int idx, int plvl, int iseed) SetRndSeed(iseed); itype = RndPremiumItem(plvl >> 2, plvl) - 1; GetItemAttrs(ii, itype, plvl); - GetItemBonus(ii, itype, plvl >> 1, plvl, 1); + GetItemBonus(ii, itype, plvl >> 1, plvl, TRUE); item[ii]._iSeed = iseed; item[ii]._iCreateInfo = plvl | 0x800; @@ -3814,7 +3814,7 @@ void RecreateBoyItem(int ii, int idx, int lvl, int iseed) SetRndSeed(iseed); itype = RndBoyItem(lvl) - 1; GetItemAttrs(ii, itype, lvl); - GetItemBonus(ii, itype, lvl, 2 * lvl, 1); + GetItemBonus(ii, itype, lvl, 2 * lvl, TRUE); item[ii]._iSeed = iseed; item[ii]._iCreateInfo = lvl | 0x1000; item[ii]._iIdentified = TRUE; @@ -3836,7 +3836,7 @@ void RecreateWitchItem(int ii, int idx, int lvl, int iseed) if (iblvl == -1 && item[ii]._iMiscId == IMISC_STAFF) iblvl = 2 * lvl; if (iblvl != -1) - GetItemBonus(ii, itype, iblvl >> 1, iblvl, 1); + GetItemBonus(ii, itype, iblvl >> 1, iblvl, TRUE); } item[ii]._iSeed = iseed; diff --git a/Source/lighting.cpp b/Source/lighting.cpp index 2c56c6e3aad..8ecf8f4131b 100644 --- a/Source/lighting.cpp +++ b/Source/lighting.cpp @@ -1285,8 +1285,8 @@ void lighting_color_cycling() tbl[0] = tbl[1]; tbl++; } - *tbl++ = col; - tbl += 224; + *tbl = col; + tbl += 225; } } diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 515d41674da..9c91c8abb8a 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -221,42 +221,49 @@ void CopyChar(const void *src, void *dst) void CopyShort(const void *src, void *dst) { - *(unsigned short*)dst = SwapLE16(*(unsigned short*)src); + unsigned short buf; + memcpy(&buf, src, 2); tbuff += 2; + buf = SwapLE16(buf); + memcpy(dst, &buf, 2); } void CopyShorts(const void *src, const int n, void *dst) { - unsigned short *s=src, *d=dst; - int i=n; - tbuff += 2*n; - while(i) { - *d = SwapLE16(*s); - ++d; ++s; --i; + const auto *s = reinterpret_cast(src); + auto *d = reinterpret_cast(dst); + for(int i = 0; i < n; i++) { + CopyShort(s, d); + ++d; ++s; } } void CopyInt(const void *src, void *dst) { - *(unsigned int*)dst = SwapLE32(*(unsigned int*)src); + unsigned int buf; + memcpy(&buf, src, 4); tbuff += 4; + buf = SwapLE32(buf); + memcpy(dst, &buf, 4); } void CopyInts(const void *src, const int n, void *dst) { - unsigned int *s=src, *d=dst; - int i=n; - tbuff += 4*n; - while(i) { - *d = SwapLE32(*s); - ++d; ++s; --i; + const auto *s = reinterpret_cast(src); + auto *d = reinterpret_cast(dst); + for(int i = 0; i < n; i++) { + CopyInt(s, d); + ++d; ++s; } } void CopyInt64(const void *src, void *dst) { - *(unsigned long long*)dst = SDL_SwapLE64(*(unsigned long long*)src); + unsigned long long buf; + memcpy(&buf, src, 8); tbuff += 8; + buf = SDL_SwapLE64(buf); + memcpy(dst, &buf, 8); } void LoadPlayer(int i) @@ -1706,7 +1713,7 @@ void LoadLevel() AutomapZoomReset(); ResyncQuests(); SyncPortals(); - dolighting = 1; + dolighting = TRUE; for (i = 0; i < MAX_PLRS; i++) { if (plr[i].plractive && currlevel == plr[i].plrlevel) diff --git a/Source/mainmenu.cpp b/Source/mainmenu.cpp index e762a939245..29f779df57b 100644 --- a/Source/mainmenu.cpp +++ b/Source/mainmenu.cpp @@ -22,13 +22,13 @@ void mainmenu_refresh_music() #endif } -void __stdcall mainmenu_change_name(int arg1, int arg2, int arg3, int arg4, char *name_1, char *name_2) +void mainmenu_change_name(int arg1, int arg2, int arg3, int arg4, char *name_1, char *name_2) { if (UiValidPlayerName(name_2)) pfile_rename_hero(name_1, name_2); } -int __stdcall mainmenu_select_hero_dialog( +int mainmenu_select_hero_dialog( const _SNETPROGRAMDATA *client_info, const _SNETPLAYERDATA *user_info, const _SNETUIDATA *ui_info, @@ -159,7 +159,7 @@ BOOL mainmenu_multi_player() void mainmenu_play_intro() { music_stop(); - play_movie("gendata\\diablo1.smk", 1); + play_movie("gendata\\diablo1.smk", TRUE); mainmenu_refresh_music(); } #endif diff --git a/Source/mainmenu.h b/Source/mainmenu.h index c2bc0dd637c..f7259d3b61d 100644 --- a/Source/mainmenu.h +++ b/Source/mainmenu.h @@ -5,8 +5,8 @@ extern char gszHero[16]; void mainmenu_refresh_music(); -void __stdcall mainmenu_change_name(int arg1, int arg2, int arg3, int arg4, char *name_1, char *name_2); -int __stdcall mainmenu_select_hero_dialog( +void mainmenu_change_name(int arg1, int arg2, int arg3, int arg4, char *name_1, char *name_2); +int mainmenu_select_hero_dialog( const _SNETPROGRAMDATA *client_info, const _SNETPLAYERDATA *user_info, const _SNETUIDATA *ui_info, diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 9104c6e4822..5c23e5b2ca7 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -821,7 +821,7 @@ BOOL PlayerMHit(int pnum, int m, int dist, int mind, int maxd, int mtype, BOOLEA if (plr[pnum]._pHitPoints >> 6 <= 0) { SyncPlrKill(pnum, earflag); } else { - StartPlrHit(pnum, dam, 0); + StartPlrHit(pnum, dam, FALSE); } } } @@ -935,7 +935,7 @@ BOOL Plr2PlrMHit(int pnum, int p, int mindam, int maxdam, int dist, int mtype, B } else { if (pnum == myplr) NetSendCmdDamage(TRUE, p, dam); - StartPlrHit(p, dam, 0); + StartPlrHit(p, dam, FALSE); } } return TRUE; @@ -1067,6 +1067,10 @@ void SetMissAnim(int mi, int animtype) { int dir = missile[mi]._mimfnum; + if (animtype > MFILE_NULL) { + animtype = MFILE_NULL; + } + missile[mi]._miAnimType = animtype; missile[mi]._miAnimFlags = misfiledata[animtype].mFlags; missile[mi]._miAnimData = misfiledata[animtype].mAnimData[dir]; @@ -1176,7 +1180,7 @@ void InitMissiles() if (missile[mi]._mitype == MIS_INFRA) { src = missile[mi]._misource; if (src == myplr) - CalcPlrItemVals(src, 1); + CalcPlrItemVals(src, TRUE); } } } @@ -2092,7 +2096,7 @@ void AddIdentify(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy if (sbookflag) sbookflag = FALSE; if (!invflag) { - invflag = 1; + invflag = TRUE; if (sgbControllerActive) FocusOnInventory(); } @@ -2193,7 +2197,7 @@ void AddRepair(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy, if (sbookflag) sbookflag = FALSE; if (!invflag) { - invflag = 1; + invflag = TRUE; if (sgbControllerActive) FocusOnInventory(); } @@ -2209,7 +2213,7 @@ void AddRecharge(int mi, int sx, int sy, int dx, int dy, int midir, char mienemy if (sbookflag) sbookflag = FALSE; if (!invflag) { - invflag = 1; + invflag = TRUE; if (sgbControllerActive) FocusOnInventory(); } @@ -2583,7 +2587,7 @@ void MI_LArrow(int i) maxd = random_(68, 10) + 1 + currlevel * 2; } missiledata[MIS_LARROW].mResist = MISR_LIGHTNING; - CheckMissileCol(i, mind, maxd, 0, missile[i]._mix, missile[i]._miy, 1); + CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, TRUE); } if (missile[i]._mitype == MIS_FARROW) { if (p != -1) { @@ -2594,7 +2598,7 @@ void MI_LArrow(int i) maxd = random_(68, 10) + 1 + currlevel * 2; } missiledata[MIS_FARROW].mResist = MISR_FIRE; - CheckMissileCol(i, mind, maxd, 0, missile[i]._mix, missile[i]._miy, 1); + CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, TRUE); } missiledata[missile[i]._mitype].mResist = rst; } else { @@ -2619,7 +2623,7 @@ void MI_LArrow(int i) if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) { rst = missiledata[missile[i]._mitype].mResist; missiledata[missile[i]._mitype].mResist = 0; - CheckMissileCol(i, mind, maxd, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE); missiledata[missile[i]._mitype].mResist = rst; } if (!missile[i]._mirange) { @@ -2670,7 +2674,7 @@ void MI_Arrow(int i) maxd = 2 * currlevel; } if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) - CheckMissileCol(i, mind, maxd, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (!missile[i]._mirange) missile[i]._miDelFlag = TRUE; PutMissile(i); @@ -2709,7 +2713,7 @@ void MI_Firebolt(int i) d = currlevel + random_(78, 2 * currlevel); } if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) { - CheckMissileCol(i, d, d, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, d, d, FALSE, missile[i]._mix, missile[i]._miy, FALSE); } if (!missile[i]._mirange) { missile[i]._miDelFlag = TRUE; @@ -2768,7 +2772,7 @@ void MI_Lightball(int i) missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); j = missile[i]._mirange; - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = j; obj = dObject[tx][ty]; @@ -2792,7 +2796,7 @@ void mi_null_33(int i) missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (!missile[i]._mirange) missile[i]._miDelFlag = TRUE; PutMissile(i); @@ -2804,7 +2808,7 @@ void MI_Acidpud(int i) missile[i]._mirange--; range = missile[i]._mirange; - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE); missile[i]._mirange = range; if (!range) { if (missile[i]._mimfnum) { @@ -2831,7 +2835,7 @@ void MI_Firewall(int i) missile[i]._miAnimFrame = 13; missile[i]._miAnimAdd = -1; } - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 1); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, TRUE); if (!missile[i]._mirange) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); @@ -2871,29 +2875,29 @@ void MI_Fireball(int i) missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) - CheckMissileCol(i, dam, dam, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, dam, dam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (!missile[i]._mirange) { mx = missile[i]._mix; my = missile[i]._miy; ChangeLight(missile[i]._mlid, missile[i]._mix, my, missile[i]._miAnimFrame); if (!CheckBlock(px, py, mx, my)) - CheckMissileCol(i, dam, dam, 0, mx, my, 1); + CheckMissileCol(i, dam, dam, FALSE, mx, my, TRUE); if (!CheckBlock(px, py, mx, my + 1)) - CheckMissileCol(i, dam, dam, 0, mx, my + 1, 1); + CheckMissileCol(i, dam, dam, FALSE, mx, my + 1, TRUE); if (!CheckBlock(px, py, mx, my - 1)) - CheckMissileCol(i, dam, dam, 0, mx, my - 1, 1); + CheckMissileCol(i, dam, dam, FALSE, mx, my - 1, TRUE); if (!CheckBlock(px, py, mx + 1, my)) - CheckMissileCol(i, dam, dam, 0, mx + 1, my, 1); + CheckMissileCol(i, dam, dam, FALSE, mx + 1, my, TRUE); if (!CheckBlock(px, py, mx + 1, my - 1)) - CheckMissileCol(i, dam, dam, 0, mx + 1, my - 1, 1); + CheckMissileCol(i, dam, dam, FALSE, mx + 1, my - 1, TRUE); if (!CheckBlock(px, py, mx + 1, my + 1)) - CheckMissileCol(i, dam, dam, 0, mx + 1, my + 1, 1); + CheckMissileCol(i, dam, dam, FALSE, mx + 1, my + 1, TRUE); if (!CheckBlock(px, py, mx - 1, my)) - CheckMissileCol(i, dam, dam, 0, mx - 1, my, 1); + CheckMissileCol(i, dam, dam, FALSE, mx - 1, my, TRUE); if (!CheckBlock(px, py, mx - 1, my + 1)) - CheckMissileCol(i, dam, dam, 0, mx - 1, my + 1, 1); + CheckMissileCol(i, dam, dam, FALSE, mx - 1, my + 1, TRUE); if (!CheckBlock(px, py, mx - 1, my - 1)) - CheckMissileCol(i, dam, dam, 0, mx - 1, my - 1, 1); + CheckMissileCol(i, dam, dam, FALSE, mx - 1, my - 1, TRUE); if (!TransList[dTransVal[mx][my]] || (missile[i]._mixvel < 0 && ((TransList[dTransVal[mx][my + 1]] && nSolidTable[dPiece[mx][my + 1]]) || (TransList[dTransVal[mx][my - 1]] && nSolidTable[dPiece[mx][my - 1]])))) { missile[i]._mix++; @@ -3018,7 +3022,7 @@ void MI_Lightning(int i) missile[i]._mirange--; j = missile[i]._mirange; if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = j; if (!missile[i]._mirange) { @@ -3068,12 +3072,12 @@ void MI_Flash(int i) plr[missile[i]._misource]._pInvincible = TRUE; } missile[i]._mirange--; - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix - 1, missile[i]._miy, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix + 1, missile[i]._miy, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix - 1, missile[i]._miy + 1, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy + 1, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix + 1, missile[i]._miy + 1, 1); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy + 1, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy + 1, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy + 1, TRUE); if (!missile[i]._mirange) { missile[i]._miDelFlag = TRUE; if (missile[i]._micaster == 0) { @@ -3091,9 +3095,9 @@ void MI_Flash2(int i) plr[missile[i]._misource]._pInvincible = TRUE; } missile[i]._mirange--; - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix - 1, missile[i]._miy - 1, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy - 1, 1); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix + 1, missile[i]._miy - 1, 1); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix - 1, missile[i]._miy - 1, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy - 1, TRUE); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix + 1, missile[i]._miy - 1, TRUE); if (!missile[i]._mirange) { missile[i]._miDelFlag = TRUE; if (missile[i]._micaster == 0) { @@ -3228,7 +3232,7 @@ void MI_Firemove(int i) missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); j = missile[i]._mirange; - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) missile[i]._mirange = j; if (!missile[i]._mirange) { @@ -3386,7 +3390,7 @@ void MI_Weapexp(int i) maxd = plr[id]._pILMaxDam; missiledata[missile[i]._mitype].mResist = MISR_LIGHTNING; } - CheckMissileCol(i, mind, maxd, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, mind, maxd, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (!missile[i]._miVar1) { missile[i]._mlid = AddLight(missile[i]._mix, missile[i]._miy, 9); } else { @@ -3502,7 +3506,7 @@ void MI_Boom(int i) { missile[i]._mirange--; if (!missile[i]._miVar1) - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 0, missile[i]._mix, missile[i]._miy, 1); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, TRUE); if (missile[i]._miHitFlag == TRUE) missile[i]._miVar1 = 1; if (!missile[i]._mirange) @@ -3764,7 +3768,7 @@ void MI_Flame(int i) missile[i]._mirange--; missile[i]._miVar2--; k = missile[i]._mirange; - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 1, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, TRUE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._mirange == 0 && missile[i]._miHitFlag == TRUE) missile[i]._mirange = k; if (!missile[i]._miVar2) @@ -3835,7 +3839,7 @@ void MI_Cbolt(int i) missile[i]._mitxoff += missile[i]._mixvel; missile[i]._mityoff += missile[i]._miyvel; GetMissilePos(i); - CheckMissileCol(i, missile[i]._midam, missile[i]._midam, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, missile[i]._midam, missile[i]._midam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); if (missile[i]._miHitFlag == TRUE) { missile[i]._miVar1 = 8; missile[i]._mimfnum = 0; @@ -3865,7 +3869,7 @@ void MI_Hbolt(int i) GetMissilePos(i); dam = missile[i]._midam; if (missile[i]._mix != missile[i]._misx || missile[i]._miy != missile[i]._misy) { - CheckMissileCol(i, dam, dam, 0, missile[i]._mix, missile[i]._miy, 0); + CheckMissileCol(i, dam, dam, FALSE, missile[i]._mix, missile[i]._miy, FALSE); } if (!missile[i]._mirange) { missile[i]._mitxoff -= missile[i]._mixvel; @@ -3905,23 +3909,23 @@ void MI_Element(int i) py = plr[id].WorldY; ChangeLight(missile[i]._mlid, cx, cy, missile[i]._miAnimFrame); if (!CheckBlock(px, py, cx, cy)) - CheckMissileCol(i, dam, dam, 1, cx, cy, 1); + CheckMissileCol(i, dam, dam, TRUE, cx, cy, TRUE); if (!CheckBlock(px, py, cx, cy + 1)) - CheckMissileCol(i, dam, dam, 1, cx, cy + 1, 1); + CheckMissileCol(i, dam, dam, TRUE, cx, cy + 1, TRUE); if (!CheckBlock(px, py, cx, cy - 1)) - CheckMissileCol(i, dam, dam, 1, cx, cy - 1, 1); + CheckMissileCol(i, dam, dam, TRUE, cx, cy - 1, TRUE); if (!CheckBlock(px, py, cx + 1, cy)) - CheckMissileCol(i, dam, dam, 1, cx + 1, cy, 1); /* check x/y */ + CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy, TRUE); /* check x/y */ if (!CheckBlock(px, py, cx + 1, cy - 1)) - CheckMissileCol(i, dam, dam, 1, cx + 1, cy - 1, 1); + CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy - 1, TRUE); if (!CheckBlock(px, py, cx + 1, cy + 1)) - CheckMissileCol(i, dam, dam, 1, cx + 1, cy + 1, 1); + CheckMissileCol(i, dam, dam, TRUE, cx + 1, cy + 1, TRUE); if (!CheckBlock(px, py, cx - 1, cy)) - CheckMissileCol(i, dam, dam, 1, cx - 1, cy, 1); + CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy, TRUE); if (!CheckBlock(px, py, cx - 1, cy + 1)) - CheckMissileCol(i, dam, dam, 1, cx - 1, cy + 1, 1); + CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy + 1, TRUE); if (!CheckBlock(px, py, cx - 1, cy - 1)) - CheckMissileCol(i, dam, dam, 1, cx - 1, cy - 1, 1); + CheckMissileCol(i, dam, dam, TRUE, cx - 1, cy - 1, TRUE); if (!missile[i]._mirange) { missile[i]._miDelFlag = TRUE; AddUnLight(missile[i]._mlid); @@ -3932,7 +3936,7 @@ void MI_Element(int i) GetMissilePos(i); cx = missile[i]._mix; cy = missile[i]._miy; - CheckMissileCol(i, dam, dam, 0, cx, cy, 0); + CheckMissileCol(i, dam, dam, FALSE, cx, cy, FALSE); if (!missile[i]._miVar3 && cx == missile[i]._miVar4 && cy == missile[i]._miVar5) missile[i]._miVar3 = 1; if (missile[i]._miVar3 == 1) { @@ -3984,7 +3988,7 @@ void MI_Bonespirit(int i) GetMissilePos(i); cx = missile[i]._mix; cy = missile[i]._miy; - CheckMissileCol(i, dam, dam, FALSE, cx, cy, 0); + CheckMissileCol(i, dam, dam, FALSE, cx, cy, FALSE); if (missile[i]._miVar3 == 0 && cx == missile[i]._miVar4 && cy == missile[i]._miVar5) missile[i]._miVar3 = 1; if (missile[i]._miVar3 == 1) { diff --git a/Source/monstdat.cpp b/Source/monstdat.cpp index 0e1a0e1adbd..c94cf7fd4c7 100644 --- a/Source/monstdat.cpp +++ b/Source/monstdat.cpp @@ -222,7 +222,7 @@ BYTE MonstAvailTbl[] = { 2, // Storm Rider 2, // Storm Lord 2, // Maelstorm - 2, // Devil Kin Brute + 0, // Devil Kin Brute 2, // Winged-Demon 2, // Gargoyle 2, // Blood Claw diff --git a/Source/monster.cpp b/Source/monster.cpp index fe61c03a3cf..1909b570037 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -1042,9 +1042,9 @@ void SetMapMonsters(BYTE *pMap, int startx, int starty) PlaceUniqueMonst(UMT_BLACKJADE, 0, 0); } lm = (WORD *)pMap; - rw = SwapLE16(*lm); + rw = SDL_SwapLE16(*lm); lm++; - rh = SwapLE16(*lm); + rh = SDL_SwapLE16(*lm); lm += (rw * rh + 1); rw = rw << 1; rh = rh << 1; @@ -1053,7 +1053,7 @@ void SetMapMonsters(BYTE *pMap, int startx, int starty) for (j = 0; j < rh; j++) { for (i = 0; i < rw; i++) { if (*lm) { - mtype = AddMonsterType(MonstConvTbl[SwapLE16(*lm) - 1], 2); + mtype = AddMonsterType(MonstConvTbl[SDL_SwapLE16(*lm) - 1], 2); PlaceMonster(nummonsters++, mtype, i + startx + 16, j + starty + 16); } lm++; @@ -1651,7 +1651,7 @@ void MonstStartKill(int i, int pnum, BOOL sendmsg) monster[i]._mhitpoints = 0; SetRndSeed(monster[i]._mRndSeed); if (QuestStatus(QTYPE_GARB) && monster[i].mName == UniqMonst[UMT_GARBUD].mName) { - CreateTypeItem(monster[i]._mx + 1, monster[i]._my + 1, TRUE, 4, FALSE, TRUE, FALSE); + CreateTypeItem(monster[i]._mx + 1, monster[i]._my + 1, TRUE, 4, 0, TRUE, FALSE); } else if (i > 3) { SpawnItem(i, monster[i]._mx, monster[i]._my, sendmsg); } @@ -2151,7 +2151,7 @@ void M_TryH2HHit(int i, int pnum, int Hit, int MinDam, int MaxDam) SyncPlrKill(pnum, 0); return; } - StartPlrHit(pnum, dam, 0); + StartPlrHit(pnum, dam, FALSE); if (monster[i]._mFlags & MFLAG_KNOCKBACK) { if (plr[pnum]._pmode != PM_GOTHIT) StartPlrHit(pnum, 0, TRUE); @@ -2404,7 +2404,7 @@ int M_DoTalk(int i) && !(Monst->_mFlags & MFLAG_QUEST_COMPLETE)) { quests[QTYPE_ZHAR]._qactive = 2; quests[QTYPE_ZHAR]._qlog = TRUE; - CreateTypeItem(Monst->_mx + 1, Monst->_my + 1, FALSE, 0, 24, TRUE, 0); + CreateTypeItem(Monst->_mx + 1, Monst->_my + 1, FALSE, 0, 24, TRUE, FALSE); Monst->_mFlags |= MFLAG_QUEST_COMPLETE; } if (Monst->mName == UniqMonst[UMT_SNOTSPIL].mName) { @@ -2539,13 +2539,13 @@ void DoEnding() #ifndef SPAWN if (plr[myplr]._pClass == PC_WARRIOR) { - play_movie("gendata\\DiabVic2.smk", 0); + play_movie("gendata\\DiabVic2.smk", FALSE); } else if (plr[myplr]._pClass == PC_SORCERER) { - play_movie("gendata\\DiabVic1.smk", 0); + play_movie("gendata\\DiabVic1.smk", FALSE); } else { - play_movie("gendata\\DiabVic3.smk", 0); + play_movie("gendata\\DiabVic3.smk", FALSE); } - play_movie("gendata\\Diabend.smk", 0); + play_movie("gendata\\Diabend.smk", FALSE); bMusicOn = gbMusicOn; gbMusicOn = TRUE; @@ -2555,7 +2555,7 @@ void DoEnding() music_start(TMUSIC_L2); loop_movie = TRUE; - play_movie("gendata\\loopdend.smk", 1); + play_movie("gendata\\loopdend.smk", TRUE); loop_movie = FALSE; music_stop(); @@ -5083,7 +5083,7 @@ void PrintMonstHistory(int mt) } } } - pinfoflag = 1; + pinfoflag = TRUE; } void PrintUniqueHistory() @@ -5152,7 +5152,7 @@ void MissToMonst(int i, int x, int y) M_TryH2HHit(m, dPlayer[oldx][oldy] - 1, 500, Monst->mMinDamage2, Monst->mMaxDamage2); if (pnum == dPlayer[oldx][oldy] - 1 && (Monst->MType->mtype < MT_NSNAKE || Monst->MType->mtype > MT_GSNAKE)) { if (plr[pnum]._pmode != 7 && plr[pnum]._pmode != 8) - StartPlrHit(pnum, 0, 1); + StartPlrHit(pnum, 0, TRUE); newx = oldx + offset_x[Monst->_mdir]; newy = oldy + offset_y[Monst->_mdir]; if (PosOkPlayer(pnum, newx, newy)) { @@ -5327,7 +5327,7 @@ int M_SpawnSkel(int x, int y, int dir) if (IsSkel(Monsters[i].mtype)) j++; } - skel = AddMonster(x, y, dir, i - 1, 1); + skel = AddMonster(x, y, dir, i - 1, TRUE); if (skel != -1) M_StartSpStand(skel, dir); @@ -5422,7 +5422,7 @@ int PreSpawnSkeleton() if (IsSkel(Monsters[i].mtype)) j++; } - skel = AddMonster(0, 0, 0, i - 1, 0); + skel = AddMonster(0, 0, 0, i - 1, FALSE); if (skel != -1) M_StartStand(skel, 0); diff --git a/Source/monster.h b/Source/monster.h index 45d884df7a5..4411b223ae4 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -6,6 +6,7 @@ extern int MissileFileFlag; extern int monstkills[MAXMONSTERS]; extern int monstactive[MAXMONSTERS]; extern int nummonsters; +extern BOOLEAN sgbSaveSoundOn; extern MonsterStruct monster[MAXMONSTERS]; extern int totalmonsters; extern CMonster Monsters[MAX_LVLMTYPES]; diff --git a/Source/movie.cpp b/Source/movie.cpp index 115c14876b1..fb31647cde1 100644 --- a/Source/movie.cpp +++ b/Source/movie.cpp @@ -1,5 +1,6 @@ #include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" +#include "../SourceX/miniwin/ddraw.h" DEVILUTION_BEGIN_NAMESPACE @@ -19,17 +20,16 @@ void play_movie(char *pszMovie, BOOL user_can_close) MSG Msg; while (video_stream && movie_playing) { while (movie_playing && PeekMessage(&Msg)) { - TranslateMessage(&Msg); switch (Msg.message) { case WM_KEYDOWN: - case WM_CHAR: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: - if (user_can_close || (Msg.message == WM_CHAR && Msg.wParam == VK_ESCAPE)) + if (user_can_close || (Msg.message == WM_KEYDOWN && Msg.wParam == VK_ESCAPE)) movie_playing = FALSE; break; case WM_QUIT: - movie_playing = FALSE; + SVidPlayEnd(video_stream); + exit(0); break; } } @@ -40,6 +40,8 @@ void play_movie(char *pszMovie, BOOL user_can_close) SVidPlayEnd(video_stream); sound_disable_music(FALSE); movie_playing = FALSE; + SDL_GetMouseState(&MouseX, &MouseY); + OutputToLogical(&MouseX, &MouseY); } DEVILUTION_END_NAMESPACE diff --git a/Source/movie.h b/Source/movie.h index 03fcab32bbe..2df65c6aa4f 100644 --- a/Source/movie.h +++ b/Source/movie.h @@ -6,7 +6,7 @@ extern BYTE movie_playing; extern BOOL loop_movie; void play_movie(char *pszMovie, BOOL user_can_close); -LRESULT __stdcall MovieWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +LRESULT MovieWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); /* rdata */ diff --git a/Source/mpqapi.cpp b/Source/mpqapi.cpp index ac11a4ca28b..c249f050c85 100644 --- a/Source/mpqapi.cpp +++ b/Source/mpqapi.cpp @@ -15,21 +15,6 @@ _BLOCKENTRY *sgpBlockTbl; HANDLE sghArchive = INVALID_HANDLE_VALUE; -BOOL mpqapi_set_hidden(const char *pszArchive, BOOL hidden) -{ - DWORD dwFileAttributes; - DWORD dwFileAttributesToSet; - - dwFileAttributes = GetFileAttributes(pszArchive); - if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) - return GetLastError() == ERROR_FILE_NOT_FOUND; - dwFileAttributesToSet = hidden ? FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN : 0; - if (dwFileAttributes == dwFileAttributesToSet) - return TRUE; - else - return SetFileAttributes(pszArchive, dwFileAttributesToSet); -} - void mpqapi_remove_hash_entry(const char *pszName) { _HASHENTRY *pHashTbl; @@ -130,7 +115,7 @@ int mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale) return -1; } -void mpqapi_remove_hash_entries(BOOL(__stdcall *fnGetName)(DWORD, char *)) +void mpqapi_remove_hash_entries(BOOL(*fnGetName)(DWORD, char *)) { DWORD dwIndex, i; char pszFileName[MAX_PATH]; @@ -324,7 +309,7 @@ BOOL mpqapi_has_file(const char *pszName) return FetchHandle(pszName) != -1; } -BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar) +BOOL OpenMPQ(const char *pszArchive, DWORD dwChar) { DWORD dwFlagsAndAttributes; DWORD key; @@ -332,13 +317,10 @@ BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar) _FILEHEADER fhdr; InitHash(); - if (!mpqapi_set_hidden(pszArchive, hidden)) { - return FALSE; - } dwFlagsAndAttributes = gbMaxPlayers > 1 ? FILE_FLAG_WRITE_THROUGH : 0; sghArchive = CreateFile(pszArchive, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); if (sghArchive == INVALID_HANDLE_VALUE) { - sghArchive = CreateFile(pszArchive, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, dwFlagsAndAttributes | (hidden ? FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN : 0), NULL); + sghArchive = CreateFile(pszArchive, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, dwFlagsAndAttributes, NULL); if (sghArchive == INVALID_HANDLE_VALUE) return FALSE; save_archive_modified = TRUE; diff --git a/Source/mpqapi.h b/Source/mpqapi.h index 9afe8fe961a..9fe1fad5749 100644 --- a/Source/mpqapi.h +++ b/Source/mpqapi.h @@ -6,7 +6,6 @@ extern char mpq_buf[4096]; extern BOOL save_archive_modified; extern BOOLEAN save_archive_open; -BOOL mpqapi_set_hidden(const char *pszArchive, BOOL hidden); void mpqapi_store_creation_time(const char *pszArchive, DWORD dwChar); BOOL mpqapi_reg_load_modification_time(char *dst, int size); void mpqapi_xor_buf(char *pbData); @@ -17,14 +16,14 @@ void mpqapi_alloc_block(int block_offset, int block_size); _BLOCKENTRY *mpqapi_new_block(int *block_index); int FetchHandle(const char *pszName); int mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale); -void mpqapi_remove_hash_entries(BOOL(__stdcall *fnGetName)(DWORD, char *)); +void mpqapi_remove_hash_entries(BOOL(*fnGetName)(DWORD, char *)); BOOL mpqapi_write_file(const char *pszName, const BYTE *pbData, DWORD dwLen); _BLOCKENTRY *mpqapi_add_file(const char *pszName, _BLOCKENTRY *pBlk, int block_index); BOOL mpqapi_write_file_contents(const char *pszName, const BYTE *pbData, DWORD dwLen, _BLOCKENTRY *pBlk); int mpqapi_find_free_block(int size, int *block_size); void mpqapi_rename(char *pszOld, char *pszNew); BOOL mpqapi_has_file(const char *pszName); -BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar); +BOOL OpenMPQ(const char *pszArchive, DWORD dwChar); BOOL ParseMPQHeader(_FILEHEADER *pHdr, DWORD *pdwNextFileStart); void CloseMPQ(const char *pszArchive, BOOL bFree, DWORD dwChar); void mpqapi_store_modified_time(const char *pszArchive, DWORD dwChar); diff --git a/Source/msg.cpp b/Source/msg.cpp index e1e624d8292..8b41e7e3f56 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -579,7 +579,7 @@ void DeltaLoadLevel() item[ii]._ix = x; item[ii]._iy = y; dItem[x][y] = ii + 1; - RespawnItem(ii, 0); + RespawnItem(ii, FALSE); numitems++; } } @@ -1259,13 +1259,13 @@ void DeltaImportJunk(BYTE *src) if (*src == 0xFF) { memset(&sgJunk.portal[i], 0xFF, sizeof(DPortal)); src++; - SetPortalStats(i, 0, 0, 0, 0, 0); + SetPortalStats(i, FALSE, 0, 0, 0, 0); } else { memcpy(&sgJunk.portal[i], src, sizeof(DPortal)); src += sizeof(DPortal); SetPortalStats( i, - 1, + TRUE, sgJunk.portal[i].x, sgJunk.portal[i].y, sgJunk.portal[i].level, @@ -1369,7 +1369,7 @@ DWORD On_SBSPELL(TCmd *pCmd, int pnum) return sizeof(*p); } -void __cdecl msg_errorf(const char *pszFmt, ...) +void msg_errorf(const char *pszFmt, ...) { static DWORD msg_err_timer; DWORD ticks; @@ -1664,7 +1664,7 @@ void delta_put_item(TCmdPItem *pI, int x, int y, BYTE bLevel) void check_update_plr(int pnum) { if (gbMaxPlayers != 1 && pnum == myplr) - pfile_update(1); + pfile_update(TRUE); } DWORD On_SYNCPUTITEM(TCmd *pCmd, int pnum) diff --git a/Source/msg.h b/Source/msg.h index 3b2123f432c..580e06b37e7 100644 --- a/Source/msg.h +++ b/Source/msg.h @@ -66,7 +66,7 @@ DWORD On_ADDMAG(TCmd *pCmd, int pnum); DWORD On_ADDDEX(TCmd *pCmd, int pnum); DWORD On_ADDVIT(TCmd *pCmd, int pnum); DWORD On_SBSPELL(TCmd *pCmd, int pnum); -void __cdecl msg_errorf(const char *pszFmt, ...); +void msg_errorf(const char *pszFmt, ...); DWORD On_GOTOGETITEM(TCmd *pCmd, int pnum); DWORD On_REQUESTGITEM(TCmd *pCmd, int pnum); BOOL i_own_level(int nReqLevel); diff --git a/Source/multi.cpp b/Source/multi.cpp index 77626c2a8ac..69c65dc3cd3 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -39,7 +39,7 @@ const int event_types[3] = { }; #ifdef _DEBUG -void __cdecl dumphist(const char *pszFmt, ...) +void dumphist(const char *pszFmt, ...) { static FILE *sgpHistFile = NULL; DWORD dwTicks; @@ -636,7 +636,7 @@ void multi_event_handler(BOOL add) } } -void __stdcall multi_handle_events(_SNETEVENT *pEvt) +void multi_handle_events(_SNETEVENT *pEvt) { DWORD LeftReason; DWORD *data; @@ -943,7 +943,7 @@ void recv_plrinfo(int pnum, TCmdPlrInfoHdr *p, BOOL recv) sgwPackPlrOffsetTbl[pnum] = 0; multi_player_left_msg(pnum, 0); plr[pnum]._pGFXLoad = 0; - UnPackPlayer(&netplr[pnum], pnum, 1); + UnPackPlayer(&netplr[pnum], pnum, TRUE); if (!recv) { #ifdef _DEBUG diff --git a/Source/multi.h b/Source/multi.h index f02eea78360..4b62c778f9c 100644 --- a/Source/multi.h +++ b/Source/multi.h @@ -16,7 +16,7 @@ extern BYTE gbDeltaSender; extern int player_state[MAX_PLRS]; #ifdef _DEBUG -void __cdecl dumphist(const char *pszFmt, ...); +void dumphist(const char *pszFmt, ...); #endif void multi_msg_add(BYTE *pbMsg, BYTE bLen); void NetSendLoPri(BYTE *pbMsg, BYTE bLen); @@ -44,7 +44,7 @@ void multi_process_tmsgs(); void multi_send_zero_packet(int pnum, BYTE bCmd, BYTE *pbSrc, DWORD dwLen); void NetClose(); void multi_event_handler(BOOL add); -void __stdcall multi_handle_events(_SNETEVENT *pEvt); +void multi_handle_events(_SNETEVENT *pEvt); BOOL NetInit(BOOL bSinglePlayer, BOOL *pfExitProgram); void buffer_init(TBuffer *pBuf); void multi_send_pinfo(int pnum, char cmd); diff --git a/Source/nthread.cpp b/Source/nthread.cpp index 76e32834182..8d7bd5f7e11 100644 --- a/Source/nthread.cpp +++ b/Source/nthread.cpp @@ -166,7 +166,7 @@ void nthread_start(BOOL set_turn_upper_bit) } } -unsigned int __stdcall nthread_handler(void *) +unsigned int nthread_handler(void *) { int delta; BOOL received; diff --git a/Source/nthread.h b/Source/nthread.h index 2a27b78fc93..331ae0f89b9 100644 --- a/Source/nthread.h +++ b/Source/nthread.h @@ -20,7 +20,7 @@ DWORD nthread_send_and_recv_turn(DWORD cur_turn, int turn_delta); BOOL nthread_recv_turns(BOOL *pfSendAsync); void nthread_set_turn_upper_bit(); void nthread_start(BOOL set_turn_upper_bit); -unsigned int __stdcall nthread_handler(void *); +unsigned int nthread_handler(void *); void nthread_cleanup(); void nthread_ignore_mutex(BOOL bStart); BOOL nthread_has_500ms_passed(BOOL unused); diff --git a/Source/objects.cpp b/Source/objects.cpp index 01b83fe72a9..59e68534704 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -1531,7 +1531,7 @@ void Obj_Circle(int i) if (quests[QTYPE_VB]._qactive == 2) quests[QTYPE_VB]._qvar1 = 4; AddMissile(plr[myplr].WorldX, plr[myplr].WorldY, 35, 46, plr[myplr]._pdir, MIS_RNDTELEPORT, 0, myplr, 0, 0); - track_repeat_walk(0); + track_repeat_walk(FALSE); sgbMouseDown = 0; ClrPlrPath(myplr); StartStand(myplr, 0); @@ -2545,12 +2545,12 @@ void OperateChest(int pnum, int i, BOOL sendmsg) SetRndSeed(object[i]._oRndSeed); if (setlevel) { for (j = 0; j < object[i]._oVar1; j++) { - CreateRndItem(object[i]._ox, object[i]._oy, TRUE, sendmsg, 0); + CreateRndItem(object[i]._ox, object[i]._oy, TRUE, sendmsg, FALSE); } } else { for (j = 0; j < object[i]._oVar1; j++) { if (object[i]._oVar2) - CreateRndItem(object[i]._ox, object[i]._oy, 0, sendmsg, 0); + CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); else CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg); } @@ -2709,7 +2709,7 @@ void OperateSarc(int pnum, int i, BOOL sendmsg) object[i]._oAnimDelay = 3; SetRndSeed(object[i]._oRndSeed); if (object[i]._oVar1 <= 2) - CreateRndItem(object[i]._ox, object[i]._oy, 0, sendmsg, 0); + CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); if (object[i]._oVar1 >= 8) SpawnSkeleton(object[i]._oVar2, object[i]._ox, object[i]._oy); if (pnum == myplr) @@ -3203,11 +3203,11 @@ void OperateShrine(int pnum, int i, int sType) if (pnum != myplr) return; if (2 * currlevel < 7) { - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLMANA, 0, 1); - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLHEAL, 0, 1); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLMANA, FALSE, TRUE); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLHEAL, FALSE, TRUE); } else { - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, 0, 1); - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, 0, 1); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, FALSE, TRUE); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, FALSE, TRUE); } plr[pnum]._pMana = plr[pnum]._pMaxMana; plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase; @@ -3328,7 +3328,7 @@ void OperateShrine(int pnum, int i, int sType) for (yy = 0; yy < DMAXY; yy++) { for (xx = 0; xx < DMAXX; xx++) { - automapview[xx][yy] = 1; + automapview[xx][yy] = TRUE; } } InitDiabloMsg(EMSG_SHRINE_SECLUDED); @@ -3432,9 +3432,9 @@ void OperateSkelBook(int pnum, int i, BOOL sendmsg) if (!deltaload) { SetRndSeed(object[i]._oRndSeed); if (random_(161, 5)) - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, 21, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, 21, sendmsg, FALSE); else - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, 24, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, 24, sendmsg, FALSE); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } @@ -3450,7 +3450,7 @@ void OperateBookCase(int pnum, int i, BOOL sendmsg) object[i]._oSelFlag = 0; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_BOOK, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_BOOK, sendmsg, FALSE); if (QuestStatus(QTYPE_ZHAR) && monster[MAX_PLRS].mName == UniqMonst[UMT_ZHAR].mName && monster[MAX_PLRS]._msquelch == UCHAR_MAX @@ -3472,7 +3472,7 @@ void OperateDecap(int pnum, int i, BOOL sendmsg) object[i]._oSelFlag = 0; if (!deltaload) { SetRndSeed(object[i]._oRndSeed); - CreateRndItem(object[i]._ox, object[i]._oy, 0, sendmsg, 0); + CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } @@ -3490,13 +3490,13 @@ void OperateArmorStand(int pnum, int i, BOOL sendmsg) SetRndSeed(object[i]._oRndSeed); uniqueRnd = random_(0, 2); if (currlevel <= 5) { - CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_LARMOR, 0, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_LARMOR, 0, sendmsg, FALSE); } else if (currlevel >= 6 && currlevel <= 9) { - CreateTypeItem(object[i]._ox, object[i]._oy, uniqueRnd, ITYPE_MARMOR, 0, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, uniqueRnd, ITYPE_MARMOR, 0, sendmsg, FALSE); } else if (currlevel >= 10 && currlevel <= 12) { - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_HARMOR, 0, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_HARMOR, 0, sendmsg, FALSE); } else if (currlevel >= 13 && currlevel <= 16) { - CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_HARMOR, 0, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_HARMOR, 0, sendmsg, FALSE); } if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); @@ -3699,9 +3699,9 @@ void OperateWeaponRack(int pnum, int i, BOOL sendmsg) return; if (leveltype > 1) - CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, weaponType, 0, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, weaponType, 0, sendmsg, FALSE); else - CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, weaponType, 0, sendmsg, 0); + CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, weaponType, 0, sendmsg, FALSE); if (pnum == myplr) NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i); } @@ -3872,9 +3872,9 @@ void SyncOpL1Door(int pnum, int cmd, int i) do_sync = TRUE; if (do_sync) { if (object[i]._otype == OBJ_L1LDOOR) - OperateL1LDoor(-1, i, 0); + OperateL1LDoor(-1, i, FALSE); if (object[i]._otype == OBJ_L1RDOOR) - OperateL1RDoor(-1, i, 0); + OperateL1RDoor(-1, i, FALSE); } } @@ -3895,9 +3895,9 @@ void SyncOpL2Door(int pnum, int cmd, int i) do_sync = TRUE; if (do_sync) { if (object[i]._otype == OBJ_L2LDOOR) - OperateL2LDoor(-1, i, 0); + OperateL2LDoor(-1, i, FALSE); if (object[i]._otype == OBJ_L2RDOOR) - OperateL2RDoor(-1, i, 0); + OperateL2RDoor(-1, i, FALSE); } } @@ -3918,9 +3918,9 @@ void SyncOpL3Door(int pnum, int cmd, int i) do_sync = TRUE; if (do_sync) { if (object[i]._otype == OBJ_L3LDOOR) - OperateL2LDoor(-1, i, 0); + OperateL2LDoor(-1, i, FALSE); if (object[i]._otype == OBJ_L3RDOOR) - OperateL2RDoor(-1, i, 0); + OperateL2RDoor(-1, i, FALSE); } } @@ -3972,11 +3972,11 @@ void SyncOpObject(int pnum, int cmd, int i) OperateBookCase(pnum, i, FALSE); break; case OBJ_DECAP: - OperateDecap(pnum, i, 0); + OperateDecap(pnum, i, FALSE); break; case OBJ_ARMORSTAND: case OBJ_WARARMOR: - OperateArmorStand(pnum, i, 0); + OperateArmorStand(pnum, i, FALSE); break; case OBJ_GOATSHRINE: OperateGoatShrine(pnum, i, LS_GSHRINE); @@ -4081,9 +4081,9 @@ void BreakBarrel(int pnum, int i, int dam, BOOL forcebreak, int sendmsg) for (yp = object[i]._oy - 1; yp <= object[i]._oy + 1; yp++) { for (xp = object[i]._ox - 1; xp <= object[i]._ox + 1; xp++) { if (dMonster[xp][yp] > 0) - MonsterTrapHit(dMonster[xp][yp] - 1, 1, 4, 0, 1, 0); + MonsterTrapHit(dMonster[xp][yp] - 1, 1, 4, 0, 1, FALSE); if (dPlayer[xp][yp] > 0) - PlayerMHit(dPlayer[xp][yp] - 1, -1, 0, 8, 16, 1, 0, 0); + PlayerMHit(dPlayer[xp][yp] - 1, -1, 0, 8, 16, 1, FALSE, 0); if (dObject[xp][yp] > 0) { oi = dObject[xp][yp] - 1; if (object[oi]._otype == OBJ_BARRELEX && object[oi]._oBreak != -1) @@ -4098,7 +4098,7 @@ void BreakBarrel(int pnum, int i, int dam, BOOL forcebreak, int sendmsg) if (!object[i]._oVar3) CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg); else - CreateRndItem(object[i]._ox, object[i]._oy, 0, sendmsg, 0); + CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE); } if (object[i]._oVar2 >= 8) SpawnSkeleton(object[i]._oVar4, object[i]._ox, object[i]._oy); @@ -4127,7 +4127,7 @@ void BreakObject(int pnum, int oi) break; case OBJ_BARREL: case OBJ_BARRELEX: - BreakBarrel(pnum, oi, objdam, 0, 1); + BreakBarrel(pnum, oi, objdam, FALSE, TRUE); break; } } @@ -4135,7 +4135,7 @@ void BreakObject(int pnum, int oi) void SyncBreakObj(int pnum, int oi) { if (object[oi]._otype >= OBJ_BARREL && object[oi]._otype <= OBJ_BARRELEX) - BreakBarrel(pnum, oi, 0, TRUE, 0); + BreakBarrel(pnum, oi, 0, TRUE, FALSE); } void SyncL1Doors(int i) diff --git a/Source/palette.cpp b/Source/palette.cpp index e11a8225c21..3de01e349c3 100644 --- a/Source/palette.cpp +++ b/Source/palette.cpp @@ -88,7 +88,7 @@ void LoadPalette(char *pszFileName) assert(pszFileName); - WOpenFile(pszFileName, &pBuf, 0); + WOpenFile(pszFileName, &pBuf, FALSE); WReadFile(pBuf, (char *)PalData, sizeof(PalData), pszFileName); WCloseFile(pBuf); diff --git a/Source/pfile.cpp b/Source/pfile.cpp index 3c92d813f38..530ea4ada62 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -62,7 +62,7 @@ BOOL pfile_open_archive(BOOL update, DWORD save_num) char FileName[MAX_PATH]; pfile_get_save_path(FileName, sizeof(FileName), save_num); - if (OpenMPQ(FileName, FALSE, save_num)) + if (OpenMPQ(FileName, save_num)) return TRUE; return FALSE; @@ -102,9 +102,7 @@ BOOL pfile_create_player_description(char *dst, DWORD len) _uiheroinfo uihero; myplr = 0; -//#if !defined(__BIG_ENDIAN__) pfile_read_player_from_save(); -//#endif game_2_ui_player(plr, &uihero, gbValidSaveFile); UiSetupPlayerInfo(gszHero, &uihero, GAME_ID); @@ -187,7 +185,7 @@ BYTE game_2_ui_class(const PlayerStruct *p) return uiclass; } -BOOL __stdcall pfile_ui_set_hero_infos(BOOL(__stdcall *ui_add_hero_info)(_uiheroinfo *)) +BOOL pfile_ui_set_hero_infos(BOOL(*ui_add_hero_info)(_uiheroinfo *)) { DWORD i, save_num; char FileName[MAX_PATH]; @@ -218,7 +216,6 @@ BOOL __stdcall pfile_ui_set_hero_infos(BOOL(__stdcall *ui_add_hero_info)(_uihero BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack) { HANDLE file; - BOOL decoded; DWORD dwlen, nSize; BYTE *buf; @@ -237,16 +234,8 @@ BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack) DWORD read; buf = DiabloAllocPtr(dwlen); if (SFileReadFile(file, buf, dwlen, &read, NULL)) { - decoded = TRUE; read = codec_decode(buf, dwlen, password); - if (!read && gbMaxPlayers > 1) { - GetComputerName(password, &nSize); - if (SFileSetFilePointer(file, 0, NULL, FILE_BEGIN) || !SFileReadFile(file, buf, dwlen, &read, NULL)) - decoded = FALSE; - else - read = codec_decode(buf, dwlen, password); - } - if (decoded && read == sizeof(*pPack)) { + if (read == sizeof(*pPack)) { memcpy(pPack, buf, sizeof(*pPack)); ret = TRUE; } @@ -292,7 +281,7 @@ BOOL pfile_archive_contains_game(HANDLE hsArchive, DWORD save_num) return TRUE; } -BOOL __stdcall pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats) +BOOL pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats) { int c; @@ -317,7 +306,7 @@ char pfile_get_player_class(unsigned int player_class_nr) return pc_class; } -BOOL __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo) +BOOL pfile_ui_save_create(_uiheroinfo *heroinfo) { DWORD save_num; char cl; @@ -348,7 +337,7 @@ BOOL __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo) return TRUE; } -BOOL __stdcall pfile_get_file_name(DWORD lvl, char *dst) +BOOL pfile_get_file_name(DWORD lvl, char *dst) { const char *fmt; @@ -373,7 +362,7 @@ BOOL __stdcall pfile_get_file_name(DWORD lvl, char *dst) return TRUE; } -BOOL __stdcall pfile_delete_save(_uiheroinfo *hero_info) +BOOL pfile_delete_save(_uiheroinfo *hero_info) { DWORD save_num; char FileName[MAX_PATH]; @@ -453,7 +442,7 @@ void pfile_remove_temp_files() } } -BOOL __stdcall GetTempSaveNames(DWORD dwIndex, char *szTemp) +BOOL GetTempSaveNames(DWORD dwIndex, char *szTemp) { const char *fmt; @@ -497,7 +486,7 @@ void pfile_rename_temp_to_perm() pfile_flush(TRUE, dwChar); } -BOOL __stdcall GetPermSaveNames(DWORD dwIndex, char *szPerm) +BOOL GetPermSaveNames(DWORD dwIndex, char *szPerm) { const char *fmt; @@ -573,19 +562,7 @@ BYTE *pfile_read(const char *pszName, DWORD *pdwLen) *pdwLen = codec_decode(buf, *pdwLen, password); if (*pdwLen == 0) { - // BUGFIFX: *pdwLen has already been overwritten with zero and the savefile has been closed - // there is no way this can work correctly - if (gbMaxPlayers > 1) { - GetComputerName(password, &nSize); - if (SFileSetFilePointer(save, 0, NULL, FILE_BEGIN)) - app_fatal("Unable to read save file"); - - if (!SFileReadFile(save, buf, *pdwLen, &nread, NULL)) - app_fatal("Unable to read save file"); - *pdwLen = codec_decode(buf, *pdwLen, password); - } - if (*pdwLen == 0) - app_fatal("Invalid save file"); + app_fatal("Invalid save file"); } } return buf; diff --git a/Source/pfile.h b/Source/pfile.h index f619748ec2e..d47dc518bbe 100644 --- a/Source/pfile.h +++ b/Source/pfile.h @@ -17,25 +17,25 @@ BOOL pfile_rename_hero(const char *name_1, const char *name_2); void pfile_flush_W(); void game_2_ui_player(const PlayerStruct *p, _uiheroinfo *heroinfo, BOOL bHasSaveFile); BYTE game_2_ui_class(const PlayerStruct *p); -BOOL __stdcall pfile_ui_set_hero_infos(BOOL(__stdcall *ui_add_hero_info)(_uiheroinfo *)); +BOOL pfile_ui_set_hero_infos(BOOL(*ui_add_hero_info)(_uiheroinfo *)); char *GetSaveDirectory(char *dst, int dst_size, DWORD save_num); BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack); HANDLE pfile_open_save_archive(BOOL *showFixedMsg, DWORD save_num); void pfile_SFileCloseArchive(HANDLE hsArchive); BOOL pfile_archive_contains_game(HANDLE hsArchive, DWORD save_num); -BOOL __stdcall pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats); +BOOL pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats); char pfile_get_player_class(unsigned int player_class_nr); -BOOL __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo); -BOOL __stdcall pfile_get_file_name(DWORD lvl, char *dst); -BOOL __stdcall pfile_delete_save(_uiheroinfo *hero_info); +BOOL pfile_ui_save_create(_uiheroinfo *heroinfo); +BOOL pfile_get_file_name(DWORD lvl, char *dst); +BOOL pfile_delete_save(_uiheroinfo *hero_info); void pfile_read_player_from_save(); void GetTempLevelNames(char *szTemp); void GetPermLevelNames(char *szPerm); void pfile_get_game_name(char *dst); void pfile_remove_temp_files(); -BOOL __stdcall GetTempSaveNames(DWORD dwIndex, char *szTemp); +BOOL GetTempSaveNames(DWORD dwIndex, char *szTemp); void pfile_rename_temp_to_perm(); -BOOL __stdcall GetPermSaveNames(DWORD dwIndex, char *szPerm); +BOOL GetPermSaveNames(DWORD dwIndex, char *szPerm); void pfile_write_save_file(const char *pszName, BYTE *pbData, DWORD dwLen, DWORD qwLen); void pfile_strcpy(char *dst, const char *src); BYTE *pfile_read(const char *pszName, DWORD *pdwLen); diff --git a/Source/player.cpp b/Source/player.cpp index a98c0ef6592..855abb547ba 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -1145,7 +1145,7 @@ void StartWalkStand(int pnum) plr[pnum]._pxoff = 0; plr[pnum]._pyoff = 0; - CheckEFlag(pnum, 0); + CheckEFlag(pnum, FALSE); if (pnum == myplr) { ScrollInfo._sxoff = 0; diff --git a/Source/plrmsg.cpp b/Source/plrmsg.cpp index 8539fe35fbe..e8d21540614 100644 --- a/Source/plrmsg.cpp +++ b/Source/plrmsg.cpp @@ -36,7 +36,7 @@ char *ErrorPlrMsg(const char *pszMsg) return result; } -size_t __cdecl EventPlrMsg(const char *pszFmt, ...) +size_t EventPlrMsg(const char *pszFmt, ...) { _plrmsg *pMsg; va_list va; diff --git a/Source/plrmsg.h b/Source/plrmsg.h index 10b78b48cea..0cccbf51f2a 100644 --- a/Source/plrmsg.h +++ b/Source/plrmsg.h @@ -6,7 +6,7 @@ extern _plrmsg plr_msgs[PMSG_COUNT]; void plrmsg_delay(BOOL delay); char *ErrorPlrMsg(const char *pszMsg); -size_t __cdecl EventPlrMsg(const char *pszFmt, ...); +size_t EventPlrMsg(const char *pszFmt, ...); void SendPlrMsg(int pnum, const char *pszStr); void ClearPlrMsg(); void InitPlrMsg(); diff --git a/Source/render.cpp b/Source/render.cpp index 5338db03fc4..744628add85 100644 --- a/Source/render.cpp +++ b/Source/render.cpp @@ -4,7 +4,7 @@ DEVILUTION_BEGIN_NAMESPACE #define NO_OVERDRAW -typedef enum { +enum { RT_SQUARE, RT_TRANSPARENT, RT_LTRIANGLE, diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index c43f7bb607f..4054245067a 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -666,7 +666,7 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy, int eflag) } if (MissilePreFlag) { - DrawMissile(sx, sy, dx, dy, 1); + DrawMissile(sx, sy, dx, dy, TRUE); } if (light_table_index < lightmax && bDead != 0) { @@ -701,7 +701,7 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy, int eflag) if (dMonster[sx][sy] > 0) { DrawMonsterHelper(sx, sy, 0, dx, dy, eflag); } - DrawMissile(sx, sy, dx, dy, 0); + DrawMissile(sx, sy, dx, dy, FALSE); DrawObject(sx, sy, dx, dy, 0); DrawItem(sx, sy, dx, dy, 0); @@ -905,6 +905,9 @@ static void DrawGame(int x, int y) } } +// DevilutionX extension. +extern void DrawControllerModifierHints(); + /** * @brief Start rendering of screen, town variation * @param StartX Center of view in dPiece coordinate @@ -959,6 +962,7 @@ void DrawView(int StartX, int StartY) gmenu_draw_pause(); } + DrawControllerModifierHints(); DrawPlrMsg(); gmenu_draw(); doom_draw(); @@ -1210,6 +1214,7 @@ void scrollrt_draw_game_screen(BOOL draw_cursor) scrollrt_draw_cursor_back_buffer(); unlock_buf(0); } + RenderPresent(); } /** @@ -1279,6 +1284,7 @@ void DrawAndBlit() lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); + RenderPresent(); drawhpflag = FALSE; drawmanaflag = FALSE; diff --git a/Source/stores.cpp b/Source/stores.cpp index f381eaeedf8..33bf2eace33 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -1410,7 +1410,7 @@ void StartStore(char s) for (t = s;; t = STORE_SMITH) { sbookflag = FALSE; - invflag = 0; + invflag = FALSE; chrflag = FALSE; questlog = FALSE; dropGoldFlag = FALSE; @@ -1884,7 +1884,7 @@ void S_SBuyEnter() done = FALSE; for (i = 0; i < 40 && !done; i++) { - done = AutoPlace(myplr, i, cursW / 28, cursH / 28, 0); + done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); @@ -1945,7 +1945,7 @@ void S_SPBuyEnter() SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; for (i = 0; i < 40 && !done; i++) { - done = AutoPlace(myplr, i, cursW / 28, cursH / 28, 0); + done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); @@ -2196,7 +2196,7 @@ void S_WBuyEnter() done = FALSE; for (i = 0; i < 40 && !done; i++) { - done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, 0); + done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) @@ -2363,7 +2363,7 @@ void S_BBuyEnter() SetCursor_(plr[myplr].HoldItem._iCurs + CURSOR_FIRSTITEM); done = FALSE; for (i = 0; i < 40 && !done; i++) { - done = AutoPlace(myplr, i, cursW / 28, cursH / 28, 0); + done = AutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); @@ -2494,7 +2494,7 @@ void S_HBuyEnter() done = FALSE; i = 0; for (i = 0; i < 40 && !done; i++) { - done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, 0); + done = SpecialAutoPlace(myplr, i, cursW / 28, cursH / 28, FALSE); } if (done) StartStore(STORE_CONFIRM); diff --git a/Source/themes.cpp b/Source/themes.cpp index e1922d124b5..a4d0ea139ad 100644 --- a/Source/themes.cpp +++ b/Source/themes.cpp @@ -500,7 +500,7 @@ void PlaceThemeMonsts(int t, int f) for (xp = 0; xp < MAXDUNX; xp++) { if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]] && dItem[xp][yp] == 0 && dObject[xp][yp] == 0) { if (random_(0, f) == 0) { - AddMonster(xp, yp, random_(0, 8), mtype, 1); + AddMonster(xp, yp, random_(0, 8), mtype, TRUE); } } } @@ -858,7 +858,7 @@ void Theme_GoatShrine(int t) for (yy = themey - 1; yy <= themey + 1; yy++) { for (xx = themex - 1; xx <= themex + 1; xx++) { if (dTransVal[xx][yy] == themes[t].ttval && !nSolidTable[dPiece[xx][yy]] && (xx != themex || yy != themey)) { - AddMonster(xx, yy, DIR_SW, themeVar1, 1); + AddMonster(xx, yy, DIR_SW, themeVar1, TRUE); } } } diff --git a/Source/trigs.cpp b/Source/trigs.cpp index 83d8ab2ba5a..82e4ca43016 100644 --- a/Source/trigs.cpp +++ b/Source/trigs.cpp @@ -91,7 +91,7 @@ int L4PentaList[33] = { void InitNoTriggers() { numtrigs = 0; - trigflag = 0; + trigflag = FALSE; } #endif @@ -180,7 +180,7 @@ void InitL1Triggers() } } } - trigflag = 0; + trigflag = FALSE; } #ifndef SPAWN @@ -214,7 +214,7 @@ void InitL2Triggers() } } } - trigflag = 0; + trigflag = FALSE; } void InitL3Triggers() @@ -246,7 +246,7 @@ void InitL3Triggers() } } } - trigflag = 0; + trigflag = FALSE; } void InitL4Triggers() @@ -290,12 +290,12 @@ void InitL4Triggers() } } } - trigflag = 0; + trigflag = FALSE; } void InitSKingTriggers() { - trigflag = 0; + trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 82; trigs[0]._ty = 42; @@ -304,7 +304,7 @@ void InitSKingTriggers() void InitSChambTriggers() { - trigflag = 0; + trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 70; trigs[0]._ty = 39; @@ -313,7 +313,7 @@ void InitSChambTriggers() void InitPWaterTriggers() { - trigflag = 0; + trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 30; trigs[0]._ty = 83; @@ -322,7 +322,7 @@ void InitPWaterTriggers() void InitVPTriggers() { - trigflag = 0; + trigflag = FALSE; numtrigs = 1; trigs[0]._tx = 35; trigs[0]._ty = 32; diff --git a/SourceS/file_util.h b/SourceS/file_util.h new file mode 100644 index 00000000000..44ef9c940c2 --- /dev/null +++ b/SourceS/file_util.h @@ -0,0 +1,23 @@ +#pragma once + +#if _POSIX_C_SOURCE >= 200112L +#include +#else +#include +#endif + +namespace dvl { + +inline bool FileExists(const char *path) +{ +#if _POSIX_C_SOURCE >= 200112L + return ::access(path, F_OK) == 0; +#else + auto *file = std::fopen(path, "rb"); + if (file == nullptr) return false; + std::fclose(file); + return true; +#endif +} + +} // namespace dvl diff --git a/SourceS/miniwin.h b/SourceS/miniwin.h index 94b5aa17aab..589831766b9 100644 --- a/SourceS/miniwin.h +++ b/SourceS/miniwin.h @@ -33,5 +33,4 @@ #endif #ifdef DEVILUTION_ENGINE #include "miniwin/misc_macro.h" -#include "miniwin/com_macro.h" #endif diff --git a/SourceS/miniwin/com.h b/SourceS/miniwin/com.h index ce248af8f44..9a52ea5b743 100644 --- a/SourceS/miniwin/com.h +++ b/SourceS/miniwin/com.h @@ -4,7 +4,7 @@ namespace dvl { struct IDirectSoundBuffer { virtual void Release() = 0; - virtual void GetStatus(LPDWORD pdwStatus) = 0; + virtual bool IsPlaying() = 0; virtual void Play(int lVolume, int lPan) = 0; virtual void Stop() = 0; virtual int SetChunk(BYTE *fileData, DWORD dwBytes) = 0; @@ -12,11 +12,6 @@ struct IDirectSoundBuffer { typedef IDirectSoundBuffer *LPDIRECTSOUNDBUFFER; -const auto DVL_DS_OK = 0; const auto DVL_ERROR_SUCCESS = 0L; -const auto DVL_DSBSTATUS_PLAYING = 0x00000001; - -constexpr auto DVL_SW_HIDE = 0; -constexpr auto DVL_SW_SHOWNORMAL = 1; } // namespace dvl diff --git a/SourceS/miniwin/com_macro.h b/SourceS/miniwin/com_macro.h deleted file mode 100644 index df358d4dd17..00000000000 --- a/SourceS/miniwin/com_macro.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#define SW_HIDE DVL_SW_HIDE -#define SW_SHOWNORMAL DVL_SW_SHOWNORMAL - -#define E_FAIL DVL_E_FAIL -#define S_OK DVL_S_OK - -#define DDBLTFAST_WAIT 0x00000010 - -#define ERROR_SUCCESS DVL_ERROR_SUCCESS -#define DS_OK DVL_DS_OK diff --git a/SourceS/miniwin/misc.h b/SourceS/miniwin/misc.h index 050506d1528..b4e0111793f 100644 --- a/SourceS/miniwin/misc.h +++ b/SourceS/miniwin/misc.h @@ -71,7 +71,7 @@ typedef LONG LCID; typedef DWORD COLORREF; -typedef LRESULT(CALLBACK *WNDPROC)(HWND, UINT, WPARAM, LPARAM); +typedef LRESULT(*WNDPROC)(HWND, UINT, WPARAM, LPARAM); #pragma pack(push, 1) typedef struct waveformat_tag { @@ -175,48 +175,40 @@ typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Blink; } LIST_ENTRY, *PLIST_ENTRY; -DWORD WINAPI GetTickCount(); +DWORD GetTickCount(); -DWORD WINAPI GetLastError(); -void WINAPI SetLastError(DWORD dwErrCode); +WINBOOL CloseHandle(HANDLE hObject); -WINBOOL WINAPI CloseHandle(HANDLE hObject); - -HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset, WINBOOL bInitialState, +HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset, WINBOOL bInitialState, LPCSTR lpName); BOOL CloseEvent(HANDLE event); void SetEvent(HANDLE hEvent); void ResetEvent(HANDLE hEvent); -int WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); +int WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); void SetCursorPos(int X, int Y); void FocusOnCharInfo(); -SHORT WINAPI GetAsyncKeyState(int vKey); +SHORT GetAsyncKeyState(int vKey); -WINBOOL WINAPI PeekMessageA(LPMSG lpMsg); +WINBOOL PeekMessageA(LPMSG lpMsg); -WINBOOL WINAPI TranslateMessage(const MSG *lpMsg); -LRESULT WINAPI DispatchMessageA(const MSG *lpMsg); -WINBOOL WINAPI PostMessageA(UINT Msg, WPARAM wParam, LPARAM lParam); +WINBOOL TranslateMessage(const MSG *lpMsg); +LRESULT DispatchMessageA(const MSG *lpMsg); +WINBOOL PostMessageA(UINT Msg, WPARAM wParam, LPARAM lParam); bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight); -typedef LONG(WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)( - struct _EXCEPTION_POINTERS *ExceptionInfo); - -uintptr_t __cdecl DVL_beginthreadex(void *_Security, unsigned _StackSize, unsigned(__stdcall *_StartAddress)(void *), +uintptr_t DVL_beginthreadex(void *_Security, unsigned _StackSize, unsigned(*_StartAddress)(void *), void *_ArgList, unsigned _InitFlag, unsigned *_ThrdAddr); -HANDLE WINAPI GetCurrentThread(); -DWORD WINAPI GetCurrentThreadId(); -WINBOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority); -void WINAPI Sleep(DWORD dwMilliseconds); +DWORD GetCurrentThreadId(); +WINBOOL SetThreadPriority(HANDLE hThread, int nPriority); +void Sleep(DWORD dwMilliseconds); -int WINAPIV wsprintfA(LPSTR, LPCSTR, ...); -int WINAPIV wvsprintfA(LPSTR dest, LPCSTR format, va_list arglist); -int __cdecl _strcmpi(const char *_Str1, const char *_Str2); -int __cdecl _strnicmp(const char *_Str1, const char *_Str2, size_t n); -char *__cdecl _itoa(int _Value, char *_Dest, int _Radix); +int wsprintfA(LPSTR, LPCSTR, ...); +int wvsprintfA(LPSTR dest, LPCSTR format, va_list arglist); +int _strcmpi(const char *_Str1, const char *_Str2); +int _strnicmp(const char *_Str1, const char *_Str2, size_t n); // // File I/O @@ -321,20 +313,17 @@ typedef struct _IMAGE_SECTION_HEADER { typedef LONG LSTATUS, HKEY, REGSAM, PHKEY; -WINBOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, +WINBOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); -DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); -WINBOOL WINAPI SetEndOfFile(HANDLE hFile); -DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName); -WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes); -HANDLE WINAPI CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, +DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +WINBOOL SetEndOfFile(HANDLE hFile); +HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); -WINBOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, +WINBOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); -DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); -WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize); -WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName); +DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); +WINBOOL DeleteFileA(LPCSTR lpFileName); typedef struct _CONTEXT { @@ -408,25 +397,6 @@ typedef struct _CONTEXT { typedef CONTEXT *PCONTEXT; -// -// Exception record definition. -// - -typedef struct _EXCEPTION_RECORD { - DWORD ExceptionCode; - DWORD ExceptionFlags; - struct _EXCEPTION_RECORD *ExceptionRecord; - PVOID ExceptionAddress; - DWORD NumberParameters; -} EXCEPTION_RECORD; - -typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; - -typedef struct _EXCEPTION_POINTERS { - PEXCEPTION_RECORD ExceptionRecord; - PCONTEXT ContextRecord; -} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS; - typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; PVOID AllocationBase; @@ -450,7 +420,7 @@ typedef struct { extern void LoadCharNames(); extern void LoadAndPlaySound(char *FilePath, int lVolume, int lPan); extern void DrawArtWithMask(int SX, int SY, int SW, int SH, int nFrame, BYTE bMask, void *pBuffer); -extern BOOL __cdecl LoadArtWithPal(char *pszFile, void **pBuffer, int frames, DWORD *data); +extern BOOL LoadArtWithPal(char *pszFile, void **pBuffer, int frames, DWORD *data); constexpr auto DVL_WM_SYSKEYUP = 0x0105; constexpr auto DVL_VER_PLATFORM_WIN32_NT = 2; @@ -461,7 +431,6 @@ constexpr auto DVL_GENERIC_WRITE = 0x40000000L; constexpr auto DVL_OPEN_EXISTING = 3; constexpr auto DVL_FILE_BEGIN = 0; constexpr auto DVL_FILE_CURRENT = 1; -constexpr auto DVL_ERROR_FILE_NOT_FOUND = 2; constexpr auto DVL_WM_QUIT = 0x0012; constexpr auto DVL_INFINITE = 0xFFFFFFFF; diff --git a/SourceS/miniwin/misc_macro.h b/SourceS/miniwin/misc_macro.h index ba33703d6c1..6d2c1f55d5a 100644 --- a/SourceS/miniwin/misc_macro.h +++ b/SourceS/miniwin/misc_macro.h @@ -49,12 +49,8 @@ #define GENERIC_WRITE DVL_GENERIC_WRITE #define OPEN_EXISTING DVL_OPEN_EXISTING #define OPEN_ALWAYS 4 -#define ERROR_FILE_NOT_FOUND DVL_ERROR_FILE_NOT_FOUND +#define ERROR_SUCCESS DVL_ERROR_SUCCESS #define FILE_ATTRIBUTE_NORMAL 128 -#define FILE_ATTRIBUTE_HIDDEN 0x00000002 -#define FILE_ATTRIBUTE_SYSTEM 0x00000004 -#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 -#define FILE_SHARE_READ 1 #define OFS_MAXPATHNAME DVL_OFS_MAXPATHNAME @@ -91,10 +87,7 @@ #define KEY_WRITE 0x20006 #define REG_SZ 1 -#define GetFileAttributes GetFileAttributesA -#define SetFileAttributes SetFileAttributesA #define CreateFile CreateFileA -#define GetComputerName GetComputerNameA #define DeleteFile DeleteFileA #define GWL_STYLE (-16) diff --git a/SourceS/miniwin/popdecl.inc b/SourceS/miniwin/popdecl.inc deleted file mode 100644 index 12f244442c1..00000000000 --- a/SourceS/miniwin/popdecl.inc +++ /dev/null @@ -1,7 +0,0 @@ -#pragma pop_macro("__cdecl") -#pragma pop_macro("__fastcall") -#pragma pop_macro("__stdcall") -#pragma pop_macro("CALLBACK") -#pragma pop_macro("APIENTRY") -#pragma pop_macro("WINAPI") -#pragma pop_macro("WINAPIV") diff --git a/SourceS/miniwin/pushdecl.inc b/SourceS/miniwin/pushdecl.inc deleted file mode 100644 index 39c0a364f6f..00000000000 --- a/SourceS/miniwin/pushdecl.inc +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DEVILUTION_ENGINE -#pragma push_macro("__cdecl") -#pragma push_macro("__fastcall") -#pragma push_macro("__stdcall") -#pragma push_macro("CALLBACK") -#pragma push_macro("APIENTRY") -#pragma push_macro("WINAPI") -#pragma push_macro("WINAPIV") -#endif - -#undef __cdecl -#undef __fastcall -#undef __stdcall -#undef CALLBACK -#undef APIENTRY -#undef WINAPI -#undef WINAPIV -#define __cdecl -#define __fastcall -#define __stdcall -#define CALLBACK -#define APIENTRY -#define WINAPI -#define WINAPIV diff --git a/SourceS/miniwin/thread.h b/SourceS/miniwin/thread.h index 501db368e0a..fa8e5bbbc23 100644 --- a/SourceS/miniwin/thread.h +++ b/SourceS/miniwin/thread.h @@ -3,9 +3,9 @@ namespace dvl { typedef void *CRITICAL_SECTION, **LPCRITICAL_SECTION; -void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); -void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); -void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); -void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); } // namespace dvl diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 57787900494..5d213dd3171 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -3,6 +3,8 @@ #include #ifndef USE_SDL1 +#define SDLC_KEYSTATE_LEFTCTRL SDL_SCANCODE_LCTRL +#define SDLC_KEYSTATE_RIGHTCTRL SDL_SCANCODE_RCTRL #define SDLC_KEYSTATE_LEFTSHIFT SDL_SCANCODE_LSHIFT #define SDLC_KEYSTATE_RIGHTSHIFT SDL_SCANCODE_RSHIFT #define SDLC_KEYSTATE_MENU SDL_SCANCODE_MENU @@ -22,6 +24,8 @@ extern "C" extern SDL_Surface *vampire_MakeTripleBuffer(SDL_Surface *surf); } //extern C #endif +#define SDLC_KEYSTATE_LEFTCTRL SDLK_LCTRL +#define SDLC_KEYSTATE_RIGHTCTRL SDLK_RCTRL #define SDLC_KEYSTATE_LEFTSHIFT SDLK_LSHIFT #define SDLC_KEYSTATE_RIGHTSHIFT SDLK_LSHIFT #define SDLC_KEYSTATE_MENU SDLK_MENU @@ -53,11 +57,7 @@ inline int SDLC_SetColorKey(SDL_Surface *surface, Uint32 key) inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors) { #ifdef USE_SDL1 - int flags = SDL_LOGPAL; -#if SDL1_VIDEO_MODE_BPP == 8 - flags |= SDL_PHYSPAL; -#endif - return SDL_SetPalette(surface, flags, colors, firstcolor, ncolors) - 1; + return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) - 1; #else return SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, ncolors); #endif diff --git a/SourceX/DiabloUI/credits.cpp b/SourceX/DiabloUI/credits.cpp index 326eb821476..42f6bb2345b 100644 --- a/SourceX/DiabloUI/credits.cpp +++ b/SourceX/DiabloUI/credits.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/SourceX/DiabloUI/diabloui.cpp b/SourceX/DiabloUI/diabloui.cpp index b346253d8e0..c53843df6b7 100644 --- a/SourceX/DiabloUI/diabloui.cpp +++ b/SourceX/DiabloUI/diabloui.cpp @@ -36,6 +36,7 @@ Art ArtBackground; Art ArtCursor; Art ArtHero; bool gbSpawned; +int heroLevel; void (*gfnSoundFunction)(char *file); void (*gfnListFocus)(int value); @@ -188,6 +189,29 @@ void selhero_CatToName(char *in_buf, char *out_buf, int cnt) void UiFocusNavigation(SDL_Event *event) { + switch (event->type) { + case SDL_KEYUP: + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEMOTION: +#ifndef USE_SDL1 + case SDL_MOUSEWHEEL: +#endif + case SDL_JOYBUTTONUP: + case SDL_JOYAXISMOTION: + case SDL_JOYBALLMOTION: + case SDL_JOYHATMOTION: +#ifndef USE_SDL1 + case SDL_FINGERUP: + case SDL_FINGERMOTION: + case SDL_CONTROLLERBUTTONUP: + case SDL_CONTROLLERAXISMOTION: + case SDL_WINDOWEVENT: +#endif + case SDL_SYSWMEVENT: + mainmenu_restart_repintro(); + break; + } + switch (GetMenuAction(*event)) { case MenuAction::SELECT: UiFocusNavigationSelect(); @@ -216,27 +240,16 @@ void UiFocusNavigation(SDL_Event *event) break; } - switch (event->type) { - case SDL_KEYUP: - case SDL_MOUSEBUTTONUP: - case SDL_MOUSEMOTION: #ifndef USE_SDL1 - case SDL_MOUSEWHEEL: -#endif - case SDL_JOYBUTTONUP: - case SDL_JOYAXISMOTION: - case SDL_JOYBALLMOTION: - case SDL_JOYHATMOTION: -#ifndef USE_SDL1 - case SDL_FINGERUP: - case SDL_FINGERMOTION: - case SDL_CONTROLLERBUTTONUP: - case SDL_CONTROLLERAXISMOTION: - case SDL_WINDOWEVENT: -#endif - case SDL_SYSWMEVENT: - mainmenu_restart_repintro(); + if (event->type == SDL_MOUSEWHEEL) { + if (event->wheel.y > 0) { + UiFocus(SelectedItem - 1, UiItemsWraps); + } else if (event->wheel.y < 0) { + UiFocus(SelectedItem + 1, UiItemsWraps); + } + return; } +#endif if (SDL_IsTextInputActive()) { switch (event->type) { @@ -300,6 +313,15 @@ void UiFocusNavigation(SDL_Event *event) void UiHandleEvents(SDL_Event *event) { + if (event->type == SDL_MOUSEMOTION) { +#ifdef USE_SDL1 + OutputToLogical(&event->motion.x, &event->motion.y); +#endif + MouseX = event->motion.x; + MouseY = event->motion.y; + return; + } + if (event->type == SDL_QUIT) exit(0); @@ -308,6 +330,13 @@ void UiHandleEvents(SDL_Event *event) InitController(); return; } + + if (event->type == SDL_WINDOWEVENT) { + if (event->window.event == SDL_WINDOWEVENT_SHOWN) + gbActive = true; + else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) + gbActive = false; + } #endif } @@ -376,7 +405,6 @@ void UiInitialize() int UiProfileGetString() { - DUMMY(); return 0; } @@ -416,6 +444,27 @@ BOOL UiValidPlayerName(char *name) if (*letter < 0x20 || (*letter > 0x7E && *letter < 0xC0)) return false; + char *reserved[] = { + "gvdl", + "dvou", + "tiju", + "cjudi", + "bttipmf", + "ojhhfs", + "cmj{{bse", + "benjo", + }; + + char tmpname[PLR_NAME_LEN]; + strcpy(tmpname, name); + for (size_t i = 0, n = strlen(tmpname); i < n; i++) + tmpname[i]++; + + for (uint32_t i = 0; i < sizeof(reserved) / sizeof(*reserved); i++) { + if (strstr(tmpname, reserved[i])) + return false; + } + return true; } @@ -808,8 +857,6 @@ void DrawMouse() if (sgbControllerActive) return; - SDL_GetMouseState(&MouseX, &MouseY); - OutputToLogical(&MouseX, &MouseY); DrawArt(MouseX, MouseY, &ArtCursor); } diff --git a/SourceX/DiabloUI/diabloui.h b/SourceX/DiabloUI/diabloui.h index 1a710750b08..79de800fd15 100644 --- a/SourceX/DiabloUI/diabloui.h +++ b/SourceX/DiabloUI/diabloui.h @@ -26,6 +26,7 @@ extern Art ArtBackground; extern Art ArtCursor; extern Art ArtHero; extern bool gbSpawned; +extern int heroLevel; constexpr auto MAINMENU_BACKGROUND = UiImage(&ArtBackground, { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT }); constexpr auto MAINMENU_LOGO = UiImage(&ArtLogos[LOGO_MED], /*animated=*/true, /*frame=*/0, { 0, 0, 0, 0 }, UIS_CENTER); diff --git a/SourceX/DiabloUI/dialogs.cpp b/SourceX/DiabloUI/dialogs.cpp index 14e9c5f7be7..a1236a397b5 100644 --- a/SourceX/DiabloUI/dialogs.cpp +++ b/SourceX/DiabloUI/dialogs.cpp @@ -16,7 +16,6 @@ extern SDL_Surface *pal_surface; namespace { Art dialogArt; -Art progressArt; char dialogText[256]; char dialogCaption[1024]; bool fontWasLoaded; @@ -25,29 +24,17 @@ bool textInputWasActive; UiItem *dialogItems; std::size_t dialogItemsSize; -enum class State { - DEFAULT = 0, - OK, - CANCEL, -}; - -State state; +bool dialogEnd; void DialogActionOK() { - state = State::OK; -} - -void DialogActionCancel() -{ - state = State::CANCEL; + dialogEnd = true; } -constexpr auto DIALOG_ART_S = UiImage(&dialogArt, { 180, 168, 280, 144 }); constexpr auto DIALOG_ART_L = UiImage(&dialogArt, { 127, 100, 385, 280 }); UiItem OK_DIALOG[] = { - DIALOG_ART_S, + UiImage(&dialogArt, { 180, 168, 280, 144 }), UiText(dialogText, { 200, 211, 240, 80 }, UIS_CENTER), MakeSmlButton("OK", &DialogActionOK, 265, 265), }; @@ -59,26 +46,6 @@ UiItem OK_DIALOG_WITH_CAPTION[] = { MakeSmlButton("OK", &DialogActionOK, 264, 335), }; -UiItem PROGRESS_DIALOG[] = { - DIALOG_ART_S, - UiText(dialogText, { 180, 177, 280, 43 }, UIS_CENTER), - UiImage(&progressArt, { 205, 220, 228, 38 }), - MakeSmlButton("Cancel", &DialogActionCancel, 330, 265), -}; - -UiListItem SELOK_DIALOG_ITEMS[] = { - { "OK", 0 } -}; -UiItem SELOK_DIALOG[] = { - UiText(dialogText, { 140, 210, 400, 168 }, UIS_CENTER), - UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER), -}; - -UiItem SPAWNERR_DIALOG[] = { - UiText("The Rogue and Sorcerer are only available in the full retail version of Diablo. For ordering information visit https://www.gog.com/game/diablo.", { 140, 199, 400, 177 }), - UiArtTextButton("OK", &DialogActionOK, { 230, 407, 180, 43 }), -}; - // clang-format off #define BLANKCOLOR { 0, 0xFF, 0, 0 } // clang-format on @@ -248,7 +215,7 @@ void Deinit() void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std::size_t render_behind_size) { SDL_Event event; - state = State::DEFAULT; + dialogEnd = false; if (render_behind_size == 0) { LoadBackgroundArt("ui_art\\black.pcx"); if (ArtBackground.surface == nullptr) { @@ -266,7 +233,7 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std switch (GetMenuAction(event)) { case MenuAction::BACK: case MenuAction::SELECT: - state = State::OK; + dialogEnd = true; break; default: break; @@ -284,7 +251,7 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std UiRenderItems(items, num_items); DrawMouse(); UiFadeIn(); - } while (state == State::DEFAULT); + } while (!dialogEnd); } } // namespace diff --git a/SourceX/DiabloUI/fonts.cpp b/SourceX/DiabloUI/fonts.cpp index 754d1c4b0fa..c1dec4b1b5f 100644 --- a/SourceX/DiabloUI/fonts.cpp +++ b/SourceX/DiabloUI/fonts.cpp @@ -52,7 +52,7 @@ void UnloadArtFonts() void LoadTtfFont() { if (!TTF_WasInit()) { if (TTF_Init() == -1) { - printf("TTF_Init: %s\n", TTF_GetError()); + SDL_Log("TTF_Init: %s", TTF_GetError()); exit(1); } atexit(TTF_Quit); @@ -60,7 +60,7 @@ void LoadTtfFont() { font = TTF_OpenFont(TTF_FONT_PATH, 17); if (font == NULL) { - printf("TTF_OpenFont: %s\n", TTF_GetError()); + SDL_Log("TTF_OpenFont: %s", TTF_GetError()); return; } diff --git a/SourceX/DiabloUI/mainmenu.cpp b/SourceX/DiabloUI/mainmenu.cpp index 91e04a2f2af..8e145eb4964 100644 --- a/SourceX/DiabloUI/mainmenu.cpp +++ b/SourceX/DiabloUI/mainmenu.cpp @@ -1,5 +1,6 @@ #include "devilution.h" #include "DiabloUI/diabloui.h" +#include "DiabloUI/selok.h" namespace dvl { @@ -8,11 +9,11 @@ DWORD dwAttractTicks; int MainMenuResult; UiListItem MAINMENU_DIALOG_ITEMS[] = { - {"Single Player", MAINMENU_SINGLE_PLAYER}, - {"Multi Player", MAINMENU_MULTIPLAYER}, - {"Replay Intro", MAINMENU_REPLAY_INTRO}, - {"Show Credits", MAINMENU_SHOW_CREDITS}, - {"Exit Diablo", MAINMENU_EXIT_DIABLO} + { "Single Player", MAINMENU_SINGLE_PLAYER }, + { "Multi Player", MAINMENU_MULTIPLAYER }, + { "Replay Intro", MAINMENU_REPLAY_INTRO }, + { "Show Credits", MAINMENU_SHOW_CREDITS }, + { "Exit Diablo", MAINMENU_EXIT_DIABLO } }; UiItem MAINMENU_DIALOG[] = { MAINMENU_BACKGROUND, @@ -41,8 +42,6 @@ void mainmenu_Load(char *name, void (*fnSound)(char *file)) gfnSoundFunction = fnSound; MAINMENU_DIALOG[size(MAINMENU_DIALOG) - 1].art_text.text = name; - MainMenuResult = 0; - if (!gbSpawned) { LoadBackgroundArt("ui_art\\mainmenu.pcx"); } else { @@ -59,23 +58,31 @@ void mainmenu_Free() BOOL UiMainMenuDialog(char *name, int *pdwResult, void (*fnSound)(char *file), int attractTimeOut) { - mainmenu_attract_time_out = attractTimeOut; - mainmenu_Load(name, fnSound); + MainMenuResult = 0; + while (MainMenuResult == 0) { + mainmenu_attract_time_out = attractTimeOut; + mainmenu_Load(name, fnSound); - mainmenu_restart_repintro(); // for automatic starts + mainmenu_restart_repintro(); // for automatic starts - while (MainMenuResult == 0) { - UiPollAndRender(); - if (GetTickCount() >= dwAttractTicks) { - MainMenuResult = MAINMENU_ATTRACT_MODE; + while (MainMenuResult == 0) { + UiPollAndRender(); + if (!gbSpawned && GetTickCount() >= dwAttractTicks) { + MainMenuResult = MAINMENU_ATTRACT_MODE; + } } - } - BlackPalette(); - mainmenu_Free(); + BlackPalette(); + mainmenu_Free(); + + if (gbSpawned && MainMenuResult == MAINMENU_REPLAY_INTRO) { + UiSelOkDialog(nullptr, "The Diablo introduction cinematic is only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.", true); + MainMenuResult = 0; + } + } *pdwResult = MainMenuResult; return true; } -} +} // namespace dvl diff --git a/SourceX/DiabloUI/progress.cpp b/SourceX/DiabloUI/progress.cpp index c591195308d..3383b4128b4 100644 --- a/SourceX/DiabloUI/progress.cpp +++ b/SourceX/DiabloUI/progress.cpp @@ -8,12 +8,29 @@ namespace dvl { +Art dialogArt; +char dialogText[256]; +Art progressArt; Art ArtPopupSm; Art ArtProgBG; Art ProgFil; SDL_Surface *msgSurface; SDL_Surface *cancleSurface; int textWidth; +bool endMenu; + +void DialogActionCancel() +{ + endMenu = true; +} + +// TODO use PROGRESS_DIALOG for rendering the progressbar or delete it +UiItem PROGRESS_DIALOG[] = { + UiImage(&dialogArt, { 180, 168, 280, 144 }), + UiText(dialogText, { 180, 177, 280, 43 }, UIS_CENTER), + UiImage(&progressArt, { 205, 220, 228, 38 }), + MakeSmlButton("Cancel", &DialogActionCancel, 330, 265), +}; void progress_Load(char *msg) { @@ -82,7 +99,7 @@ BOOL UiProgressDialog(HWND window, char *msg, int enable, int (*fnfunc)(), int r { progress_Load(msg); - bool endMenu = false; + endMenu = false; int progress = 0; SDL_Event event; diff --git a/SourceX/DiabloUI/selgame.cpp b/SourceX/DiabloUI/selgame.cpp index 6e20d0f22cf..e43e946bb67 100644 --- a/SourceX/DiabloUI/selgame.cpp +++ b/SourceX/DiabloUI/selgame.cpp @@ -5,6 +5,7 @@ #include "DiabloUI/diabloui.h" #include "DiabloUI/text.h" #include "DiabloUI/dialogs.h" +#include "DiabloUI/selok.h" namespace dvl { @@ -26,6 +27,9 @@ constexpr UiArtTextButton SELGAME_CANCEL = UiArtTextButton("CANCEL", &UiFocusNav UiArtText SELGAME_DESCRIPTION(selgame_Description, { 35, 256, 205, 192 }); +namespace { + +char title[32]; UiListItem SELDIFF_DIALOG_ITEMS[] = { { "Normal", DIFF_NORMAL }, { "Nightmare", DIFF_NIGHTMARE }, @@ -34,7 +38,7 @@ UiListItem SELDIFF_DIALOG_ITEMS[] = { UiItem SELDIFF_DIALOG[] = { MAINMENU_BACKGROUND, MAINMENU_LOGO, - UiArtText("Create Game", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), + UiArtText(title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), UiArtText(selgame_Label, { 34, 211, 205, 33 }, UIS_CENTER | UIS_BIG), // DIFF SELGAME_DESCRIPTION, UiArtText("Select Difficulty", { 299, 211, 295, 35 }, UIS_CENTER | UIS_BIG), @@ -43,7 +47,7 @@ UiItem SELDIFF_DIALOG[] = { SELGAME_CANCEL, }; -constexpr UiArtText SELUDPGAME_TITLE = UiArtText("Join TCP/UDP Games", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG); +constexpr UiArtText SELUDPGAME_TITLE = UiArtText(title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG); constexpr UiArtText SELUDPGAME_DESCRIPTION_LABEL = UiArtText("Description:", { 35, 211, 205, 192 }, UIS_MED); UiListItem SELUDPGAME_DIALOG_ITEMS[] = { @@ -86,6 +90,8 @@ UiItem ENTERPASSWORD_DIALOG[] = { SELGAME_CANCEL, }; +} // namespace + void selgame_Free() { ArtBackground.Unload(); @@ -103,6 +109,7 @@ void selgame_GameSelection_Init() } getIniValue("Phone Book", "Entry1", selgame_Ip, 128); + strcpy(title, "Client-Server (TCP)"); UiInitList(0, 1, selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, SELUDPGAME_DIALOG, size(SELUDPGAME_DIALOG)); } @@ -126,9 +133,11 @@ void selgame_GameSelection_Select(int value) switch (value) { case 0: + strcpy(title, "Create Game"); UiInitList(0, NUM_DIFFICULTIES - 1, selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, SELDIFF_DIALOG, size(SELDIFF_DIALOG)); break; case 1: + strcpy(title, "Join TCP Games"); UiInitList(0, 0, NULL, selgame_Password_Init, selgame_GameSelection_Init, ENTERIP_DIALOG, size(ENTERIP_DIALOG)); break; } @@ -160,8 +169,32 @@ void selgame_Diff_Focus(int value) WordWrapArtStr(selgame_Description, SELGAME_DESCRIPTION.rect.w); } +bool IsDifficultyAllowed(int value) +{ + if (value == 0 || (value == 1 && heroLevel >= 20) || (value == 2 && heroLevel >= 30)) { + return true; + } + + selgame_Free(); + BlackPalette(); + + if (value == 1) + UiSelOkDialog(title, "Your character must reach level 20 before you can enter a multiplayer game of Nightmare difficulty.", false); + if (value == 2) + UiSelOkDialog(title, "Your character must reach level 30 before you can enter a multiplayer game of Hell difficulty.", false); + + LoadBackgroundArt("ui_art\\selgame.pcx"); + + return false; +} + void selgame_Diff_Select(int value) { + if (!IsDifficultyAllowed(value)) { + selgame_GameSelection_Select(0); + return; + } + gbDifficulty = value; if (provider == SELCONN_LOOPBACK) { @@ -193,13 +226,18 @@ void selgame_Password_Select(int value) if (selgame_selectedGame) { setIniValue("Phone Book", "Entry1", selgame_Ip); if (SNetJoinGame(selgame_selectedGame, selgame_Ip, selgame_Password, NULL, NULL, gdwPlayerId)) { + if (!IsDifficultyAllowed(m_client_info->initdata->bDiff)) { + selgame_GameSelection_Select(1); + return; + } + UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); selgame_endMenu = true; } else { - UiErrorOkDialog( - "Unable to establish a connection.", - PROJECT_NAME " v" PROJECT_VERSION " game not found or password invalid.", - ENTERPASSWORD_DIALOG, size(ENTERPASSWORD_DIALOG)); + selgame_Free(); + BlackPalette(); + UiSelOkDialog("Multi Player Game", SDL_GetError(), false); + LoadBackgroundArt("ui_art\\selgame.pcx"); selgame_Password_Init(selgame_selectedGame); } return; @@ -212,7 +250,10 @@ void selgame_Password_Select(int value) UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); selgame_endMenu = true; } else { - UiErrorOkDialog("Unable to create game.", ENTERPASSWORD_DIALOG, size(ENTERPASSWORD_DIALOG)); + selgame_Free(); + BlackPalette(); + UiSelOkDialog("Multi Player Game", SDL_GetError(), false); + LoadBackgroundArt("ui_art\\selgame.pcx"); selgame_Password_Init(0); } } @@ -239,4 +280,4 @@ int UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_in return selgame_enteringGame; } -} +} // namespace dvl diff --git a/SourceX/DiabloUI/selhero.cpp b/SourceX/DiabloUI/selhero.cpp index 5e28d574eb7..be3c2d5c961 100644 --- a/SourceX/DiabloUI/selhero.cpp +++ b/SourceX/DiabloUI/selhero.cpp @@ -1,15 +1,16 @@ #include "selhero.h" -#include #include #include #include #include "DiabloUI/diabloui.h" -#include "DiabloUI/dialogs.h" +#include "../../DiabloUI/diabloui.h" #include "devilution.h" -#include "scrollbar.h" -#include "selyesno.h" +#include "DiabloUI/dialogs.h" +#include "DiabloUI/scrollbar.h" +#include "DiabloUI/selyesno.h" +#include "DiabloUI/selok.h" namespace dvl { @@ -32,8 +33,6 @@ BOOL(*gfnHeroStats) (unsigned int, _uidefaultstats *); BOOL(*gfnHeroCreate) (_uiheroinfo *); -BOOL(*gfnHeroDelete) -(_uiheroinfo *); namespace { @@ -59,7 +58,7 @@ UiListItem SELLIST_DIALOG_ITEMS[kMaxViewportItems]; UiItem SELLIST_DIALOG[] = { UiArtText("Select Hero", { 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG), UiList(SELLIST_DIALOG_ITEMS, 265, 256, 320, 26, UIS_CENTER | UIS_MED | UIS_GOLD), - MakeScrollBar({585, 244, 25, 178}), + MakeScrollBar({ 585, 244, 25, 178 }), UiArtTextButton("OK", &UiFocusNavigationSelect, { 239, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD), UiArtTextButton("Delete", &selhero_UiFocusNavigationYesNo, { 364, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_DISABLED), UiArtTextButton("Cancel", &UiFocusNavigationEsc, { 489, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD) @@ -239,6 +238,15 @@ void selhero_ClassSelector_Focus(int value) void selhero_ClassSelector_Select(int value) { + if (gbSpawned && (value == 1 || value == 2)) { + selhero_Free(); + BlackPalette(); + UiSelOkDialog(nullptr, "The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.", false); + LoadBackgroundArt("ui_art\\selhero.pcx"); + selhero_List_Select(selhero_SaveCount); + return; + } + strcpy(title, "New Single Player Hero"); if (selhero_isMultiPlayer) { strcpy(title, "New Multi Player Hero"); @@ -262,14 +270,42 @@ void selhero_ClassSelector_Esc() void selhero_Name_Select(int value) { - if (gfnHeroCreate(&selhero_heroInfo)) { - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); - selhero_endMenu = true; + + if (!UiValidPlayerName(selhero_heroInfo.name)) { + selhero_Free(); + BlackPalette(); + UiSelOkDialog(title, "Invalid name. A name cannot contain spaces, reserved characters, or reserved words.\n", false); + LoadBackgroundArt("ui_art\\selhero.pcx"); } else { - UiErrorOkDialog("Unable to create character.", SELHERO_DIALOG, size(SELHERO_DIALOG)); - memset(selhero_heroInfo.name, '\0', sizeof(selhero_heroInfo.name)); - selhero_ClassSelector_Select(selhero_heroInfo.heroclass); + bool overwrite = true; + for (std::size_t i = 0; i < selhero_SaveCount; i++) { + if (strcasecmp(selhero_heros[i].name, selhero_heroInfo.name) == 0) { + selhero_Free(); + BlackPalette(); + char dialogText[256]; + sprintf(dialogText, "Character already exists. Do you want to overwrite \"%s\"?", selhero_heroInfo.name); + overwrite = UiSelHeroYesNoDialog(title, dialogText); + LoadBackgroundArt("ui_art\\selhero.pcx"); + break; + } + } + + if (overwrite) { + if (gfnHeroCreate(&selhero_heroInfo)) { + UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + selhero_endMenu = true; + return; + } else { + UiErrorOkDialog("Unable to create character.", SELHERO_DIALOG, size(SELHERO_DIALOG)); + } + } } + + memset(selhero_heroInfo.name, '\0', sizeof(selhero_heroInfo.name)); +#ifdef PREFILL_PLAYER_NAME + strcpy(selhero_heroInfo.name, selhero_GenerateName(selhero_heroInfo.heroclass)); +#endif + selhero_ClassSelector_Select(selhero_heroInfo.heroclass); } void selhero_Name_Esc() @@ -316,7 +352,6 @@ BOOL UiSelHeroDialog( selhero_result = *dlgresult; gfnHeroStats = fnstats; gfnHeroCreate = fncreate; - gfnHeroDelete = fnremove; selhero_navigateYesNo = false; @@ -339,13 +374,23 @@ BOOL UiSelHeroDialog( selhero_Free(); if (selhero_navigateYesNo) { - if (!UiSelHeroDelYesNoDialog(gfnHeroDelete, &selhero_heroInfo, selhero_isMultiPlayer)) - app_fatal("Unable to load Yes/No dialog"); + char dialogTitle[32]; + char dialogText[256]; + if (selhero_isMultiPlayer) { + strcpy(dialogTitle, "Delete Multi Player Hero"); + } else { + strcpy(dialogTitle, "Delete Single Player Hero"); + } + sprintf(dialogText, "Are you sure you want to delete the character \"%s\"?", selhero_heroInfo.name); + + if (UiSelHeroYesNoDialog(dialogTitle, dialogText)) + fnremove(&selhero_heroInfo); } } while (selhero_navigateYesNo); *dlgresult = selhero_result; strcpy(name, selhero_heroInfo.name); + heroLevel = selhero_heroInfo.level; UnloadScrollBar(); return true; diff --git a/SourceX/DiabloUI/selok.cpp b/SourceX/DiabloUI/selok.cpp new file mode 100644 index 00000000000..2023ed49f0a --- /dev/null +++ b/SourceX/DiabloUI/selok.cpp @@ -0,0 +1,86 @@ +#include "devilution.h" +#include "DiabloUI/diabloui.h" +#include "DiabloUI/text.h" +#include "DiabloUI/selok.h" + +namespace dvl { + +namespace { + +char dialogText[256]; + +} // namespace + +int selok_endMenu; +char selok_title[32]; + +void selok_Free() +{ + ArtBackground.Unload(); +} + +void selok_Select(int value) +{ + selok_endMenu = true; +} + +void selok_Esc() +{ + selok_endMenu = true; +} + +UiListItem SELOK_DIALOG_ITEMS[] = { + { "OK", 0 } +}; + +UiItem SELOK_DIALOG[] = { + MAINMENU_BACKGROUND, + MAINMENU_LOGO, + UiArtText(selok_title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), + UiArtText(dialogText, { 140, 210, 560, 168 }, UIS_MED), + UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD) +}; + +UiItem SPAWNERR_DIALOG[] = { + MAINMENU_BACKGROUND, + MAINMENU_LOGO, + UiArtText(dialogText, { 140, 197, 560, 168 }, UIS_MED), + UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD) +}; + +void UiSelOkDialog(const char *title, const char *body, bool background) +{ + if (!background) { + LoadBackgroundArt("ui_art\\black.pcx"); + } else { + if (!gbSpawned) { + LoadBackgroundArt("ui_art\\mainmenu.pcx"); + } else { + LoadBackgroundArt("ui_art\\swmmenu.pcx"); + } + } + + UiItem *items = SPAWNERR_DIALOG; + int itemCnt = size(SPAWNERR_DIALOG); + if (title != nullptr) { + strcpy(selok_title, title); + items = SELOK_DIALOG; + itemCnt = size(SELOK_DIALOG); + } + + strcpy(dialogText, body); + WordWrapArtStr(dialogText, 280); + + UiInitList(0, 0, NULL, selok_Select, selok_Esc, items, itemCnt, false, NULL); + + selok_endMenu = false; + while (!selok_endMenu) { + UiRenderItems(items, itemCnt); + UiPollAndRender(); + } + + BlackPalette(); + + selok_Free(); +} +} // namespace dvl diff --git a/SourceX/DiabloUI/selok.h b/SourceX/DiabloUI/selok.h new file mode 100644 index 00000000000..05e95358800 --- /dev/null +++ b/SourceX/DiabloUI/selok.h @@ -0,0 +1,11 @@ +#pragma once + +#include "devilution.h" + +namespace dvl { +void UiSelOkDialog(const char *title, const char *body, bool background); +void selok_Free(); +void selok_Select(int value); +void selok_Esc(); + +} diff --git a/SourceX/DiabloUI/selyesno.cpp b/SourceX/DiabloUI/selyesno.cpp index 8966a0537c0..0f20339a832 100644 --- a/SourceX/DiabloUI/selyesno.cpp +++ b/SourceX/DiabloUI/selyesno.cpp @@ -6,10 +6,8 @@ namespace dvl { -_uiheroinfo selyesno_heroInfo; -int selyesno_endMenu; -BOOL(*selyesno_gfnRemove) -(_uiheroinfo *); +bool selyesno_endMenu; +bool selyesno_value; char selyesno_confirmationMessage[256]; char selyesno_title[32]; @@ -34,37 +32,27 @@ void selyesno_Free() void selyesno_Select(int value) { - if (value == 0) - selyesno_gfnRemove(&selyesno_heroInfo); - + selyesno_value = value == 0; selyesno_endMenu = true; } void selyesno_Esc() { + selyesno_value = false; selyesno_endMenu = true; } -BOOL UiSelHeroDelYesNoDialog( - BOOL (*fnremove)(_uiheroinfo *), - _uiheroinfo *selectHero, - bool isMultiplayer) +bool UiSelHeroYesNoDialog(const char *title, const char *body) { - selyesno_heroInfo = *selectHero; - selyesno_gfnRemove = fnremove; LoadBackgroundArt("ui_art\\black.pcx"); - if (isMultiplayer) { - strcpy(selyesno_title, "Delete Multi Player Hero"); - } else { - strcpy(selyesno_title, "Delete Single Player Hero"); - } - - sprintf(selyesno_confirmationMessage, "Are you sure you want to delete the character \"%s\"?", selyesno_heroInfo.name); + strcpy(selyesno_title, title); + strcpy(selyesno_confirmationMessage, body); WordWrapArtStr(selyesno_confirmationMessage, SELYESNO_DIALOG_CONFIRMATION_MESSAGE->rect.w); UiInitList(0, 1, NULL, selyesno_Select, selyesno_Esc, SELYESNO_DIALOG, size(SELYESNO_DIALOG), true, NULL); + selyesno_value = true; selyesno_endMenu = false; while (!selyesno_endMenu) { UiRenderItems(SELYESNO_DIALOG, size(SELYESNO_DIALOG)); @@ -74,6 +62,7 @@ BOOL UiSelHeroDelYesNoDialog( BlackPalette(); selyesno_Free(); - return true; + + return selyesno_value; } } diff --git a/SourceX/DiabloUI/selyesno.h b/SourceX/DiabloUI/selyesno.h index e1b77fa5c1f..4405b5dcdb3 100644 --- a/SourceX/DiabloUI/selyesno.h +++ b/SourceX/DiabloUI/selyesno.h @@ -3,7 +3,7 @@ #include "devilution.h" namespace dvl { -BOOL UiSelHeroDelYesNoDialog(BOOL (*fnremove)(_uiheroinfo *), _uiheroinfo *selectHero, bool isMultiplayer); +bool UiSelHeroYesNoDialog(const char *title, const char *body); void selyesno_Free(); void selyesno_Select(int value); void selyesno_Esc(); diff --git a/SourceX/controls/README.md b/SourceX/controls/README.md index 770854e037f..241848a6ac3 100644 --- a/SourceX/controls/README.md +++ b/SourceX/controls/README.md @@ -35,5 +35,5 @@ cmake .. -DUSE_SDL1=ON -DHAS_KBCTRL=1 -DPREFILL_PLAYER_NAME=ON \ -DKBCTRL_BUTTON_LEFTSHOULDER=SDLK_LEFTBRACKET \ -DKBCTRL_BUTTON_LEFTSTICK=SDLK_TAB \ -DKBCTRL_BUTTON_START=SDLK_RETURN \ --DKBCTRL_MODIFIER_KEY=SDLK_LSHIFT +-DKBCTRL_BUTTON_BACK=SDLK_LSHIFT ``` diff --git a/SourceX/controls/controller_buttons.h b/SourceX/controls/controller_buttons.h index 3da3ad2c646..9e1405fa035 100644 --- a/SourceX/controls/controller_buttons.h +++ b/SourceX/controls/controller_buttons.h @@ -28,4 +28,12 @@ enum class ControllerButton { BUTTON_DPAD_RIGHT }; +inline bool IsDPadButton(ControllerButton button) +{ + return button == ControllerButton::BUTTON_DPAD_UP + || button == ControllerButton::BUTTON_DPAD_DOWN + || button == ControllerButton::BUTTON_DPAD_LEFT + || button == ControllerButton::BUTTON_DPAD_RIGHT; +} + } // namespace dvl diff --git a/SourceX/controls/controller_motion.cpp b/SourceX/controls/controller_motion.cpp index 8b9772d2040..123d444a375 100644 --- a/SourceX/controls/controller_motion.cpp +++ b/SourceX/controls/controller_motion.cpp @@ -3,6 +3,7 @@ #include "controls/devices/game_controller.h" #include "controls/devices/joystick.h" #include "controls/devices/kbcontroller.h" +#include "controls/controller.h" namespace dvl { @@ -93,7 +94,32 @@ bool ProcessControllerMotion(const SDL_Event &event) if (ProcessKbCtrlAxisMotion(event)) return true; #endif - return false; + + // SELECT + D-Pad simulating mouse movement. + if (!IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) { + rightStickX = 0; + rightStickY = 0; + return false; + } + + const ControllerButtonEvent ctrl_event = ToControllerButtonEvent(event); + if (!IsDPadButton(ctrl_event.button)) + return false; + if (IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_LEFT)) { + rightStickX = -1; + } else if (IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_RIGHT)) { + rightStickX = 1; + } else { + rightStickX = 0; + } + if (IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_UP)) { + rightStickY = 1; + } else if (IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_DOWN)) { + rightStickY = -1; + } else { + rightStickY = 0; + } + return true; } } // namespace dvl diff --git a/SourceX/controls/devices/kbcontroller.cpp b/SourceX/controls/devices/kbcontroller.cpp index 3fb40e5e069..670444bc34c 100644 --- a/SourceX/controls/devices/kbcontroller.cpp +++ b/SourceX/controls/devices/kbcontroller.cpp @@ -3,25 +3,11 @@ #if HAS_KBCTRL == 1 #include "controls/controller_motion.h" -#include "sdl2_to_1_2_backports.h" #include "sdl_compat.h" #include "stubs.h" namespace dvl { -namespace { - -bool IsModifierKey() -{ -#ifdef KBCTRL_MODIFIER_KEY - return SDLC_GetKeyState()[KBCTRL_MODIFIER_KEY]; -#else - return false; -#endif -} - -} // namespace - ControllerButton KbCtrlToControllerButton(const SDL_Event &event) { switch (event.type) { @@ -32,24 +18,16 @@ ControllerButton KbCtrlToControllerButton(const SDL_Event &event) case KBCTRL_IGNORE_1: return ControllerButton::IGNORE; #endif -#ifdef KBCTRL_MODIFIER_KEY - case KBCTRL_MODIFIER_KEY: - return ControllerButton::IGNORE; -#endif #ifdef KBCTRL_BUTTON_A case KBCTRL_BUTTON_A: return ControllerButton::BUTTON_A; #endif #ifdef KBCTRL_BUTTON_B case KBCTRL_BUTTON_B: // Right button - if (IsModifierKey()) - return ControllerButton::BUTTON_RIGHTSTICK; return ControllerButton::BUTTON_B; #endif #ifdef KBCTRL_BUTTON_X case KBCTRL_BUTTON_X: // Left button - if (IsModifierKey()) - return ControllerButton::BUTTON_BACK; return ControllerButton::BUTTON_X; #endif #ifdef KBCTRL_BUTTON_Y @@ -66,14 +44,10 @@ ControllerButton KbCtrlToControllerButton(const SDL_Event &event) #endif #ifdef KBCTRL_BUTTON_LEFTSHOULDER case KBCTRL_BUTTON_LEFTSHOULDER: - if (IsModifierKey()) - return ControllerButton::AXIS_TRIGGERLEFT; return ControllerButton::BUTTON_LEFTSHOULDER; #endif #ifdef KBCTRL_BUTTON_RIGHTSHOULDER case KBCTRL_BUTTON_RIGHTSHOULDER: - if (IsModifierKey()) - return ControllerButton::AXIS_TRIGGERRIGHT; return ControllerButton::BUTTON_RIGHTSHOULDER; #endif #ifdef KBCTRL_BUTTON_START @@ -86,26 +60,18 @@ ControllerButton KbCtrlToControllerButton(const SDL_Event &event) #endif #ifdef KBCTRL_BUTTON_DPAD_UP case KBCTRL_BUTTON_DPAD_UP: - if (IsModifierKey()) - return ControllerButton::IGNORE; return ControllerButton::BUTTON_DPAD_UP; #endif #ifdef KBCTRL_BUTTON_DPAD_DOWN case KBCTRL_BUTTON_DPAD_DOWN: - if (IsModifierKey()) - return ControllerButton::IGNORE; return ControllerButton::BUTTON_DPAD_DOWN; #endif #ifdef KBCTRL_BUTTON_DPAD_LEFT case KBCTRL_BUTTON_DPAD_LEFT: - if (IsModifierKey()) - return ControllerButton::IGNORE; return ControllerButton::BUTTON_DPAD_LEFT; #endif #ifdef KBCTRL_BUTTON_DPAD_RIGHT case KBCTRL_BUTTON_DPAD_RIGHT: - if (IsModifierKey()) - return ControllerButton::IGNORE; return ControllerButton::BUTTON_DPAD_RIGHT; #endif default: @@ -184,7 +150,9 @@ int ControllerButtonToKbCtrlKeyCode(ControllerButton button) } } -bool IsButtonPressed(ControllerButton button) +} // namespace + +bool IsKbCtrlButtonPressed(ControllerButton button) { int key_code = ControllerButtonToKbCtrlKeyCode(button); if (key_code == -1) @@ -196,44 +164,11 @@ bool IsButtonPressed(ControllerButton button) #endif } -} // namespace - -bool IsKbCtrlButtonPressed(ControllerButton button) -{ - if (IsModifierKey() && (button == ControllerButton::BUTTON_DPAD_UP || button == ControllerButton::BUTTON_DPAD_DOWN || button == ControllerButton::BUTTON_DPAD_LEFT || button == ControllerButton::BUTTON_DPAD_RIGHT)) - return false; - return IsButtonPressed(button); -} - bool ProcessKbCtrlAxisMotion(const SDL_Event &event) { - if (!IsModifierKey()) { - rightStickX = 0; - rightStickY = 0; - return false; - } - if (event.type != SDL_KEYUP && event.type != SDL_KEYDOWN) - return false; - const auto sym = event.key.keysym.sym; - if (sym != KBCTRL_BUTTON_DPAD_UP && sym != KBCTRL_BUTTON_DPAD_DOWN && sym != KBCTRL_BUTTON_DPAD_LEFT && sym != KBCTRL_BUTTON_DPAD_RIGHT) - return false; - if (IsButtonPressed(ControllerButton::BUTTON_DPAD_LEFT)) { - rightStickX = -1; - } else if (IsButtonPressed(ControllerButton::BUTTON_DPAD_RIGHT)) { - rightStickX = 1; - } else { - rightStickX = 0; - } - if (IsButtonPressed(ControllerButton::BUTTON_DPAD_UP)) { - rightStickY = 1; - } else if (IsButtonPressed(ControllerButton::BUTTON_DPAD_DOWN)) { - rightStickY = -1; - } else { - rightStickY = 0; - } - return true; + // Mapping keyboard to right stick axis not implemented. + return false; } - } // namespace dvl #endif diff --git a/SourceX/controls/game_controls.cpp b/SourceX/controls/game_controls.cpp index af10532d0ab..89142d8a5cc 100644 --- a/SourceX/controls/game_controls.cpp +++ b/SourceX/controls/game_controls.cpp @@ -7,6 +7,7 @@ #include "controls/devices/game_controller.h" #include "controls/devices/joystick.h" #include "controls/menu_controls.h" +#include "controls/modifier_hints.h" #include "controls/plrctrls.h" namespace dvl { @@ -26,8 +27,6 @@ DWORD translate_controller_button_to_key(ControllerButton controller_button) return DVL_VK_TAB; // Map case ControllerButton::BUTTON_START: return DVL_VK_ESCAPE; - case ControllerButton::BUTTON_BACK: - return 'Q'; // Quest log case ControllerButton::BUTTON_DPAD_LEFT: return DVL_VK_LEFT; case ControllerButton::BUTTON_DPAD_RIGHT: @@ -43,57 +42,182 @@ DWORD translate_controller_button_to_key(ControllerButton controller_button) } // namespace +bool start_modifier_active = false; +bool select_modifier_active = false; + bool GetGameAction(const SDL_Event &event, GameAction *action) { const ControllerButtonEvent ctrl_event = ToControllerButtonEvent(event); - if (!InGameMenu()) { + const bool in_game_menu = InGameMenu(); + + start_modifier_active = !in_game_menu && IsControllerButtonPressed(ControllerButton::BUTTON_START); + select_modifier_active = !in_game_menu && IsControllerButtonPressed(ControllerButton::BUTTON_BACK); + + // SELECT + D-Pad simulating mouse movement. + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK) && IsDPadButton(ctrl_event.button)) { + return true; + } + + // START + SELECT + if (!ctrl_event.up + && ((ctrl_event.button == ControllerButton::BUTTON_BACK && IsControllerButtonPressed(ControllerButton::BUTTON_START)) + || (ctrl_event.button == ControllerButton::BUTTON_START && IsControllerButtonPressed(ControllerButton::BUTTON_BACK)))) { + select_modifier_active = start_modifier_active = false; + *action = GameActionSendKey{ DVL_VK_ESCAPE, ctrl_event.up }; + return true; + } + + if (!in_game_menu) { switch (ctrl_event.button) { - case ControllerButton::IGNORE: - return true; - case ControllerButton::AXIS_TRIGGERLEFT: // ZL (aka L2) - if (!ctrl_event.up) - *action = GameAction(GameActionType::TOGGLE_CHARACTER_INFO); - return true; - case ControllerButton::AXIS_TRIGGERRIGHT: // ZR (aka R2) - if (!ctrl_event.up) - *action = GameAction(GameActionType::TOGGLE_INVENTORY); - return true; - case ControllerButton::BUTTON_B: // Right button - if (!ctrl_event.up) - *action = GameAction(GameActionType::PRIMARY_ACTION); - return true; - case ControllerButton::BUTTON_Y: // Top button - if (!ctrl_event.up) - *action = GameAction(GameActionType::SECONDARY_ACTION); - return true; - case ControllerButton::BUTTON_X: // Left button - if (!ctrl_event.up) - *action = GameAction(GameActionType::CAST_SPELL); - return true; - case ControllerButton::BUTTON_A: // Bottom button - if (!ctrl_event.up) - *action = GameAction(GameActionType::TOGGLE_QUICK_SPELL_MENU); - return true; case ControllerButton::BUTTON_LEFTSHOULDER: - if (!stextflag && !ctrl_event.up) - *action = GameAction(GameActionType::USE_HEALTH_POTION); - return true; + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) { + if (!IsAutomapActive()) + *action = GameActionSendMouseClick{ GameActionSendMouseClick::LEFT, ctrl_event.up }; + return true; + } + break; case ControllerButton::BUTTON_RIGHTSHOULDER: - if (!stextflag && !ctrl_event.up) - *action = GameAction(GameActionType::USE_MANA_POTION); + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) { + if (!IsAutomapActive()) + *action = GameActionSendMouseClick{ GameActionSendMouseClick::RIGHT, ctrl_event.up }; + return true; + } + break; + case ControllerButton::AXIS_TRIGGERLEFT: // ZL (aka L2) + if (!ctrl_event.up) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameAction(GameActionType::TOGGLE_QUEST_LOG); + else + *action = GameAction(GameActionType::TOGGLE_CHARACTER_INFO); + } return true; - case ControllerButton::BUTTON_DPAD_UP: - case ControllerButton::BUTTON_DPAD_DOWN: - case ControllerButton::BUTTON_DPAD_LEFT: - case ControllerButton::BUTTON_DPAD_RIGHT: - // The rest is handled in charMovement() on every game_logic() call. + case ControllerButton::AXIS_TRIGGERRIGHT: // ZR (aka R2) + if (!ctrl_event.up) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameAction(GameActionType::TOGGLE_SPELL_BOOK); + else + *action = GameAction(GameActionType::TOGGLE_INVENTORY); + } return true; - case ControllerButton::BUTTON_RIGHTSTICK: - *action = GameActionSendMouseClick { GameActionSendMouseClick::LEFT, ctrl_event.up }; + case ControllerButton::BUTTON_LEFTSTICK: + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) { + if (!IsAutomapActive()) + *action = GameActionSendMouseClick{ GameActionSendMouseClick::LEFT, ctrl_event.up }; + return true; + } + break; + case ControllerButton::BUTTON_START: + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) { + *action = GameActionSendKey{ DVL_VK_ESCAPE, ctrl_event.up }; + } return true; + break; default: break; } + if (IsControllerButtonPressed(ControllerButton::BUTTON_START)) { + switch (ctrl_event.button) { + case ControllerButton::IGNORE: + case ControllerButton::BUTTON_START: + return true; + case ControllerButton::BUTTON_DPAD_UP: + *action = GameActionSendKey{ DVL_VK_ESCAPE, ctrl_event.up }; + return true; + case ControllerButton::BUTTON_DPAD_RIGHT: + if (!ctrl_event.up) + *action = GameAction(GameActionType::TOGGLE_INVENTORY); + return true; + case ControllerButton::BUTTON_DPAD_DOWN: + *action = GameActionSendKey{ DVL_VK_TAB, ctrl_event.up }; + return true; + case ControllerButton::BUTTON_DPAD_LEFT: + if (!ctrl_event.up) + *action = GameAction(GameActionType::TOGGLE_CHARACTER_INFO); + return true; + case ControllerButton::BUTTON_Y: // Top button + // Not mapped. Reserved for future use. + return true; + case ControllerButton::BUTTON_B: // Right button + // Not mapped. TODO: map to attack in place. + return true; + case ControllerButton::BUTTON_A: // Bottom button + if (!ctrl_event.up) + *action = GameAction(GameActionType::TOGGLE_SPELL_BOOK); + return true; + case ControllerButton::BUTTON_X: // Left button + if (!ctrl_event.up) + *action = GameAction(GameActionType::TOGGLE_QUEST_LOG); + return true; + default: + return true; + } + } + if (!questlog && !sbookflag) { + switch (ctrl_event.button) { + case ControllerButton::IGNORE: + return true; + case ControllerButton::BUTTON_B: // Right button + if (!ctrl_event.up) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameActionSendKey{ DVL_VK_F8, ctrl_event.up }; + else + *action = GameAction(GameActionType::PRIMARY_ACTION); + } + return true; + case ControllerButton::BUTTON_Y: // Top button + if (!ctrl_event.up) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameActionSendKey{ DVL_VK_F6, ctrl_event.up }; + else + *action = GameAction(GameActionType::SECONDARY_ACTION); + } + return true; + case ControllerButton::BUTTON_X: // Left button + if (!ctrl_event.up) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameActionSendKey{ DVL_VK_F5, ctrl_event.up }; + else + *action = GameAction(GameActionType::CAST_SPELL); + } + return true; + case ControllerButton::BUTTON_A: // Bottom button + if (!ctrl_event.up) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameActionSendKey{ DVL_VK_F7, ctrl_event.up }; + else + *action = GameAction(GameActionType::TOGGLE_QUICK_SPELL_MENU); + } + return true; + case ControllerButton::BUTTON_LEFTSHOULDER: + if (!stextflag && !ctrl_event.up) + *action = GameAction(GameActionType::USE_HEALTH_POTION); + return true; + case ControllerButton::BUTTON_RIGHTSHOULDER: + if (!stextflag && !ctrl_event.up) + *action = GameAction(GameActionType::USE_MANA_POTION); + return true; + case ControllerButton::BUTTON_DPAD_UP: + case ControllerButton::BUTTON_DPAD_DOWN: + case ControllerButton::BUTTON_DPAD_LEFT: + case ControllerButton::BUTTON_DPAD_RIGHT: + // The rest of D-Pad actions are handled in charMovement() on every game_logic() call. + return true; + case ControllerButton::BUTTON_RIGHTSTICK: + if (!IsAutomapActive()) { + if (IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) + *action = GameActionSendMouseClick{ GameActionSendMouseClick::RIGHT, ctrl_event.up }; + else + *action = GameActionSendMouseClick{ GameActionSendMouseClick::LEFT, ctrl_event.up }; + } + return true; + default: + break; + } + } + } + + if (ctrl_event.button == ControllerButton::BUTTON_BACK) { + return true; // Ignore mod button } // By default, map to a keyboard key. diff --git a/SourceX/controls/game_controls.h b/SourceX/controls/game_controls.h index bcad974f9bb..7dfb8a94180 100644 --- a/SourceX/controls/game_controls.h +++ b/SourceX/controls/game_controls.h @@ -14,6 +14,8 @@ enum class GameActionType { TOGGLE_INVENTORY, TOGGLE_CHARACTER_INFO, TOGGLE_QUICK_SPELL_MENU, + TOGGLE_SPELL_BOOK, + TOGGLE_QUEST_LOG, SEND_KEY, SEND_MOUSE_CLICK, }; @@ -81,4 +83,7 @@ struct MoveDirection { }; MoveDirection GetMoveDirection(); +extern bool start_modifier_active; +extern bool select_modifier_active; + } // namespace dvl diff --git a/SourceX/controls/modifier_hints.cpp b/SourceX/controls/modifier_hints.cpp new file mode 100644 index 00000000000..ede43ea2326 --- /dev/null +++ b/SourceX/controls/modifier_hints.cpp @@ -0,0 +1,137 @@ +#include "controls/modifier_hints.h" + +#include + +#include "devilution.h" +#include "controls/controller.h" +#include "controls/game_controls.h" + +namespace dvl { + +namespace { + +int CalculateTextWidth(const char *s) +{ + int l = 0; + while (*s) { + l += fontkern[fontframe[gbFontTransTbl[static_cast(*s++)]]] + 1; + } + return l; +} + +int SpaceWidth() +{ + static const int kSpaceWidth = CalculateTextWidth(" "); + return kSpaceWidth; +} + +struct CircleMenuHint { + CircleMenuHint(bool is_dpad, const char *top, const char *right, const char *bottom, const char *left) + : is_dpad(is_dpad) + , top(top) + , top_w(CalculateTextWidth(top)) + , right(right) + , right_w(CalculateTextWidth(right)) + , bottom(bottom) + , bottom_w(CalculateTextWidth(bottom)) + , left(left) + , left_w(CalculateTextWidth(left)) + , x_mid(left_w + SpaceWidth() * 2.5) + { + } + + int width() const + { + return 2 * x_mid; + } + + bool is_dpad; + + const char *top; + int top_w; + const char *right; + int right_w; + const char *bottom; + int bottom_w; + const char *left; + int left_w; + + int x_mid; +}; + +bool IsTopActive(const CircleMenuHint &hint) +{ + if (hint.is_dpad) + return IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_UP); + return IsControllerButtonPressed(ControllerButton::BUTTON_Y); +} + +bool IsRightActive(const CircleMenuHint &hint) +{ + if (hint.is_dpad) + return IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_RIGHT); + return IsControllerButtonPressed(ControllerButton::BUTTON_B); +} + +bool IsBottomActive(const CircleMenuHint &hint) +{ + if (hint.is_dpad) + return IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_DOWN); + return IsControllerButtonPressed(ControllerButton::BUTTON_A); +} + +bool IsLeftActive(const CircleMenuHint &hint) +{ + if (hint.is_dpad) + return IsControllerButtonPressed(ControllerButton::BUTTON_DPAD_LEFT); + return IsControllerButtonPressed(ControllerButton::BUTTON_X); +} + +text_color CircleMenuHintTextColor(bool active) +{ + return active ? COL_BLUE : COL_GOLD; +} + +void DrawCircleMenuHint(const CircleMenuHint &hint, int x, int y) +{ + constexpr int kLineHeight = 25; + PrintGameStr(x + hint.x_mid - hint.top_w / 2, y, hint.top, CircleMenuHintTextColor(IsTopActive(hint))); + y += kLineHeight; + + PrintGameStr(x, y, hint.left, CircleMenuHintTextColor(IsLeftActive(hint))); + PrintGameStr(x + hint.left_w + 5 * SpaceWidth(), y, hint.right, CircleMenuHintTextColor(IsRightActive(hint))); + y += kLineHeight; + + PrintGameStr(x + hint.x_mid - hint.bottom_w / 2, y, hint.bottom, CircleMenuHintTextColor(IsBottomActive(hint))); +} + +constexpr int kCircleMarginX = 16; +constexpr int kCirclesTop = PANEL_TOP - 76; + +void DrawStartModifierMenu() +{ + if (!start_modifier_active) + return; + static const CircleMenuHint kDpad(/*is_dpad=*/true, /*top=*/"Menu", /*right=*/"Inv", /*bottom=*/"Map", /*left=*/"Char"); + static const CircleMenuHint kButtons(/*is_dpad=*/false, /*top=*/"", /*right=*/"", /*bottom=*/"Spells", /*left=*/"Quests"); + DrawCircleMenuHint(kDpad, kCircleMarginX, kCirclesTop); + DrawCircleMenuHint(kButtons, SCREEN_WIDTH - kButtons.width() - kCircleMarginX, kCirclesTop); +} + +void DrawSelectModifierMenu() +{ + if (!select_modifier_active) + return; + static const CircleMenuHint kSpells(/*is_dpad=*/false, "F6", "F8", "F7", "F5"); + DrawCircleMenuHint(kSpells, SCREEN_WIDTH - kSpells.width() - kCircleMarginX, kCirclesTop); +} + +} // namespace + +void DrawControllerModifierHints() +{ + DrawStartModifierMenu(); + DrawSelectModifierMenu(); +} + +} // namespace dvl diff --git a/SourceX/controls/modifier_hints.h b/SourceX/controls/modifier_hints.h new file mode 100644 index 00000000000..0095d8ada14 --- /dev/null +++ b/SourceX/controls/modifier_hints.h @@ -0,0 +1,7 @@ +#pragma once + +namespace dvl { + +void DrawControllerModifierHints(); + +} // namespace dvl diff --git a/SourceX/controls/plrctrls.cpp b/SourceX/controls/plrctrls.cpp index 158d11a38ce..353b117b9fa 100644 --- a/SourceX/controls/plrctrls.cpp +++ b/SourceX/controls/plrctrls.cpp @@ -4,6 +4,7 @@ #include #include +#include "controls/controller.h" #include "controls/controller_motion.h" #include "controls/game_controls.h" @@ -18,7 +19,6 @@ int speedspellcount = 0; bool InGameMenu() { return stextflag > 0 - || questlog || helpflag || talkflag || qtextflag @@ -226,7 +226,7 @@ void FindRangedTarget() void FindMeleeTarget() { - bool visited[MAXDUNX][MAXDUNY] = { 0 }; + bool visited[MAXDUNX][MAXDUNY] = { { 0 } }; int maxSteps = 25; // Max steps for FindPath is 25 int rotations; bool canTalk; @@ -719,6 +719,23 @@ void HotSpellMove(MoveDirection dir) } } +void SpellBookMove(MoveDirection dir) +{ + DWORD ticks = GetTickCount(); + if (ticks - invmove < repeatRate) { + return; + } + invmove = ticks; + + if (dir.x == MoveDirectionX::LEFT) { + if (sbooktab > 0) + sbooktab--; + } else if (dir.x == MoveDirectionX::RIGHT) { + if (sbooktab < 3) + sbooktab++; + } +} + static const direction kFaceDir[3][3] = { // NONE UP DOWN { DIR_OMNI, DIR_N, DIR_S }, // NONE @@ -806,7 +823,9 @@ void WalkInDir(MoveDirection dir) void Movement() { - if (InGameMenu()) + if (InGameMenu() || questlog + || IsControllerButtonPressed(ControllerButton::BUTTON_START) + || IsControllerButtonPressed(ControllerButton::BUTTON_BACK)) return; MoveDirection move_dir = GetMoveDirection(); @@ -820,66 +839,68 @@ void Movement() AttrIncBtnSnap(move_dir.y); } else if (spselflag) { HotSpellMove(move_dir); + } else if (sbookflag) { + SpellBookMove(move_dir); } else { WalkInDir(move_dir); } } struct RightStickAccumulator { - void start(int *x, int *y) + void pool(int *x, int *y, int slowdown) { - hiresDX += rightStickX * kGranularity; - hiresDY += rightStickY * kGranularity; + DWORD tc = SDL_GetTicks(); + hiresDX += rightStickX * (tc - lastTc); + hiresDY += rightStickY * (tc - lastTc); *x += hiresDX / slowdown; *y += -hiresDY / slowdown; - } - - void finish() - { + lastTc = tc; // keep track of remainder for sub-pixel motion hiresDX %= slowdown; hiresDY %= slowdown; } - static const int kGranularity = (1 << 15) - 1; - int slowdown; // < kGranularity - int hiresDX; - int hiresDY; + void clear() + { + lastTc = SDL_GetTicks(); + } + + DWORD lastTc = SDL_GetTicks(); + int hiresDX = 0; + int hiresDY = 0; }; } // namespace +bool IsAutomapActive() { + return automapflag && currlevel != DTYPE_TOWN; +} + void HandleRightStickMotion() { + static RightStickAccumulator acc; // deadzone is handled in ScaleJoystickAxes() already - if (rightStickX == 0 && rightStickY == 0) + if (rightStickX == 0 && rightStickY == 0) { + acc.clear(); return; + } - if (automapflag) { // move map - static RightStickAccumulator acc = { /*slowdown=*/(1 << 14) + (1 << 13), 0, 0 }; + if (IsAutomapActive()) { // move map int dx = 0, dy = 0; - acc.start(&dx, &dy); - if (dy > 1) - AutomapUp(); - else if (dy < -1) - AutomapDown(); - else if (dx < -1) - AutomapRight(); - else if (dx > 1) - AutomapLeft(); - acc.finish(); - } else { // move cursor + acc.pool(&dx, &dy, 32); + AutoMapXOfs += dy + dx; + AutoMapYOfs += dy - dx; + return; + } + + { // move cursor sgbControllerActive = false; - static RightStickAccumulator acc = { /*slowdown=*/(1 << 13) + (1 << 12), 0, 0 }; int x = MouseX; int y = MouseY; - acc.start(&x, &y); - if (x < 0) - x = 0; - if (y < 0) - y = 0; + acc.pool(&x, &y, 2); + x = std::min(std::max(x, 0), SCREEN_WIDTH - 1); + y = std::min(std::max(y, 0), SCREEN_HEIGHT - 1); SetCursorPos(x, y); - acc.finish(); } } @@ -996,8 +1017,13 @@ void UpdateSpellTarget() pcursmonst = -1; const auto &player = plr[myplr]; - cursmx = player._px + kOffsets[player._pdir][0]; - cursmy = player._py + kOffsets[player._pdir][1]; + + int range = 1; + if (plr[myplr]._pRSpell == SPL_TELEPORT) + range = 4; + + cursmx = player._px + kOffsets[player._pdir][0] * range; + cursmy = player._py + kOffsets[player._pdir][1] * range; } /** @@ -1019,7 +1045,7 @@ bool TryDropItem() void PerformSpellAction() { - if (InGameMenu()) + if (InGameMenu() || questlog || sbookflag) return; if (invflag) { diff --git a/SourceX/controls/plrctrls.h b/SourceX/controls/plrctrls.h index be81dd3201e..2bc22d072ef 100644 --- a/SourceX/controls/plrctrls.h +++ b/SourceX/controls/plrctrls.h @@ -24,6 +24,9 @@ void HandleRightStickMotion(); // Whether we're in a dialog menu that the game handles natively with keyboard controls. bool InGameMenu(); +// Whether the automap is being displayed. +bool IsAutomapActive(); + void UseBeltItem(int type); // Talk to towners, click on inv items, attack, etc. diff --git a/SourceX/dvlnet/abstract_net.h b/SourceX/dvlnet/abstract_net.h index 73430c37e24..a01fcde86a5 100644 --- a/SourceX/dvlnet/abstract_net.h +++ b/SourceX/dvlnet/abstract_net.h @@ -13,6 +13,11 @@ namespace net { typedef std::vector buffer_t; typedef unsigned long provider_t; class dvlnet_exception : public std::exception { +public: + const char *what() const throw() override + { + return "Network error"; + } }; class abstract_net { diff --git a/SourceX/dvlnet/frame_queue.h b/SourceX/dvlnet/frame_queue.h index 8c75a0ad3c4..8e48bfa8bd6 100644 --- a/SourceX/dvlnet/frame_queue.h +++ b/SourceX/dvlnet/frame_queue.h @@ -8,6 +8,11 @@ namespace dvl { namespace net { class frame_queue_exception : public dvlnet_exception { +public: + const char *what() const throw() override + { + return "Incorrect frame size"; + } }; typedef uint32_t framesize_t; diff --git a/SourceX/dvlnet/packet.h b/SourceX/dvlnet/packet.h index 9eb512aa92c..d5584e6059d 100644 --- a/SourceX/dvlnet/packet.h +++ b/SourceX/dvlnet/packet.h @@ -35,6 +35,11 @@ static constexpr plr_t PLR_MASTER = 0xFE; static constexpr plr_t PLR_BROADCAST = 0xFF; class packet_exception : public dvlnet_exception { +public: + const char *what() const throw() override + { + return "Incorrect package size"; + } }; class packet { @@ -57,7 +62,7 @@ class packet { public: packet(const key_t &k) - : key(k) {}; + : key(k) {}; const buffer_t &data(); @@ -152,7 +157,7 @@ void packet_in::process_element(T &x) throw packet_exception(); std::memcpy(&x, decrypted_buffer.data(), sizeof(T)); decrypted_buffer.erase(decrypted_buffer.begin(), - decrypted_buffer.begin() + sizeof(T)); + decrypted_buffer.begin() + sizeof(T)); } template <> @@ -181,7 +186,7 @@ inline void packet_out::create(plr_t s, plr_t d, turn_t u) template <> inline void packet_out::create(plr_t s, plr_t d, - cookie_t c, buffer_t i) + cookie_t c, buffer_t i) { if (have_encrypted || have_decrypted) ABORT(); @@ -195,7 +200,7 @@ inline void packet_out::create(plr_t s, plr_t d, template <> inline void packet_out::create(plr_t s, plr_t d, cookie_t c, - plr_t n, buffer_t i) + plr_t n, buffer_t i) { if (have_encrypted || have_decrypted) ABORT(); @@ -222,7 +227,7 @@ inline void packet_out::create(plr_t s, plr_t d, plr_t n) template <> inline void packet_out::create(plr_t s, plr_t d, plr_t n, - leaveinfo_t l) + leaveinfo_t l) { if (have_encrypted || have_decrypted) ABORT(); diff --git a/SourceX/dvlnet/tcp_client.cpp b/SourceX/dvlnet/tcp_client.cpp index 6edffee38c7..dac7bcd7254 100644 --- a/SourceX/dvlnet/tcp_client.cpp +++ b/SourceX/dvlnet/tcp_client.cpp @@ -17,7 +17,7 @@ int tcp_client::create(std::string addrstr, std::string passwd) local_server.reset(new tcp_server(ioc, addrstr, port, passwd)); return join(local_server->localhost_self(), passwd); } catch (std::system_error &e) { - eprintf("%s\n", e.what()); + SDL_SetError(e.what()); return -1; } } @@ -34,7 +34,7 @@ int tcp_client::join(std::string addrstr, std::string passwd) asio::ip::tcp::no_delay option(true); sock.set_option(option); } catch (std::exception &e) { - eprintf("%s\n", e.what()); + SDL_SetError(e.what()); return -1; } start_recv(); @@ -49,6 +49,7 @@ int tcp_client::join(std::string addrstr, std::string passwd) try { poll(); } catch (const std::runtime_error &e) { + SDL_SetError(e.what()); return -1; } if (plr_self != PLR_BROADCAST) @@ -56,7 +57,12 @@ int tcp_client::join(std::string addrstr, std::string passwd) SDL_Delay(ms_sleep); } } - return (plr_self == PLR_BROADCAST ? -1 : plr_self); + if (plr_self == PLR_BROADCAST) { + SDL_SetError("Unable to connect"); + return -1; + } + + return plr_self; } void tcp_client::poll() diff --git a/SourceX/dvlnet/tcp_server.cpp b/SourceX/dvlnet/tcp_server.cpp index 630e8e71f52..86c4c4e87e5 100644 --- a/SourceX/dvlnet/tcp_server.cpp +++ b/SourceX/dvlnet/tcp_server.cpp @@ -82,6 +82,7 @@ void tcp_server::handle_recv(scc con, const asio::error_code &ec, handle_recv_packet(*pkt); } } catch (dvlnet_exception &e) { + SDL_Log("Network error: %s", e.what()); drop_connection(con); return; } diff --git a/SourceX/dvlnet/tcp_server.h b/SourceX/dvlnet/tcp_server.h index c6bddfde786..2c2140e916e 100644 --- a/SourceX/dvlnet/tcp_server.h +++ b/SourceX/dvlnet/tcp_server.h @@ -16,6 +16,11 @@ namespace dvl { namespace net { class server_exception : public dvlnet_exception { +public: + const char *what() const throw() override + { + return "Invalid player ID"; + } }; class tcp_server { diff --git a/SourceX/dvlnet/udp_p2p.cpp b/SourceX/dvlnet/udp_p2p.cpp index f07dbd2b47e..db53d23f08f 100644 --- a/SourceX/dvlnet/udp_p2p.cpp +++ b/SourceX/dvlnet/udp_p2p.cpp @@ -32,6 +32,7 @@ int udp_p2p::create(std::string addrstr, std::string passwd) try { sock.bind(endpoint(ipaddr, port)); } catch (std::exception &e) { + SDL_SetError(e.what()); return -1; } plr_self = 0; @@ -53,10 +54,10 @@ int udp_p2p::join(std::string addrstr, std::string passwd) master = themaster; { // hack: try to join for 5 seconds randombytes_buf(reinterpret_cast(&cookie_self), - sizeof(cookie_t)); + sizeof(cookie_t)); auto pkt = pktfty->make_packet(PLR_BROADCAST, - PLR_MASTER, cookie_self, - game_init_info); + PLR_MASTER, cookie_self, + game_init_info); send(*pkt); for (auto i = 0; i < 5; ++i) { recv(); @@ -91,10 +92,12 @@ void udp_p2p::recv() auto pkt = pktfty->make_packet(pkt_buf); recv_decrypted(*pkt, sender); } catch (packet_exception &e) { + SDL_Log("Incorrect package size"); // drop packet } } } catch (std::exception &e) { + SDL_Log(e.what()); return; } } @@ -120,7 +123,7 @@ std::set udp_p2p::dests_for_addr(plr_t dest, endpoint sender) if (i != plr_self && connected_table[i]) ret.insert(nexthop_table[i]); ret.insert(connection_requests_pending.begin(), - connection_requests_pending.end()); + connection_requests_pending.end()); } else if (dest == PLR_MASTER) { if (master != none) ret.insert(master); @@ -139,8 +142,8 @@ void udp_p2p::handle_join_request(packet &pkt, endpoint sender) } } auto reply = pktfty->make_packet(plr_self, PLR_BROADCAST, - pkt.cookie(), i, - game_init_info); + pkt.cookie(), i, + game_init_info); send(*reply); } diff --git a/SourceX/dx.cpp b/SourceX/dx.cpp index 96c478ef000..95d9d3e6091 100644 --- a/SourceX/dx.cpp +++ b/SourceX/dx.cpp @@ -1,7 +1,6 @@ #include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" #include "miniwin/ddraw.h" -#include "miniwin/com_macro.h" #include namespace dvl { @@ -43,8 +42,6 @@ SDL_Surface *renderer_texture_surface = nullptr; /** 8-bit surface wrapper around #gpBuffer */ SDL_Surface *pal_surface; -bool bufferUpdated = false; - static void dx_create_back_buffer() { pal_surface = SDL_CreateRGBSurfaceWithFormat(0, BUFFER_WIDTH, BUFFER_HEIGHT, 8, SDL_PIXELFORMAT_INDEX8); @@ -119,7 +116,6 @@ static void unlock_buf_priv() if (sgdwLockCount == 0) { gpBufEnd -= (uintptr_t)gpBuffer; //gpBuffer = NULL; unable to return to menu - RenderPresent(); } sgMemCrit.Leave(); } @@ -216,7 +212,6 @@ void BltFast(DWORD dwX, DWORD dwY, LPRECT lpSrcRect) ErrSdl(); } } - bufferUpdated = true; } /** @@ -237,10 +232,10 @@ void LimitFrameRate() void RenderPresent() { SDL_Surface *surface = GetOutputSurface(); - assert(!SDL_MUSTLOCK(surface)); - if (!bufferUpdated) { + if (!gbActive) { + LimitFrameRate(); return; } @@ -275,8 +270,6 @@ void RenderPresent() } LimitFrameRate(); #endif - - bufferUpdated = false; } void PaletteGetEntries(DWORD dwNumEntries, LPPALETTEENTRY lpEntries) diff --git a/SourceX/main.cpp b/SourceX/main.cpp index bed3cdbb3ac..59608606b03 100644 --- a/SourceX/main.cpp +++ b/SourceX/main.cpp @@ -1,4 +1,3 @@ -#include #include #ifdef __SWITCH__ #include "platform/switch/network.h" @@ -13,25 +12,11 @@ extern "C" const char *__asan_default_options() } #endif -static std::string build_cmdline(int argc, char **argv) -{ - std::string str; - for (int i = 1; i < argc; i++) { - if (i != 1) { - str += ' '; - } - str += argv[i]; - } - return str; -} - int main(int argc, char **argv) { - auto cmdline = build_cmdline(argc, argv); - #ifdef __SWITCH__ switch_enable_network(); #endif - return dvl::WinMain(NULL, NULL, (char *)cmdline.c_str(), 0); + return dvl::DiabloMain(argc, argv); } diff --git a/SourceX/miniwin/ddraw.h b/SourceX/miniwin/ddraw.h index ec3c129ef77..3873cf8f2bf 100644 --- a/SourceX/miniwin/ddraw.h +++ b/SourceX/miniwin/ddraw.h @@ -14,7 +14,6 @@ extern SDL_Texture *texture; extern SDL_Palette *palette; extern SDL_Surface *pal_surface; extern unsigned int pal_surface_palette_version; -extern bool bufferUpdated; // Returns: // SDL1: Video surface. diff --git a/SourceX/miniwin/dsound.cpp b/SourceX/miniwin/dsound.cpp index 97e2fc72d20..db6baba37bb 100644 --- a/SourceX/miniwin/dsound.cpp +++ b/SourceX/miniwin/dsound.cpp @@ -12,21 +12,22 @@ void DirectSoundBuffer::Release() Mix_FreeChunk(chunk); }; -void DirectSoundBuffer::GetStatus(LPDWORD pdwStatus) +bool DirectSoundBuffer::IsPlaying() { for (int i = 1; i < Mix_AllocateChannels(-1); i++) { if (Mix_GetChunk(i) == chunk && Mix_Playing(i)) { - *pdwStatus = DVL_DSBSTATUS_PLAYING; - break; + return true; } } + + return false; }; void DirectSoundBuffer::Play(int lVolume, int lPan) { int channel = Mix_PlayChannel(-1, chunk, 0); if (channel == -1) { - SDL_Log("Too few channels, skipping sound\n"); + SDL_Log("Too few channels, skipping sound"); return; } diff --git a/SourceX/miniwin/dsound.h b/SourceX/miniwin/dsound.h index 941aaef2444..d67d2ae3dd5 100644 --- a/SourceX/miniwin/dsound.h +++ b/SourceX/miniwin/dsound.h @@ -9,7 +9,7 @@ namespace dvl { struct DirectSoundBuffer final : public IDirectSoundBuffer { public: void Release() override; - void GetStatus(LPDWORD pdwStatus) override; + bool IsPlaying() override; void Play(int lVolume, int lPan) override; void Stop() override; int SetChunk(BYTE *fileData, DWORD dwBytes) override; diff --git a/SourceX/miniwin/misc.cpp b/SourceX/miniwin/misc.cpp index f59eda3b0ca..31fd82723f5 100644 --- a/SourceX/miniwin/misc.cpp +++ b/SourceX/miniwin/misc.cpp @@ -8,11 +8,6 @@ #include "DiabloUI/diabloui.h" #include "DiabloUI/dialogs.h" -#ifdef _MSC_VER -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#endif - #if defined(USE_SDL1) && defined(RETROFW) #include #endif @@ -24,22 +19,16 @@ #ifndef SDL1_VIDEO_MODE_FLAGS #define SDL1_VIDEO_MODE_FLAGS SDL_SWSURFACE #endif +#ifndef SDL1_VIDEO_MODE_WIDTH +#define SDL1_VIDEO_MODE_WIDTH nWidth +#endif +#ifndef SDL1_VIDEO_MODE_HEIGHT +#define SDL1_VIDEO_MODE_HEIGHT nHeight +#endif #endif namespace dvl { -DWORD last_error; - -DWORD GetLastError() -{ - return last_error; -} - -void SetLastError(DWORD dwErrCode) -{ - last_error = dwErrCode; -} - int wsprintfA(LPSTR dest, LPCSTR format, ...) { va_list args; @@ -62,26 +51,6 @@ int _strnicmp(const char *_Str1, const char *_Str2, size_t n) return strncasecmp(_Str1, _Str2, n); } -char *_itoa(int _Value, char *_Dest, int _Radix) -{ - switch (_Radix) { - case 8: - sprintf(_Dest, "%o", _Value); - break; - case 10: - sprintf(_Dest, "%d", _Value); - break; - case 16: - sprintf(_Dest, "%x", _Value); - break; - default: - UNIMPLEMENTED(); - break; - } - - return _Dest; -} - DWORD GetTickCount() { return SDL_GetTicks(); @@ -92,14 +61,6 @@ void Sleep(DWORD dwMilliseconds) SDL_Delay(dwMilliseconds); } -WINBOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize) -{ - DUMMY(); - strncpy(lpBuffer, "localhost", *nSize); - *nSize = strlen(lpBuffer); - return true; -} - WINBOOL DeleteFileA(LPCSTR lpFileName) { char name[DVL_MAX_PATH]; @@ -118,6 +79,24 @@ WINBOOL DeleteFileA(LPCSTR lpFileName) return true; } +namespace { + +#ifdef USE_SDL1 +void InitVideoMode(int width, int height, int bpp, std::uint32_t flags) +{ + const auto &best = *SDL_GetVideoInfo(); + SDL_Log("Best video mode reported as: %dx%d bpp=%d hw_available=%u", + best.current_w, best.current_h, best.vfmt->BitsPerPixel, best.hw_available); + SDL_Log("Setting video mode %dx%d bpp=%u flags=0x%08X", width, height, bpp, flags); + SDL_SetVideoMode(width, height, bpp, flags); + const auto ¤t = *SDL_GetVideoInfo(); + SDL_Log("Video mode is now %dx%d bpp=%u", + current.current_w, current.current_h, current.vfmt->BitsPerPixel); +} +#endif + +} // namespace + bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight) { if (SDL_Init(SDL_INIT_EVERYTHING & ~SDL_INIT_HAPTIC) <= -1) { @@ -128,12 +107,15 @@ bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight) #ifdef USE_SDL1 SDL_EnableUNICODE(1); +#endif +#if defined(USE_SDL1) || defined(__SWITCH__) InitController(); #endif int upscale = 1; DvlIntSetting("upscale", &upscale); - DvlIntSetting("fullscreen", (int *)&fullscreen); + if (fullscreen) + DvlIntSetting("fullscreen", (int *)&fullscreen); int grabInput = 1; DvlIntSetting("grab input", &grabInput); @@ -144,14 +126,14 @@ bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight) flags |= SDL_FULLSCREEN; SDL_WM_SetCaption(lpWindowName, WINDOW_ICON_NAME); #ifndef RETROFW - SDL_SetVideoMode(nWidth, nHeight, SDL1_VIDEO_MODE_BPP, flags); + InitVideoMode(SDL1_VIDEO_MODE_WIDTH, SDL1_VIDEO_MODE_HEIGHT, SDL1_VIDEO_MODE_BPP, flags); #else // RETROFW // JZ4760 IPU scaler (e.g. on RG-300 v2/3) - automatic high-quality scaling. if (access("/proc/jz/ipu", F_OK) == 0 || access("/proc/jz/ipu_ratio", F_OK) == 0) { - SDL_SetVideoMode(nWidth, nHeight, SDL1_VIDEO_MODE_BPP, flags); + InitVideoMode(SDL1_VIDEO_MODE_WIDTH, SDL1_VIDEO_MODE_HEIGHT, SDL1_VIDEO_MODE_BPP, flags); } else { // Other RetroFW devices have 320x480 screens with non-square pixels. - SDL_SetVideoMode(320, 480, SDL1_VIDEO_MODE_BPP, flags); + InitVideoMode(320, 480, SDL1_VIDEO_MODE_BPP, flags); } #endif window = SDL_GetVideoSurface(); @@ -183,6 +165,10 @@ bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight) #ifdef USE_SDL1 refreshDelay = 1000000 / 60; // 60hz +#else + SDL_DisplayMode mode; + SDL_GetDisplayMode(0, 0, &mode); + refreshDelay = 1000000 / mode.refresh_rate; #endif if (upscale) { @@ -202,12 +188,6 @@ bool SpawnWindow(LPCSTR lpWindowName, int nWidth, int nHeight) if (SDL_RenderSetLogicalSize(renderer, nWidth, nHeight) <= -1) { ErrSdl(); } -#endif - } else { -#ifndef USE_SDL1 - SDL_DisplayMode mode; - SDL_GetDisplayMode(0, 0, &mode); - refreshDelay = 1000000 / mode.refresh_rate; #endif } diff --git a/SourceX/miniwin/misc_io.cpp b/SourceX/miniwin/misc_io.cpp index 5356139e863..6f4fe927e5e 100644 --- a/SourceX/miniwin/misc_io.cpp +++ b/SourceX/miniwin/misc_io.cpp @@ -1,5 +1,6 @@ #include -#include +#include +#include #include #include #include @@ -19,7 +20,7 @@ struct memfile { std::size_t pos = 0; }; -static std::set files; +static std::unordered_set files; HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, @@ -27,7 +28,7 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, { char name[DVL_MAX_PATH]; TranslateFileName(name, sizeof(name), lpFileName); - DUMMY_PRINT("file: %s (%s)", lpFileName, name); + SDL_Log("file: %s (%s)", lpFileName, name); UNIMPLEMENTED_UNLESS(!(dwDesiredAccess & ~(DVL_GENERIC_READ | DVL_GENERIC_WRITE))); memfile *file = new memfile; file->path = name; @@ -54,7 +55,7 @@ WINBOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDW memfile *file = static_cast(hFile); UNIMPLEMENTED_UNLESS(!lpOverlapped); size_t len = std::min(file->buf.size() - file->pos, nNumberOfBytesToRead); - std::copy(file->buf.begin() + file->pos, file->buf.begin() + file->pos + len, static_cast(lpBuffer)); + std::memcpy(lpBuffer, file->buf.data() + file->pos, len); file->pos += len; *lpNumberOfBytesRead = len; return true; @@ -75,9 +76,7 @@ WINBOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, return true; if (file->buf.size() < file->pos + nNumberOfBytesToWrite) file->buf.resize(file->pos + nNumberOfBytesToWrite); - std::copy(static_cast(lpBuffer), - static_cast(lpBuffer) + nNumberOfBytesToWrite, - file->buf.begin() + file->pos); + std::memcpy(file->buf.data() + file->pos, lpBuffer, nNumberOfBytesToWrite); file->pos += nNumberOfBytesToWrite; *lpNumberOfBytesWritten = nNumberOfBytesToWrite; return true; @@ -92,7 +91,8 @@ DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveH } else if (dwMoveMethod == DVL_FILE_CURRENT) { file->pos += lDistanceToMove; } else { - UNIMPLEMENTED(); + UNIMPLEMENTED(); + } if (file->buf.size() < file->pos + 1) file->buf.resize(file->pos + 1); @@ -106,37 +106,21 @@ WINBOOL SetEndOfFile(HANDLE hFile) return true; } -DWORD GetFileAttributesA(LPCSTR lpFileName) -{ - char name[DVL_MAX_PATH]; - TranslateFileName(name, sizeof(name), lpFileName); - std::ifstream filestream(name, std::ios::binary); - if (filestream.fail()) { - SetLastError(DVL_ERROR_FILE_NOT_FOUND); - return (DWORD)-1; - } - return 0x80; -} - -WINBOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) -{ - return true; -} - void ShowOutOfDiskError() { - char *text = "Failed to save, please free some disk space and try again."; + constexpr char text[] = "Failed to save, please free some disk space and try again."; UiErrorOkDialog("Out of Disk Space", text); } WINBOOL CloseHandle(HANDLE hObject) { memfile *file = static_cast(hObject); - if (files.find(file) == files.end()) + const auto file_it = files.find(file); + if (file_it == files.end()) return CloseEvent(hObject); std::unique_ptr ufile(file); // ensure that delete file is // called on returning - files.erase(file); + files.erase(file_it); std::ofstream filestream(file->path + ".tmp", std::ios::binary | std::ios::trunc); if (filestream.fail()) { ShowOutOfDiskError(); diff --git a/SourceX/miniwin/misc_msg.cpp b/SourceX/miniwin/misc_msg.cpp index 52878e93162..00fe322e80a 100644 --- a/SourceX/miniwin/misc_msg.cpp +++ b/SourceX/miniwin/misc_msg.cpp @@ -237,7 +237,7 @@ static int translate_sdl_key(SDL_Keysym key) } else if (sym >= SDLK_F1 && sym <= SDLK_F12) { return DVL_VK_F1 + (sym - SDLK_F1); } - DUMMY_PRINT("unknown key: name=%s sym=0x%X scan=%d mod=0x%X", SDL_GetKeyName(sym), sym, key.scancode, key.mod); + SDL_Log("unknown key: name=%s sym=0x%X scan=%d mod=0x%X", SDL_GetKeyName(sym), sym, key.scancode, key.mod); return -1; } } @@ -258,7 +258,7 @@ WPARAM keystate_for_mouse(WPARAM ret) WINBOOL false_avail(const char *name, int value) { - DUMMY_PRINT("Unhandled SDL event: %s %d", name, value); + SDL_Log("Unhandled SDL event: %s %d", name, value); return true; } @@ -396,7 +396,7 @@ WINBOOL PeekMessageA(LPMSG lpMsg) sgbControllerActive = true; if (movie_playing) { - lpMsg->message = DVL_WM_CHAR; + lpMsg->message = DVL_WM_KEYDOWN; if (action.type == GameActionType::SEND_KEY) lpMsg->wParam = action.send_key.vk_code; return true; @@ -423,8 +423,10 @@ WINBOOL PeekMessageA(LPMSG lpMsg) break; case GameActionType::TOGGLE_QUICK_SPELL_MENU: if (!invflag || BlurInventory()) { - lpMsg->message = DVL_WM_KEYDOWN; - lpMsg->wParam = 'S'; + if (!spselflag) + DoSpeedBook(); + else + spselflag = false; chrflag = false; questlog = false; sbookflag = false; @@ -441,6 +443,15 @@ WINBOOL PeekMessageA(LPMSG lpMsg) FocusOnCharInfo(); } break; + case GameActionType::TOGGLE_QUEST_LOG: + if (!questlog) { + StartQuestlog(); + chrflag = false; + spselflag = false; + } else { + questlog = false; + } + break; case GameActionType::TOGGLE_INVENTORY: if (invflag) { BlurInventory(); @@ -453,6 +464,13 @@ WINBOOL PeekMessageA(LPMSG lpMsg) FocusOnInventory(); } break; + case GameActionType::TOGGLE_SPELL_BOOK: + if (BlurInventory()) { + invflag = false; + spselflag = false; + sbookflag = !sbookflag; + } + break; case GameActionType::SEND_KEY: lpMsg->message = action.send_key.up ? DVL_WM_KEYUP : DVL_WM_KEYDOWN; lpMsg->wParam = action.send_key.vk_code; @@ -531,6 +549,18 @@ WINBOOL PeekMessageA(LPMSG lpMsg) } } break; #ifndef USE_SDL1 + case SDL_MOUSEWHEEL: + lpMsg->message = DVL_WM_KEYDOWN; + if (e.wheel.y > 0) { + lpMsg->wParam = GetAsyncKeyState(DVL_VK_CONTROL) ? DVL_VK_OEM_PLUS : DVL_VK_UP; + } else if (e.wheel.y < 0) { + lpMsg->wParam = GetAsyncKeyState(DVL_VK_CONTROL) ? DVL_VK_OEM_MINUS : DVL_VK_DOWN; + } else if (e.wheel.x > 0) { + lpMsg->wParam = DVL_VK_LEFT; + } else if (e.wheel.x < 0) { + lpMsg->wParam = DVL_VK_RIGHT; + } + break; #if SDL_VERSION_ATLEAST(2, 0, 4) case SDL_AUDIODEVICEADDED: return false_avail("SDL_AUDIODEVICEADDED", e.adevice.which); @@ -612,7 +642,38 @@ WINBOOL TranslateMessage(const MSG *lpMsg) if (!upper && is_alpha) { key = tolower(key); } else if (shift && is_numeric) { - key = key == '0' ? ')' : key - 0x10; + switch (key) { + case '1': + key = '!'; + break; + case '2': + key = '@'; + break; + case '3': + key = '#'; + break; + case '4': + key = '$'; + break; + case '5': + key = '%'; + break; + case '6': + key = '^'; + break; + case '7': + key = '&'; + break; + case '8': + key = '*'; + break; + case '9': + key = '('; + break; + case '0': + key = ')'; + break; + } } else if (is_oem) { // XXX: This probably only supports US keyboard layout switch (key) { @@ -637,7 +698,6 @@ WINBOOL TranslateMessage(const MSG *lpMsg) case DVL_VK_OEM_7: key = shift ? '"' : '\''; break; - case DVL_VK_OEM_MINUS: key = shift ? '_' : '-'; break; @@ -678,6 +738,8 @@ SHORT GetAsyncKeyState(int vKey) return SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_RIGHT); const Uint8 *state = SDLC_GetKeyState(); switch (vKey) { + case DVL_VK_CONTROL: + return state[SDLC_KEYSTATE_LEFTCTRL] || state[SDLC_KEYSTATE_RIGHTCTRL] ? 0x8000 : 0; case DVL_VK_SHIFT: return state[SDLC_KEYSTATE_LEFTSHIFT] || state[SDLC_KEYSTATE_RIGHTSHIFT] ? 0x8000 : 0; case DVL_VK_MENU: @@ -697,9 +759,7 @@ SHORT GetAsyncKeyState(int vKey) LRESULT DispatchMessageA(const MSG *lpMsg) { - DUMMY_ONCE(); assert(CurrentProc); - // assert(CurrentProc == GM_Game); return CurrentProc(NULL, lpMsg->message, lpMsg->wParam, lpMsg->lParam); } diff --git a/SourceX/miniwin/thread.cpp b/SourceX/miniwin/thread.cpp index 8404171ee9b..22571318bbe 100644 --- a/SourceX/miniwin/thread.cpp +++ b/SourceX/miniwin/thread.cpp @@ -57,12 +57,6 @@ DWORD GetCurrentThreadId() return SDL_GetThreadID(NULL); } -HANDLE GetCurrentThread() -{ - // Only used for SetThreadPriority, which is unimplemented - return NULL; -} - WINBOOL SetThreadPriority(HANDLE hThread, int nPriority) { // SDL cannot set the priority of the non-current thread diff --git a/SourceX/sound.cpp b/SourceX/sound.cpp index 189134c4b6e..9ca31d23826 100644 --- a/SourceX/sound.cpp +++ b/SourceX/sound.cpp @@ -38,17 +38,10 @@ char *sgszMusicTracks[NUM_MUSIC] = { BOOL snd_playing(TSnd *pSnd) { - DWORD dwStatus; - - if (!pSnd) - return false; - - if (pSnd->DSB == NULL) + if (pSnd == NULL || pSnd->DSB == NULL) return false; - pSnd->DSB->GetStatus(&dwStatus); - - return dwStatus == DVL_DSBSTATUS_PLAYING; + return pSnd->DSB->IsPlaying(); } void snd_play_snd(TSnd *pSnd, int lVolume, int lPan) @@ -127,6 +120,7 @@ void snd_init(HWND hWnd) { sound_load_volume("Sound Volume", &sglSoundVolume); gbSoundOn = sglSoundVolume > VOLUME_MIN; + sgbSaveSoundOn = gbSoundOn; sound_load_volume("Music Volume", &sglMusicVolume); gbMusicOn = sglMusicVolume > VOLUME_MIN; diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 77b378fa070..6086699c9c1 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -16,8 +16,11 @@ namespace dvl { +std::string basePath; + DWORD nLastError = 0; bool directFileAccess = false; +char SBasePath[DVL_MAX_PATH]; static std::string getIniPath() { @@ -33,6 +36,11 @@ static Mix_Chunk *SFileChunk; void GetBasePath(char *buffer, size_t size) { + if (basePath.length()) { + snprintf(buffer, size, "%s", basePath.c_str()); + return; + } + char *path = SDL_GetBasePath(); if (path == NULL) { SDL_Log(SDL_GetError()); @@ -160,9 +168,11 @@ BOOL SFileOpenFile(const char *filename, HANDLE *phFile) if (directFileAccess) { char directPath[DVL_MAX_PATH] = "\0"; + char tmpPath[DVL_MAX_PATH] = "\0"; for (size_t i = 0; i < strlen(filename); i++) { - directPath[i] = AsciiToLowerTable_Path[static_cast(filename[i])]; + tmpPath[i] = AsciiToLowerTable_Path[static_cast(filename[i])]; } + snprintf(directPath, DVL_MAX_PATH, "%s%s", SBasePath, tmpPath); result = SFileOpenFileEx((HANDLE)0, directPath, 0xFFFFFFFF, phFile); } if (!result && patch_rt_mpq) { @@ -508,7 +518,9 @@ void SVidPlayBegin(char *filename, int a2, int a3, int a4, int a5, int flags, HA return; } - SVidLoop = flags & 0x40000; + SVidLoop = false; + if (flags & 0x40000) + SVidLoop = true; bool enableVideo = !(flags & 0x100000); bool enableAudio = !(flags & 0x1000000); //0x8 // Non-interlaced @@ -752,7 +764,7 @@ BOOL SVidPlayContinue(void) return false; } #endif - bufferUpdated = true; + RenderPresent(); double now = SDL_GetTicks() * 1000; @@ -829,9 +841,9 @@ int SStrCopy(char *dest, const char *src, int max_length) return strlen(dest); } -BOOL SFileSetBasePath(char *) +BOOL SFileSetBasePath(char *path) { - DUMMY(); + strncpy(SBasePath, path, DVL_MAX_PATH); return true; } diff --git a/defs.h b/defs.h index 7b730453e33..11c48d1b224 100644 --- a/defs.h +++ b/defs.h @@ -165,10 +165,6 @@ #define ERR_DLG(title, text) ErrDlg(title, text, __FILE__, __LINE__) -#ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - // To apply to certain functions which have local variables aligned by 1 for unknown yet reason #if (_MSC_VER == 1200) #define ALIGN_BY_1 __declspec(align(1)) @@ -180,3 +176,8 @@ #define SwapLE16 SDL_SwapLE16 #define ErrSdl() ErrDlg("SDL Error", SDL_GetError(), __FILE__, __LINE__) + +#ifdef _MSC_VER +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif diff --git a/structs.h b/structs.h index e16ccf0d882..9362aa94ad5 100644 --- a/structs.h +++ b/structs.h @@ -1333,7 +1333,7 @@ typedef struct _SNETUIDATA { void(* profilecallback)(); int profilefields; void(* profilebitmapcallback)(); - int(__stdcall *selectnamecallback)( + int(*selectnamecallback)( const struct _SNETPROGRAMDATA *, const struct _SNETPLAYERDATA *, const struct _SNETUIDATA *, diff --git a/types.h b/types.h index ebd2ad7b1ee..83cf1709bf7 100644 --- a/types.h +++ b/types.h @@ -8,7 +8,6 @@ #define DEVILUTION_BEGIN_NAMESPACE namespace dvl { #define DEVILUTION_END_NAMESPACE } -#include "miniwin/pushdecl.inc" #include "miniwin.h" DEVILUTION_BEGIN_NAMESPACE @@ -18,23 +17,4 @@ DEVILUTION_BEGIN_NAMESPACE #include "enums.h" #include "structs.h" -// If defined, use copy protection [Default -> Defined] -#if !defined(_DEBUG) && !defined(SPAWN) -//#define COPYPROT -#endif - -// If defined, don't reload for debuggers [Default -> Undefined] -// Note that with patch 1.03 the command line was hosed, this is required to pass arguments to the game -#ifdef _DEBUG -#define DEBUGGER -#endif - -// If defined, don't fry the CPU [Default -> Undefined] -//#ifdef _DEBUG -#define SLEEPFIX -//#endif - -// If defined, fix palette glitch in Windows Vista+ [Default -> Undefined] -//#define COLORFIX - #endif From 1fed5fb00cbedcbbadf3e47311d6b95e5f4c9470 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 30 Jan 2020 21:55:44 +0100 Subject: [PATCH 090/107] fixed invisible cursor in-game --- Source/scrollrt.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 4054245067a..65e4c1c2e3a 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -1204,8 +1204,7 @@ void scrollrt_draw_game_screen(BOOL draw_cursor) #ifdef __AMIGA__ if(ac68080_saga) { - lock_buf(0); - unlock_buf(0); // forces flip before cursor restore display when in saga mode + RenderPresent(); // forces flip before cursor restore display when in saga mode } #endif @@ -1214,6 +1213,10 @@ void scrollrt_draw_game_screen(BOOL draw_cursor) scrollrt_draw_cursor_back_buffer(); unlock_buf(0); } + +#ifdef __AMIGA__ + if(!ac68080_saga) +#endif RenderPresent(); } @@ -1276,14 +1279,16 @@ void DrawAndBlit() #ifdef __AMIGA__ if(ac68080_saga) { - lock_buf(0); - unlock_buf(0); // forces flip before cursor restore display when in saga mode + RenderPresent(); // forces flip before cursor restore display when in saga mode } #endif lock_buf(0); scrollrt_draw_cursor_back_buffer(); unlock_buf(0); +#ifdef __AMIGA__ + if(!ac68080_saga) +#endif RenderPresent(); drawhpflag = FALSE; From 8cc83117f90306d462a99f37e45acccda50a4069 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Thu, 30 Jan 2020 22:20:29 +0100 Subject: [PATCH 091/107] fixed '-x' cmdline flag (force windowed mode) not working on saga --- CMake/amiga/m68k-amigaos.cmake | 3 ++- SourceX/platform/amiga/ac68080_support.c | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index b0338e79fcd..2f786eb787c 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -76,7 +76,8 @@ foreach(_wrapped malloc free realloc - calloc) + calloc + SDL_VideoInit) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=${_wrapped}") endforeach(_wrapped) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 5a8c2556b17..67ed34d1c1b 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -210,7 +210,7 @@ static void start(void) atexit(stop); if (SysBase->AttnFlags &(1 << 10)) { - ac68080_saga = 255; //!_ZN3dvl10fullscreenE; // disable if not fullscreen + ac68080_saga = _ZN3dvl10fullscreenE ? 255:0; // disable if not fullscreen bufmem = dlmemalign(32/* byte alignment for saga */, 3*FRAME_BUFFER_SZ); if(bufmem) { @@ -447,3 +447,18 @@ int simple_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, } return 0; } + +// get rid of SDL's saga detection because it isn't necessary +// and produce garbage when not fullscreen during splash-logo-video +extern int __real_SDL_VideoInit (const char *driver_name, Uint32 flags); +int __wrap_SDL_VideoInit (const char *driver_name, Uint32 flags) +{ + ULONG bak = SysBase->AttnFlags; + int ret; + + SysBase->AttnFlags &= ~(1 << 10); + ret = __real_SDL_VideoInit(driver_name, flags); + SysBase->AttnFlags = bak; + + return ret; +} From 16ee36dd3c8e58e9bab4577df506fe5d39b218ef Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 7 Feb 2020 00:39:42 +0100 Subject: [PATCH 092/107] added assert_failed() to compile NDEBUG mode --- SourceX/platform/amiga/ac68080_support.c | 7 +++++++ SourceX/platform/amiga/memopt.asm | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 67ed34d1c1b..04bae234e57 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -196,6 +196,13 @@ void *__wrap_calloc(size_t num, size_t size) /*****************************************************************************/ +void assert_fail (char *file, int line, char *exp) { + printf("Assertion failed: %s\nFile: %s\nLine: %d\n",exp,file,line); + while(1) Delay(50); +} + +/*****************************************************************************/ + static void stop(void) { if(bufmem) { diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index f3542abacad..a0880efefd5 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -54,7 +54,7 @@ ___wrap_memcpy .exit * remove initial comparison so that it now only costs 1 cycle move.w #$203c,.entry ; move.l #nnnn,d0 - move.w #$7200,.entry+6 ; moveq.w #0,d1 + move.w #$7200,.entry+6 ; moveq #0,d1 move.w #$4e75,.exit ; #rts rts ; no need to ClearCacheU on apollo! From fd079d6f4569f3905d76873578278484635f89b6 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Fri, 7 Feb 2020 00:48:22 +0100 Subject: [PATCH 093/107] speedup of Cl2BlitSafe() with AMMX & 68k asm. Cpu usage of this fcn drop from 7-8% down to 4% --- Source/engine.cpp | 13 +++ SourceX/platform/amiga/render68k.asm | 164 ++++++++++++++++++++++++--- 2 files changed, 163 insertions(+), 14 deletions(-) diff --git a/Source/engine.cpp b/Source/engine.cpp index f73a7358df4..27207d9feec 100644 --- a/Source/engine.cpp +++ b/Source/engine.cpp @@ -916,6 +916,12 @@ void Cl2Draw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth) nWidth); } +#if defined(__AMIGA__) +extern "C" { + extern void Cl2BlitSafe_68k(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSiz, int nWidth); +} +#endif + void Cl2BlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; @@ -923,6 +929,13 @@ void Cl2BlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) BYTE fill; BYTE *src, *dst; +#if defined(__AMIGA__) +{ + Cl2BlitSafe_68k(pDecodeTo, pRLEBytes, nDataSize, nWidth); + return; +} +#endif + src = pRLEBytes; dst = pDecodeTo; w = nWidth; diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 70cb125d135..61e27190d06 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -617,14 +617,14 @@ _RenderLine2 *------------------------------------------------------------------------------------ xdef _setup - + m68k_render dc.l _RenderLine0 REPT 14 dc.l _RenderLine2 ENDR dc.l _RenderLine1 - + ammx_render dc.l _RenderLine0_AMMX REPT 14 @@ -713,9 +713,9 @@ _RenderTile_RT_TRANSPARENT move.b (a1)+,d0 ; p2 bgt .L4 ; p1 bra .L3 ; p2 -.L2 move.l d6,d1 ; p2 +.L2 move.l d6,d1 ; p2 lsl.l d0,d6 ; p1 - jsr (a4) ; p1 + jsr (a4) ; p1 move.b (a1)+,d0 ; p1 bgt .L4 ; p1 .L3 add.b d0,d7 ; p2 @@ -725,9 +725,9 @@ _RenderTile_RT_TRANSPARENT lsl.l d0,d6 ; p2 move.b (a1)+,d0 ; p1 ble .L3 ; p1 -.L4 sub.b d0,d7 ; p2 +.L4 sub.b d0,d7 ; p2 bne .L2 ; p1 - move.l d6,d1 ; p2 + move.l d6,d1 ; p2 jsr (a4) ; p1 sub.w #BUFFER_WIDTH+32,a0 ; p1 tst.l a6 ; p2 @@ -811,9 +811,9 @@ triangR_ macro .i set .i-2 ENDR endm - + ifeq INLINE_BLOCK16 - + _block16 block16_ rts @@ -822,7 +822,7 @@ _triangL rts _triangR triangR_ - rts + rts block16 macro bsr _block16 endm @@ -832,9 +832,9 @@ triangL macro triangR macro bsr _triangR endm - + else - + block16 macro block16_ endm @@ -844,9 +844,9 @@ triangL macro triangR macro triangR_ endm - + endc - + *------------------------------------------------------------------------------------ * extern void RenderTile_RT_SQUARE(BYTE *dst, BYTE *src, BYTE *tbl, DWORD *mask) _RenderTile_RT_SQUARE @@ -910,4 +910,140 @@ _RenderTile_RT_RTRIANGLE ENDR epilogue_7 -* end of file \ No newline at end of file + +*------------------------------------------------------------------------------------ + XDEF _Cl2BlitSafe_68k + +_Cl2BlitSafe_68k + rsreset +.regs rs.l 3 + rs.l 1 +.pDecodeTo rs.l 1 +.pRLEBytes rs.l 1 +.nDataSize rs.l 1 +.nWidth rs.l 1 + + movem.l d2-d4,-(sp) + move.l .pDecodeTo(sp),a1 ; a1 = dst + move.l .pRLEBytes(sp),a0 ; a0 = src + move.l .nDataSize(sp),d2 ; d2 = nDataSize + move.l .nWidth(sp),d4 ; d4 = nWidth + + move.l d4,d1 ; d1 = w + tst.l d2 + beq.b .done + +.loop + moveq #0,d0 + move.b (a0)+,d0 ; d0 = width + bpl.b .if1 + + neg.b d0 + + moveq #-65,d3 + add.l d0,d3 ; d3 = -65-width + ble.b .if4 + + move.l d3,d0 ; width -= 65 > 0 + subq.l #1,d2 ; --nDataSize + move.b (a0)+,d3 ; fill = *src++ + + cmp2.l __ZN3dvl10gpBufStartE,a1 + bcs.b .if1 ; if (dst < gpBufEnd && dst > gpBufStart) { + sub.l d0,d1 ; w -= width +.p5 jmp .if5_68k.l + +.if4 + sub.l d0,d2 ; nDataSize -= width + cmp2.l __ZN3dvl10gpBufStartE,a1 + bcs.b .if7 ; if (dst < gpBufEnd && dst > gpBufStart) { + sub.l d0,d1 ; w -= width +.p6 jmp .if6_68k.l + +.if7 ; else !(dst < gpBufEnd && dst > gpBufStart) + add.l d0,a0 ; src+=width +.if1 + beq.b .next + sub.l d1,d0 ; d0 = width-w + ble.b .if3 ; if(width > w) { + +.if2 ; while(width) { + lea -BUFFER_WIDTH(a1,d1.l),a1 ; dst += w - BUFFER_WIDTH + sub.l d4,a1 ; dst -= w (== dst + w(prev) - BUFFER_WIDTH - w(new) + move.l d4,d1 ; w = nWidth + sub.l d4,d0 ; d0 = width-w + bhi.b .if2 ; if(width > w) { + +.if3 + add.l d1,a1 ; .. dst += w + move.l d0,d1 + neg.l d1 ; d1 = w = -(width-w) = w - width + add.l d0,a1 ; dst += width-w + bne.b .next ; if !w ==> continue + +.adv ; if(!w) + sub.w #BUFFER_WIDTH,a1 + move.l d4,d1 + suba.l d4,a1 +.next + subq.l #1,d2 + bne .loop +.done + movem.l (sp)+,d2-d4 + +.tst_ammx + tst.b _ac68080_ammx + bne.b .exit + lea .if5_ammx,a0 + lea .if6_ammx,a1 + move.l a0,.p5+2 + move.l a1,.p6+2 + move.w #$4e75,.tst_ammx +.exit + rts + +.if5_68k ; while(width) { + move.b d3,(a1)+ ; *dst++ = fill: + subq.l #1,d0 ; -width; + bne.b .if5_68k ; } + tst.l d1 ; if(!w) + beq.b .adv ; w = nWidth ; ds -= BUFFER_WIDTH + w + bra.b .next ; else continue + +.if6_68k ; while(width) { + move.b (a0)+,(a1)+ ; *dst++=*src++; + subq.l #1,d0 ; --width; + bne.b .if6_68k ; } +.adv2 + tst.l d1 ; if(!w) + beq.b .adv ; {w = nWidth ; ds -= BUFFER_WIDTH + w} + bra.b .next ; else continue + +.if5_ammx + vperm #$77777777,d3,d3,e0 + bank 0,1,movea.l,a1,a1 + add.l d0,a1 +.if5_ammx1 + storec e0,d0,(b1)+ + subq.l #8,d0 + storec e0,d0,(b1)+ + subq.l #8,d0 + bhi.b .if5_ammx1 + bra.b .adv2 + +.if6_ammx + bank 0,1,movea.l,a0,a0 ; movea a0,b0 + add.l d0,a0 + bank 0,1,movea.l,a1,a1 ; movea a1,b1 + add.l d0,a1 +.if6_ammx1 + load (b0)+,e0 + storec e0,d0,(b1)+ + subq.l #8,d0 + load (b0)+,e0 + storec e0,d0,(b1)+ + subq.l #8,d0 + bhi.b .if6_ammx1 + bra.b .adv2 + +* end of file From 776601ff8d79d934febf28c3d03f56ef232c0435 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 8 Feb 2020 14:50:35 +0100 Subject: [PATCH 094/107] reformat source code a bit --- SourceX/platform/amiga/ac68080_support.c | 332 +++++++++++------------ 1 file changed, 166 insertions(+), 166 deletions(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 04bae234e57..b9c11fd9108 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -50,7 +50,7 @@ extern SDL_Surface *pal_surface; // #define PressEscKey _ZN3dvl11PressEscKeyEv // extern int PressEscKey(void); -#define gamemenu_quit_game _ZN3dvl18gamemenu_quit_gameEi +#define gamemenu_quit_game _ZN3dvl18gamemenu_quit_gameEi extern void gamemenu_quit_game(int); // #define mainmenu_restart_repintro _ZN3dvl25mainmenu_restart_repintroEv @@ -88,71 +88,71 @@ extern struct IntuitionBase *IntuitionBase; /*****************************************************************************/ /* stack requirements */ -#define MINSTACK (128*1024) /* 128kb */ +#define MINSTACK (128*1024) /* 128kb */ #ifdef __SASC -__near /* sas/c */ +__near /* sas/c */ #endif -size_t __stack = MINSTACK; /* ixemul, vbcc */ +size_t __stack = MINSTACK; /* ixemul, vbcc */ /*****************************************************************************/ /* malloc replacement */ -#define SANITY_CHK 0 -#define REPLACE_SYS_MALLOC 1 +#define SANITY_CHK 0 +#define REPLACE_SYS_MALLOC 1 #define USE_DL_PREFIX -#define lower_malloc __real_malloc -#define lower_free __real_free +#define lower_malloc __real_malloc +#define lower_free __real_free extern void *lower_malloc(size_t); extern void lower_free(void *); -#define HAVE_MORECORE 0 +#define HAVE_MORECORE 0 -#define HAVE_MMAP 1 -#define HAVE_MUNMAP 1 -#define MMAP_CLEARS 0 -#define HAVE_MREMAP 0 +#define HAVE_MMAP 1 +#define HAVE_MUNMAP 1 +#define MMAP_CLEARS 0 +#define HAVE_MREMAP 0 #define LACKS_SYS_MMAN_H -#define MMAP my_mmap -#define MUNMAP my_munmap -#define DIRECT_MMAP MMAP +#define MMAP my_mmap +#define MUNMAP my_munmap +#define DIRECT_MMAP MMAP static void* MMAP(size_t len) { - void *p = lower_malloc(len+4); // +1 to avoid contiguous + void *p = lower_malloc(len+4); // +1 to avoid contiguous #if SANITY_CHK - if(p) { - ULONG *q = p; - *q = q; - p = ++q; - } - printf("MMAP(%d) = %p\n", len, p); + if(p) { + ULONG *q = p; + *q = q; + p = ++q; + } + printf("MMAP(%d) = %p\n", len, p); #endif - if(!p) { - printf("Out of memory (%d bytes requested).\n", len+4); - dlmalloc_stats(); - } - return p; + if(!p) { + printf("Out of memory (%d bytes requested).\n", len+4); + dlmalloc_stats(); + } + return p; } static int MUNMAP(void *p, size_t len) { #if SANITY_CHK - printf("MUNMAP(%p, %d)\n", p, len); - if(p) { - ULONG *q = p; --q; - if(*q == q) p = q; - else { - errno = EINVAL; - printf("Not MMAP!\n"); - return -1; - } - } + printf("MUNMAP(%p, %d)\n", p, len); + if(p) { + ULONG *q = p; --q; + if(*q == q) p = q; + else { + errno = EINVAL; + printf("Not MMAP!\n"); + return -1; + } + } #endif - lower_free(p); - return 0; + lower_free(p); + return 0; } #include "malloc.c" @@ -160,45 +160,45 @@ static int MUNMAP(void *p, size_t len) void *__wrap_malloc(size_t size) { #if REPLACE_SYS_MALLOC - return dlmalloc(size); + return dlmalloc(size); #else - return __real_malloc(size); + return __real_malloc(size); #endif } void __wrap_free(void *ptr) { #if REPLACE_SYS_MALLOC - dlfree(ptr); + dlfree(ptr); #else - __real_free(ptr); + __real_free(ptr); #endif } void *__wrap_realloc(void *ptr, size_t size) { #if REPLACE_SYS_MALLOC - return dlrealloc(ptr, size); + return dlrealloc(ptr, size); #else - extern void *__real_realloc(void *ptr, size_t size); - return __real_realloc(ptr,size); + extern void *__real_realloc(void *ptr, size_t size); + return __real_realloc(ptr,size); #endif } void *__wrap_calloc(size_t num, size_t size) { #if REPLACE_SYS_MALLOC - return dlcalloc(num, size); + return dlcalloc(num, size); #else - extern void *__real_calloc(size_t num, size_t size); - return __real_calloc(num,size); + extern void *__real_calloc(size_t num, size_t size); + return __real_calloc(num,size); #endif } /*****************************************************************************/ void assert_fail (char *file, int line, char *exp) { - printf("Assertion failed: %s\nFile: %s\nLine: %d\n",exp,file,line); - while(1) Delay(50); + printf("Assertion failed: %s\nFile: %s\nLine: %d\n",exp,file,line); + while(1) Delay(50); } /*****************************************************************************/ @@ -206,7 +206,7 @@ void assert_fail (char *file, int line, char *exp) { static void stop(void) { if(bufmem) { - dlfree(bufmem); + dlfree(bufmem); bufmem_roll = bufmem = NULL; } } @@ -215,16 +215,16 @@ static void start(void) { started = 255; atexit(stop); - + if (SysBase->AttnFlags &(1 << 10)) { ac68080_saga = _ZN3dvl10fullscreenE ? 255:0; // disable if not fullscreen bufmem = dlmemalign(32/* byte alignment for saga */, 3*FRAME_BUFFER_SZ); - if(bufmem) { - bufmem_roll = bufmem + 2*FRAME_BUFFER_SZ; - } else { - ac68080_saga = 0; - } + if(bufmem) { + bufmem_roll = bufmem + 2*FRAME_BUFFER_SZ; + } else { + ac68080_saga = 0; + } if(!VampireBase) VampireBase = OpenResource( V_VAMPIRENAME ); if(VampireBase && VampireBase->lib_Version >= 45 && @@ -247,95 +247,95 @@ static void start(void) } } -SDL_Surface* vampire_MakeTripleBuffer(SDL_Surface *surf) +SDL_Surface* vampire_MakeTripleBuffer(SDL_Surface *surf) { - if(!started) start(); - - if(ac68080_saga - && surf->w==BUFFER_WIDTH - && surf->h==BUFFER_HEIGHT - && surf->pitch==BUFFER_WIDTH - ) { - surf->flags |= SDL_PREALLOC; - SDL_free(surf->pixels); - surf->pixels = bufmem; - } else ac68080_saga = 0; - return surf; -} + if(!started) start(); + + if(ac68080_saga + && surf->w==BUFFER_WIDTH + && surf->h==BUFFER_HEIGHT + && surf->pitch==BUFFER_WIDTH + ) { + surf->flags |= SDL_PREALLOC; + SDL_free(surf->pixels); + surf->pixels = bufmem; + } else ac68080_saga = 0; + return surf; +} static __attribute__((noinline)) void doChkSignals(void) { - static UBYTE closing; - ULONG signal = SetSignal(0,0); - if(closing) { - SDL_Event sdlevent; - sdlevent.type = SDL_KEYDOWN; - sdlevent.key.keysym.sym = SDLK_ESCAPE; - SDL_PushEvent(&sdlevent); - sdlevent.type = SDL_KEYUP; - sdlevent.key.keysym.sym = SDLK_ESCAPE; - SDL_PushEvent(&sdlevent); - } - if(signal & SIGBREAKF_CTRL_E) { - time_t t; - SetSignal(0, SIGBREAKF_CTRL_E); - - t = time(0); - printf("\nMemory statistics on %s", ctime(&t)); - dlmalloc_stats(); - printf("\n"); - } - if(signal & SIGBREAKF_CTRL_C) { - SetSignal(0, SIGBREAKF_CTRL_C); - - printf("Ctrl-C received\n"); - gamemenu_quit_game(0); - closing = 255; - } + static UBYTE closing; + ULONG signal = SetSignal(0,0); + if(closing) { + SDL_Event sdlevent; + sdlevent.type = SDL_KEYDOWN; + sdlevent.key.keysym.sym = SDLK_ESCAPE; + SDL_PushEvent(&sdlevent); + sdlevent.type = SDL_KEYUP; + sdlevent.key.keysym.sym = SDLK_ESCAPE; + SDL_PushEvent(&sdlevent); + } + if(signal & SIGBREAKF_CTRL_E) { + time_t t; + SetSignal(0, SIGBREAKF_CTRL_E); + + t = time(0); + printf("\nMemory statistics on %s", ctime(&t)); + dlmalloc_stats(); + printf("\n"); + } + if(signal & SIGBREAKF_CTRL_C) { + SetSignal(0, SIGBREAKF_CTRL_C); + + printf("Ctrl-C received\n"); + gamemenu_quit_game(0); + closing = 255; + } } static void chkSignals(void) { - static UBYTE closing, ctr; - if(!ctr) { - ctr = 4; - doChkSignals(); - } else { - --ctr; - } + static UBYTE closing, ctr; + if(!ctr) { + ctr = 4; + doChkSignals(); + } else { + --ctr; + } } static void blitRect(UBYTE *dst, UBYTE *src, UWORD x, UWORD y, size_t w, UWORD h) { - src += SCREENXY(x,y); - dst += SCREENXY(x,y); - memcpy(dst-x, src-x, BUFFER_WIDTH*h); - - // do { - // memcpy(dst, src, w); - // src += BUFFER_WIDTH; - // dst += BUFFER_WIDTH; - // } while(--h); + src += SCREENXY(x,y); + dst += SCREENXY(x,y); + memcpy(dst-x, src-x, BUFFER_WIDTH*h); + + // do { + // memcpy(dst, src, w); + // src += BUFFER_WIDTH; + // dst += BUFFER_WIDTH; + // } while(--h); } // check if palette has changed static void doPalette(void) { - static int last_version = 0; - if(last_version!=pal_palette_version) { - last_version = pal_palette_version; - SDL_SetColors(SDL_GetVideoSurface(), pal_palette->colors, 0, pal_palette->ncolors); - } + static int last_version = 0; + if(last_version!=pal_palette_version) { + last_version = pal_palette_version; + SDL_SetColors(SDL_GetVideoSurface(), pal_palette->colors, 0, pal_palette->ncolors); + } } // set saga regs to dsplay screen at ptr (modulo bytes to skip at end of line) static void setFrameBufferRegs(UBYTE *ptr, UWORD modulo) { - volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ + volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ volatile UWORD *mod = (UBYTE**)0xDFF1E6; /* Frame buffer modulo */ - *dpy = ptr; - *mod = modulo; + *dpy = ptr; + *mod = modulo; } static void doFlip(void) @@ -343,7 +343,7 @@ static void doFlip(void) struct Screen *first_screen; #if DIRTY - // hacky way to debug + // hacky way to debug *dpy = (void*)(~31&(int)pal_surface->pixels); return; #endif @@ -359,57 +359,57 @@ static void doFlip(void) if(first_screen == game_screen) #endif { - UBYTE *ptr = pal_surface->pixels; - LONG dlt = ptr == bufmem_roll ? -2*FRAME_BUFFER_SZ : FRAME_BUFFER_SZ; + UBYTE *ptr = pal_surface->pixels; + LONG dlt = ptr == bufmem_roll ? -2*FRAME_BUFFER_SZ : FRAME_BUFFER_SZ; - setFrameBufferRegs(ptr + SCREENXY(0,0), BUFFER_WIDTH - SCREEN_WIDTH); + setFrameBufferRegs(ptr + SCREENXY(0,0), BUFFER_WIDTH - SCREEN_WIDTH); #if ROLL_PTR - // printf("ptr=%p // %p %p %p %p\n", ptr,bufmem, bufmem+FRAME_BUFFER_SZ, bufmem+2*FRAME_BUFFER_SZ, bufmem+3*FRAME_BUFFER_SZ); + // printf("ptr=%p // %p %p %p %p\n", ptr,bufmem, bufmem+FRAME_BUFFER_SZ, bufmem+2*FRAME_BUFFER_SZ, bufmem+3*FRAME_BUFFER_SZ); - // need to copy parts of previous screen? + // need to copy parts of previous screen? if(copy_previous) - { - --copy_previous; - if(copy_all) blitRect(ptr+dlt, ptr, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - else blitRect(ptr+dlt, ptr, PANEL_LEFT, PANEL_TOP, PANEL_WIDTH, PANEL_HEIGHT); - } + { + --copy_previous; + if(copy_all) blitRect(ptr+dlt, ptr, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + else blitRect(ptr+dlt, ptr, PANEL_LEFT, PANEL_TOP, PANEL_WIDTH, PANEL_HEIGHT); + } // advance ptr - pal_surface->pixels = (ptr += dlt); + pal_surface->pixels = (ptr += dlt); #endif } - doPalette(); + doPalette(); } int vampire_Flip(const SDL_Surface* surf) { - chkSignals(); - - if(last_was_pal) { - last_was_pal = 0; - doFlip(); - } else { - return SDL_Flip(surf); - } + chkSignals(); + + if(last_was_pal) { + last_was_pal = 0; + doFlip(); + } else { + return SDL_Flip(surf); + } } int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect) { - if(ac68080_saga && src==pal_surface) { - last_was_pal = 255; - if(!srcRect || srcRect->h>=SCREEN_HEIGHT) { - copy_all = 255; - copy_previous = 3; - } else if(srcRect->y + srcRect->h > PANEL_Y // something drawn in panel - && !(srcRect->w==288 && srcRect->h==60) // ignore descpane - ) { - copy_all = 0; - copy_previous = 3; - } - return 0; - } else return SDL_BlitSurface(src, srcRect, dst, dstRect); + if(ac68080_saga && src==pal_surface) { + last_was_pal = 255; + if(!srcRect || srcRect->h>=SCREEN_HEIGHT) { + copy_all = 255; + copy_previous = 3; + } else if(srcRect->y + srcRect->h > PANEL_Y // something drawn in panel + && !(srcRect->w==288 && srcRect->h==60) // ignore descpane + ) { + copy_all = 0; + copy_previous = 3; + } + return 0; + } else return SDL_BlitSurface(src, srcRect, dst, dstRect); } #define min(a,b) ((a)<=(b)?(a):(b)) @@ -460,12 +460,12 @@ int simple_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, extern int __real_SDL_VideoInit (const char *driver_name, Uint32 flags); int __wrap_SDL_VideoInit (const char *driver_name, Uint32 flags) { - ULONG bak = SysBase->AttnFlags; - int ret; - - SysBase->AttnFlags &= ~(1 << 10); - ret = __real_SDL_VideoInit(driver_name, flags); - SysBase->AttnFlags = bak; - - return ret; + ULONG bak = SysBase->AttnFlags; + int ret; + + SysBase->AttnFlags &= ~(1 << 10); + ret = __real_SDL_VideoInit(driver_name, flags); + SysBase->AttnFlags = bak; + + return ret; } From 5782c4a8c4773fd87612c560f01eb4b7ba9bd0b2 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 8 Feb 2020 14:54:03 +0100 Subject: [PATCH 095/107] fixed modulo type --- SourceX/platform/amiga/ac68080_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index b9c11fd9108..1cd61562f7c 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -332,7 +332,7 @@ static void doPalette(void) static void setFrameBufferRegs(UBYTE *ptr, UWORD modulo) { volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ - volatile UWORD *mod = (UBYTE**)0xDFF1E6; /* Frame buffer modulo */ + volatile UWORD *mod = (UWORD**)0xDFF1E6; /* Frame buffer modulo */ *dpy = ptr; *mod = modulo; From e978034057470607326e7ec20d663845b3040b67 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 8 Feb 2020 14:54:54 +0100 Subject: [PATCH 096/107] fixed modulo type --- SourceX/platform/amiga/ac68080_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 1cd61562f7c..b955b215847 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -332,7 +332,7 @@ static void doPalette(void) static void setFrameBufferRegs(UBYTE *ptr, UWORD modulo) { volatile UBYTE **dpy = (UBYTE**)0xDFF1EC; /* Frame buffer address */ - volatile UWORD *mod = (UWORD**)0xDFF1E6; /* Frame buffer modulo */ + volatile UWORD *mod = (UWORD*)0xDFF1E6; /* Frame buffer modulo */ *dpy = ptr; *mod = modulo; From ea759ffdc065f261a1da7b6b250eeb2210d9a03f Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 15 Feb 2020 14:45:59 +0100 Subject: [PATCH 097/107] fixed stupid erro making the exe crahs on non-vamp amigas --- SourceX/platform/amiga/render68k.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 61e27190d06..01b40e638bc 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -993,7 +993,7 @@ _Cl2BlitSafe_68k .tst_ammx tst.b _ac68080_ammx - bne.b .exit + beq.b .exit lea .if5_ammx,a0 lea .if6_ammx,a1 move.l a0,.p5+2 From 5d2eaf12e785b232a50bf5048460939374532b68 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Sat, 15 Feb 2020 23:42:00 +0100 Subject: [PATCH 098/107] removed bank with makes vampire freeze --- SourceX/platform/amiga/render68k.asm | 82 ++++++++++++++-------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/SourceX/platform/amiga/render68k.asm b/SourceX/platform/amiga/render68k.asm index 01b40e638bc..ccb7d86a725 100755 --- a/SourceX/platform/amiga/render68k.asm +++ b/SourceX/platform/amiga/render68k.asm @@ -32,18 +32,18 @@ INLINE_BLOCK16 set 1 ; 1 seem faster, but hard to tell cnop 0,4 -bank macro - inline -.aa equ * - dc.w (%0111000100000000+((\1)*%100)+(\2)+((.bb)*%1000000)) - ifb \5 - \3 \4 - else - \3 \4,\5 - endc -.bb equ (*-.aa-4)>>1 - einline - endm +*bank macro +* inline +*.aa equ * +* dc.w (%0111000100000000+((\1)*%100)+(\2)+((.bb)*%1000000)) +* ifb \5 +* \3 \4 +* else +* \3 \4,\5 +* endc +*.bb equ (*-.aa-4)>>1 +* einline +* endm * ----------------------------------------------------------------------------- * inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD mask) @@ -1002,6 +1002,32 @@ _Cl2BlitSafe_68k .exit rts +.if5_ammx + vperm #$77777777,d3,d3,e0 + pea (a1,d0.l) +.if5_ammx1 + storec e0,d0,(a1)+ + subq.l #8,d0 + bhi.b .if5_ammx1 + tst.l d1 ; if(!w) + movea.l (sp)+,a1 + beq.b .adv ; {w = nWidth ; ds -= BUFFER_WIDTH + w} + bra.b .next ; else continue + +.if6_ammx + pea (a1,d0.l) + pea (a0,d0.l) +.if6_ammx1 + load (a0)+,e0 + storec e0,d0,(a1)+ + subq.l #8,d0 + bhi.b .if6_ammx1 + tst.l d1 ; if(!w) + movea.l (sp)+,a0 ; fused + movea.l (sp)+,a1 ; fused + beq.b .adv ; {w = nWidth ; ds -= BUFFER_WIDTH + w} + bra.b .next ; else continue + .if5_68k ; while(width) { move.b d3,(a1)+ ; *dst++ = fill: subq.l #1,d0 ; -width; @@ -1014,36 +1040,8 @@ _Cl2BlitSafe_68k move.b (a0)+,(a1)+ ; *dst++=*src++; subq.l #1,d0 ; --width; bne.b .if6_68k ; } -.adv2 tst.l d1 ; if(!w) - beq.b .adv ; {w = nWidth ; ds -= BUFFER_WIDTH + w} - bra.b .next ; else continue - -.if5_ammx - vperm #$77777777,d3,d3,e0 - bank 0,1,movea.l,a1,a1 - add.l d0,a1 -.if5_ammx1 - storec e0,d0,(b1)+ - subq.l #8,d0 - storec e0,d0,(b1)+ - subq.l #8,d0 - bhi.b .if5_ammx1 - bra.b .adv2 - -.if6_ammx - bank 0,1,movea.l,a0,a0 ; movea a0,b0 - add.l d0,a0 - bank 0,1,movea.l,a1,a1 ; movea a1,b1 - add.l d0,a1 -.if6_ammx1 - load (b0)+,e0 - storec e0,d0,(b1)+ - subq.l #8,d0 - load (b0)+,e0 - storec e0,d0,(b1)+ - subq.l #8,d0 - bhi.b .if6_ammx1 - bra.b .adv2 + beq.w .adv ; {w = nWidth ; ds -= BUFFER_WIDTH + w} + bra.w .next ; else continue * end of file From c7a78fcda77006df425cd2eef7ba81dce86ca061 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 17 Feb 2020 19:00:47 +0100 Subject: [PATCH 099/107] added ascii-art for aros --- SourceX/platform/amiga/ac68080_support.c | 25 ++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index b955b215847..d4cb303951c 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -73,6 +73,7 @@ extern void gamemenu_quit_game(int); UBYTE ac68080_saga = 0; UBYTE ac68080_ammx = 0; +UBYTE aros_is_here = 0; static USHORT copy_previous = 0; @@ -213,9 +214,11 @@ static void stop(void) static void start(void) { + void *aros_lib; + started = 255; atexit(stop); - + if (SysBase->AttnFlags &(1 << 10)) { ac68080_saga = _ZN3dvl10fullscreenE ? 255:0; // disable if not fullscreen @@ -232,7 +235,7 @@ static void start(void) ac68080_ammx = 255; } - printf("Vampire accelerator detected"); + printf("^8^ Vampire ^8^ accelerator detected"); if(ac68080_ammx || ac68080_saga) { printf(". Using"); if(ac68080_saga) { @@ -245,6 +248,24 @@ static void start(void) } printf(".\n"); } + + aros_is_here = 255; + if((aros_lib = OpenLibrary("aros.library", 0L))) { + CloseLibrary(aros_lib); + aros_is_here = 255; + printf("AROS detected.\n"); + } + if(aros_is_here) + printf("\n" + " ( ( ( ( ( (\n" + " ( ) ) ) ( %s\n" + " \\`-_ ((( _-'/ ) (\n" + " ) <0> <0> ( ( ( ,-------. ,------- .-------. ,-----\n" + " ( ==_*_== ) ) ( | | | | | |\n" + " `--_____--' ( ( `----- ° ° `-------' -----'\n" + "\n", + ac68080_ammx ? " VAMPIRE SAYS HELLO TO" + : "DEVILUTIONX SAYS HELLO TO"); } SDL_Surface* vampire_MakeTripleBuffer(SDL_Surface *surf) From e8d23db5e7426b3b36a39d01b2c0cff1ada8c7c6 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 17 Feb 2020 19:58:12 +0100 Subject: [PATCH 100/107] added ascii-art for aros --- SourceX/platform/amiga/ac68080_support.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index d4cb303951c..9b15a51ec67 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -257,12 +257,13 @@ static void start(void) } if(aros_is_here) printf("\n" - " ( ( ( ( ( (\n" - " ( ) ) ) ( %s\n" - " \\`-_ ((( _-'/ ) (\n" - " ) <0> <0> ( ( ( ,-------. ,------- .-------. ,-----\n" - " ( ==_*_== ) ) ( | | | | | |\n" - " `--_____--' ( ( `----- ° ° `-------' -----'\n" + " _--------___\n" + " ( ( ) ) ( %s\n" + " \\`-_ `' _-'/ `.\n" + " ) <0> <0> ( ( ,-------. ,------- .-------. ,-----\n" + " ( ==_*_== ) ) | | | | | |\n" + " `--_____--' )' `----- ¹ ¹ `-------' -----'\n" + " ;,'\n" "\n", ac68080_ammx ? " VAMPIRE SAYS HELLO TO" : "DEVILUTIONX SAYS HELLO TO"); From a248ebc776b4fbe270c10d1274bd687a593f1bda Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Mon, 17 Feb 2020 22:23:08 +0100 Subject: [PATCH 101/107] increased fps why using AMMX version of SDL_MixAudio_m68k_S16MSB --- CMake/amiga/m68k-amigaos.cmake | 5 ++-- SourceX/platform/amiga/memopt.asm | 40 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/CMake/amiga/m68k-amigaos.cmake b/CMake/amiga/m68k-amigaos.cmake index 2f786eb787c..d2bfd9deb0f 100755 --- a/CMake/amiga/m68k-amigaos.cmake +++ b/CMake/amiga/m68k-amigaos.cmake @@ -53,7 +53,7 @@ endif() # Compiler flags if(PROFILE) - set(FLAGS_COMMON "-D__PROFILE__ -pg") + set(FLAGS_COMMON "-D__PROFILE__ -pg -D_DEBUG") else() set(FLAGS_COMMON "-fomit-frame-pointer") endif() @@ -77,7 +77,8 @@ foreach(_wrapped free realloc calloc - SDL_VideoInit) + SDL_VideoInit + SDL_MixAudio_m68k_S16MSB) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=${_wrapped}") endforeach(_wrapped) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index a0880efefd5..79c0b68e906 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -226,5 +226,45 @@ _ConvertUInt64BufferAMMX subq.l #8,d0 bhi .loop rts + +* void SDL_MixAudio_m68k_S16MSB(short* dst, short* src, long len, long volume) + + xref ___real_SDL_MixAudio_m68k_S16MSB + xdef ___wrap_SDL_MixAudio_m68k_S16MSB + +SDL_MixAudio_m68k_S16MSB + jmp ___real_SDL_MixAudio_m68k_S16MSB +___wrap_SDL_MixAudio_m68k_S16MSB + rsreset + rs.l 1 +.dst rs.l 1 +.src rs.l 1 +.len rs.l 1 +.vol rs.l 1 + +.entry + tst.b _ac68080_ammx + beq.b SDL_MixAudio_m68k_S16MSB + move.l .len(sp),d0 + and.l #-2,d0 + beq.b .exit + move.l .vol(sp),d1 + lsl.l #1,d1 ; make volume 8.8 + move.l .dst(sp),a1 ; get dst + move.l .src(sp),a0 ; get src + vperm #$67676767,d1,d1,d1 ; copy volume 4 time +.loop + pmul88 (a0)+,d1,e0 ; src-sample * volume + paddw (a1),e0,e0 ; add dst ignoring saturation + storec e0,d0,(a1)+ ; store result + subq.l #8,d0 + bhi.s .loop +.exit +* remove initial comparison so that it now only costs 1 cycle + move.w #$203c,.entry ; move.l #nnnn,d0 + move.w #$7200,.entry+6 ; moveq #0,d1 + move.w #$4e75,.exit ; #rts + rts ; no need to ClearCacheU on apollo! + * end of file \ No newline at end of file From b763cb324ef0429cd12303e0df278d3c9cde8180 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 18 Feb 2020 12:44:18 +0100 Subject: [PATCH 102/107] software saturation add now works --- SourceX/platform/amiga/memopt.asm | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index 79c0b68e906..ce2a16f728a 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -254,10 +254,26 @@ ___wrap_SDL_MixAudio_m68k_S16MSB move.l .dst(sp),a1 ; get dst move.l .src(sp),a0 ; get src vperm #$67676767,d1,d1,d1 ; copy volume 4 time + .loop pmul88 (a0)+,d1,e0 ; src-sample * volume - paddw (a1),e0,e0 ; add dst ignoring saturation - storec e0,d0,(a1)+ ; store result + load (a1),e1 + +; sw implementation of vaddssw inspired from: +; http://rg1-teaching.mpi-inf.mpg.de/advancedc-ws08/script/lecture10.pdf + paddw e0,e1,e2 ; sum = x+y + + pmaxuw.w #$7FFF,e0,e3 + pminuw.w #$8000,e3,e3 ; big = (x>>15) ^ 32767 + + peor e2,e0,e0 ; x ^= sum + peor e2,e1,e1 ; y ^= sum + pand e0,e1,e1 ; overflow = x&y + vperm #$00224466,e1,e1,e1 ; set b7 at proper place for ilm + + storeilm e2,e1,e3 ; sum = overflow<0 ? big : sum + + storec e3,d0,(a1)+ ; store result subq.l #8,d0 bhi.s .loop .exit From b8f03c196e9fa441ea7fc8d4598d3b36206e2e68 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 18 Feb 2020 12:45:52 +0100 Subject: [PATCH 103/107] added ascii-art for aros --- SourceX/platform/amiga/ac68080_support.c | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index 9b15a51ec67..b1bd0e7826e 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -235,7 +235,7 @@ static void start(void) ac68080_ammx = 255; } - printf("^8^ Vampire ^8^ accelerator detected"); + printf("Vampire accelerator detected"); if(ac68080_ammx || ac68080_saga) { printf(". Using"); if(ac68080_saga) { @@ -246,25 +246,25 @@ static void start(void) printf(" AMMX"); } } - printf(".\n"); + printf(". ^8^\n"); } - aros_is_here = 255; + //aros_is_here = 255; if((aros_lib = OpenLibrary("aros.library", 0L))) { CloseLibrary(aros_lib); aros_is_here = 255; - printf("AROS detected.\n"); - } - if(aros_is_here) + printf("AROS detected.\n"); + } + if(aros_is_here) printf("\n" - " _--------___\n" - " ( ( ) ) ( %s\n" - " \\`-_ `' _-'/ `.\n" - " ) <0> <0> ( ( ,-------. ,------- .-------. ,-----\n" - " ( ==_*_== ) ) | | | | | |\n" - " `--_____--' )' `----- ¹ ¹ `-------' -----'\n" - " ;,'\n" - "\n", + " _-------___\n" + " _ ( ( ( ( _( %s\n" + " \\`-_ `v' _-'/ `.\n" + " ) <0> <0> ( ( ,-------. ,------- .-------. ,-----\n" + " ( ==_*_== ) ) | | | | | |\n" + " `--_____--' )' `----- ¹ ¹ `-------' -----'\n" + " ;'\n" + "\n", ac68080_ammx ? " VAMPIRE SAYS HELLO TO" : "DEVILUTIONX SAYS HELLO TO"); } From bebd534f921d9babee8ce9aaad07fc005b730c19 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 18 Feb 2020 12:50:46 +0100 Subject: [PATCH 104/107] made aros use 320240 screen in place of 320x200 wich seem buggy --- SourceS/sdl_compat.h | 1 + SourceX/storm/storm.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SourceS/sdl_compat.h b/SourceS/sdl_compat.h index 5d213dd3171..2e13cd7b607 100644 --- a/SourceS/sdl_compat.h +++ b/SourceS/sdl_compat.h @@ -18,6 +18,7 @@ extern "C" { extern char ac68080_saga; extern char ac68080_ammx; + extern char aros_is_here; extern int vampire_Flip(SDL_Surface *surf); extern int vampire_BlitSurface(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect); diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index 6086699c9c1..f789c5f334b 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -591,7 +591,7 @@ void SVidPlayBegin(char *filename, int a2, int a3, int a4, int a5, int flags, HA #elif SDL1_VIDEO_MODE_BPP == 8 SDL_SetVideoMode(SVidWidth, #ifdef __AMIGA__ // fixes video not being centered - SVidHeight<200?200:SVidHeight, + SVidHeight<200?(aros_is_here?240:200):SVidHeight, #else SVidHeight, #endif From 4b4b6100bb3c47e0314cf1e8a733058c17a4faef Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Tue, 18 Feb 2020 20:40:12 +0100 Subject: [PATCH 105/107] added ascii-art for aros --- SourceX/platform/amiga/ac68080_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/platform/amiga/ac68080_support.c b/SourceX/platform/amiga/ac68080_support.c index b1bd0e7826e..6ab360f07db 100755 --- a/SourceX/platform/amiga/ac68080_support.c +++ b/SourceX/platform/amiga/ac68080_support.c @@ -262,7 +262,7 @@ static void start(void) " \\`-_ `v' _-'/ `.\n" " ) <0> <0> ( ( ,-------. ,------- .-------. ,-----\n" " ( ==_*_== ) ) | | | | | |\n" - " `--_____--' )' `----- ¹ ¹ `-------' -----'\n" + " `--_____--' )' `----- ' ' `-------' -----'\n" " ;'\n" "\n", ac68080_ammx ? " VAMPIRE SAYS HELLO TO" From a2f5717ff71dd21f2c9d1e711f2f8b242c2231ab Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 19 Feb 2020 17:13:57 +0100 Subject: [PATCH 106/107] faster asm implem of vaddssw. might fix click noise when walking with only bg music --- SourceX/platform/amiga/memopt.asm | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/SourceX/platform/amiga/memopt.asm b/SourceX/platform/amiga/memopt.asm index ce2a16f728a..eaaf363e557 100755 --- a/SourceX/platform/amiga/memopt.asm +++ b/SourceX/platform/amiga/memopt.asm @@ -256,9 +256,16 @@ ___wrap_SDL_MixAudio_m68k_S16MSB vperm #$67676767,d1,d1,d1 ; copy volume 4 time .loop - pmul88 (a0)+,d1,e0 ; src-sample * volume + pmul88 (a0)+,d1,e0 ; src-sample * volume load (a1),e1 - + ifne 1 + pmaxsw.w #0,e1,e2 ; e2 = + positive dst-samples / 0 otherwise + psubw e1,e2,e1 ; e1 = - negative dst-samples / 0 otherwise + paddw.w #$8000,e0,e0 ; make unsigned + paddusw e2,e0,e0 ; add positive samples, saturate at $ff + psubusw e1,e0,e0 ; subtract negative samples, saturate at $00 + psubw.w #$8000,e0,e3 ; make signed + else ; sw implementation of vaddssw inspired from: ; http://rg1-teaching.mpi-inf.mpg.de/advancedc-ws08/script/lecture10.pdf paddw e0,e1,e2 ; sum = x+y @@ -272,7 +279,7 @@ ___wrap_SDL_MixAudio_m68k_S16MSB vperm #$00224466,e1,e1,e1 ; set b7 at proper place for ilm storeilm e2,e1,e3 ; sum = overflow<0 ? big : sum - + endc storec e3,d0,(a1)+ ; store result subq.l #8,d0 bhi.s .loop From 04d34586c9f7b442b44cf2bb4df012c0d9f2a8e7 Mon Sep 17 00:00:00 2001 From: Samuel-DEVULDER Date: Wed, 19 Feb 2020 18:32:58 +0100 Subject: [PATCH 107/107] another attempt at removeing stripes on polish version --- SourceX/storm/storm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SourceX/storm/storm.cpp b/SourceX/storm/storm.cpp index f789c5f334b..0859969572d 100644 --- a/SourceX/storm/storm.cpp +++ b/SourceX/storm/storm.cpp @@ -591,7 +591,7 @@ void SVidPlayBegin(char *filename, int a2, int a3, int a4, int a5, int flags, HA #elif SDL1_VIDEO_MODE_BPP == 8 SDL_SetVideoMode(SVidWidth, #ifdef __AMIGA__ // fixes video not being centered - SVidHeight<200?(aros_is_here?240:200):SVidHeight, + (SVidWidth<=320 && SVidHeight<=200 && !aros_is_here) ? 200 : SVidHeight, #else SVidHeight, #endif