gpu: a bit better idle bit handling
authornotaz <notasas@gmail.com>
Sun, 8 Oct 2023 22:20:07 +0000 (01:20 +0300)
committernotaz <notasas@gmail.com>
Sun, 8 Oct 2023 22:46:11 +0000 (01:46 +0300)
notaz/pcsx_rearmed#217

Makefile
frontend/libretro.c
frontend/plugin_lib.c
frontend/plugin_lib.h
jni/Android.mk
libpcsxcore/gpu.c [new file with mode: 0644]
libpcsxcore/gpu.h
libpcsxcore/psxdma.c
plugins/gpulib/gpu.c
plugins/gpulib/gpu.h

index a083d52..9779ddc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -56,7 +56,7 @@ OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore
        libpcsxcore/misc.o libpcsxcore/plugins.o libpcsxcore/ppf.o libpcsxcore/psxbios.o \
        libpcsxcore/psxcommon.o libpcsxcore/psxcounters.o libpcsxcore/psxdma.o \
        libpcsxcore/psxhw.o libpcsxcore/psxinterpreter.o libpcsxcore/psxmem.o libpcsxcore/r3000a.o \
-       libpcsxcore/sio.o libpcsxcore/spu.o
+       libpcsxcore/sio.o libpcsxcore/spu.o libpcsxcore/gpu.o
 OBJS += libpcsxcore/gte.o libpcsxcore/gte_nf.o libpcsxcore/gte_divider.o
 
 ifeq ($(DEBUG), 1)
index b8b1166..d21b1a2 100644 (file)
@@ -27,6 +27,7 @@
 #include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
 #include "../libpcsxcore/r3000a.h"
+#include "../libpcsxcore/gpu.h"
 #include "../plugins/dfsound/out.h"
 #include "../plugins/dfsound/spu_config.h"
 #include "cspace.h"
@@ -488,6 +489,7 @@ struct rearmed_cbs pl_rearmed_cbs = {
    .pl_vout_close    = vout_close,
    .mmap             = pl_mmap,
    .munmap           = pl_munmap,
+   .gpu_state_change = gpu_state_change,
    /* from psxcounters */
    .gpu_hcnt         = &hSyncCount,
    .gpu_frame_count  = &frame_counter,
index 917ae17..2339028 100644 (file)
@@ -33,6 +33,7 @@
 #include "psemu_plugin_defs.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../libpcsxcore/psxmem_map.h"
+#include "../libpcsxcore/gpu.h"
 
 #define HUD_HEIGHT 10
 
@@ -770,6 +771,7 @@ struct rearmed_cbs pl_rearmed_cbs = {
        .mmap = pl_mmap,
        .munmap = pl_munmap,
        .pl_set_gpu_caps = pl_set_gpu_caps,
+       .gpu_state_change = gpu_state_change,
 };
 
 /* watchdog */
index e48ed52..6b2d718 100644 (file)
@@ -49,6 +49,7 @@ void  pl_switch_dispmode(void);
 void  pl_timing_prepare(int is_pal);
 void  pl_frame_limit(void);
 
+// for communication with gpulib
 struct rearmed_cbs {
        void  (*pl_get_layer_pos)(int *x, int *y, int *w, int *h);
        int   (*pl_vout_open)(void);
@@ -61,6 +62,8 @@ struct rearmed_cbs {
        // only used by some frontends
        void  (*pl_vout_set_raw_vram)(void *vram);
        void  (*pl_set_gpu_caps)(int caps);
+       // emulation related
+       void  (*gpu_state_change)(int what);
        // some stats, for display by some plugins
        int flips_per_sec, cpu_usage;
        float vsps_cur; // currect vsync/s
index 03c2a28..971c45d 100644 (file)
@@ -41,6 +41,7 @@ SOURCES_C := $(CORE_DIR)/cdriso.c \
              $(CORE_DIR)/r3000a.c \
              $(CORE_DIR)/sio.c \
              $(CORE_DIR)/spu.c \
+             $(CORE_DIR)/gpu.c \
              $(CORE_DIR)/gte.c \
              $(CORE_DIR)/gte_nf.c \
              $(CORE_DIR)/gte_divider.c
diff --git a/libpcsxcore/gpu.c b/libpcsxcore/gpu.c
new file mode 100644 (file)
index 0000000..1eadf59
--- /dev/null
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ ***************************************************************************/
+
+#include "gpu.h"
+#include "psxdma.h"
+
+void gpu_state_change(int what)
+{
+       enum psx_gpu_state state = what;
+       switch (state)
+       {
+       case PGS_VRAM_TRANSFER_START:
+               HW_GPU_STATUS &= ~SWAP32(PSXGPU_nBUSY);
+               break;
+       case PGS_VRAM_TRANSFER_END:
+               HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
+               break;
+       case PGS_PRIMITIVE_START:
+               HW_GPU_STATUS &= ~SWAP32(PSXGPU_nBUSY);
+               GPUDMA_INT(200); // see gpuInterrupt
+               break;
+       }
+}
index 21384e5..ef9c718 100644 (file)
        HW_GPU_STATUS |= SWAP32(GPU_readStatus() & ~PSXGPU_TIMING_BITS); \
 }
 
+enum psx_gpu_state {
+  PGS_VRAM_TRANSFER_START,
+  PGS_VRAM_TRANSFER_END,
+  PGS_PRIMITIVE_START, // for non-dma only
+};
+
+void gpu_state_change(int what);
+
 #endif /* __GPU_H__ */
index c0aee7e..0ffec81 100644 (file)
@@ -156,6 +156,8 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
 
                        HW_DMA2_MADR = SWAPu32(madr + words_copy * 4);
 
+                       // careful: gpu_state_change() also messes with this
+                       HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY);
                        // already 32-bit word size ((size * 4) / 4)
                        GPUDMA_INT(words / 4);
                        return;
@@ -177,6 +179,8 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
 
                        HW_DMA2_MADR = SWAPu32(madr);
 
+                       // careful: gpu_state_change() also messes with this
+                       HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY);
                        // already 32-bit word size ((size * 4) / 4)
                        GPUDMA_INT(words / 4);
                        return;
@@ -214,6 +218,8 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
        DMA_INTERRUPT(2);
 }
 
+// note: this is also (ab)used for non-dma prim command
+// to delay gpu returning to idle state, see gpu_state_change()
 void gpuInterrupt() {
        if (HW_DMA2_CHCR == SWAP32(0x01000401) && !(HW_DMA2_MADR & SWAP32(0x800000)))
        {
index 271c89c..6814819 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdlib.h> /* for calloc */
 
 #include "gpu.h"
+#include "../../libpcsxcore/gpu.h" // meh
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #ifdef __GNUC__
@@ -482,6 +483,8 @@ static void start_vram_transfer(uint32_t pos_word, uint32_t size_word, int is_re
 
   log_io("start_vram_transfer %c (%d, %d) %dx%d\n", is_read ? 'r' : 'w',
     gpu.dma.x, gpu.dma.y, gpu.dma.w, gpu.dma.h);
+  if (gpu.gpu_state_change)
+    gpu.gpu_state_change(PGS_VRAM_TRANSFER_START);
 }
 
 static void finish_vram_transfer(int is_read)
@@ -493,6 +496,8 @@ static void finish_vram_transfer(int is_read)
     renderer_update_caches(gpu.dma_start.x, gpu.dma_start.y,
                            gpu.dma_start.w, gpu.dma_start.h, 0);
   }
+  if (gpu.gpu_state_change)
+    gpu.gpu_state_change(PGS_VRAM_TRANSFER_END);
 }
 
 static void do_vram_copy(const uint32_t *params)
@@ -671,12 +676,16 @@ static noinline int do_cmd_buffer(uint32_t *data, int count)
   return count - pos;
 }
 
-static void flush_cmd_buffer(void)
+static noinline void flush_cmd_buffer(void)
 {
   int left = do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len);
   if (left > 0)
     memmove(gpu.cmd_buffer, gpu.cmd_buffer + gpu.cmd_len - left, left * 4);
-  gpu.cmd_len = left;
+  if (left != gpu.cmd_len) {
+    if (!gpu.dma.h && gpu.gpu_state_change)
+      gpu.gpu_state_change(PGS_PRIMITIVE_START);
+    gpu.cmd_len = left;
+  }
 }
 
 void GPUwriteDataMem(uint32_t *mem, int count)
@@ -963,6 +972,7 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
 
   gpu.mmap = cbs->mmap;
   gpu.munmap = cbs->munmap;
+  gpu.gpu_state_change = cbs->gpu_state_change;
 
   // delayed vram mmap
   if (gpu.vram == NULL)
index b3a2302..28458cf 100644 (file)
@@ -114,6 +114,7 @@ struct psx_gpu {
     (int *x, int *y, int *w, int *h, int *vram_h);
   void *(*mmap)(unsigned int size);
   void  (*munmap)(void *ptr, unsigned int size);
+  void  (*gpu_state_change)(int what); // psx_gpu_state
 };
 
 extern struct psx_gpu gpu;