From b2f00ba330250f6697bec20188505cc6dd1c6e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 5 Jan 2021 12:10:02 +0100 Subject: [PATCH 01/12] Heavily optimized common copper list routines. --- lib/libgfx/CopMoveLong.c | 19 ++++++++++--------- lib/libgfx/CopMoveWord.c | 11 +++++------ lib/libgfx/CopWait.c | 15 ++++++--------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/lib/libgfx/CopMoveLong.c b/lib/libgfx/CopMoveLong.c index 831be8ef..9c9de6e7 100644 --- a/lib/libgfx/CopMoveLong.c +++ b/lib/libgfx/CopMoveLong.c @@ -1,16 +1,17 @@ #include -CopInsT *CopMoveLong(CopListT *list, u_short reg, void *data) { - CopInsT *ptr = list->curr; - u_short *ins = (u_short *)ptr; +CopInsT *CopMoveLong(CopListT *list, u_short reg, void *ptr) { + CopInsT *ins = list->curr; + u_int data = (u_int)ptr; reg &= 0x01fe; + reg += 2; - *ins++ = reg; - *ins++ = (u_int)data >> 16; - *ins++ = reg + 2; - *ins++ = (u_int)data; + *((u_short *)ins)++ = reg; + *((u_short *)ins)++ = data; + *((u_short *)ins)++ = reg - 2; + *((u_short *)ins)++ = swap16(data); - list->curr = (CopInsT *)ins; - return ptr; + list->curr = ins; + return ins - 2; } diff --git a/lib/libgfx/CopMoveWord.c b/lib/libgfx/CopMoveWord.c index 1ac71bf2..37389328 100644 --- a/lib/libgfx/CopMoveWord.c +++ b/lib/libgfx/CopMoveWord.c @@ -1,12 +1,11 @@ #include CopInsT *CopMoveWord(CopListT *list, u_short reg, u_short data) { - CopInsT *ptr = list->curr; - u_short *ins = (u_short *)ptr; + CopInsT *ins = list->curr; - *ins++ = reg & 0x01fe; - *ins++ = data; + *((u_short *)ins)++ = reg & 0x01fe; + *((u_short *)ins)++ = data; - list->curr = (CopInsT *)ins; - return ptr; + list->curr = ins; + return ins - 1; } diff --git a/lib/libgfx/CopWait.c b/lib/libgfx/CopWait.c index e7fb03cb..17788627 100644 --- a/lib/libgfx/CopWait.c +++ b/lib/libgfx/CopWait.c @@ -1,15 +1,12 @@ #include CopInsT *CopWait(CopListT *list, u_short vp, u_short hp) { - CopInsT *ptr = list->curr; - u_char *bp = (u_char *)ptr; - u_short *wp; + CopInsT *ins = list->curr; - *bp++ = vp; - *bp++ = hp | 1; - wp = (u_short *)bp; - *wp++ = 0xfffe; + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_short *)ins)++ = 0xfffe; - list->curr = (CopInsT *)wp; - return ptr; + list->curr = ins; + return ins - 1; } From 51473bb19c4c7c7840f1239b5e1b5a3a2381db66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 5 Jan 2021 12:11:26 +0100 Subject: [PATCH 02/12] Vertical scaling - first attempt. --- effects/scaler/Makefile | 7 +++ effects/scaler/data/stars-die.png | 3 ++ effects/scaler/scaler.c | 80 +++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 effects/scaler/Makefile create mode 100644 effects/scaler/data/stars-die.png create mode 100644 effects/scaler/scaler.c diff --git a/effects/scaler/Makefile b/effects/scaler/Makefile new file mode 100644 index 00000000..3eba1ad1 --- /dev/null +++ b/effects/scaler/Makefile @@ -0,0 +1,7 @@ +TOPDIR := $(realpath ../..) + +CLEAN-FILES := data/stars-die.c + +PNG2C.stars-die := --bitmap image,320x256x5,+interleaved --palette image_pal,32 + +include $(TOPDIR)/build/effect.mk diff --git a/effects/scaler/data/stars-die.png b/effects/scaler/data/stars-die.png new file mode 100644 index 00000000..0faf9936 --- /dev/null +++ b/effects/scaler/data/stars-die.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aecfc44106b2d8168984b948dc78f6be1509d3c6f1db368fac17b2686fb0863 +size 24313 diff --git a/effects/scaler/scaler.c b/effects/scaler/scaler.c new file mode 100644 index 00000000..5bed85c7 --- /dev/null +++ b/effects/scaler/scaler.c @@ -0,0 +1,80 @@ +#include "effect.h" +#include "custom.h" +#include "copper.h" +#include "bitmap.h" +#include "palette.h" +#include "profiler.h" + +#include "data/stars-die.c" + +#define LINES 256 + +static CopListT *cp0, *cp1; + +/* static */ void MakeCopperList(CopListT *cp, short height) { + short ys = (LINES - height) / 2; + int dy = (LINES << 16) / height; + + CopInit(cp); + CopSetupDisplayWindow(cp, MODE_LORES, X(0), Y(ys), image.width, height); + CopSetupBitplanes(cp, NULL, &image, image.depth); + + { + short n = (short)(dy >> 16) * (short)image.depth; + short mod = (short)image.bytesPerRow * (short)(n - 1); + int y = 0; + short i; + + for (i = 1; i < height; i++) { + short _mod = mod; + int ny = y + dy; + if ((u_short)ny < (u_short)y) + _mod += image.bytesPerRow * image.depth; + CopWait(cp, Y(ys + i), 0); + CopMove16(cp, bpl1mod, _mod); + CopMove16(cp, bpl2mod, _mod); + y = ny; + } + } + + CopEnd(cp); +} + +/* static */ void Init(void) { + LoadPalette(&image_pal, 0); + SetupPlayfield(MODE_LORES, image.depth, + X(0), Y(0), image.width, image.height); + + cp0 = NewCopList(40 + LINES * 3); + cp1 = NewCopList(40 + LINES * 3); + MakeCopperList(cp0, LINES); + CopListActivate(cp0); + + EnableDMA(DMAF_RASTER); +} + +static void Kill(void) { + DisableDMA(DMAF_COPPER | DMAF_RASTER); + DeleteCopList(cp0); + DeleteCopList(cp1); +} + +PROFILE(Scaler); + +static void Render(void) { + static short val = 0, dir = 1; + + ProfilerStart(Scaler); + MakeCopperList(cp0, LINES - val); + ProfilerStop(Scaler); + + CopListRun(cp0); + TaskWaitVBlank(); + { CopListT *tmp = cp0; cp0 = cp1; cp1 = tmp; } + + val += dir; + if ((val == 0) || (val == LINES - 2)) + dir = -dir; +} + +EFFECT(scaler, NULL, NULL, Init, Kill, Render); From 0c779bd5e34902f3533ba391c47790959fdac70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 5 Jan 2021 21:33:22 +0100 Subject: [PATCH 03/12] Optimize more copper routines. --- include/copper.h | 17 +++++++---------- lib/libgfx/CopInit.c | 2 +- lib/libgfx/CopLoadColor.c | 12 +++++++----- lib/libgfx/CopLoadPal.c | 8 +++++--- lib/libgfx/CopMoveWord.c | 2 +- lib/libgfx/CopSkip.c | 12 ++++++++++++ lib/libgfx/CopWait.c | 2 +- lib/libgfx/CopWaitSafe.c | 9 ++++----- lib/libgfx/CopWaitSkip.c | 15 --------------- lib/libgfx/Makefile | 2 +- 10 files changed, 39 insertions(+), 42 deletions(-) create mode 100644 lib/libgfx/CopSkip.c delete mode 100644 lib/libgfx/CopWaitSkip.c diff --git a/include/copper.h b/include/copper.h index 54a35bfe..12f7ffd2 100644 --- a/include/copper.h +++ b/include/copper.h @@ -34,12 +34,10 @@ typedef union { } move; } CopInsT; -#define CLF_VPOVF 1 /* Vertical Position counter overflowed */ - typedef struct { CopInsT *curr; u_short length; - u_short flags; + u_char overflow; /* -1 if Vertical Position counter overflowed */ CopInsT entry[0]; } CopListT; @@ -57,29 +55,28 @@ static inline void CopListRun(CopListT *list) { } /* Low-level functions */ -CopInsT *CopMoveWord(CopListT *list, u_short reg, u_short data); +CopInsT *CopMoveWord(CopListT *list, u_short reg, short data); CopInsT *CopMoveLong(CopListT *list, u_short reg, void *data); -#define CSREG(reg) (u_short)offsetof(struct Custom, reg) +#define CSREG(reg) offsetof(struct Custom, reg) #define CopMove16(cp, reg, data) CopMoveWord(cp, CSREG(reg), data) #define CopMove32(cp, reg, data) CopMoveLong(cp, CSREG(reg), data) /* Official way to represent no-op copper instruction. */ #define CopNoOp(cp) CopMoveWord(cp, 0x1FE, 0) -CopInsT *CopWait(CopListT *list, u_short vp, u_short hp); +CopInsT *CopWait(CopListT *list, short vp, short hp); CopInsT *CopWaitMask(CopListT *list, u_short vp, u_short hp, u_short vpmask asm("d2"), u_short hpmask asm("d3")); /* Handles Copper Vertical Position counter overflow, by inserting CopWaitEOL * at first WAIT instruction with VP >= 256. */ -CopInsT *CopWaitSafe(CopListT *list, u_short vp, u_short hp); +CopInsT *CopWaitSafe(CopListT *list, short vp, short hp); /* The most significant bit of vertical position cannot be masked out (overlaps * with blitter-finished-disable bit), so we have to pass upper bit as well. */ #define CopWaitH(cp, vp, hp) CopWaitMask(cp, vp & 128, hp, 0, 255) #define CopWaitV(cp, vp) CopWaitMask(cp, vp, 0, 255, 0) -#define CopWaitEOL(cp, vp) CopWait(cp, vp, LASTHP) CopInsT *CopSkip(CopListT *list, u_short vp, u_short hp); CopInsT *CopSkipMask(CopListT *list, u_short vp, u_short hp, @@ -103,8 +100,8 @@ static inline void CopInsSet16(CopInsT *ins, u_short data) { } /* High-level functions */ -CopInsT *CopLoadPal(CopListT *list, const PaletteT *palette, u_short start); -CopInsT *CopLoadColor(CopListT *list, u_short start, u_short end, u_short color); +CopInsT *CopLoadPal(CopListT *list, const PaletteT *palette, short start); +CopInsT *CopLoadColor(CopListT *list, short start, short end, short color); void CopSetupMode(CopListT *list, u_short mode, u_short depth); void CopSetupDisplayWindow(CopListT *list, u_short mode, diff --git a/lib/libgfx/CopInit.c b/lib/libgfx/CopInit.c index 24b3871f..9df16255 100644 --- a/lib/libgfx/CopInit.c +++ b/lib/libgfx/CopInit.c @@ -2,5 +2,5 @@ void CopInit(CopListT *list) { list->curr = list->entry; - list->flags = 0; + list->overflow = 0; } diff --git a/lib/libgfx/CopLoadColor.c b/lib/libgfx/CopLoadColor.c index 4a0c2a1e..72226af3 100644 --- a/lib/libgfx/CopLoadColor.c +++ b/lib/libgfx/CopLoadColor.c @@ -1,14 +1,16 @@ #include -CopInsT *CopLoadColor(CopListT *list, u_short start, u_short end, u_short color) -{ +CopInsT *CopLoadColor(CopListT *list, short start, short end, short color) { CopInsT *ptr = list->curr; u_short *ins = (u_short *)ptr; + short n = end - start - 1; + short reg = CSREG(color[start]); - while (start <= end) { - *ins++ = CSREG(color[start++]); + do { + *ins++ = reg; *ins++ = color; - } + reg += 2; + } while (--n != -1); list->curr = (CopInsT *)ins; return ptr; diff --git a/lib/libgfx/CopLoadPal.c b/lib/libgfx/CopLoadPal.c index 68cbbed7..bb974368 100644 --- a/lib/libgfx/CopLoadPal.c +++ b/lib/libgfx/CopLoadPal.c @@ -1,14 +1,16 @@ #include -CopInsT *CopLoadPal(CopListT *list, const PaletteT *palette, u_short start) { +CopInsT *CopLoadPal(CopListT *list, const PaletteT *palette, short start) { CopInsT *ptr = list->curr; u_short *ins = (u_short *)ptr; u_short *c = palette->colors; - short n = min(palette->count, (u_short)(32 - start)) - 1; + short n = min((short)palette->count, (short)(32 - start)) - 1; + short reg = CSREG(color[start]); do { - *ins++ = CSREG(color[start++]); + *ins++ = reg; *ins++ = *c++; + reg += 2; } while (--n != -1); list->curr = (CopInsT *)ins; diff --git a/lib/libgfx/CopMoveWord.c b/lib/libgfx/CopMoveWord.c index 37389328..a3a5108a 100644 --- a/lib/libgfx/CopMoveWord.c +++ b/lib/libgfx/CopMoveWord.c @@ -1,6 +1,6 @@ #include -CopInsT *CopMoveWord(CopListT *list, u_short reg, u_short data) { +CopInsT *CopMoveWord(CopListT *list, u_short reg, short data) { CopInsT *ins = list->curr; *((u_short *)ins)++ = reg & 0x01fe; diff --git a/lib/libgfx/CopSkip.c b/lib/libgfx/CopSkip.c new file mode 100644 index 00000000..7ee1f77c --- /dev/null +++ b/lib/libgfx/CopSkip.c @@ -0,0 +1,12 @@ +#include + +CopInsT *CopSkip(CopListT *list, u_short vp, u_short hp) { + CopInsT *ins = list->curr; + + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_short *)ins)++ = 0xffff; + + list->curr = ins; + return ins - 1; +} diff --git a/lib/libgfx/CopWait.c b/lib/libgfx/CopWait.c index 17788627..a966c881 100644 --- a/lib/libgfx/CopWait.c +++ b/lib/libgfx/CopWait.c @@ -1,6 +1,6 @@ #include -CopInsT *CopWait(CopListT *list, u_short vp, u_short hp) { +CopInsT *CopWait(CopListT *list, short vp, short hp) { CopInsT *ins = list->curr; *((u_char *)ins)++ = vp; diff --git a/lib/libgfx/CopWaitSafe.c b/lib/libgfx/CopWaitSafe.c index 9900e6ab..6074abbd 100644 --- a/lib/libgfx/CopWaitSafe.c +++ b/lib/libgfx/CopWaitSafe.c @@ -1,11 +1,10 @@ #include -CopInsT *CopWaitSafe(CopListT *list, u_short vp, u_short hp) { - if (!(list->flags & CLF_VPOVF) && (vp >= 256)) { +CopInsT *CopWaitSafe(CopListT *list, short vp, short hp) { + if (vp >= 256 && !list->overflow) { + list->overflow = -1; /* Wait for last waitable position to control when overflow occurs. */ - CopWaitEOL(list, 255); - list->flags |= CLF_VPOVF; + *((u_int *)list->curr)++ = 0xffdffffe; } - return CopWait(list, vp, hp); } diff --git a/lib/libgfx/CopWaitSkip.c b/lib/libgfx/CopWaitSkip.c deleted file mode 100644 index 02c4cbef..00000000 --- a/lib/libgfx/CopWaitSkip.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -CopInsT *CopSkip(CopListT *list, u_short vp, u_short hp) { - CopInsT *ptr = list->curr; - u_char *bp = (u_char *)ptr; - u_short *wp; - - *bp++ = vp; - *bp++ = hp | 1; - wp = (u_short *)bp; - *wp++ = 0xffff; - - list->curr = (CopInsT *)wp; - return ptr; -} diff --git a/lib/libgfx/Makefile b/lib/libgfx/Makefile index d99b2744..db5ff38e 100644 --- a/lib/libgfx/Makefile +++ b/lib/libgfx/Makefile @@ -24,12 +24,12 @@ SOURCES := \ CopSetupManualSprites.c \ CopSetupMode.c \ CopSetupSprites.c \ + CopSkip.c \ CopSkipMask.c \ CopUpdateBitplanes.c \ CopWait.c \ CopWaitMask.c \ CopWaitSafe.c \ - CopWaitSkip.c \ CpuEdge.c \ CpuLine.c \ DeleteBitmap.c \ From 2ec6f66a04816d0547158cd9c80b9747cf34f43e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 5 Jan 2021 21:43:32 +0100 Subject: [PATCH 04/12] Move some code to subprocedure. --- effects/scaler/scaler.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/effects/scaler/scaler.c b/effects/scaler/scaler.c index 5bed85c7..baedd1f2 100644 --- a/effects/scaler/scaler.c +++ b/effects/scaler/scaler.c @@ -11,32 +11,33 @@ static CopListT *cp0, *cp1; +/* static */ void VerticalScaler(CopListT *cp, short ys, short height) { + short rowmod = image.bytesPerRow * image.depth; + int dy = (LINES << 16) / height; + short n = (short)(dy >> 16) * (short)image.depth; + short mod = (short)image.bytesPerRow * (short)(n - 1); + int y = 0; + short i; + + for (i = 1; i < height; i++) { + short _mod = mod; + int ny = y + dy; + if ((u_short)ny < (u_short)y) + _mod += rowmod; + CopWaitSafe(cp, Y(ys + i), X(0)); + CopMove16(cp, bpl1mod, _mod); + CopMove16(cp, bpl2mod, _mod); + y = ny; + } +} + /* static */ void MakeCopperList(CopListT *cp, short height) { short ys = (LINES - height) / 2; - int dy = (LINES << 16) / height; CopInit(cp); CopSetupDisplayWindow(cp, MODE_LORES, X(0), Y(ys), image.width, height); CopSetupBitplanes(cp, NULL, &image, image.depth); - - { - short n = (short)(dy >> 16) * (short)image.depth; - short mod = (short)image.bytesPerRow * (short)(n - 1); - int y = 0; - short i; - - for (i = 1; i < height; i++) { - short _mod = mod; - int ny = y + dy; - if ((u_short)ny < (u_short)y) - _mod += image.bytesPerRow * image.depth; - CopWait(cp, Y(ys + i), 0); - CopMove16(cp, bpl1mod, _mod); - CopMove16(cp, bpl2mod, _mod); - y = ny; - } - } - + VerticalScaler(cp, ys, height); CopEnd(cp); } From 3f061bc1f1be6a16f78252e734c33cedac41e441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 5 Jan 2021 23:25:04 +0100 Subject: [PATCH 05/12] Optimize sh*t out of it - now I'm content :) --- include/copper.h | 141 ++++++++++++++++++++++++++++++--------- lib/libgfx/CopEnd.c | 9 --- lib/libgfx/CopInit.c | 6 -- lib/libgfx/CopMoveLong.c | 17 ----- lib/libgfx/CopMoveWord.c | 11 --- lib/libgfx/CopSkip.c | 12 ---- lib/libgfx/CopSkipMask.c | 16 ----- lib/libgfx/CopWait.c | 12 ---- lib/libgfx/CopWaitMask.c | 16 ----- lib/libgfx/CopWaitSafe.c | 10 --- lib/libgfx/Makefile | 9 --- 11 files changed, 110 insertions(+), 149 deletions(-) delete mode 100644 lib/libgfx/CopEnd.c delete mode 100644 lib/libgfx/CopInit.c delete mode 100644 lib/libgfx/CopMoveLong.c delete mode 100644 lib/libgfx/CopMoveWord.c delete mode 100644 lib/libgfx/CopSkip.c delete mode 100644 lib/libgfx/CopSkipMask.c delete mode 100644 lib/libgfx/CopWait.c delete mode 100644 lib/libgfx/CopWaitMask.c delete mode 100644 lib/libgfx/CopWaitSafe.c diff --git a/include/copper.h b/include/copper.h index 12f7ffd2..be2dc9f5 100644 --- a/include/copper.h +++ b/include/copper.h @@ -43,7 +43,17 @@ typedef struct { CopListT *NewCopList(u_short length); void DeleteCopList(CopListT *list); -void CopInit(CopListT *list); + +static inline void CopInit(CopListT *list) { + list->curr = list->entry; + list->overflow = 0; +} + +static inline void CopEnd(CopListT *list) { + CopInsT *ins = list->curr; + *((u_int *)ins)++ = 0xfffffffe; + list->curr = ins; +} /* @brief Enable copper and activate copper list. * @warning This function busy-waits for vertical blank. */ @@ -55,50 +65,119 @@ static inline void CopListRun(CopListT *list) { } /* Low-level functions */ -CopInsT *CopMoveWord(CopListT *list, u_short reg, short data); -CopInsT *CopMoveLong(CopListT *list, u_short reg, void *data); - #define CSREG(reg) offsetof(struct Custom, reg) -#define CopMove16(cp, reg, data) CopMoveWord(cp, CSREG(reg), data) -#define CopMove32(cp, reg, data) CopMoveLong(cp, CSREG(reg), data) +#define CopMove16(cp, reg, data) CopMoveWord((cp), CSREG(reg), (data)) +#define CopMove32(cp, reg, data) CopMoveLong((cp), CSREG(reg), (int)(data)) + +static inline CopInsT *CopMoveWord(CopListT *list, short reg, short data) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + *((u_short *)ins)++ = reg; + *((u_short *)ins)++ = data; + list->curr = ins; + return pos; +} + +static inline void CopInsSet16(CopInsT *ins, short data) { + ins->move.data = data; +} + +static inline CopInsT *CopMoveLong(CopListT *list, short reg, int data) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + *((u_short *)ins)++ = reg + 2; + *((u_short *)ins)++ = data; + *((u_short *)ins)++ = reg; + *((u_short *)ins)++ = swap16(data); + list->curr = ins; + return pos; +} + +static inline void CopInsSet32(CopInsT *ins, void *data) { + asm volatile("movew %0,%2\n" + "swap %0\n" + "movew %0,%1\n" + : "+d" (data) + : "m" (ins[1].move.data), "m" (ins[0].move.data)); +} /* Official way to represent no-op copper instruction. */ #define CopNoOp(cp) CopMoveWord(cp, 0x1FE, 0) -CopInsT *CopWait(CopListT *list, short vp, short hp); -CopInsT *CopWaitMask(CopListT *list, u_short vp, u_short hp, - u_short vpmask asm("d2"), u_short hpmask asm("d3")); +/* Wait for raster beam position to be greater or equal to (vp, hp). */ +static inline CopInsT *CopWait(CopListT *list, short vp, short hp) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_short *)ins)++ = 0xfffe; + list->curr = ins; + return pos; +} /* Handles Copper Vertical Position counter overflow, by inserting CopWaitEOL * at first WAIT instruction with VP >= 256. */ -CopInsT *CopWaitSafe(CopListT *list, short vp, short hp); +static inline CopInsT *CopWaitSafe(CopListT *list, short vp, short hp) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + if (vp > 255 && !list->overflow) { + list->overflow = -1; + /* Wait for last waitable position to control when overflow occurs. */ + *((u_int *)ins)++ = 0xffdffffe; + } + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_short *)ins)++ = 0xfffe; + list->curr = ins; + return pos; +} + +/* Similar to CopWait, but masks bits in beam position counters. */ +static inline CopInsT *CopWaitMask(CopListT *list, short vp, short hp, + short vpmask, short hpmask) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_char *)ins)++ = 0x80 | vpmask; + *((u_char *)ins)++ = hpmask & 0xfe; + list->curr = ins; + return pos; +} /* The most significant bit of vertical position cannot be masked out (overlaps * with blitter-finished-disable bit), so we have to pass upper bit as well. */ -#define CopWaitH(cp, vp, hp) CopWaitMask(cp, vp & 128, hp, 0, 255) -#define CopWaitV(cp, vp) CopWaitMask(cp, vp, 0, 255, 0) - -CopInsT *CopSkip(CopListT *list, u_short vp, u_short hp); -CopInsT *CopSkipMask(CopListT *list, u_short vp, u_short hp, - u_short vpmask asm("d2"), u_short hpmask asm("d3")); - -#define CopSkipH(cp, vp, hp) CopSkipMask(cp, vp & 128, hp, 0, 255) -#define CopSkipV(cp, vp) CopSkipMask(cp, vp, 0, 255, 0) - -void CopEnd(CopListT *list); - -static inline void CopInsSet32(CopInsT *ins, void *data) { - asm volatile("movew %0,%2\n" - "swap %0\n" - "movew %0,%1\n" - : "+d" (data) - : "m" (ins[0].move.data), "m" (ins[1].move.data)); +#define CopWaitH(cp, vp, hp) CopWaitMask((cp), (vp) & 128, (hp), 0, 255) +#define CopWaitV(cp, vp) CopWaitMask((cp), (vp), 0, 255, 0) + +/* Skip next instruction if the video beam has already reached a specified + * (vp, hp) position. */ +static inline CopInsT *CopSkip(CopListT *list, short vp, short hp) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_short *)ins)++ = 0xffff; + list->curr = ins; + return pos; } -static inline void CopInsSet16(CopInsT *ins, u_short data) { - ins->move.data = data; +/* Similar to CopSkip, but masks bits in beam position counters. */ +static inline CopInsT *CopSkipMask(CopListT *list, short vp, short hp, + short vpmask, short hpmask) { + CopInsT *pos = list->curr; + CopInsT *ins = list->curr; + *((u_char *)ins)++ = vp; + *((u_char *)ins)++ = hp | 1; + *((u_char *)ins)++ = 0x80 | vpmask; + *((u_char *)ins)++ = hpmask | 1; + list->curr = ins; + return pos; } +#define CopSkipH(cp, vp, hp) CopSkipMask((cp), (vp) & 128, (hp), 0, 255) +#define CopSkipV(cp, vp) CopSkipMask((cp), (vp), 0, 255, 0) + /* High-level functions */ CopInsT *CopLoadPal(CopListT *list, const PaletteT *palette, short start); CopInsT *CopLoadColor(CopListT *list, short start, short end, short color); @@ -117,7 +196,7 @@ void CopUpdateBitplanes(CopInsT **bplptr, const BitmapT *bitmap, short n); void CopSetupDualPlayfield(CopListT *list, CopInsT **bplptr, const BitmapT *pf1, const BitmapT *pf2); -static inline CopInsT *CopSetColor(CopListT *list, short i, u_short value) { +static inline CopInsT *CopSetColor(CopListT *list, short i, short value) { return CopMove16(list, color[i], value); } diff --git a/lib/libgfx/CopEnd.c b/lib/libgfx/CopEnd.c deleted file mode 100644 index 85b7be42..00000000 --- a/lib/libgfx/CopEnd.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -void CopEnd(CopListT *list) { - u_int *ins = (u_int *)list->curr; - - *ins++ = 0xfffffffe; - - list->curr = (CopInsT *)ins; -} diff --git a/lib/libgfx/CopInit.c b/lib/libgfx/CopInit.c deleted file mode 100644 index 9df16255..00000000 --- a/lib/libgfx/CopInit.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -void CopInit(CopListT *list) { - list->curr = list->entry; - list->overflow = 0; -} diff --git a/lib/libgfx/CopMoveLong.c b/lib/libgfx/CopMoveLong.c deleted file mode 100644 index 9c9de6e7..00000000 --- a/lib/libgfx/CopMoveLong.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -CopInsT *CopMoveLong(CopListT *list, u_short reg, void *ptr) { - CopInsT *ins = list->curr; - u_int data = (u_int)ptr; - - reg &= 0x01fe; - reg += 2; - - *((u_short *)ins)++ = reg; - *((u_short *)ins)++ = data; - *((u_short *)ins)++ = reg - 2; - *((u_short *)ins)++ = swap16(data); - - list->curr = ins; - return ins - 2; -} diff --git a/lib/libgfx/CopMoveWord.c b/lib/libgfx/CopMoveWord.c deleted file mode 100644 index a3a5108a..00000000 --- a/lib/libgfx/CopMoveWord.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -CopInsT *CopMoveWord(CopListT *list, u_short reg, short data) { - CopInsT *ins = list->curr; - - *((u_short *)ins)++ = reg & 0x01fe; - *((u_short *)ins)++ = data; - - list->curr = ins; - return ins - 1; -} diff --git a/lib/libgfx/CopSkip.c b/lib/libgfx/CopSkip.c deleted file mode 100644 index 7ee1f77c..00000000 --- a/lib/libgfx/CopSkip.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -CopInsT *CopSkip(CopListT *list, u_short vp, u_short hp) { - CopInsT *ins = list->curr; - - *((u_char *)ins)++ = vp; - *((u_char *)ins)++ = hp | 1; - *((u_short *)ins)++ = 0xffff; - - list->curr = ins; - return ins - 1; -} diff --git a/lib/libgfx/CopSkipMask.c b/lib/libgfx/CopSkipMask.c deleted file mode 100644 index 24a3e7b3..00000000 --- a/lib/libgfx/CopSkipMask.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -CopInsT *CopSkipMask(CopListT *list, u_short vp, u_short hp, - u_short vpmask asm("d2"), u_short hpmask asm("d3")) -{ - CopInsT *ptr = (CopInsT *)list->curr; - u_char *ins = (u_char *)ptr; - - *ins++ = vp; - *ins++ = hp | 1; - *ins++ = 0x80 | vpmask; - *ins++ = hpmask | 1; - - list->curr = (CopInsT *)ins; - return ptr; -} diff --git a/lib/libgfx/CopWait.c b/lib/libgfx/CopWait.c deleted file mode 100644 index a966c881..00000000 --- a/lib/libgfx/CopWait.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -CopInsT *CopWait(CopListT *list, short vp, short hp) { - CopInsT *ins = list->curr; - - *((u_char *)ins)++ = vp; - *((u_char *)ins)++ = hp | 1; - *((u_short *)ins)++ = 0xfffe; - - list->curr = ins; - return ins - 1; -} diff --git a/lib/libgfx/CopWaitMask.c b/lib/libgfx/CopWaitMask.c deleted file mode 100644 index 97af0b8d..00000000 --- a/lib/libgfx/CopWaitMask.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -CopInsT *CopWaitMask(CopListT *list, u_short vp, u_short hp, - u_short vpmask asm("d2"), u_short hpmask asm("d3")) -{ - CopInsT *ptr = list->curr; - u_char *ins = (u_char *)ptr; - - *ins++ = vp; - *ins++ = hp | 1; - *ins++ = 0x80 | vpmask; - *ins++ = hpmask & 0xfe; - - list->curr = (CopInsT *)ins; - return ptr; -} diff --git a/lib/libgfx/CopWaitSafe.c b/lib/libgfx/CopWaitSafe.c deleted file mode 100644 index 6074abbd..00000000 --- a/lib/libgfx/CopWaitSafe.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -CopInsT *CopWaitSafe(CopListT *list, short vp, short hp) { - if (vp >= 256 && !list->overflow) { - list->overflow = -1; - /* Wait for last waitable position to control when overflow occurs. */ - *((u_int *)list->curr)++ = 0xffdffffe; - } - return CopWait(list, vp, hp); -} diff --git a/lib/libgfx/Makefile b/lib/libgfx/Makefile index db5ff38e..11422e19 100644 --- a/lib/libgfx/Makefile +++ b/lib/libgfx/Makefile @@ -9,13 +9,9 @@ SOURCES := \ ClipArea.c \ ColorTab.c \ ColorTransition.c \ - CopEnd.c \ - CopInit.c \ CopListActivate.c \ CopLoadColor.c \ CopLoadPal.c \ - CopMoveLong.c \ - CopMoveWord.c \ CopSetupBitplaneArea.c \ CopSetupBitplaneFetch.c \ CopSetupBitplanes.c \ @@ -24,12 +20,7 @@ SOURCES := \ CopSetupManualSprites.c \ CopSetupMode.c \ CopSetupSprites.c \ - CopSkip.c \ - CopSkipMask.c \ CopUpdateBitplanes.c \ - CopWait.c \ - CopWaitMask.c \ - CopWaitSafe.c \ CpuEdge.c \ CpuLine.c \ DeleteBitmap.c \ From 3354e9dc61ea00691fb845f8864641a28597cad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Wed, 6 Jan 2021 12:23:14 +0100 Subject: [PATCH 06/12] Display (normal & interleaved) bitmap upside down. --- include/copper.h | 2 ++ lib/libgfx/CopSetupBitplanes.c | 6 ++-- lib/libgfx/CopSetupBitplanesUpsideDown.c | 40 ++++++++++++++++++++++++ lib/libgfx/Makefile | 1 + 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 lib/libgfx/CopSetupBitplanesUpsideDown.c diff --git a/include/copper.h b/include/copper.h index be2dc9f5..ad2cea40 100644 --- a/include/copper.h +++ b/include/copper.h @@ -189,6 +189,8 @@ void CopSetupBitplaneFetch(CopListT *list, u_short mode, u_short xs, u_short w); void CopSetupBitplanes(CopListT *list, CopInsT **bplptr, const BitmapT *bitmap, u_short depth); +void CopSetupBitplanesUpsideDown(CopListT *list, CopInsT **bplptr, + const BitmapT *bitmap, u_short depth); void CopSetupBitplaneArea(CopListT *list, u_short mode, u_short depth, const BitmapT *bitmap, short x, short y, const Area2D *area); diff --git a/lib/libgfx/CopSetupBitplanes.c b/lib/libgfx/CopSetupBitplanes.c index eafdcb6c..b6b67d60 100644 --- a/lib/libgfx/CopSetupBitplanes.c +++ b/lib/libgfx/CopSetupBitplanes.c @@ -6,13 +6,15 @@ void CopSetupBitplanes(CopListT *list, CopInsT **bplptr, { void **planes = bitmap->planes; short n = depth - 1; - short i = 0; + short reg = CSREG(bplpt); do { - CopInsT *ins = CopMove32(list, bplpt[i++], *planes++); + CopInsT *ins = CopMoveLong(list, reg, (int)(*planes++)); if (bplptr) *bplptr++ = ins; + + reg += 4; } while (--n != -1); } diff --git a/lib/libgfx/CopSetupBitplanesUpsideDown.c b/lib/libgfx/CopSetupBitplanesUpsideDown.c new file mode 100644 index 00000000..6b2633b4 --- /dev/null +++ b/lib/libgfx/CopSetupBitplanesUpsideDown.c @@ -0,0 +1,40 @@ +#include + +void CopSetupBitplanesUpsideDown(CopListT *list, CopInsT **bplptr, + const BitmapT *bitmap, u_short depth) +{ + short bytesPerLine = bitmap->bytesPerRow; + int start; + + if (bitmap->flags & BM_INTERLEAVED) + bytesPerLine *= (short)bitmap->depth; + + start = bytesPerLine * (short)(bitmap->height - 1); + + { + void **planes = bitmap->planes; + short n = depth - 1; + short reg = CSREG(bplpt); + + do { + CopInsT *ins = CopMoveLong(list, reg, (int)(*planes++) + start); + + if (bplptr) + *bplptr++ = ins; + + reg += 4; + } while (--n != -1); + } + + { + short modulo; + + if (bitmap->flags & BM_INTERLEAVED) + modulo = (short)bitmap->bytesPerRow * (short)(depth + 1); + else + modulo = 2 * bitmap->bytesPerRow; + + CopMove16(list, bpl1mod, -modulo); + CopMove16(list, bpl2mod, -modulo); + } +} diff --git a/lib/libgfx/Makefile b/lib/libgfx/Makefile index 11422e19..657698cb 100644 --- a/lib/libgfx/Makefile +++ b/lib/libgfx/Makefile @@ -15,6 +15,7 @@ SOURCES := \ CopSetupBitplaneArea.c \ CopSetupBitplaneFetch.c \ CopSetupBitplanes.c \ + CopSetupBitplanesUpsideDown.c \ CopSetupDisplayWindow.c \ CopSetupDualPlayfield.c \ CopSetupManualSprites.c \ From a99997d2cde4306deeded9ae33ba795fc4b93095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 19 Jan 2021 08:22:48 +0100 Subject: [PATCH 07/12] This procedure is not generic enough to be a part of library. --- include/copper.h | 2 -- lib/libgfx/CopSetupBitplanesUpsideDown.c | 40 ------------------------ lib/libgfx/Makefile | 1 - 3 files changed, 43 deletions(-) delete mode 100644 lib/libgfx/CopSetupBitplanesUpsideDown.c diff --git a/include/copper.h b/include/copper.h index ad2cea40..be2dc9f5 100644 --- a/include/copper.h +++ b/include/copper.h @@ -189,8 +189,6 @@ void CopSetupBitplaneFetch(CopListT *list, u_short mode, u_short xs, u_short w); void CopSetupBitplanes(CopListT *list, CopInsT **bplptr, const BitmapT *bitmap, u_short depth); -void CopSetupBitplanesUpsideDown(CopListT *list, CopInsT **bplptr, - const BitmapT *bitmap, u_short depth); void CopSetupBitplaneArea(CopListT *list, u_short mode, u_short depth, const BitmapT *bitmap, short x, short y, const Area2D *area); diff --git a/lib/libgfx/CopSetupBitplanesUpsideDown.c b/lib/libgfx/CopSetupBitplanesUpsideDown.c deleted file mode 100644 index 6b2633b4..00000000 --- a/lib/libgfx/CopSetupBitplanesUpsideDown.c +++ /dev/null @@ -1,40 +0,0 @@ -#include - -void CopSetupBitplanesUpsideDown(CopListT *list, CopInsT **bplptr, - const BitmapT *bitmap, u_short depth) -{ - short bytesPerLine = bitmap->bytesPerRow; - int start; - - if (bitmap->flags & BM_INTERLEAVED) - bytesPerLine *= (short)bitmap->depth; - - start = bytesPerLine * (short)(bitmap->height - 1); - - { - void **planes = bitmap->planes; - short n = depth - 1; - short reg = CSREG(bplpt); - - do { - CopInsT *ins = CopMoveLong(list, reg, (int)(*planes++) + start); - - if (bplptr) - *bplptr++ = ins; - - reg += 4; - } while (--n != -1); - } - - { - short modulo; - - if (bitmap->flags & BM_INTERLEAVED) - modulo = (short)bitmap->bytesPerRow * (short)(depth + 1); - else - modulo = 2 * bitmap->bytesPerRow; - - CopMove16(list, bpl1mod, -modulo); - CopMove16(list, bpl2mod, -modulo); - } -} diff --git a/lib/libgfx/Makefile b/lib/libgfx/Makefile index 657698cb..11422e19 100644 --- a/lib/libgfx/Makefile +++ b/lib/libgfx/Makefile @@ -15,7 +15,6 @@ SOURCES := \ CopSetupBitplaneArea.c \ CopSetupBitplaneFetch.c \ CopSetupBitplanes.c \ - CopSetupBitplanesUpsideDown.c \ CopSetupDisplayWindow.c \ CopSetupDualPlayfield.c \ CopSetupManualSprites.c \ From 6cbbd5bf2c6d8f484b5c2fb70adadab45bbf4a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 19 Jan 2021 09:18:08 +0100 Subject: [PATCH 08/12] Proper double buffering. --- effects/scaler/scaler.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/effects/scaler/scaler.c b/effects/scaler/scaler.c index baedd1f2..2f2c5ecc 100644 --- a/effects/scaler/scaler.c +++ b/effects/scaler/scaler.c @@ -8,10 +8,13 @@ #include "data/stars-die.c" #define LINES 256 +#define DEPTH 5 -static CopListT *cp0, *cp1; +static CopListT *cp[2]; +static CopInsT *bplptr[2][DEPTH]; +static short active = 0; -/* static */ void VerticalScaler(CopListT *cp, short ys, short height) { +/* static */ void VerticalScalerForward(CopListT *cp, short ys, short height) { short rowmod = image.bytesPerRow * image.depth; int dy = (LINES << 16) / height; short n = (short)(dy >> 16) * (short)image.depth; @@ -32,12 +35,13 @@ static CopListT *cp0, *cp1; } /* static */ void MakeCopperList(CopListT *cp, short height) { +/* static */ void MakeCopperList(CopListT *cp, CopInsT **bplptr, short height) { short ys = (LINES - height) / 2; CopInit(cp); CopSetupDisplayWindow(cp, MODE_LORES, X(0), Y(ys), image.width, height); - CopSetupBitplanes(cp, NULL, &image, image.depth); - VerticalScaler(cp, ys, height); + CopSetupBitplanes(cp, bplptr, &image, image.depth); + VerticalScalerForward(cp, ys, height); CopEnd(cp); } @@ -46,18 +50,18 @@ static CopListT *cp0, *cp1; SetupPlayfield(MODE_LORES, image.depth, X(0), Y(0), image.width, image.height); - cp0 = NewCopList(40 + LINES * 3); - cp1 = NewCopList(40 + LINES * 3); - MakeCopperList(cp0, LINES); - CopListActivate(cp0); + cp[0] = NewCopList(40 + LINES * 3); + cp[1] = NewCopList(40 + LINES * 3); + MakeCopperList(cp[active], bplptr[active], LINES); + CopListActivate(cp[active]); EnableDMA(DMAF_RASTER); } static void Kill(void) { DisableDMA(DMAF_COPPER | DMAF_RASTER); - DeleteCopList(cp0); - DeleteCopList(cp1); + DeleteCopList(cp[0]); + DeleteCopList(cp[1]); } PROFILE(Scaler); @@ -66,16 +70,17 @@ static void Render(void) { static short val = 0, dir = 1; ProfilerStart(Scaler); - MakeCopperList(cp0, LINES - val); + MakeCopperList(cp[active], bplptr[active], LINES - val); ProfilerStop(Scaler); - CopListRun(cp0); + CopListRun(cp[active]); TaskWaitVBlank(); - { CopListT *tmp = cp0; cp0 = cp1; cp1 = tmp; } val += dir; if ((val == 0) || (val == LINES - 2)) dir = -dir; + + active ^= 1; } EFFECT(scaler, NULL, NULL, Init, Kill, Render); From 3193e3d897309f760523588563aa5312759cd32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 19 Jan 2021 09:30:26 +0100 Subject: [PATCH 09/12] Flip image upside down when height is negative. --- effects/scaler/scaler.c | 63 ++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/effects/scaler/scaler.c b/effects/scaler/scaler.c index 2f2c5ecc..8d4e5f3e 100644 --- a/effects/scaler/scaler.c +++ b/effects/scaler/scaler.c @@ -11,10 +11,9 @@ #define DEPTH 5 static CopListT *cp[2]; -static CopInsT *bplptr[2][DEPTH]; static short active = 0; -/* static */ void VerticalScalerForward(CopListT *cp, short ys, short height) { +static void VerticalScalerForward(CopListT *cp, short ys, short height) { short rowmod = image.bytesPerRow * image.depth; int dy = (LINES << 16) / height; short n = (short)(dy >> 16) * (short)image.depth; @@ -34,14 +33,56 @@ static short active = 0; } } -/* static */ void MakeCopperList(CopListT *cp, short height) { -/* static */ void MakeCopperList(CopListT *cp, CopInsT **bplptr, short height) { - short ys = (LINES - height) / 2; +static void CopSetupBitplanesReverse(CopListT *list, CopInsT **bplptr, + const BitmapT *bitmap, u_short depth) +{ + short bytesPerLine = bitmap->bytesPerRow; + int start; + + if (bitmap->flags & BM_INTERLEAVED) + bytesPerLine *= (short)bitmap->depth; + + start = bytesPerLine * (short)(bitmap->height - 1); + + { + void **planes = bitmap->planes; + short n = depth - 1; + short reg = CSREG(bplpt); + + do { + CopInsT *ins = CopMoveLong(list, reg, (int)(*planes++) + start); + + if (bplptr) + *bplptr++ = ins; + + reg += 4; + } while (--n != -1); + } + + { + short modulo; + + if (bitmap->flags & BM_INTERLEAVED) + modulo = (short)bitmap->bytesPerRow * (short)(depth + 1); + else + modulo = 2 * bitmap->bytesPerRow; + + CopMove16(list, bpl1mod, -modulo); + CopMove16(list, bpl2mod, -modulo); + } +} + +static void MakeCopperList(CopListT *cp, short height) { + short ys = (LINES - abs(height)) / 2; CopInit(cp); CopSetupDisplayWindow(cp, MODE_LORES, X(0), Y(ys), image.width, height); - CopSetupBitplanes(cp, bplptr, &image, image.depth); - VerticalScalerForward(cp, ys, height); + if (height > 0) { + CopSetupBitplanes(cp, NULL, &image, image.depth); + VerticalScalerForward(cp, ys, height); + } else if (height < 0) { + CopSetupBitplanesReverse(cp, NULL, &image, image.depth); + } CopEnd(cp); } @@ -52,7 +93,7 @@ static short active = 0; cp[0] = NewCopList(40 + LINES * 3); cp[1] = NewCopList(40 + LINES * 3); - MakeCopperList(cp[active], bplptr[active], LINES); + MakeCopperList(cp[active], LINES); CopListActivate(cp[active]); EnableDMA(DMAF_RASTER); @@ -67,17 +108,17 @@ static void Kill(void) { PROFILE(Scaler); static void Render(void) { - static short val = 0, dir = 1; + static short val = LINES, dir = -1; ProfilerStart(Scaler); - MakeCopperList(cp[active], bplptr[active], LINES - val); + MakeCopperList(cp[active], val); ProfilerStop(Scaler); CopListRun(cp[active]); TaskWaitVBlank(); val += dir; - if ((val == 0) || (val == LINES - 2)) + if (val == -LINES) dir = -dir; active ^= 1; From ffc3ffed58541a583936f29eaa7507d2545506c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 19 Jan 2021 21:45:16 +0100 Subject: [PATCH 10/12] Works correctly! :D --- effects/scaler/scaler.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/effects/scaler/scaler.c b/effects/scaler/scaler.c index 8d4e5f3e..1684c8eb 100644 --- a/effects/scaler/scaler.c +++ b/effects/scaler/scaler.c @@ -72,21 +72,42 @@ static void CopSetupBitplanesReverse(CopListT *list, CopInsT **bplptr, } } +static void VerticalScalerReverse(CopListT *cp, short ys, short height) { + short rowmod = image.bytesPerRow * image.depth; + int dy = (LINES << 16) / height; + short n = (short)(dy >> 16) * (short)image.depth; + short mod = (short)image.bytesPerRow * (short)(n + 1); + int y = 0; + short i; + + for (i = 1; i < height; i++) { + short _mod = mod; + int ny = y + dy; + if ((u_short)ny < (u_short)y) + _mod += rowmod; + CopWaitSafe(cp, Y(ys + i), X(0)); + CopMove16(cp, bpl1mod, -_mod); + CopMove16(cp, bpl2mod, -_mod); + y = ny; + } +} + static void MakeCopperList(CopListT *cp, short height) { short ys = (LINES - abs(height)) / 2; CopInit(cp); - CopSetupDisplayWindow(cp, MODE_LORES, X(0), Y(ys), image.width, height); + CopSetupDisplayWindow(cp, MODE_LORES, X(0), Y(ys), image.width, abs(height)); if (height > 0) { CopSetupBitplanes(cp, NULL, &image, image.depth); VerticalScalerForward(cp, ys, height); } else if (height < 0) { CopSetupBitplanesReverse(cp, NULL, &image, image.depth); + VerticalScalerReverse(cp, ys, -height); } CopEnd(cp); } -/* static */ void Init(void) { +static void Init(void) { LoadPalette(&image_pal, 0); SetupPlayfield(MODE_LORES, image.depth, X(0), Y(0), image.width, image.height); From 26d165703041f69944a6ecdf3ee2303d6c7aaab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Tue, 19 Jan 2021 22:05:50 +0100 Subject: [PATCH 11/12] Fix second bounce. --- effects/scaler/scaler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/effects/scaler/scaler.c b/effects/scaler/scaler.c index 1684c8eb..aee139f6 100644 --- a/effects/scaler/scaler.c +++ b/effects/scaler/scaler.c @@ -139,7 +139,7 @@ static void Render(void) { TaskWaitVBlank(); val += dir; - if (val == -LINES) + if (abs(val) == LINES) dir = -dir; active ^= 1; From 0f6b9fd7686c8d84d707ce96f36a1128ab052246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Bac=C5=82awski?= Date: Mon, 25 Jan 2021 09:12:33 +0100 Subject: [PATCH 12/12] Add tool for precalculating scaler table. --- effects/scaler/Makefile | 1 + effects/scaler/scalertab/.gitignore | 1 + effects/scaler/scalertab/Makefile | 3 ++ effects/scaler/scalertab/main.go | 75 +++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 effects/scaler/scalertab/.gitignore create mode 100644 effects/scaler/scalertab/Makefile create mode 100644 effects/scaler/scalertab/main.go diff --git a/effects/scaler/Makefile b/effects/scaler/Makefile index 3eba1ad1..86a04c5a 100644 --- a/effects/scaler/Makefile +++ b/effects/scaler/Makefile @@ -1,6 +1,7 @@ TOPDIR := $(realpath ../..) CLEAN-FILES := data/stars-die.c +SUBDIRS := scalertab PNG2C.stars-die := --bitmap image,320x256x5,+interleaved --palette image_pal,32 diff --git a/effects/scaler/scalertab/.gitignore b/effects/scaler/scalertab/.gitignore new file mode 100644 index 00000000..d675eb8e --- /dev/null +++ b/effects/scaler/scalertab/.gitignore @@ -0,0 +1 @@ +scalertab diff --git a/effects/scaler/scalertab/Makefile b/effects/scaler/scalertab/Makefile new file mode 100644 index 00000000..339e6e1c --- /dev/null +++ b/effects/scaler/scalertab/Makefile @@ -0,0 +1,3 @@ +TOPDIR := $(realpath ../../..) + +include $(TOPDIR)/build/go.mk diff --git a/effects/scaler/scalertab/main.go b/effects/scaler/scalertab/main.go new file mode 100644 index 00000000..969ef43a --- /dev/null +++ b/effects/scaler/scalertab/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + "math" + "sort" +) + +type Row struct { + err float64 // average error + columns []int // current set of columns + removed int // which column was removed from working image + original int // the column from original picture that was removed +} + +func estimate(S []int, n int, N int) []Row { + if n == 1 { + R := make([]Row, 1) + R[0] = Row{0.0, []int{S[0]}, 1, S[1]} + return R + } + + di := float64(N-1) / float64(n-1) + I := make([]float64, n) + for i := 0; i < n; i++ { + I[i] = float64(i) * di + } + + rows := make([]Row, n+1) + + for i := 0; i <= n; i++ { + C := make([]int, n) + sum := 0.0 + for j := 0; j < n; j++ { + if j >= i { + C[j] = S[j+1] + } else { + C[j] = S[j] + } + delta := I[j] - float64(C[j]) + sum += delta * delta + } + rows[i] = Row{math.Sqrt(sum) / float64(n), C, i, S[i]} + } + + sort.Slice(rows, func(i, j int) bool { + return rows[i].err < rows[j].err + }) + + R := estimate(rows[0].columns, n-1, N) + for _, row := range rows[1:1] { + C := estimate(row.columns, n-1, N) + if R[len(R)-1].err > C[len(C)-1].err { + R = C + } + } + + return append(R, rows[0]) +} + +func main() { + N := 40 + S := make([]int, N) + for i := 0; i < N; i++ { + S[i] = i + } + R := estimate(S, N-1, N) + R = append(R, Row{0.0, S, -1, -1}) + err := 0.0 + for i, row := range R { + fmt.Printf("%3d: [%d] = %d\n", i+1, row.removed, row.original) + err += row.err + } + fmt.Printf("\naverage error: %.3f\n", err/float64(N-1)) +}