소스 검색

Implement generalized vga pipeline

Big Picture:
https://gist.github.com/ErnWong/7db67164224aaa3be5f6fcc2a6f5dd21

Fixes #26, and fixes #179.

Implements:
 - mode 4/5, x, and everything in between
 - page flipping, panning, split screen
 - transitions and animations that depend on changing dac_map and
vga256_palette.
 - a linked list to keep track of what pixels have what color, so in
theory it doesn't need to redraw the entire buffer every time the
palettes are modified. Currently slow and incorrect.
 - improved display-disable signal timing (port 3DA)

Changes:

 - Add layering concept to ScreenAdapter. The idea is that using the
built-in drawImageData to handle the split screens, panning, and page
flipping would be more efficient than writing a loop to recopy pixels
one by one.

 - All video modes are now handled by the same generalized pipeline, so
non-standard video modes and configurations such as Mode X will work.

 - Video size and buffer size are now determined from register values.

 - The code for converting the plane write data into pixel colors (also
known as the "shifting" or the "serializing" step) is deferred until the
next fill-buffer event. This appears to make programs (esp. games) run
smoother. See vga_replot

 - Separate VGA redraw from SVGA 8 bpp redraw
Ernest Wong 6 년 전
부모
커밋
2a74c9d5af
3개의 변경된 파일893개의 추가작업 그리고 136개의 파일을 삭제
  1. 61 4
      src/browser/screen.js
  2. 6 0
      src/config.js
  3. 826 132
      src/vga.js

+ 61 - 4
src/browser/screen.js

@@ -64,6 +64,8 @@ function ScreenAdapter(screen_container, bus)
         // number of rows
         text_mode_height;
 
+    var layers = [];
+
     var screen = this;
 
     // 0x12345 -> "#012345"
@@ -167,13 +169,27 @@ function ScreenAdapter(screen_container, bus)
         this.update_cursor_scanline(data[0], data[1]);
     }, this);
 
+    bus.register("screen-update-layers", function(data)
+    {
+        this.layers = data;
+    }, this);
+
     bus.register("screen-set-size-text", function(data)
     {
         this.set_size_text(data[0], data[1]);
     }, this);
     bus.register("screen-set-size-graphical", function(data)
     {
-        this.set_size_graphical(data[0], data[1]);
+        if(DEBUG_SCREEN_LAYERS)
+        {
+            data[0] = data[3];
+            data[1] = data[4];
+        }
+        if(!data[0]) data[0] = 1;
+        if(!data[1]) data[1] = 1;
+        if(!data[3]) data[3] = data[0];
+        if(!data[4]) data[4] = data[1];
+        this.set_size_graphical(data[0], data[1], data[3], data[4]);
     }, this);
 
 
@@ -294,7 +310,7 @@ function ScreenAdapter(screen_container, bus)
         update_scale_text();
     };
 
-    this.set_size_graphical = function(width, height)
+    this.set_size_graphical = function(width, height, buffer_width, buffer_height)
     {
         graphic_screen.style.display = "block";
 
@@ -307,13 +323,20 @@ function ScreenAdapter(screen_container, bus)
         // Make sure to call this here, because pixels are transparent otherwise
         //screen.clear_screen();
 
-        graphic_image_data = graphic_context.createImageData(width, height);
+        graphic_image_data = graphic_context.createImageData(buffer_width, buffer_height);
         graphic_buffer = new Uint8Array(graphic_image_data.data.buffer);
         graphic_buffer32 = new Int32Array(graphic_image_data.data.buffer);
 
         graphical_mode_width = width;
         graphical_mode_height = height;
 
+        this.layers =
+        [{
+            screen_x: 0, screen_y: 0,
+            buffer_x: 0, buffer_y: 0,
+            buffer_width: width, buffer_height: height
+        }];
+
         this.bus.send("screen-tell-buffer", [graphic_buffer32], [graphic_buffer32.buffer]);
         update_scale_graphic();
     };
@@ -487,7 +510,7 @@ function ScreenAdapter(screen_container, bus)
 
     this.update_buffer = function(min, max)
     {
-        if(max < min)
+        /*if(max < min)
         {
             return;
         }
@@ -501,6 +524,40 @@ function ScreenAdapter(screen_container, bus)
             0, min_y,
             graphical_mode_width, max_y - min_y + 1
         );
+        */
+        this.clear_screen();
+        if(DEBUG_SCREEN_LAYERS)
+        {
+            graphic_context.putImageData(
+                graphic_image_data,
+                0, 0
+            );
+            graphic_context.strokeStyle = "#0F0";
+            graphic_context.lineWidth = 4;
+            this.layers.forEach((layer) =>
+            {
+                graphic_context.strokeRect(
+                    layer.buffer_x,
+                    layer.buffer_y,
+                    layer.buffer_width,
+                    layer.buffer_height
+                );
+            });
+            graphic_context.lineWidth = 1;
+            return;
+        }
+        this.layers.forEach((layer) =>
+        {
+            graphic_context.putImageData(
+                graphic_image_data,
+                layer.screen_x - layer.buffer_x,
+                layer.screen_y - layer.buffer_y,
+                layer.buffer_x,
+                layer.buffer_y,
+                layer.buffer_width,
+                layer.buffer_height
+            );
+        });
     };
 
     this.init();

+ 6 - 0
src/config.js

@@ -28,6 +28,12 @@ var LOG_PAGE_FAULTS = false;
 var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC &
                           ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK;
 
+/**
+ * @const
+ * Draws entire buffer and visualizes the layers that would be drawn
+ */
+var DEBUG_SCREEN_LAYERS = DEBUG && false;
+
 
 /** @const */
 var ENABLE_HPET = DEBUG && false;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 826 - 132
src/vga.js


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.