Implement hardware cursor support (9x now displays mouse cursor)

This commit is contained in:
starfrost013
2025-06-22 15:59:44 +01:00
parent c5480af062
commit d5a9411fe7
4 changed files with 83 additions and 53 deletions

View File

@@ -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

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<width>620</width>
<height>350</height>
</rect>
</property>
@@ -18,13 +18,13 @@
</property>
<property name="minimumSize">
<size>
<width>600</width>
<width>620</width>
<height>350</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>600</width>
<width>620</width>
<height>350</height>
</size>
</property>
@@ -88,7 +88,7 @@
<x>10</x>
<y>30</y>
<width>151</width>
<height>16</height>
<height>21</height>
</rect>
</property>
<property name="text">
@@ -98,7 +98,7 @@
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>420</x>
<x>390</x>
<y>30</y>
<width>91</width>
<height>16</height>
@@ -111,14 +111,14 @@
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>510</x>
<x>480</x>
<y>30</y>
<width>49</width>
<width>81</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;PLACEHOLDER 9000&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;PLACEHOLDER&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="plainTextEdit_2">
@@ -137,13 +137,26 @@
<x>10</x>
<y>60</y>
<width>151</width>
<height>16</height>
<height>21</height>
</rect>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Pixel Depth&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="loadSavestateBtn">
<property name="geometry">
<rect>
<x>10</x>
<y>110</y>
<width>231</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Load nvplay savestate from real hardware</string>
</property>
</widget>
</widget>
</widget>
</item>

View File

@@ -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)

View File

@@ -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*)&current_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");