shithub: psxe

Download patch

ref: 695852c66e89f45f510bab529ac9b9281f8884b0
parent: 93c6a6727cc410af6921820dc8ef6f2016aebba3
author: allkern <lisandroaalarcon@gmail.com>
date: Sun Sep 17 17:57:24 EDT 2023

Implement rectangle decoding

--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -150,6 +150,124 @@
     }
 }
 
+void gpu_render_rect(psx_gpu_t* gpu, rect_data_t data) {
+    uint16_t width, height;
+
+    switch ((data.attrib >> 3) & 3) {
+        case RS_VARIABLE: { width = data.width; height = data.height; } break;
+        case RS_1X1     : { width = 1         ; height = 1          ; } break;
+        case RS_8X8     : { width = 8         ; height = 8          ; } break;
+        case RS_16X16   : { width = 16        ; height = 16         ; } break;
+    }
+
+    int clutx = (data.clut & 0x3f) << 4;
+    int cluty = (data.clut >> 6) & 0x1ff;
+
+    /* Offset coordinates */
+    data.v0.x += gpu->off_x;
+    data.v0.y += gpu->off_y;
+
+    /* Calculate bounding box */
+    // int xmin = max(data.v0.x, gpu->draw_x1);
+    // int ymin = max(data.v0.y, gpu->draw_y1);
+    int xmax = data.v0.x + width; //min(xmin + width, gpu->draw_x2);
+    int ymax = data.v0.y + height; //min(ymin + height, gpu->draw_y2);
+
+    int32_t xc = 0, yc = 0;
+
+    for (int16_t y = data.v0.y; y < ymax; y++) {
+        for (int16_t x = data.v0.x; x < xmax; x++) {
+            int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
+                     (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
+
+            if (!bc)
+                goto skip;
+
+            uint16_t color;
+
+            if (data.attrib & RA_TEXTURED) {
+                uint16_t texel = gpu_fetch_texel(
+                    gpu,
+                    data.v0.tx + xc, data.v0.ty + yc,
+                    gpu->texp_x, gpu->texp_y,
+                    clutx, cluty,
+                    gpu->texp_d
+                );
+
+                if (!texel)
+                    goto skip;
+
+                int tr = ((texel >> 0 ) & 0x1f) << 3;
+                int tg = ((texel >> 5 ) & 0x1f) << 3;
+                int tb = ((texel >> 10) & 0x1f) << 3;
+
+                int mr = (data.v0.c >> 0 ) & 0xff;
+                int mg = (data.v0.c >> 8 ) & 0xff;
+                int mb = (data.v0.c >> 16) & 0xff;
+
+                int cr = (tr * mr) / 0x80;
+                int cg = (tg * mg) / 0x80;
+                int cb = (tb * mb) / 0x80;
+
+                uint32_t rgb = cr | (cg << 8) | (cb << 16);
+
+                color = BGR555(rgb);
+            } else {
+                color = BGR555(data.v0.c);
+            }
+
+            int cr = ((color >> 0 ) & 0x1f) << 3;
+            int cg = ((color >> 5 ) & 0x1f) << 3;
+            int cb = ((color >> 10) & 0x1f) << 3;
+
+            if (data.attrib & RA_TRANSP) {
+                uint16_t back = gpu->vram[x + (y * 1024)];
+
+                int br = ((back >> 0 ) & 0x1f) << 3;
+                int bg = ((back >> 5 ) & 0x1f) << 3;
+                int bb = ((back >> 10) & 0x1f) << 3;
+
+                switch ((gpu->gpustat >> 5) & 3) {
+                    case 0: {
+                        cr = (cr / 2) + (br / 2);
+                        cg = (cg / 2) + (bg / 2);
+                        cb = (cb / 2) + (bb / 2);
+                    } break;
+                    case 1: {
+                        cr = cr + br;
+                        cg = cg + bg;
+                        cb = cb + bb;
+                    } break;
+                    case 2: {
+                        cr = cr - br;
+                        cg = cg - bg;
+                        cb = cb - bb;
+                    }
+                    case 3: {
+                        cr = br + (cr / 4);
+                        cg = bg + (cg / 4);
+                        cb = bb + (cb / 4);
+                    } break;
+                }
+
+                uint32_t rgb = cr | (cg << 8) | (cb << 16);
+
+                color = BGR555(rgb);
+            }
+
+            gpu->vram[x + (y * 1024)] = color;
+
+            skip:
+
+            ++xc;
+        }
+
+        xc = 0;
+
+        ++yc;
+    }
+}
+
 void plotLineLow(psx_gpu_t* gpu, int x0, int y0, int x1, int y1, uint16_t color) {
     int dx = x1 - x0;
     int dy = y1 - y0;
@@ -440,6 +558,49 @@
     }
 }
 
+void gpu_rect(psx_gpu_t* gpu) {
+    switch (gpu->state) {
+        case GPU_STATE_RECV_CMD: {
+            gpu->state = GPU_STATE_RECV_ARGS;
+
+            int size = (gpu->buf[0] >> 27) & 3;
+            int textured = (gpu->buf[0] & 0x04000000) != 0;
+
+            gpu->cmd_args_remaining = 1 + (size == RS_VARIABLE) + textured;
+        } break;
+
+        case GPU_STATE_RECV_ARGS: {
+            if (!gpu->cmd_args_remaining) {
+                rect_data_t rect;
+
+                rect.attrib = gpu->buf[0] >> 24;
+
+                int textured = (rect.attrib & RA_TEXTURED) != 0;
+                int raw      = (rect.attrib & RA_RAW) != 0;
+
+                // Add 1 if is textured
+                int size_offset = 2 + textured;
+
+                rect.v0.c   = gpu->buf[0] & 0xffffff;
+                rect.v0.x   = gpu->buf[1] & 0xffff;
+                rect.v0.y   = gpu->buf[1] >> 16;
+                rect.v0.tx  = (gpu->buf[2] >> 0) & 0xff;
+                rect.v0.ty  = (gpu->buf[2] >> 8) & 0xff;
+                rect.clut   = gpu->buf[2] >> 16;
+                rect.width  = gpu->buf[size_offset] & 0xffff;
+                rect.height = gpu->buf[size_offset] >> 16;
+
+                if (textured && raw)
+                    rect.v0.c = 0x808080;
+
+                gpu_render_rect(gpu, rect);
+
+                gpu->state = GPU_STATE_RECV_CMD;
+            }
+        } break;
+    }
+}
+
 void gpu_cmd_a0(psx_gpu_t* gpu) {
     switch (gpu->state) {
         case GPU_STATE_RECV_CMD: {
@@ -1046,6 +1207,12 @@
 }
 
 void psx_gpu_update_cmd(psx_gpu_t* gpu) {
+    if (((gpu->buf[0] >> 29) & 7) == 3) {
+        gpu_rect(gpu);
+
+        return;
+    }
+
     switch (gpu->buf[0] >> 24) {
         case 0x00: /* nop */ break;
         case 0x01: /* Cache clear */ break;
@@ -1113,7 +1280,11 @@
             /* To-do: Implement mask bit thing */
         } break;
         default: {
+            log_set_quiet(0);
             log_fatal("Unhandled GP0(%02Xh)", gpu->buf[0] >> 24);
+            log_set_quiet(1);
+
+            exit(1);
         } break;
     }
 }
--- a/psx/dev/gpu.h
+++ b/psx/dev/gpu.h
@@ -45,11 +45,31 @@
 typedef void (*psx_gpu_cmd_t)(psx_gpu_t*);
 typedef void (*psx_gpu_event_callback_t)(psx_gpu_t*);
 
+enum {
+    RS_VARIABLE,
+    RS_1X1,
+    RS_8X8,
+    RS_16X16
+};
+
+enum {
+    RA_RAW = 1,
+    RA_TRANSP = 2,
+    RA_TEXTURED = 4
+};
+
 typedef struct {
-    int32_t x, y;
+    int16_t x, y;
     uint32_t c;
     uint8_t tx, ty;
 } vertex_t;
+
+typedef struct {
+    uint8_t attrib;
+    vertex_t v0;
+    uint16_t clut;
+    uint16_t width, height;
+} rect_data_t;
 
 struct psx_gpu_t {
     uint32_t io_base, io_size;
--