From 4153a625b9ba298398b99e977ef74bd381adc74d Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Mon, 30 Dec 2019 23:59:56 +0800
Subject: [PATCH] >  Manual commit:  Fixed SDL async-rendering bug. U201614531
 recolic Linux RECOLICPC 5.4.6-arch3-1 #1 SMP PREEMPT Tue, 24 Dec 2019
 04:36:53 +0000 x86_64 GNU/Linux  23:59:55 up 2 days,  5:33,  1 user,  load
 average: 0.51, 0.76, 0.77 8785745a2ae9e4aea8bad5d7389f9d353592de5

---
 nemu/src/device/vga.cc                        | 29 ++++++++++++++-----
 nexus-am/am/arch/x86-nemu/src/devices/video.c | 10 ++-----
 2 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/nemu/src/device/vga.cc b/nemu/src/device/vga.cc
index 6644584..906196d 100644
--- a/nemu/src/device/vga.cc
+++ b/nemu/src/device/vga.cc
@@ -18,16 +18,15 @@ static SDL_Texture *texture;
 static uint32_t (*vmem) [SCREEN_W];
 static uint32_t *screensize_port_base;
 
-void update_screen() {
-  SDL_UpdateTexture(texture, NULL, vmem, SCREEN_W * sizeof(vmem[0][0]));
-  SDL_RenderClear(renderer);
-  SDL_RenderCopy(renderer, texture, NULL, NULL);
-  SDL_RenderPresent(renderer);
+inline void SDL_ErrorCheck(int ret) {
+  if(ret != 0) {
+    rlib::println("SDL_Error: ret=", ret, ", GETERR=", SDL_GetError());
+  }
 }
 
-void init_vga() {
-  SDL_Init(SDL_INIT_VIDEO);
-  SDL_CreateWindowAndRenderer(SCREEN_W * 2, SCREEN_H * 2, 0, &window, &renderer);
+static void init_vga_impl() {
+  SDL_ErrorCheck(SDL_Init(SDL_INIT_VIDEO));
+  SDL_ErrorCheck(SDL_CreateWindowAndRenderer(SCREEN_W * 2, SCREEN_H * 2, 0, &window, &renderer));
   SDL_SetWindowTitle(window, "NEMU");
   texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
       SDL_TEXTUREACCESS_STATIC, SCREEN_W, SCREEN_H);
@@ -36,4 +35,18 @@ void init_vga() {
   *screensize_port_base = ((SCREEN_W) << 16) | (SCREEN_H);
   vmem = reinterpret_cast<decltype(vmem)>(add_mmio_map(VMEM, 0x80000, nullptr));
 }
+
+void update_screen() {
+  if(window == nullptr) init_vga_impl();
+  SDL_ErrorCheck(SDL_UpdateTexture(texture, NULL, vmem, SCREEN_W * sizeof(vmem[0][0])));
+  SDL_ErrorCheck(SDL_RenderClear(renderer));
+  SDL_ErrorCheck(SDL_RenderCopy(renderer, texture, NULL, NULL));
+  SDL_RenderPresent(renderer);
+}
+
+void init_vga() {
+  // Because of fucking SDL design, vga_init should be done in updating thread.
+  // Do nothing in main thread.
+}
+
 #endif	/* HAS_IOE */
diff --git a/nexus-am/am/arch/x86-nemu/src/devices/video.c b/nexus-am/am/arch/x86-nemu/src/devices/video.c
index 00cb3ab..2baa1f5 100644
--- a/nexus-am/am/arch/x86-nemu/src/devices/video.c
+++ b/nexus-am/am/arch/x86-nemu/src/devices/video.c
@@ -23,13 +23,9 @@ size_t video_write(uintptr_t reg, void *buf, size_t size) {
   switch (reg) {
     case _DEVREG_VIDEO_FBCTL: {
       _FBCtlReg *ctl = (_FBCtlReg *)buf;
-int i;
-int size = screen_width() * screen_height();
-for (i = 0; i < size; i ++) fb[i] = i;
-//      for(int i = 0; i < ctl->h; ++i)
-//      {
-//        memcpy(fb+(ctl->y+i)*screen_width()+ctl->x,ctl->pixels+i*ctl->w,ctl->w*4);
-//      }
+      for(int i = 0; i < ctl->h; ++i) {
+        memcpy(fb+(ctl->y+i)*screen_width()+ctl->x,ctl->pixels+i*ctl->w,ctl->w*4);
+      }
       if (ctl->sync) {
         // do nothing, hardware syncs.
       }
-- 
GitLab