jak-project/goal_src/engine/gfx/hw/display.gc

1025 lines
37 KiB
Common Lisp
Raw Normal View History

;;-*-Lisp-*-
2020-09-04 14:44:23 -04:00
(in-package goal)
;; name: display.gc
;; name in dgo: display
;; dgos: GAME, ENGINE
2021-05-01 15:51:53 -04:00
;; todo - move to font-h
(define-extern draw-string-xy (function string dma-buffer int int int int none))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TIME
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; for some reason, the display also tracks some timing stuff.
(defun get-current-time ()
"Possibly the wall-clock time"
(-> *display* base-frame-counter)
)
(defun get-integral-current-time ()
"The integral of game frame time (this slows down as we lag)"
(-> *display* integral-frame-counter)
)
(defmethod set-time-ratios display ((obj display) (slowdown float))
"Set the time ratios for the current game speed. For example, set slowdown = 1.0 if the game
2021-05-01 15:51:53 -04:00
is running at full speed or slowdown = 2.0 if the game is running at half speed."
;; don't allow slowdowns of more than 4x. This prevents the dt's in the physics
;; calculations from getting huge.
(let ((ratio (fmin 4.0 slowdown)))
(set! (-> obj time-ratio) ratio)
(let ((v1-0 (get-video-mode)))
(cond
((= v1-0 'pal)
(set! (-> obj time-adjust-ratio) (* 1.2 ratio))
(set! (-> obj seconds-per-frame) (* 0.02 ratio))
(set! (-> obj frames-per-second) (* 50.0 (/ 1.0 ratio)))
;; 6 "ticks" per frame * 50 fps = 300 ticks per second.
(set! (-> obj time-factor) 6.0)
)
(else
(set! (-> obj time-adjust-ratio) ratio)
(set! (-> obj seconds-per-frame) (* 0.016666668 ratio))
(set! (-> obj frames-per-second) (* 60.0 (/ 1.0 ratio)))
;; 5 "ticks" per frame * 60 fps = 300 ticks per second.
(set! (-> obj time-factor) 5.0)
)
)
)
)
(-> obj time-ratio)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DISPLAY ENV and DRAW ENV
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; the "display env" controls what is on screen.
;; it is controlled by writing to GS registers mapped to EE memory and is independent of drawing.
;; the "draw env" controls settings for rendering triangles
;; unlike the display env, these GS registers are set through DMA.
;; the draw env structure is actually A+D format data that can be sent directly!
(defun set-display-env ((env display-env) (psm int) (width int) (height int) (dx int) (dy int) (fbp int))
"Set the commonly used parameters of a display env.
psm: texture format
width/height: dimensions of the framebuffer
dx/dy: location on the TV screen
fpb: the framebuffer."
;; these will eventually be consumed by a sony function. I think it just sets GS registers.
;; set these to the mode that makes the GS actually work. Basically every game uses exactly this.
(set! (-> env pmode)
(new 'static 'gs-pmode :en1 #x1 :mmod #x1 :slbg #x1 :alp #xff)
)
(set! (-> env smode2) (new 'static 'gs-smode2 :int #x1 :ffmd #x1))
;; set up the framebuffer.
(set! (-> env dspfb)
(new 'static 'gs-display-fb :psm psm :fbw (sar width 6) :fbp fbp)
)
;; set up the display area (obscure PS2 video output junk)
2021-05-01 15:51:53 -04:00
(set! (-> env display)
(new 'static 'gs-display
:dw #x9ff
:dy (+ dy 50)
:dx (+ (* dx (/ 2560 width)) 652)
:dh (+ (shl height 1) -1)
:magh (+ (/ (+ width 2559) width) -1)
)
)
;; I think bgcolor = 0 is required.
(set! (-> env bgcolor) (new 'static 'gs-bgcolor))
env
)
(defun set-draw-env ((env draw-env) (psm int) (width int) (height int) (ztest int) (zpsm int) (fbp int))
"Set parameters of the draw env"
;; each register needs address + data set.
;; frame buffer:
(set! (-> env frame1addr) (gs-reg64 frame-1))
(set! (-> env frame1)
(new 'static 'gs-frame :fbw (sar width 6) :psm (logand psm 15) :fbp fbp)
)
;; dithering is enabled/disabled based on the texture format.
;; it's not allowed in psmct32 and psmct24 so I assume it's always off.
(set! (-> env dtheaddr) (gs-reg64 dthe))
(cond
((zero? (logand psm 2))
(set! (-> env dthe) (new 'static 'gs-dthe))
)
(else
(set! (-> env dthe) (new 'static 'gs-dthe :dthe #x1))
)
)
;; z buffer:
(set! (-> env zbuf1addr) (gs-reg64 zbuf-1))
(set! (-> env zbuf1)
(new 'static 'gs-zbuf
:zbp #x1c0
:psm (logand zpsm 15)
:zmsk (if (zero? ztest) 1 0)
)
)
;; pixel test. you only get to pick the ztst field.
(set! (-> env test1addr) (gs-reg64 test-1))
(cond
((zero? ztest)
(set! (-> env test1) (new 'static 'gs-test))
)
(else
(set! (-> env test1) (new 'static 'gs-test :zte #x1 :ztst ztest))
)
)
;; offset to window coordinate system (WCS)
(set! (-> env xyoffset1addr) (gs-reg64 xyoffset-1))
(set! (-> env xyoffset1)
(new 'static 'gs-xy-offset
:ofx #x7000 ;; = 1792 px = 2048 - 256, this will make 2048 the center of the screen.
2021-05-01 15:51:53 -04:00
:ofy (shl (-> *video-parms* screen-miny) 4) ;; 12.4 fixed point.
)
)
;; scissor to the given width/height (in WCS pixels)
2021-05-01 15:51:53 -04:00
(set! (-> env scissor1addr) (gs-reg64 scissor-1))
;; the lower bound is set to 0: the origin of the WCS which is the xyoffset
(set! (-> env scissor1)
(new 'static 'gs-scissor :scax1 (+ width -1) :scay1 (+ height -1))
)
;; use the prim register for primitive settings, not prmode.
(set! (-> env prmodecontaddr) (gs-reg64 prmodecont))
(set! (-> env prmodecont) (new 'static 'gs-prmode-cont :ac #x1))
;; clamp colors (don't wrap)
(set! (-> env colclampaddr) (gs-reg64 colclamp))
(set! (-> env colclamp) (new 'static 'gs-color-clamp :clamp #x1))
env
)
(defun set-draw-env-offset ((env draw-env) (x int) (y int) (arg3 int))
"Set the drawing offset (origin of the WCS).
The input x and y should be in pixels to the _center_ of the scissoring area
2021-05-01 15:51:53 -04:00
The width/height of the window are taken from the scissoring settings.
It is assumed that scax0 and scay0 are set to 0.
To center things in the usual way, call with 2048, 2048, even/odd
"
2021-05-01 15:51:53 -04:00
(set! (-> env xyoffset1)
(new 'static 'gs-xy-offset
:ofx (shl (- x
(shr (+ (-> env scissor1 scax1) 1) 1) ;; half the width.
)
4) ;; 12.4
:ofy (+ (shl (- y
(shr (+ (-> env scissor1 scay1) 1) 1)) ;; half the height.
4) ;; convert to 12.4
(if (zero? arg3) 0 8) ;; and add a half-pixel offset.
)
)
)
env
)
(defun put-display-alpha-env ((arg0 display-env))
"Set display1 and dspfb1 directly, right now.
This is unused."
(let ((v1-0 (the-as gs-bank #x12000000)))
(set! (-> v1-0 dspfb1) (-> arg0 dspfb))
(set! (-> v1-0 display1) (-> arg0 display))
)
(none)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DISPLAY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; the display structure manages all of the display and draw envs, as well as frame timing related stuff.
(defun set-display ((disp display) (psm int) (w int) (h int) (ztest int) (zpsm int))
"Set up the entire display structure, both draw and display envs"
;; set up gif-tag for the gif-packet to tset the draw env
(let ((v1-0 (-> disp gif-tag0)))
;; 8x registers, data in a+d format.
(set! (-> v1-0 tag) (new 'static 'gif-tag64 :nloop #x8 :eop #x1 :nreg #x1))
(set! (-> v1-0 regs) (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d)))
2021-05-01 15:51:53 -04:00
)
;; copy to the other envs.
(set! (-> disp gif-tag1 qword) (-> disp gif-tag0 qword))
(set! (-> disp gif-tag2 qword) (-> disp gif-tag0 qword))
;; set the display envs.
(set-display-env (-> disp display-env0) psm w h (-> *video-parms* display-dx) (-> *video-parms* display-dy) 320)
(set-display-env (-> disp display-env1) psm w h (-> *video-parms* display-dx) (-> *video-parms* display-dy) 384)
;; set the draw envs (note the framebuffers are swapped - draw 0 will draw to the fb for disp 1)
(set-draw-env (-> disp draw0) psm w h ztest zpsm 384)
(set-draw-env (-> disp draw1) psm w h ztest zpsm 320)
;; initialize a bunch of counters
(set! (-> disp base-frame-counter) (the-as uint #x493e0))
(set! (-> disp game-frame-counter) (the-as uint #x493e0))
(set! (-> disp real-frame-counter) (the-as uint #x493e0))
(set! (-> disp part-frame-counter) (the-as uint #x493e0))
(set! (-> disp integral-frame-counter) (the-as uint #x493e0))
(set! (-> disp real-integral-frame-counter) (the-as uint #x493e0))
;; and the "old" version, which I think was their value on the last... frame?
(set! (-> disp old-base-frame-counter) (+ (-> disp base-frame-counter) -1))
(set! (-> disp old-game-frame-counter) (+ (-> disp game-frame-counter) -1))
(set! (-> disp old-real-frame-counter) (+ (-> disp real-frame-counter) -1))
(set! (-> disp old-integral-frame-counter) (+ (-> disp integral-frame-counter) -1))
(set! (-> disp old-real-integral-frame-counter) (+ (-> disp real-integral-frame-counter) -1))
(set! (-> disp old-part-frame-counter) (+ (-> disp part-frame-counter) -1))
(set! (-> disp old-actual-frame-counter) (+ (-> disp actual-frame-counter) -1))
(set! (-> disp old-real-actual-frame-counter) (+ (-> disp real-actual-frame-counter) -1))
disp
)
(defun set-display2 ((disp display) (psm int) (w int) (h int) (ztest int) (zpsm int))
"Set the display and draw envs only. This assumes you have already done a set-display."
(set-display-env (-> disp display-env0) psm w h (-> *video-parms* display-dx) (-> *video-parms* display-dy) 320)
(set-display-env (-> disp display-env1) psm w h (-> *video-parms* display-dx) (-> *video-parms* display-dy) 384)
(set-draw-env (-> disp draw0) psm w h ztest zpsm 384)
(set-draw-env (-> disp draw1) psm w h ztest zpsm 320)
disp
)
(defun allocate-dma-buffers ((arg0 display))
"Allocate the main DMA buffers!"
(when (zero? (-> arg0 frames 0 frame calc-buf))
;; not sure what these "calc-buf"s are. Maybe VU0 DMA or other small stuff that is used in the same frame?
(set! (-> arg0 frames 0 frame calc-buf) (new 'global 'dma-buffer 10000))
(set! (-> arg0 frames 1 frame calc-buf) (new 'global 'dma-buffer 10000))
;; the main DMA buffers for each frame's drawing.
(set! (-> arg0 frames 0 frame global-buf) (new 'global 'dma-buffer #x1ac000))
(set! (-> arg0 frames 1 frame global-buf) (new 'global 'dma-buffer #x1ac000))
;; there are separate debug buffers in debug mode that live in the debug heap.
;; these are used to draw all of the debug stuff.
(when *debug-segment*
(set! (-> arg0 frames 0 frame debug-buf) (new 'debug 'dma-buffer #x800000))
(set! (-> arg0 frames 1 frame debug-buf) (new 'debug 'dma-buffer #x800000))
)
)
arg0
)
(define *font-context* (new 'global 'font-context *font-default-matrix* 0 24 0.0 0 (the uint 3)))
(define *pause-context* (new 'global 'font-context *font-default-matrix* 256 170 0.0 3 (the uint 3)))
2021-05-01 15:51:53 -04:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PROFILE BAR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod add-frame profile-bar ((obj profile-bar) (name symbol) (color rgba))
"Add a block to the profile bar. Looks at the timer to determine the current time."
(if *debug-segment*
(let ((new-frame (-> obj data (-> obj profile-frame-count))))
(set! (-> obj profile-frame-count) (+ (-> obj profile-frame-count) 1))
(set! (-> new-frame name) name)
(set! (-> new-frame time-stamp) (timer-count (the-as timer-bank #x10000800)))
(set! (-> new-frame color) color)
new-frame
)
)
)
(defmethod reset profile-bar ((obj profile-bar))
"Clear all blocks from the profile bar. Adds the start block"
(set! (-> obj profile-frame-count) 0)
(add-frame obj 'start (new 'static 'rgba :r #x40 :b #x40 :a #x80))
obj
)
(defmethod add-end-frame profile-bar ((obj profile-bar) (name symbol) (color rgba))
"Finish the frame."
(let ((new-frame (-> obj data (-> obj profile-frame-count))))
(set! (-> obj profile-frame-count) (+ (-> obj profile-frame-count) 1))
(set! (-> new-frame name) name)
(set! (-> new-frame time-stamp) (the-as uint *ticks-per-frame*))
(set! (-> new-frame color) color)
new-frame
)
)
;; location and size
(define *profile-x* 1808)
(define *profile-y* (+ (-> *video-parms* screen-miny) 8))
(define *profile-w* 416)
(define *profile-h* 8)
;; ticks or percent?
(define *profile-ticks* #f)
(defmethod draw profile-bar ((obj profile-bar) (buf dma-buffer) (bar-pos int))
"Draw the bar! The bar pos shouldn't be changed."
;; recompute y stuff based on the current relative-y-scale.
(let ((height (the int (* 8.0 (-> *video-parms* relative-y-scale)))))
(set! *profile-y* (+ (-> *video-parms* screen-miny) height)) ;; px
(set! *profile-h* height) ;; px
2021-05-01 15:51:53 -04:00
)
(let ((block-idx 1) ;; block to draw (0 is 'start)
(block-count (-> obj profile-frame-count)) ;; total number of blocks
(left (shl *profile-x* 4)) ;; x (12.4) of the current block. initialized to start of bar.
(end-time 0) ;; end of last block
;; if there's a single really slow frame, we want its time to appear for
;; a little while so you can actually notice. This caches the worst time
;; over the last ~1 second. It's a static array so it won't get reset
;; between runs.
(worst-time-cache (new 'static 'array uint32 2 #x0 #x0))
)
;; the position for this particular bar in y.
(let ((screen-y (the int (* (the float bar-pos) (-> *video-parms* relative-y-scale)))))
;; set up dma/vif tags:
(let* ((t1-0 buf)
(direct-tag (the-as dma-packet (-> t1-0 base))))
;; dma
(set! (-> direct-tag dma)
(new 'static 'dma-tag
:id (dma-tag-id cnt)
:qwc (+ (shl block-count 1) -1) ;; 2 quadwords per non-starting block + 1 (giftag)
)
)
;; vif - direct: send straight to gif.
(set! (-> direct-tag vif0) (new 'static 'vif-tag))
(set! (-> direct-tag vif1)
(new 'static 'vif-tag
:cmd (vif-cmd direct)
:msk #x1
:imm (+ (shl block-count 1) -1) ;; same qwc as above.
)
)
(set! (-> t1-0 base) (&+ (the-as pointer direct-tag) 16))
)
;; set up gif tag
(let* ((t1-1 buf)
(start-gif-tag (the-as gs-gif-tag (-> t1-1 base)))
)
;; NREG = 4, one for each block, except for the first.
(set! (-> start-gif-tag tag)
(new 'static 'gif-tag64
:eop #x1
:flg #x1
:nreg #x4
:nloop (+ block-count -1)
)
)
;; each block gets a prim, color, and two vertices.
(set! (-> start-gif-tag regs)
(new 'static 'gif-tag-regs
:regs0 (gif-reg-id prim)
:regs1 (gif-reg-id rgbaq)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id xyzf2)
2021-05-01 15:51:53 -04:00
)
)
(set! (-> t1-1 base) (&+ (the-as pointer start-gif-tag) 16))
)
;; loop through blocks to draw.
(while (< block-idx block-count)
(let ((block (-> obj data block-idx)))
;; add first three regs (prim, color, one vertex)
(let* ((t2-4 buf)
(t3-8 (-> t2-4 base))
)
;; draw sprite (alpha blend enable)
(set! (-> (the-as (pointer gs-prim) t3-8) 0)
(new 'static 'gs-prim :prim (gs-prim-type sprite) :abe #x1)
)
2021-05-01 15:51:53 -04:00
;; set color.
(set! (-> (the-as (pointer uint64) t3-8) 1)
(the-as uint (-> block color))
)
2021-05-01 15:51:53 -04:00
;; set vertex (left side)
(set! (-> (the-as (pointer gs-xyzf) t3-8) 2)
(new 'static 'gs-xyzf
:z #x3fffff
:y (shl (+ *profile-y* screen-y) 4) ;; 12.4
:x left ;; end of previous bar
)
2021-05-01 15:51:53 -04:00
)
(set! (-> t2-4 base) (&+ t3-8 24))
)
;; update end-time, when the work for the frame is done.
;; don't include end-draw.
(if (!= (-> block name) 'end-draw)
(set! end-time (the-as int (-> block time-stamp)))
)
;; compute left, the end of this bar.
(set! left
(shl (+ *profile-x* ;; bar start
(/ (* (-> block time-stamp) (the-as uint *profile-w*)) ;; fraction of ticks per frame
(the-as uint *ticks-per-frame*)
)
)
4 ;; convert to 12.4
)
)
)
;; add other vertex.
(let* ((t1-8 buf)
(t2-8 (-> t1-8 base))
)
(set! (-> (the-as (pointer gs-xyzf) t2-8) 0)
(new 'static 'gs-xyzf
:z #x3fffff
:y (shl (+ (+ *profile-y* screen-y) *profile-h*) 4) ;; add height.
:x left ;; now the end of this bar.
)
2021-05-01 15:51:53 -04:00
)
(set! (-> t1-8 base) (&+ t2-8 8))
)
;; next block!
(+! block-idx 1)
)
;; end loop over blocks.
)
;; update the worst time cache if its more than 75 frames old, or we did worse
;; than the cached value.
;; we use bar-pos/10 as the index into the cache, which is kind of sketchy.
(when (or (< 75 (- (-> *display* real-frame-counter) (-> obj cache-time)))
(>= end-time (the-as int (-> worst-time-cache (/ bar-pos 10))))
)
(set! (-> worst-time-cache (/ bar-pos 10)) (the-as uint end-time))
(set! (-> obj cache-time) (-> *display* real-frame-counter))
)
;; draw the time, either in ticks or percent.
(cond
(*profile-ticks*
(let ((s3-0 draw-string-xy))
(format (clear *temp-string*) "~5D" (-> worst-time-cache (/ bar-pos 10)))
(s3-0 *temp-string* buf 488 (+ bar-pos 8) 0 17)
)
(the float (-> worst-time-cache (/ bar-pos 10)))
)
(else
;; for some reason, they use 104% here. This means that when you see
;; 100%, it actually means ~96% of ticks-per-frame.
;; this is possibly because there's some time in between reaching here
;; and when the next one starts (in drawable.gc)
2021-05-01 15:51:53 -04:00
(let ((f30-0 (/ (* 104.0 (the float (-> worst-time-cache (/ bar-pos 10))))
(the float *ticks-per-frame*)
)
)
)
(let ((s4-1 draw-string-xy))
(format (clear *temp-string*) "~5,,2f" f30-0)
(s4-1 *temp-string* buf 488 (+ bar-pos 8)
(if (>= f30-0 100.0) 3 0) ;; turn red if over 100.
17
)
)
f30-0
)
)
)
)
)
;; get rid of these methods when not debugging.
(when (not *debug-segment*)
(set! (-> profile-bar method-table 11) nothing) ;; add
(set! (-> profile-bar method-table 12) nothing) ;; end
(set! (-> profile-bar method-table 10) nothing) ;; reset
(set! (-> profile-bar method-table 13) nothing) ;; draw
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DRAWING HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun draw-sprite2d-xy ((buf dma-buffer) (x int) (y int) (w int) (h int) (color rgba))
"Draw a sprite primitive with the given color and dimensions."
;; create context and clip dimensions.
(let* ((context (new 'stack 'draw-context x y w h color))
(draw-x (max 1792 (min 2304 (+ (-> context orgx) 1792))))
(draw-y (max (min (+ (-> context orgy) (-> *video-parms* screen-miny))
(-> *video-parms* screen-maxy)
)
(-> *video-parms* screen-miny)
)
)
(draw-w (-> context width))
(draw-h (-> context height))
;; remember the address of the first dma-tag
(end-dma (the-as dma-packet (-> buf base)))
)
;; dma and vif setup
(let* ((a2-2 buf)
(dma (the-as dma-packet (-> a2-2 base)))
)
;; don't set dma or vif qwc yet.
(set! (-> dma dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> dma vif0) (new 'static 'vif-tag))
(set! (-> dma vif1) (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1))
(set! (-> a2-2 base) (&+ (the-as pointer dma) 16))
)
;; gif setup
(let* ((a2-3 buf)
(gif (the-as gs-gif-tag (-> a2-3 base)))
)
(set! (-> gif tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :flg #x1 :nreg #x4))
(set! (-> gif regs)
(new 'static 'gif-tag-regs
:regs0 (gif-reg-id prim)
:regs1 (gif-reg-id rgbaq)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id xyzf2)
2021-05-01 15:51:53 -04:00
)
)
(set! (-> a2-3 base) (&+ (the-as pointer gif) 16))
)
;; gif data
(let* ((a2-4 buf)
(gif-buf (-> a2-4 base))
)
(set! (-> (the-as (pointer gs-prim) gif-buf) 0)
(new 'static 'gs-prim :prim (gs-prim-type sprite) :abe #x1)
)
(set! (-> (the-as (pointer gs-rgbaq) gif-buf) 1)
(the-as gs-rgbaq (-> context color 0))
)
(set! (-> (the-as (pointer gs-xyzf) gif-buf) 2)
(new 'static 'gs-xyzf :z #x3fffff :y (shl draw-y 4) :x (shl draw-x 4))
)
(set! (-> (the-as (pointer gs-xyzf) gif-buf) 3)
(new 'static 'gs-xyzf
:z #x3fffff
:y (shl (max (min (+ draw-y draw-h) (-> *video-parms* screen-maxy)) (-> *video-parms* screen-miny)) 4)
:x (shl (max 1792 (min 2304 (+ draw-x draw-w))) 4)
)
)
(set! (-> a2-4 base) (&+ gif-buf 32))
)
;; patch up the qwc. This code is super weird.
(let ((total-qwc (sar (+ (- -16 (the-as int (the-as pointer end-dma))) (the-as int (-> buf base))) 4)))
(cond
((nonzero? total-qwc)
;; this is _not_ a normal bitfield set, but could be oring with a new bitfield?
(set! (-> (the-as (pointer dma-tag) end-dma) 0)
(logior
(-> (the-as (pointer dma-tag) end-dma) 0)
(the-as uint (new 'static 'dma-tag :qwc total-qwc))
)
)
;; this is an even weirder one (shl, shr, shl nested)?
(set! (-> (the-as (pointer dma-tag) end-dma) 1)
(logior (-> (the-as (pointer dma-tag) end-dma) 1)
(the-as uint (shl (shr (shl total-qwc 48) 48) 32))
)
)
)
(else
(set! (-> buf base) (the-as pointer end-dma))
)
)
)
)
(none)
)
(defun draw-quad2d ((buf dma-buffer) (context draw-context))
"Draw a quad that fills the entire context"
(let ((draw-x (max 1792 (min 2304 (+ (-> context orgx) 1792))))
(draw-y (max (min (+ (-> context orgy) (-> *video-parms* screen-miny))
(-> *video-parms* screen-maxy)
)
(-> *video-parms* screen-miny))
)
(draw-w (-> context width))
(draw-h (-> context height))
(end-dma (-> buf base))
)
;; setup dma/vif
(let* ((t0-0 buf)
(dma (the-as dma-packet (-> t0-0 base)))
)
(set! (-> dma dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> dma vif0) (new 'static 'vif-tag))
(set! (-> dma vif1) (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1))
(set! (-> t0-0 base) (&+ (the-as pointer dma) 16))
)
;; setup gif
(let* ((t0-1 buf)
(gif (the-as gs-gif-tag (-> t0-1 base)))
)
(set! (-> gif tag)
(new 'static 'gif-tag64 :nloop #x1 :eop #x1 :flg #x1 :nreg #x9)
)
(set! (-> gif regs)
(new 'static 'gif-tag-regs
:regs1 (gif-reg-id rgbaq)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id rgbaq)
:regs4 (gif-reg-id xyzf2)
:regs5 (gif-reg-id rgbaq)
:regs6 (gif-reg-id xyzf2)
:regs7 (gif-reg-id rgbaq)
:regs8 (gif-reg-id xyzf2)
2021-05-01 15:51:53 -04:00
)
)
(set! (-> t0-1 base) (&+ (the-as pointer gif) 16))
)
;; set gif data
(let* ((t0-2 buf)
(gif-buf (-> t0-2 base))
)
(set! (-> (the-as (pointer gs-prim) gif-buf) 0)
(new 'static 'gs-prim :prim (gs-prim-type tri-strip) :iip #x1 :abe #x1)
)
(set! (-> (the-as (pointer gs-rgbaq) gif-buf) 1)
(the-as gs-rgbaq (-> context color 0))
)
(set! (-> (the-as (pointer gs-xyzf) gif-buf) 2)
(new 'static 'gs-xyzf :y (shl draw-y 4) :x (shl draw-x 4))
)
(set! (-> (the-as (pointer gs-rgbaq) gif-buf) 3)
(the-as gs-rgbaq (-> context color 1))
)
(set! (-> (the-as (pointer gs-xyzf) gif-buf) 4)
(new 'static 'gs-xyzf
:y (shl draw-y 4)
:x (shl (max 1792 (min 2304 (+ draw-x draw-w))) 4)
)
)
(set! (-> (the-as (pointer gs-rgbaq) gif-buf) 5)
(the-as gs-rgbaq (-> context color 2))
)
(set! (-> (the-as (pointer gs-xyzf) gif-buf) 6)
(new 'static 'gs-xyzf
:y (shl (max (min (+ draw-y draw-h) (-> *video-parms* screen-maxy)) (-> *video-parms* screen-miny)) 4)
:x (shl draw-x 4)
)
)
(set! (-> (the-as (pointer gs-rgbaq) gif-buf) 7)
(the-as gs-rgbaq (-> context color 3))
)
(set! (-> (the-as (pointer gs-xyzf) gif-buf) 8)
(new 'static 'gs-xyzf
:y (shl (max (min (+ draw-y draw-h) (-> *video-parms* screen-maxy)) (-> *video-parms* screen-miny)) 4)
:x (shl (max 1792 (min 2304 (+ draw-x draw-w))) 4)
)
)
(set! (-> (the-as (pointer uint64) gif-buf) 9) (the-as uint 0))
(set! (-> t0-2 base) (&+ gif-buf 80))
)
;; patch qwc.
(let ((total-qwc (sar (+ (- -16 (the-as int end-dma)) (the int (-> buf base))) 4)))
(cond
((nonzero? total-qwc)
(set!
(-> (the-as (pointer dma-tag) end-dma) 0)
(logior
(-> (the-as (pointer dma-tag) end-dma) 0)
(the-as uint (new 'static 'dma-tag :qwc total-qwc))
)
)
(set!
(-> (the-as (pointer dma-tag) end-dma) 1)
(logior
(-> (the-as (pointer dma-tag) end-dma) 1)
(the-as uint (shl (shr (shl total-qwc 48) 48) 32))
)
)
)
(else
(set! (-> buf base) end-dma)
)
)
)
)
(none)
)
(defun screen-gradient ((arg0 dma-buffer) (arg1 rgba) (arg2 rgba) (arg3 rgba) (arg4 rgba))
"Fill the screen with a sprite with the given colors."
(let ((a1-2 (new 'stack 'draw-context 0 0 512 224 (the-as rgba 0))))
(set! (-> a1-2 color 0) arg1)
(set! (-> a1-2 color 1) arg2)
(set! (-> a1-2 color 2) arg3)
(set! (-> a1-2 color 3) arg4)
(draw-quad2d arg0 a1-2)
)
(none)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INTERRUPT HANDLERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; In debug mode, there was a vif handler that called (add-band (-> *display* profile-bar))
;; in non-debug, there was a vif interrupt handler that did nothing.
;; There was also a vblank hanlder that incremented *vblank-counter*, but it is disabled.
(define *oddeven* 0)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; More GS State Helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun set-display-gs-state ((dma-buf dma-buffer) (fbp int) (scx int) (scy int) (fb-msk int) (psm int))
"Set various gs state registers"
(let ((fbw (sar (+ scx 63) 6))) ;; fbw is in 2^6 units.
;; set dma and vif.
(let* ((v1-1 dma-buf)
(dma (the-as dma-packet (-> v1-1 base)))
)
;; qwc = 8 -> 1 gif tag + 7 A+D regs.
(set! (-> dma dma) (new 'static 'dma-tag :qwc #x8 :id (dma-tag-id cnt)))
(set! (-> dma vif0) (new 'static 'vif-tag :cmd (vif-cmd flusha) :msk #x1))
(set! (-> dma vif1) (new 'static 'vif-tag :imm #x8 :cmd (vif-cmd direct) :msk #x1))
(set! (-> v1-1 base) (&+ (the-as pointer dma) 16))
)
;; setup gif.
(let* ((v1-2 dma-buf)
(gif (the-as gs-gif-tag (-> v1-2 base)))
)
(set! (-> gif tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x7))
(set! (-> gif regs)
(new 'static 'gif-tag-regs
:regs0 (gif-reg-id a+d)
:regs1 (gif-reg-id a+d)
:regs2 (gif-reg-id a+d)
:regs3 (gif-reg-id a+d)
:regs4 (gif-reg-id a+d)
:regs5 (gif-reg-id a+d)
:regs6 (gif-reg-id a+d)
:regs7 (gif-reg-id a+d)
:regs8 (gif-reg-id a+d)
:regs9 (gif-reg-id a+d)
:regs10 (gif-reg-id a+d)
:regs11 (gif-reg-id a+d)
:regs12 (gif-reg-id a+d)
:regs13 (gif-reg-id a+d)
:regs14 (gif-reg-id a+d)
:regs15 (gif-reg-id a+d)
2021-05-01 15:51:53 -04:00
)
)
(set! (-> v1-2 base) (&+ (the-as pointer gif) 16))
)
;; set gif data.
(let* ((v1-3 dma-buf)
(gif-buf (-> v1-3 base))
)
;; scissor
(set! (-> (the-as (pointer gs-scissor) gif-buf) 0)
(new 'static 'gs-scissor :scax1 (+ scx -1) :scay1 (+ scy -1))
)
(set! (-> (the-as (pointer gs-reg64) gif-buf) 1) (gs-reg64 scissor-1))
;; offset
(set! (-> (the-as (pointer gs-xy-offset) gif-buf) 2) (new 'static 'gs-xy-offset))
(set! (-> (the-as (pointer gs-reg64) gif-buf) 3) (gs-reg64 xyoffset-1))
;; frame
(set! (-> (the-as (pointer gs-frame) gif-buf) 4)
(new 'static 'gs-frame :fbp fbp :fbw fbw :psm psm :fbmsk fb-msk)
)
(set! (-> (the-as (pointer gs-reg64) gif-buf) 5) (gs-reg64 frame-1))
;; ztest
(set! (-> (the-as (pointer gs-test) gif-buf) 6)
(new 'static 'gs-test :zte #x1 :ztst #x1)
)
(set! (-> (the-as (pointer gs-reg64) gif-buf) 7) (gs-reg64 test-1))
;; texa
(set! (-> (the-as (pointer gs-texa) gif-buf) 8)
(new 'static 'gs-texa :ta0 #x80 :ta1 #x80)
)
(set! (-> (the-as (pointer gs-reg64) gif-buf) 9) (gs-reg64 texa))
;; zbuf
(set! (-> (the-as (pointer gs-zbuf) gif-buf) 10)
(new 'static 'gs-zbuf :zbp #x1c0 :psm #x1 :zmsk #x1)
)
(set! (-> (the-as (pointer gs-reg64) gif-buf) 11) (gs-reg64 zbuf-1))
;; texflush
(set! (-> (the-as (pointer uint64) gif-buf) 12) (the-as uint 0))
(set! (-> (the-as (pointer gs-reg64) gif-buf) 13) (gs-reg64 texflush))
(set! (-> v1-3 base) (&+ gif-buf 112))
)
)
dma-buf
)
(defun set-display-gs-state-offset ((dma-buf dma-buffer) (fbp int) (width int) (height int) (fb-msk int) (psm int) (off-x int) (off-y int))
"Set various gs state registers"
(let ((fbw (sar (+ width 63) 6)))
(let* ((v1-1 dma-buf)
(dma (the-as dma-packet (-> v1-1 base)))
)
(set! (-> dma dma) (new 'static 'dma-tag :qwc #x8 :id (dma-tag-id cnt)))
(set! (-> dma vif0) (new 'static 'vif-tag :cmd (vif-cmd flusha) :msk #x1))
(set! (-> dma vif1)
(new 'static 'vif-tag :imm #x8 :cmd (vif-cmd direct) :msk #x1)
)
(set! (-> v1-1 base) (&+ (the-as pointer dma) 16))
)
(let* ((v1-2 dma-buf)
(gif (the-as gs-gif-tag (-> v1-2 base)))
)
(set! (-> gif tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x7))
(set! (-> gif regs)
(new 'static 'gif-tag-regs
:regs0 (gif-reg-id a+d)
:regs1 (gif-reg-id a+d)
:regs2 (gif-reg-id a+d)
:regs3 (gif-reg-id a+d)
:regs4 (gif-reg-id a+d)
:regs5 (gif-reg-id a+d)
:regs6 (gif-reg-id a+d)
:regs7 (gif-reg-id a+d)
:regs8 (gif-reg-id a+d)
:regs9 (gif-reg-id a+d)
:regs10 (gif-reg-id a+d)
:regs11 (gif-reg-id a+d)
:regs12 (gif-reg-id a+d)
:regs13 (gif-reg-id a+d)
:regs14 (gif-reg-id a+d)
:regs15 (gif-reg-id a+d)
2021-05-01 15:51:53 -04:00
)
)
(set! (-> v1-2 base) (&+ (the-as pointer gif) 16))
)
(let* ((v1-3 dma-buf)
(gif-data (the-as (pointer uint64) (-> v1-3 base)))
)
(set! (-> (the-as (pointer gs-scissor) gif-data) 0)
(new 'static 'gs-scissor :scax1 (+ width -1) :scay1 (+ height -1))
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 1) (gs-reg64 scissor-1))
(set! (-> (the-as (pointer gs-xy-offset) gif-data) 2)
(new 'static 'gs-xy-offset :ofx (shl off-x 4) :ofy (shl off-y 4))
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 3) (gs-reg64 xyoffset-1))
(set! (-> (the-as (pointer gs-frame) gif-data) 4)
(new 'static 'gs-frame :fbp fbp :fbw fbw :psm psm :fbmsk fb-msk)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 5) (gs-reg64 frame-1))
(set! (-> (the-as (pointer gs-test) gif-data) 6)
(new 'static 'gs-test :zte #x1 :ztst #x1)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 7) (gs-reg64 test-1))
(set! (-> (the-as (pointer gs-texa) gif-data) 8)
(new 'static 'gs-texa :ta0 #x80 :ta1 #x80)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 9) (gs-reg64 texa))
(set! (-> (the-as (pointer gs-zbuf) gif-data) 10)
(new 'static 'gs-zbuf :zbp #x1c0 :psm #x1 :zmsk #x1)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 11) (gs-reg64 zbuf-1))
(set! (-> gif-data 12) (the-as uint 0))
(set! (-> (the-as (pointer gs-reg64) gif-data) 13) (gs-reg64 texflush))
(set! (-> v1-3 base) (&+ (the-as pointer gif-data) 112))
)
)
dma-buf
)
(defun reset-display-gs-state ((disp display) (dma-buf dma-buffer) (oddeven int))
"Set the gs state back to something reasonable"
(let* ((onscreen (-> disp on-screen))
(hoff (shl oddeven 3)) ;; half pixel offset.
(fbp (-> disp frames onscreen draw frame1 fbp))
)
;; set dma/vif
(let* ((a3-1 dma-buf)
(dma (the-as dma-packet (-> a3-1 base)))
)
(set! (-> dma dma) (new 'static 'dma-tag :qwc #x8 :id (dma-tag-id cnt)))
(set! (-> dma vif0) (new 'static 'vif-tag :cmd (vif-cmd flusha) :msk #x1))
(set!
(-> dma vif1)
(new 'static 'vif-tag :imm #x8 :cmd (vif-cmd direct) :msk #x1)
)
(set! (-> a3-1 base) (&+ (the-as pointer dma) 16))
)
;; setup gif
(let* ((a3-2 dma-buf)
(gif (the-as gs-gif-tag (-> a3-2 base)))
)
(set! (-> gif tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x7))
(set!
(-> gif regs)
(new 'static 'gif-tag-regs
:regs0 (gif-reg-id a+d)
:regs1 (gif-reg-id a+d)
:regs2 (gif-reg-id a+d)
:regs3 (gif-reg-id a+d)
:regs4 (gif-reg-id a+d)
:regs5 (gif-reg-id a+d)
:regs6 (gif-reg-id a+d)
:regs7 (gif-reg-id a+d)
:regs8 (gif-reg-id a+d)
:regs9 (gif-reg-id a+d)
:regs10 (gif-reg-id a+d)
:regs11 (gif-reg-id a+d)
:regs12 (gif-reg-id a+d)
:regs13 (gif-reg-id a+d)
:regs14 (gif-reg-id a+d)
:regs15 (gif-reg-id a+d)
2021-05-01 15:51:53 -04:00
)
)
(set! (-> a3-2 base) (&+ (the-as pointer gif) 16))
)
(let ((gif-data (the-as (pointer uint64) (-> dma-buf base))))
(set! (-> (the-as (pointer gs-scissor) gif-data) 0)
(new 'static 'gs-scissor
:scax1 #x1ff
:scay1 (-> *video-parms* screen-masky)
)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 1) (gs-reg64 scissor-1))
(set! (-> (the-as (pointer gs-xy-offset) gif-data) 2)
(new 'static 'gs-xy-offset
:ofx #x7000
:ofy (+ (shl (-> *video-parms* screen-miny) 4) hoff)
)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 3) (gs-reg64 xyoffset-1))
(set! (-> (the-as (pointer gs-frame) gif-data) 4)
(new 'static 'gs-frame :fbw #x8 :fbp (the-as int fbp))
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 5) (gs-reg64 frame-1))
(set! (-> (the-as (pointer gs-test) gif-data) 6)
(new 'static 'gs-test :atst #x7 :zte #x1 :ztst #x2)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 7) (gs-reg64 test-1))
(set! (-> (the-as (pointer gs-texa) gif-data) 8)
(new 'static 'gs-texa :ta1 #x80)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 9) (gs-reg64 texa))
(set! (-> (the-as (pointer gs-zbuf) gif-data) 10)
(new 'static 'gs-zbuf :zbp #x1c0 :psm #x1)
)
(set! (-> (the-as (pointer gs-reg64) gif-data) 11) (gs-reg64 zbuf-1))
(set! (-> gif-data 12) (the-as uint 0))
(set! (-> (the-as (pointer gs-reg64) gif-data) 13) (gs-reg64 texflush))
(set! (-> dma-buf base) (&+ (the-as pointer gif-data) 112))
)
)
(none)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Display Setup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; separate dma list for VU0
(define *vu0-dma-list* (new 'global 'dma-buffer 4096))
;; main display structure
(define *display* (new 'global 'display 0 512 256 2 49))
;; main dma
(allocate-dma-buffers *display*)