about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-06-15 10:33:18 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-06-15 10:33:18 -0700
commitc2c6f4c7ab40356f1138a3f4d8f06464373ad50b (patch)
tree9369a4da0497b7eb70470d4e30ec65e9a611c793
parentb9fea696871aece599c4ec25ec01ee0c2c00513b (diff)
downloadmu-c2c6f4c7ab40356f1138a3f4d8f06464373ad50b.tar.gz
flickerlessly render fake screens in environment
Font rendering now happens off the real screen, which provides the effect
of double-buffering.

Apps can now also use convert-graphemes-to-pixels for more traditional
double-buffering.
-rw-r--r--103grapheme.subx44
-rw-r--r--400.mu1
-rw-r--r--500fake-screen.mu46
-rw-r--r--shell/evaluate.mu2
-rw-r--r--shell/sandbox.mu42
5 files changed, 100 insertions, 35 deletions
diff --git a/103grapheme.subx b/103grapheme.subx
index a63e3098..c5615430 100644
--- a/103grapheme.subx
+++ b/103grapheme.subx
@@ -26,6 +26,50 @@ $draw-grapheme-on-real-screen:end:
     5d/pop-to-ebp
     c3/return
 
+draw-grapheme-on-screen-array:  # screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    # if screen-width*screen-height > len(screen-data) abort
+    {
+      # ecx = len(screen-data)
+      8b/-> *(ebp+8) 1/r32/ecx
+      8b/-> *ecx 1/r32/ecx
+      # eax = screen-width*screen-height
+      ba/copy-to-edx 0/imm32
+      8b/-> *(ebp+0x20) 0/r32/eax
+      f7 4/subop/multiply-into-eax *(ebp+0x24)
+      81 7/subop/compare %edx 0/imm32
+      0f 85/jump-if-!= $draw-grapheme-on-screen-array:overflow/disp32
+      # if (eax > ecx) abort
+      39/compare %eax 1/r32/ecx
+      0f 8f/jump-if-> $draw-grapheme-on-screen-array:abort/disp32
+    }
+    # eax = screen-data+4   (skip length)
+    8b/-> *(ebp+8) 0/r32/eax
+    05/add-to-eax 4/imm32
+    #
+    (draw-grapheme-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
+$draw-grapheme-on-screen-array:end:
+    # . restore registers
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+$draw-grapheme-on-screen-array:overflow:
+    (abort "draw-grapheme-on-screen-array: screen dimensions too large")
+
+$draw-grapheme-on-screen-array:abort:
+    (abort "draw-grapheme-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")
+
 # 'buffer' here is not a valid Mu type: a naked address without a length.
 draw-grapheme-on-screen-buffer:  # buffer: (addr byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
     # . prologue
diff --git a/400.mu b/400.mu
index c8f001d7..a0f2d85b 100644
--- a/400.mu
+++ b/400.mu
@@ -1,6 +1,7 @@
 # screen
 sig pixel-on-real-screen x: int, y: int, color: int
 sig draw-grapheme-on-real-screen g: grapheme, x: int, y: int, color: int, background-color: int
+sig draw-grapheme-on-screen-array screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
 sig cursor-position-on-real-screen -> _/eax: int, _/ecx: int
 sig set-cursor-position-on-real-screen x: int, y: int
 sig draw-cursor-on-real-screen g: grapheme
diff --git a/500fake-screen.mu b/500fake-screen.mu
index 641a8d4b..59b312e2 100644
--- a/500fake-screen.mu
+++ b/500fake-screen.mu
@@ -268,7 +268,7 @@ fn clear-screen _screen: (addr screen) {
     {
       compare x, *width
       break-if->=
-      draw-code-point screen, 0x20/space, x, y, 0/fg=black, 0/bg=black
+      draw-code-point screen, 0/nul, x, y, 0/fg=black, 0/bg=black
       x <- increment
       loop
     }
@@ -580,3 +580,47 @@ fn copy-pixels _screen: (addr screen), target-screen: (addr screen) {
     loop
   }
 }
+
+# It turns out double-buffering graphemes is useless because rendering fonts
+# takes too long. (At least under Qemu.)
+# So we'll instead convert graphemes to pixels when double-buffering.
+# 'screen' must be a fake screen.
+fn convert-graphemes-to-pixels _screen: (addr screen) {
+  var screen/esi: (addr screen) <- copy _screen
+  var width-a/ebx: (addr int) <- get screen, width
+  var height-a/edx: (addr int) <- get screen, height
+  var data-ah/eax: (addr handle array byte) <- get screen, pixels
+  var _data/eax: (addr array byte) <- lookup *data-ah
+  var data: (addr array byte)
+  copy-to data, _data
+  var y/ecx: int <- copy 0
+  {
+    compare y, *height-a
+    break-if->=
+    var x/edi: int <- copy 0
+    {
+      compare x, *width-a
+      break-if->=
+      {
+        var tmp/eax: grapheme <- screen-grapheme-at screen, x, y
+        # skip null graphemes that only get created when clearing screen
+        # there may be other pixels drawn there, and we don't want to clobber them
+        # this is a situation where fake screens aren't faithful to real screens; we don't support overlap between graphemes and raw pixels
+        compare tmp, 0
+        break-if-=
+        abort "bb"
+        var g: grapheme
+        copy-to g, tmp
+        var tmp/eax: int <- screen-color-at screen, x, y
+        var fg: int
+        copy-to fg, tmp
+        var bg/eax: int <- screen-background-color-at screen, x, y
+        draw-grapheme-on-screen-array data, g, x, y, fg, bg, *width-a, *height-a
+      }
+      x <- increment
+      loop
+    }
+    y <- increment
+    loop
+  }
+}
diff --git a/shell/evaluate.mu b/shell/evaluate.mu
index 70cd544d..e976e279 100644
--- a/shell/evaluate.mu
+++ b/shell/evaluate.mu
@@ -34,7 +34,7 @@ fn evaluate _in-ah: (addr handle cell), _out-ah: (addr handle cell), env-h: (han
     var screen-obj/eax: (addr screen) <- lookup *screen-obj-ah
     compare screen-obj, 0
     break-if-=
-    var y/ecx: int <- render-screen 0/screen, screen-obj, 0x58/xmin, 2/ymin
+    render-screen 0/screen, screen-obj, 0x58/xmin, 2/ymin
     var key/eax: byte <- read-key 0/keyboard
     compare key, 0
     break-if-=
diff --git a/shell/sandbox.mu b/shell/sandbox.mu
index 1b6cd61e..a6b3453c 100644
--- a/shell/sandbox.mu
+++ b/shell/sandbox.mu
@@ -124,7 +124,7 @@ fn render-sandbox screen: (addr screen), _self: (addr sandbox), xmin: int, ymin:
     var dummy/eax: int <- draw-stream-rightward screen, value, x2, xmax, y, 7/fg=grey, 0xc5/bg=blue-bg
   }
   y <- add 2  # padding
-  y <- maybe-render-screen screen, self, xmin, y
+  maybe-render-screen screen, self, xmin, y
 }
 
 fn render-sandbox-menu screen: (addr screen), _self: (addr sandbox) {
@@ -195,20 +195,20 @@ fn maybe-render-empty-screen screen: (addr screen), _self: (addr sandbox), xmin:
   return y
 }
 
-fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int -> _/ecx: int {
+fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int {
   var self/esi: (addr sandbox) <- copy _self
   var screen-obj-cell-ah/eax: (addr handle cell) <- get self, screen-var
   var screen-obj-cell/eax: (addr cell) <- lookup *screen-obj-cell-ah
   compare screen-obj-cell, 0
   {
     break-if-!=
-    return ymin
+    return
   }
   var screen-obj-cell-type/ecx: (addr int) <- get screen-obj-cell, type
   compare *screen-obj-cell-type, 5/screen
   {
     break-if-=
-    return ymin  # silently give up on rendering the screen
+    return  # silently give up on rendering the screen
   }
   var screen-obj-ah/eax: (addr handle screen) <- get screen-obj-cell, screen-data
   var _screen-obj/eax: (addr screen) <- lookup *screen-obj-ah
@@ -217,15 +217,14 @@ fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int,
     var screen-empty?/eax: boolean <- fake-screen-empty? screen-obj
     compare screen-empty?, 0/false
     break-if-=
-    return ymin
+    return
   }
   var x/eax: int <- draw-text-rightward screen, "screen:   ", xmin, 0x99/xmax, ymin, 0x17/fg, 0xc5/bg=blue-bg
   x <- copy xmin
   x <- add 2
   var y/ecx: int <- copy ymin
   y <- increment
-  y <- render-screen screen, screen-obj, x, y
-  return y
+  render-screen screen, screen-obj, x, y
 }
 
 fn render-empty-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int -> _/ecx: int {
@@ -255,32 +254,10 @@ fn render-empty-screen screen: (addr screen), _target-screen: (addr screen), xmi
   return screen-y
 }
 
-fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int -> _/ecx: int {
+fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int {
   var target-screen/esi: (addr screen) <- copy _target-screen
-  var screen-y/edi: int <- copy ymin
-  # text data
-  {
-    var height/edx: (addr int) <- get target-screen, height
-    var y/ecx: int <- copy 0
-    {
-      compare y, *height
-      break-if->=
-      set-cursor-position screen, xmin, screen-y
-      var width/edx: (addr int) <- get target-screen, width
-      var x/ebx: int <- copy 0
-      {
-        compare x, *width
-        break-if->=
-        print-screen-cell-of-fake-screen screen, target-screen, x, y
-        move-cursor-right screen
-        x <- increment
-        loop
-      }
-      y <- increment
-      screen-y <- increment
-      loop
-    }
-  }
+  convert-graphemes-to-pixels target-screen  # might overwrite existing pixel data with graphemes
+                                             # overlapping the two is not supported
   # pixel data
   {
     # screen top left pixels x y width height
@@ -331,7 +308,6 @@ fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int
       loop
     }
   }
-  return screen-y
 }
 
 fn has-keyboard? _self: (addr sandbox) -> _/eax: boolean {