From d5a9411fe732fabe2dc2731b8715506db9d68ad4 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 22 Jun 2025 15:59:44 +0100 Subject: [PATCH] Implement hardware cursor support (9x now displays mouse cursor) --- src/include/86box/nv/vid_nv3.h | 11 ++- src/qt/qt_gpudebug_visualnv.ui | 31 ++++++--- src/video/nv/nv3/nv3_core.c | 92 +++++++++++++++---------- src/video/nv/nv3/subsystems/nv3_pfifo.c | 2 +- 4 files changed, 83 insertions(+), 53 deletions(-) diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index c89f2e9b2..632ee01fa 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -463,13 +463,6 @@ extern const device_config_t nv3t_config[]; // Confi #define NV3_PME_INTR_EN 0x200140 // Mediaport: Interrupt Enable #define NV3_PME_END 0x200FFF -// THIS IS NOT A REAL REGISTER. -// This is so my software e.g. nvplayground can determine if the software is being run in an emulator on a real RIVA 128. -// This register should have some sort of open bus, garbage or 00/FF on a real NV3/NV3T but have a string. -#define NV3_EMULATED_MARKER_START 0x269420 - -#define NV3_EMULATED_MARKER 0x0D15EA5E - #define NV3_PGRAPH_START 0x400000 // Scene graph for 2d/3d rendering...the most important part // PGRAPH Core @@ -800,6 +793,10 @@ extern const device_config_t nv3t_config[]; // Confi #define NV3_RAMIN_RAMRM_START 0x1C02000 #define NV3_RAMIN_RAMRM_END 0x1C02FFF +// I'm not sure if this can be moved. +// 4K of "PRAM" is listed at 0x6000. +#define NV3_RAMIN_OFFSET_CURSOR 0x6000 + #define NV3_RAMIN_END 0x1FFFFFF // not done diff --git a/src/qt/qt_gpudebug_visualnv.ui b/src/qt/qt_gpudebug_visualnv.ui index e103ff03e..313df859d 100644 --- a/src/qt/qt_gpudebug_visualnv.ui +++ b/src/qt/qt_gpudebug_visualnv.ui @@ -6,7 +6,7 @@ 0 0 - 600 + 620 350 @@ -18,13 +18,13 @@ - 600 + 620 350 - 600 + 620 350 @@ -88,7 +88,7 @@ 10 30 151 - 16 + 21 @@ -98,7 +98,7 @@ - 420 + 390 30 91 16 @@ -111,14 +111,14 @@ - 510 + 480 30 - 49 + 81 16 - <html><head/><body><p><span style=" font-weight:700;">PLACEHOLDER 9000</span></p></body></html> + <html><head/><body><p><span style=" font-weight:700;">PLACEHOLDER</span></p></body></html> @@ -137,13 +137,26 @@ 10 60 151 - 16 + 21 <html><head/><body><p>Pixel Depth</p></body></html> + + + + 10 + 110 + 231 + 24 + + + + Load nvplay savestate from real hardware + + diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index 21810386e..39aa0178d 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -866,9 +866,14 @@ void nv3_draw_cursor(svga_t* svga, int32_t drawline) if ((nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_CURSOR_START] >> NV3_CRTC_REGISTER_CURSOR_START_DISABLED) & 0x01) return; - // On windows, this shows up using NV_IMAGE_IN_MEMORY. + // NT GDI drivers: Load cursor using NV_IMAGE_FROM_MEMORY ("NV3LCD") + // 9x GDI drivers: Use H/W cursor in RAMIN + // Do we need to emulate it? - uint32_t vram_cursor_base = nv3->pramdac.cursor_address; + + // THIS IS CORRECT. BUT HOW DO WE FIND IT? + uint32_t ramin_cursor_position = NV3_RAMIN_OFFSET_CURSOR; + /* let's just assume buffer 0 here...that code needs to be totally rewritten*/ nv3_coord_16_t start_position = nv3->pramdac.cursor_start; @@ -890,49 +895,64 @@ void nv3_draw_cursor(svga_t* svga, int32_t drawline) We have to get a 32x32, "A"1R5G5B5-format cursor out of video memory. The alpha bit actually means - XOR with display pixel if 0, replace if 1 - Technically these are expanded to RGB10, but I don't see why this needs to happen. And our pipeline isn't set up for it anyway. + These are expanded to RGB10 only if they are XORed. We don't do this (we don't really need to + there is no grobj specified here so special casing + would be needed) so we just xor it with the current pixel format */ for (int32_t y = 0; y < NV3_PRAMDAC_CURSOR_SIZE_Y; y++) { for (int32_t x = 0; x < NV3_PRAMDAC_CURSOR_SIZE_X; x++) { - uint16_t current_pixel = vram_16[vram_cursor_base << 1]; - bool replace_bit = (current_pixel & 0x8000); - - switch (nv3->nvbase.svga.bpp) + uint16_t current_pixel = nv3_ramin_read16(ramin_cursor_position, nv3); + + // 0000 = transparent, so skip drawing + if (current_pixel) { - /* this is indexed colour but... lol */ - case 8: - if (replace_bit) - { - uint8_t final = current_pixel ^ nv3->nvbase.svga.vram[final_position]; - nv3->nvbase.svga.vram[final_position] = final; - } - else // just override - nv3->nvbase.svga.vram[final_position] = current_pixel; - case 15 ... 16: // easy case (our cursor is 15bpp format) - uint32_t index_16 = final_position >> 1; - if (replace_bit) - { - uint16_t final = current_pixel ^ vram_16[index_16]; - vram_16[index_16] = final; - } - else // just override - vram_16[index_16] = current_pixel; - case 32: - uint32_t index_32 = final_position >> 2; - if (replace_bit) - { - uint16_t final = current_pixel ^ vram_32[index_32]; - vram_32[index_32] = final; - } - else // just override - vram_32[index_32] = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, current_pixel, 15); // 565_MODE doesn't seem to matter here - break; + bool replace_bit = (current_pixel & 0x8000); + + // use buffer 0 BPIXEL + uint32_t bpixel_format = (nv3->pgraph.bpixel[0]) & 0x03; + + switch (bpixel_format) + { + case bpixel_fmt_8bit: + if (replace_bit) + nv3->nvbase.svga.vram[final_position] = current_pixel; + else //xor + { + // not sure what to do here. we'd have to search through the palette to find the closest possible colour. + uint8_t final = current_pixel ^ nv3->nvbase.svga.vram[final_position]; + nv3->nvbase.svga.vram[final_position] = final; + } + case bpixel_fmt_16bit: // easy case (our cursor is 15bpp format) + uint32_t index_16 = final_position >> 1; + + if (replace_bit) // just replace + vram_16[index_16] = current_pixel; + else // xor + { + current_pixel &= ~0x8000; // mask off the xor bit + uint16_t final = current_pixel ^ vram_16[index_16]; + vram_16[index_16] = final; + } + case bpixel_fmt_32bit: + uint32_t index_32 = final_position >> 2; + + if (replace_bit) // just replace + vram_32[index_32] = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, current_pixel, 15); // 565_MODE doesn't seem to matter here + else //xor + { + current_pixel &= ~0x8000; // mask off the xor bit + uint32_t current_pixel_32 = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, current_pixel, 15); // 565_MODE doesn't seem to matter here + + uint32_t final = current_pixel_32 ^ vram_32[index_32]; + vram_32[index_32] = final; + } + break; + } } // increment vram position - vram_cursor_base += 2; + ramin_cursor_position += 2; // go switch (nv3->nvbase.svga.bpp) diff --git a/src/video/nv/nv3/subsystems/nv3_pfifo.c b/src/video/nv/nv3/subsystems/nv3_pfifo.c index 7cd7f71a9..542aa26fa 100644 --- a/src/video/nv/nv3/subsystems/nv3_pfifo.c +++ b/src/video/nv/nv3/subsystems/nv3_pfifo.c @@ -739,7 +739,7 @@ void nv3_pfifo_cache0_pull(void) uint32_t current_context = nv3->pfifo.cache0_settings.context[0]; // only 1 entry for CACHE0 so basically ignore the other context entries? uint8_t class_id = ((nv3_ramin_context_t*)¤t_context)->class_id; - // Tell the CPU if we found a software method + // Tell the CPU if we found a software method and turn off cache pulling if (!(current_context & 0x800000)) { nv_log("The object in CACHE0 is a software object\n");