Update of /project/movitz/cvsroot/movitz/losp/x86-pc
In directory clnet:/tmp/cvs-serv10270
Modified Files:
vga.lisp
Log Message:
Patch from M. Bealby: "Double buffering, unchained mode support,
optimised clear screen +routine, general tidy up for further
expansion."
--- /project/movitz/cvsroot/movitz/losp/x86-pc/vga.lisp 2007/03/17 15:39:26 1.10
+++ /project/movitz/cvsroot/movitz/losp/x86-pc/vga.lisp 2007/03/21 21:49:11 1.11
@@ -10,7 +10,7 @@
;;;; Author: Frode Vatvedt Fjeld <frodef(a)acm.org>
;;;; Created at: Tue Sep 25 14:08:20 2001
;;;;
-;;;; $Id: vga.lisp,v 1.10 2007/03/17 15:39:26 ffjeld Exp $
+;;;; $Id: vga.lisp,v 1.11 2007/03/21 21:49:11 ffjeld Exp $
;;;;
;;;;------------------------------------------------------------------
@@ -207,14 +207,14 @@
#x38 #x39 #x3A #x3B #x3C #x3D #x3E #x3F
#x0C #x00 #x0F #x08 #x00)))
-(defconstant +vga-state-320x200x256+
+(defconstant +vga-state-320x200x256-modex+
'((:misc . #x63)
(:sequencer
- #x03 #x01 #x0F #x00 #x0E)
+ #x03 #x01 #x0F #x00 #x06)
(:crtc
#x5F #x4F #x50 #x82 #x54 #x80 #xBF #x1F
#x00 #x41 #x00 #x00 #x00 #x00 #x00 #x00
- #x9C #x0E #x8F #x28 #x40 #x98 #xB9 #xA3
+ #x9C #x0E #x8F #x28 #x00 #x96 #xB9 #xE3
#xFF)
(:graphics
#x00 #x00 #x00 #x00 #x00 #x40 #x05 #x0F
@@ -225,24 +225,18 @@
#x41 #x00 #x0F #x00 #x00)))
-;; 640x480 in testing, functions not available yet.
-(defconstant +vga-state-640x480x16+
- '((:misc . #xE3)
- (:sequencer
- #x03 #x01 #x08 #x00 #x06)
- (:crtc
- #x5F #x4F #x50 #x82 #x54 #x80 #x0B #x3E
- #x00 #x40 #x00 #x00 #x00 #x00 #x00 #x00
- #xEA #x0C #xDF #x28 #x00 #xE7 #x04 #xE3
- #xFF)
- (:graphics
- #x00 #x00 #x00 #x00 #x03 #x00 #x05 #x0F
- #xFF)
- (:attribute
- #x00 #x01 #x02 #x03 #x04 #x05 #x14 #x07
- #x38 #x39 #x3A #x3B #x3C #x3D #x3E #x3F
- #x01 #x00 #x0F #x00 #x00)))
+;; intended future wrapper for graphics modes
+(defconstant +graphical-mode-modex+
+ '(+vga-state-320x200x256-modex+ ; vga state
+ 320 ; width
+ 200 ; height
+ 3)) ; page count
+
+(defvar *vga-current-page* 0)
+(defvar *vga-page-count* 0)
+(defvar *vga-width* 0)
+(defvar *vga-height* 0)
(defconstant +vga-misc-read+ #x0c)
(defconstant +vga-misc-write+ #x02)
@@ -348,6 +342,15 @@
(setf (io-port VGA-SEQ-DATA :unsigned-byte8) pmask))
(values))
+(defun set-plane-by-bitmask (p)
+ (check-type p (integer 0 15))
+ ;; set read plane
+ (setf (io-port VGA-GC-INDEX :unsigned-byte8) 4)
+ (setf (io-port VGA-GC-DATA :unsigned-byte8) p)
+ ;; set write plane
+ (setf (io-port VGA-SEQ-INDEX :unsigned-byte8) 2)
+ (setf (io-port VGA-SEQ-DATA :unsigned-byte8) p))
+
(defun vmemwr (dst-off src start end)
(loop for i from start below end as dst upfrom dst-off
do (setf (memref-int (vga-memory-map) :index dst :type :unsigned-byte8)
@@ -1083,18 +1086,23 @@
(progn ,@body)
(restore-textmode ,vga-state-var)))))
-;; graphics functions below:
+;; graphics functions below
;;
+
+
+;; TODO: This can be optimised through two methods
+;; 1. Either write all of plane 1, then plane 2 etc (plane switches are slow)
+;; 2. Use multiple plane writes at once (see g-clear for idea)
+;; - Probably better because of large areas of the same colour
(defun rle-blit-splash (splash)
(loop with index = 0
for i from 0 below (length splash) by 2
for value = (aref splash i)
for count = (1+ (aref splash (1+ i)))
do (loop repeat count
- do (setf (memref-int (vga-memory-map)
- :index index
- :type :unsigned-byte8)
+ do (setf (pixel (mod index *vga-width*) ; ugly hackitude :(
+ (truncate index *vga-width*))
value)
(incf index)))
nil)
@@ -1102,35 +1110,82 @@
;; show the splash screen
(defun g-show-splash ()
(with-textmode-restored ()
- (setf (vga-state) +vga-state-320x200x256+)
+ (g-start)
(rle-blit-splash *vga-g-splash*)
+ (page-flip)
(read-char)
(g-clear))
(values))
;; set a pixel to a colour of our choice
-(defun g-set-pixel (x y col)
+;; always writing to the next page
+(defun (setf pixel) (col x y)
+ (set-plane (logand x 3))
(setf (memref-int (vga-memory-map)
- :index (+ (* 320 y) x)
+ :index (+ (* (truncate *vga-width* 4) y) ; pixel
+ (truncate x 4)
+ (* (truncate *vga-width* 2) ; page
+ *vga-height*
+ *vga-current-page*))
:type :unsigned-byte8)
col))
-;; clear the graphics screen (simple method but slow)
+;; clear the screen
(defun g-clear ()
- (dotimes (y 240)
- (dotimes (x 320)
- (g-set-pixel x y 0))))
+ ;; set read plane to all (bitmask 1111)
+ (set-plane-by-bitmask 15)
+ ;; writing to all 4 planes here thus 1/4 of the bytes
+ ;; and by writing 16 bits a time we get double plus good optimisation :)
+ ;; However, we wish to cover four planes, thus four times the memory
+ (loop for x from 0 below (* *vga-width* *vga-height*)
+ do (setf (memref-int (vga-memory-map)
+ :index x
+ :type :unsigned-byte16)
+ #x0000)))
+
+
+(defun unchain-video-mode ()
+ ;; disable chain-4
+ (setf (io-port VGA-SEQ-INDEX :unsigned-byte8) #x04)
+ (setf (io-port VGA-SEQ-DATA :unsigned-byte8) #x06)
+ ;; disable long mode
+ (setf (io-port VGA-CRTC-INDEX :unsigned-byte8) #x14)
+ (setf (io-port VGA-CRTC-DATA :unsigned-byte8) #x00)
+ ;; enable byte mode
+ (setf (io-port VGA-CRTC-INDEX :unsigned-byte8) #x17)
+ (setf (io-port VGA-CRTC-DATA :unsigned-byte8) #xE3))
+
+
+(defun set-page (page)
+ (setf (io-port VGA-CRTC-INDEX :unsigned-byte8) #x0C)
+ (setf (io-port VGA-CRTC-DATA :unsigned-byte8) (ldb (byte 8 8)
+ (* page
+ (truncate *vga-width* 2)
+ *vga-height*)))
+ (setf (io-port VGA-CRTC-INDEX :unsigned-byte8) #x00)
+ (setf (io-port VGA-CRTC-DATA :unsigned-byte8) (ldb (byte 8 0)
+ (* page
+ (truncate *vga-width* 2)
+ *vga-height*))))
+
+
+;; Simple wrapper to swap pages
+(defun page-flip ()
+ (set-page *vga-current-page*)
+ (setf *vga-current-page*
+ (mod (1+ *vga-current-page*)
+ *vga-page-count*)))
-;; easy way to get into / out of graphics mode
+;; easy way to get into graphics mode
(defun g-start ()
- (setf (vga-state) +vga-state-320x200x256+)
- (g-clear))
-
-
-;; BUG (doesn't restore the text)
-;; store on entering graphics state?
-(defun g-exit ()
- (set-textmode +vga-state-80x25+))
+ (setf (vga-state) +vga-state-320x200x256-modex+)
+ (setf *vga-width* 320)
+ (setf *vga-height* 200)
+ (setf *vga-page-count* 2)
+ (setf *vga-current-page* 0) ; writing page
+ (unchain-video-mode)
+ (g-clear)
+ (page-flip))
;; draw-line from ch-image
@@ -1152,7 +1207,7 @@
(x x0)
(y y0))
(declare (type fixnum d incr-e incr-ne x y))
- (g-set-pixel y x col)
+ (setf (pixel y x) col)
(dotimes (i absdx)
(cond
((<= d 0)
@@ -1162,14 +1217,14 @@
(incf d incr-ne)
(incf x xstep)
(incf y ystep)))
- (g-set-pixel y x col)))
+ (setf (pixel y x) col)))
(let ((d (- (* 2 absdy) absdx))
(incr-n (* 2 absdx))
(incr-ne (* 2 (- absdx absdy)))
(x x0)
(y y0))
(declare (type fixnum d incr-n incr-ne x y))
- (g-set-pixel y x col)
+ (setf (pixel y x) col)
(dotimes (i absdy)
(cond
((<= d 0)
@@ -1179,9 +1234,7 @@
(incf d incr-ne)
(incf y ystep)
(incf x xstep)))
- (g-set-pixel y x col))))))))
-
-
+ (setf (pixel y x) col))))))))
;; draw-circle from ch-image
;; originally written by Cyrus Harmon
@@ -1189,14 +1242,14 @@
(defmethod draw-circle (center-y center-x radius col)
(declare (type fixnum center-y center-x radius))
(flet ((circle-points (y x col)
- (g-set-pixel (+ center-y y) (+ center-x x) col)
- (g-set-pixel (+ center-y x) (+ center-x y) col)
- (g-set-pixel (- center-y x) (+ center-x y) col)
- (g-set-pixel (- center-y y) (+ center-x x) col)
- (g-set-pixel (- center-y y) (- center-x x) col)
- (g-set-pixel (- center-y x) (- center-x y) col)
- (g-set-pixel (+ center-y x) (- center-x y) col)
- (g-set-pixel (+ center-y y) (- center-x x) col)))
+ (setf (pixel (+ center-y y) (+ center-x x)) col)
+ (setf (pixel (+ center-y x) (+ center-x y)) col)
+ (setf (pixel (- center-y x) (+ center-x y)) col)
+ (setf (pixel (- center-y y) (+ center-x x)) col)
+ (setf (pixel (- center-y y) (- center-x x)) col)
+ (setf (pixel (- center-y x) (- center-x y)) col)
+ (setf (pixel (+ center-y x) (- center-x y)) col)
+ (setf (pixel (+ center-y y) (- center-x x)) col)))
(let ((x 0)
(y radius)
(d (- 1 radius))
@@ -1218,8 +1271,6 @@
(incf x)
(circle-points y x col)))))
-
-
;; additional drawing functions (rectangle / triangle)
(defmethod draw-rectangle (x1 y1 x2 y2 col)
(draw-line x1 y1 x1 y2 col)