From 911a71c67fbe2b6209bae7d957563f7a51c8aeaf Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Wed, 9 Apr 2025 21:29:46 +0100 Subject: [PATCH] very large rewrite. use custom rendering code (for both DFB and GPU) to allow sub-scanline switches; implement a real pixel clock; only blit stuff that actually changed; add void to functions for actions (this may break some things) --- src/include/86box/nv/render/vid_nv3_render.h | 10 +- src/include/86box/nv/vid_nv.h | 9 +- src/include/86box/nv/vid_nv3.h | 34 +- src/video/nv/nv3/classes/nv3_class_010_blit.c | 2 +- src/video/nv/nv3/nv3_core.c | 32 +- src/video/nv/nv3/render/nv3_render_blit.c | 50 +++ src/video/nv/nv3/render/nv3_render_core.c | 373 ++++++++++++------ .../nv/nv3/render/nv3_render_primitives.c | 3 + src/video/nv/nv3/subsystems/nv3_pramdac.c | 17 + 9 files changed, 378 insertions(+), 152 deletions(-) diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h index 567cf3cd4..11f4d2368 100644 --- a/src/include/86box/nv/render/vid_nv3_render.h +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -18,13 +18,17 @@ #pragma once /* Core */ -void nv3_render_15bpp(svga_t *svga); -void nv3_render_16bpp(svga_t *svga); -void nv3_render_32bpp(svga_t *svga); +void nv3_render_current_bpp(svga_t *svga, nv3_position_16_t position, nv3_size_16_t size, nv3_grobj_t grobj); +void nv3_render_current_bpp_dfb_8(uint32_t address); +void nv3_render_current_bpp_dfb_16(uint32_t address); +void nv3_render_current_bpp_dfb_32(uint32_t address); + void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj); uint8_t nv3_render_read_pixel_8(nv3_position_16_t position, nv3_grobj_t grobj, bool use_destination); uint16_t nv3_render_read_pixel_16(nv3_position_16_t position, nv3_grobj_t grobj, bool use_destination); uint32_t nv3_render_read_pixel_32(nv3_position_16_t position, nv3_grobj_t grobj, bool use_destination); + + uint32_t nv3_render_get_vram_address(nv3_position_16_t position, nv3_grobj_t grobj, bool use_destination); uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded); diff --git a/src/include/86box/nv/vid_nv.h b/src/include/86box/nv/vid_nv.h index 0b314d5f3..ef5e80d71 100644 --- a/src/include/86box/nv/vid_nv.h +++ b/src/include/86box/nv/vid_nv.h @@ -72,6 +72,9 @@ void nv_log_verbose_only(const char *fmt, ...); #define NV_ARCHITECTURE_NV3 3 // Riva 128 #define NV_ARCHITECTURE_NV4 4 // Riva TNT and later +#define NV_MAX_BUF_SIZE_X 1920 // Maximum buffer size, X +#define NV_MAX_BUF_SIZE_Y 1200 // Maximum buffer size, Y + typedef enum nv_bus_generation_e { // NV1 - Prototype version @@ -113,7 +116,9 @@ typedef struct nv_base_s uint32_t bar1_lfb_base; // PCI Base Address Register 1 - Linear Framebuffer (NV_BASE) nv_bus_generation bus_generation; // current bus (see nv_bus_generation documentation) uint32_t gpu_revision; // GPU Stepping - double pixel_clock_frequency; // Frequency used for pixel clock + double pixel_clock_frequency; // Frequency used for pixel clock# + double refresh_time; // Rough estimation of refresh rate, for when we can present the screen + double refresh_clock; // Time since the last refresh rivatimer_t* pixel_clock_timer; // Timer for measuring pixel clock bool pixel_clock_enabled; // Pixel Clock Enabled - stupid crap used to prevent us enabling the timer multiple times double memory_clock_frequency; // Source Frequency for PTIMER @@ -139,7 +144,7 @@ typedef struct nv_register_s int32_t address; // MMIO Address char* friendly_name; // Friendly name // reg_ptr not needed as a parameter, because we implicitly know which register si being tiwddled - uint32_t (*on_read)(); // Optional on-read function + uint32_t (*on_read)(void); // Optional on-read function void (*on_write)(uint32_t value); // Optional on-write fucntion } nv_register_t; diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index 482315e32..f11a4cdfc 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -1457,7 +1457,7 @@ void nv3_recalc_timings(svga_t* svga); void nv3_force_redraw(void* priv); /* BAR0 GPU MMIO read */ -void nv3_update_mappings(); // Update memory mappings +void nv3_update_mappings(void); // Update memory mappings uint8_t nv3_mmio_read8(uint32_t addr, void* priv); // Read 8-bit MMIO uint16_t nv3_mmio_read16(uint32_t addr, void* priv); // Read 16-bit MMIO uint32_t nv3_mmio_read32(uint32_t addr, void* priv); // Read 32-bit MMIO @@ -1556,12 +1556,12 @@ void nv3_user_write(uint32_t address, uint32_t value); // GPU subsystems // NV3 PMC -void nv3_pmc_init(); -uint32_t nv3_pmc_clear_interrupts(); +void nv3_pmc_init(void); +uint32_t nv3_pmc_clear_interrupts(void); uint32_t nv3_pmc_handle_interrupts(bool send_now); // NV3 PGRAPH -void nv3_pgraph_init(); +void nv3_pgraph_init(void); uint32_t nv3_pgraph_read(uint32_t address); void nv3_pgraph_write(uint32_t address, uint32_t value); void nv3_pgraph_vblank_start(svga_t* svga); @@ -1599,46 +1599,46 @@ void nv3_class_01c_method(uint32_t param, uint32_t method_id, nv3_ramin_c void nv3_notify_if_needed(uint32_t name, uint32_t method_id, nv3_ramin_context_t context,nv3_grobj_t grobj); // NV3 PFIFO -void nv3_pfifo_init(); +void nv3_pfifo_init(void); uint32_t nv3_pfifo_read(uint32_t address); void nv3_pfifo_write(uint32_t address, uint32_t value); void nv3_pfifo_interrupt(uint32_t id, bool fire_now); // NV3 PFIFO - Caches //cache0_push not a thing -void nv3_pfifo_cache0_pull(); +void nv3_pfifo_cache0_pull(void); void nv3_pfifo_cache1_push(uint32_t addr, uint32_t val); -void nv3_pfifo_cache1_pull(); +void nv3_pfifo_cache1_pull(void); uint32_t nv3_pfifo_cache1_normal2gray(uint32_t val); uint32_t nv3_pfifo_cache1_gray2normal(uint32_t val); -uint32_t nv3_pfifo_cache1_num_free_spaces(); +uint32_t nv3_pfifo_cache1_num_free_spaces(void); // NV3 PFB -void nv3_pfb_init(); +void nv3_pfb_init(void); // NV3 PEXTDEV/PSTRAPS -void nv3_pextdev_init(); +void nv3_pextdev_init(void); // NV3 PBUS -void nv3_pbus_init(); +void nv3_pbus_init(void); // NV3 PBUS RMA - Real Mode Access for VBIOS uint8_t nv3_pbus_rma_read(uint16_t addr); void nv3_pbus_rma_write(uint16_t addr, uint8_t val); // NV3 PRAMDAC (Final presentation) -void nv3_pramdac_init(); -void nv3_pramdac_set_vram_clock(); -void nv3_pramdac_set_pixel_clock(); +void nv3_pramdac_init(void); +void nv3_pramdac_set_vram_clock(void); +void nv3_pramdac_set_pixel_clock(void); void nv3_pramdac_pixel_clock_poll(double real_time); void nv3_pramdac_memory_clock_poll(double real_time); // NV3 PTIMER -void nv3_ptimer_init(); +void nv3_ptimer_init(void); void nv3_ptimer_tick(double real_time); // NV3 PVIDEO -void nv3_pvideo_init(); +void nv3_pvideo_init(void); // NV3 PME (Mediaport) -void nv3_pme_init(); \ No newline at end of file +void nv3_pme_init(void); \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_010_blit.c b/src/video/nv/nv3/classes/nv3_class_010_blit.c index 6582ada13..45e5155a7 100644 --- a/src/video/nv/nv3/classes/nv3_class_010_blit.c +++ b/src/video/nv/nv3/classes/nv3_class_010_blit.c @@ -59,7 +59,7 @@ void nv3_class_010_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ && nv3->pgraph.blit.size.w == 0) return; - nv3_render_blit_screen2screen(grobj); + //nv3_render_blit_screen2screen(grobj); break; default: diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index 78592160a..aa8865fdd 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -511,6 +511,21 @@ void nv3_recalc_timings(svga_t* svga) svga->hdisp += 0x100; // large screen bit } + /* Turn off override if we are in VGA mode */ + svga->override = !(pixel_mode == NV3_CRTC_REGISTER_PIXELMODE_VGA); + + /* NOTE: The RIVA 128 draws in a way almost completely separate to any other 86Box GPU. + + Basically, we only blit to buffer32 when something changes and we don't even bother using a timer. We only render when there is something to actually render. + + This is because there is no linear relationship between the contents of VRAM and the contents of the display which 86box's SVGA subsystem cannot tolerate. + In fact, the position in VRAM and pitch can be changed at any time via an NV_IMAGE_IN_MEMORY object. + + Therefore, we need to completely bypass it using svga->override and draw our own rendering functions. This allows us to use a neat optimisation trick + to only ever actually draw when we need to do something. This shouldn't be a problem in games, because the drivers will read the current refresh rate from + the Windows settings, and then, just submit objects at that pace for anything that changes on the screen. + */ + // Set the pixel mode switch (pixel_mode) { @@ -519,7 +534,7 @@ void nv3_recalc_timings(svga_t* svga) svga->bpp = 8; svga->lowres = 0; svga->map8 = svga->pallook; - svga->render = svga_render_8bpp_highres; + //svga->render = nv3_render_8bpp; break; case NV3_CRTC_REGISTER_PIXELMODE_16BPP: /* This is some sketchy shit that is an attempt at an educated guess @@ -536,13 +551,13 @@ void nv3_recalc_timings(svga_t* svga) { svga->bpp = 16; svga->lowres = 0; - svga->render = nv3_render_16bpp; + //svga->render = nv3_render_16bpp; } else { svga->bpp = 15; svga->lowres = 0; - svga->render = nv3_render_15bpp; + //svga->render = nv3_render_15bpp; } @@ -552,7 +567,7 @@ void nv3_recalc_timings(svga_t* svga) svga->bpp = 32; svga->lowres = 0; - svga->render = nv3_render_32bpp; + //svga->render = nv3_render_32bpp; break; } @@ -784,6 +799,8 @@ void nv3_dfb_write8(uint32_t addr, uint8_t val, void* priv) { addr &= (nv3->nvbase.svga.vram_mask); nv3->nvbase.svga.vram[addr] = val; + nv3->nvbase.svga.changedvram[addr >> 12] = val; + nv3_render_current_bpp_dfb_8(addr); } void nv3_dfb_write16(uint32_t addr, uint16_t val, void* priv) @@ -791,6 +808,9 @@ void nv3_dfb_write16(uint32_t addr, uint16_t val, void* priv) addr &= (nv3->nvbase.svga.vram_mask); nv3->nvbase.svga.vram[addr + 1] = (val >> 8) & 0xFF; nv3->nvbase.svga.vram[addr] = (val) & 0xFF; + nv3->nvbase.svga.changedvram[addr >> 12] = val; + nv3_render_current_bpp_dfb_16(addr); + } void nv3_dfb_write32(uint32_t addr, uint32_t val, void* priv) @@ -800,6 +820,10 @@ void nv3_dfb_write32(uint32_t addr, uint32_t val, void* priv) nv3->nvbase.svga.vram[addr + 2] = (val >> 16) & 0xFF; nv3->nvbase.svga.vram[addr + 1] = (val >> 8) & 0xFF; nv3->nvbase.svga.vram[addr] = (val) & 0xFF; + nv3->nvbase.svga.changedvram[addr >> 12] = val; + + nv3_render_current_bpp_dfb_32(addr); + } /* Cursor shit */ diff --git a/src/video/nv/nv3/render/nv3_render_blit.c b/src/video/nv/nv3/render/nv3_render_blit.c index 666a93482..09a099977 100644 --- a/src/video/nv/nv3/render/nv3_render_blit.c +++ b/src/video/nv/nv3/render/nv3_render_blit.c @@ -132,6 +132,20 @@ void nv3_render_blit_screen2screen(nv3_grobj_t grobj) nv3_position_16_t old_position = nv3->pgraph.blit.point_in; nv3_position_16_t new_position = nv3->pgraph.blit.point_out; + uint32_t src_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER) & 0x03; + + /* test DST_BUFFER code + I assume for 2d at least only one is allowed at a time + */ + + uint32_t dst_buffer = 0; // 5 = just use the source buffer + + if ((grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER0_ENABLED) & 0x01) dst_buffer = 0; + if ((grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER1_ENABLED) & 0x01) dst_buffer = 1; + if ((grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER2_ENABLED) & 0x01) dst_buffer = 2; + if ((grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER3_ENABLED) & 0x01) dst_buffer = 3; + + uint16_t end_x_in = (nv3->pgraph.blit.point_in.x + nv3->pgraph.blit.size.w); /* needed for bounds checking */ uint16_t end_x_out = (nv3->pgraph.blit.point_out.x + nv3->pgraph.blit.size.w); uint16_t end_y = (nv3->pgraph.blit.point_out.y + nv3->pgraph.blit.size.h); @@ -173,4 +187,40 @@ void nv3_render_blit_screen2screen(nv3_grobj_t grobj) vram_position = nv3_render_get_vram_address(new_position, grobj, true); memcpy(&nv3->nvbase.svga.vram[vram_position], &nv3_s2sb_line_buffer[buf_position], size_x); } + + /* + We need to blit manually here because we don't go through nv3_render_write_pixel + We also need to update all of the areas of the screen that moved. + */ + + nv3_position_16_t blit_position = {0}; + nv3_size_16_t blit_size = {0}; + + /* Change the smallest area of the screen that moved */ + if (nv3->pgraph.blit.point_out.x > nv3->pgraph.blit.point_in.x) + blit_size.w = (nv3->pgraph.blit.point_out.x - nv3->pgraph.blit.point_in.x) + nv3->pgraph.blit.size.w; + else if (nv3->pgraph.blit.point_out.x < nv3->pgraph.blit.point_in.x) + blit_size.w = (nv3->pgraph.blit.point_in.x - nv3->pgraph.blit.point_out.x) + nv3->pgraph.blit.size.w; + else + blit_size.w = nv3->pgraph.blit.size.w; + + if (nv3->pgraph.blit.point_out.y > nv3->pgraph.blit.point_in.y) + blit_size.h = (nv3->pgraph.blit.point_out.y - nv3->pgraph.blit.point_in.y) + nv3->pgraph.blit.size.h; + else if (nv3->pgraph.blit.point_out.y < nv3->pgraph.blit.point_in.y) + blit_size.h = (nv3->pgraph.blit.point_in.y - nv3->pgraph.blit.point_out.y) + nv3->pgraph.blit.size.h; + else + blit_size.h = nv3->pgraph.blit.size.h; + + if (nv3->pgraph.blit.point_out.x > nv3->pgraph.blit.point_in.x) + blit_position.x = nv3->pgraph.blit.point_in.x; + else if (nv3->pgraph.blit.point_out.x <= nv3->pgraph.blit.point_in.x) // equals case, just use out + blit_position.x = nv3->pgraph.blit.point_out.x; + + if (nv3->pgraph.blit.point_out.y > nv3->pgraph.blit.point_in.y) + blit_position.y = nv3->pgraph.blit.point_in.y; + else if (nv3->pgraph.blit.point_out.y <= nv3->pgraph.blit.point_in.y) // equals case, just use out + blit_position.y = nv3->pgraph.blit.point_out.y; + + + nv3_render_current_bpp(&nv3->nvbase.svga, blit_position, blit_size, grobj); } \ No newline at end of file diff --git a/src/video/nv/nv3/render/nv3_render_core.c b/src/video/nv/nv3/render/nv3_render_core.c index 147ac8f6e..4313ac2a6 100644 --- a/src/video/nv/nv3/render/nv3_render_core.c +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -30,6 +30,12 @@ #include <86box/nv/vid_nv3.h> #include <86box/utils/video_stdlib.h> +/* Functions only used in this translation unit */ +void nv3_render_8bpp(nv3_position_16_t position, nv3_size_16_t size, nv3_grobj_t grobj); +void nv3_render_15bpp(nv3_position_16_t position, nv3_size_16_t size, nv3_grobj_t grobj); +void nv3_render_16bpp(nv3_position_16_t position, nv3_size_16_t size, nv3_grobj_t grobj); +void nv3_render_32bpp(nv3_position_16_t position, nv3_size_16_t size, nv3_grobj_t grobj); + /* Expand a colour. NOTE: THE GPU INTERNALLY OPERATES ON RGB10!!!!!!!!!!! */ @@ -261,6 +267,38 @@ uint32_t nv3_render_get_vram_address(nv3_position_16_t position, nv3_grobj_t gro return pixel_addr_vram; } +/* Convert a dumb framebuffer address to a position. No buffer setup or anything, but just start at 0,0 for address 0. */ +nv3_position_16_t nv3_render_get_dfb_position(uint32_t vram_address) +{ + nv3_position_16_t pos = {0}; + + uint32_t pitch = nv3->nvbase.svga.hdisp; + + if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + pitch <<= 1; + else if (nv3->nvbase.svga.bpp == 32) + pitch <<= 2; + + //vram_address -= nv3->pgraph.boffset[0]; + + pos.y = (vram_address / pitch); + pos.x = (vram_address % pitch); + + /* Fixup our x position */ + if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + pos.x >>= 1; + else if (nv3->nvbase.svga.bpp == 32) + pos.x >>= 2; + + + /* there is some strange behaviour where it writes long past the end of the fb */ + if (pos.y >= nv3->nvbase.svga.monitor->target_buffer->h) pos.y = nv3->nvbase.svga.monitor->target_buffer->h - 1; + + return pos; +} + /* Read an 8bpp pixel from the framebuffer. */ uint8_t nv3_render_read_pixel_8(nv3_position_16_t position, nv3_grobj_t grobj, bool use_destination) { @@ -435,165 +473,250 @@ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grob break; } + + /* Go write the pixel */ + nv3_size_16_t size = {0}; + size.w = size.h = 1; + nv3_render_current_bpp(&nv3->nvbase.svga, position, size, grobj); } +/* Ensure the correct monitor size */ +void nv3_render_ensure_mode() +{ + bool changed = false; //doesn't check if the res is the same? + + if (nv3->nvbase.svga.hdisp != nv3->nvbase.svga.monitor->mon_xsize) + { + changed = true; + nv3->nvbase.svga.monitor->mon_xsize = nv3->nvbase.svga.hdisp; + } + + if (nv3->nvbase.svga.dispend != nv3->nvbase.svga.monitor->mon_ysize) + { + changed = true; + nv3->nvbase.svga.monitor->mon_ysize = nv3->nvbase.svga.dispend; + } + + if (changed) + { + /* set refresh rate - this is just a rough estimation right now. we need it as we only blit what changes */ + nv3->nvbase.refresh_time = 1 / (nv3->nvbase.pixel_clock_frequency / (double)ysize / (double)xsize); // rivatimers count in microseconds + set_screen_size(xsize, ysize); + } + +} + + +/* Blit to the monitor from DFB, 8bpp */ +void nv3_render_current_bpp_dfb_8(uint32_t address) +{ + +} + +/* Blit to the monitor from DFB, 15/16bpp */ +void nv3_render_current_bpp_dfb_16(uint32_t address) +{ + nv3_size_16_t size = {0}; + size.w = size.h = 1; + + nv3_position_16_t pos = nv3_render_get_dfb_position(address); + + //pos.x >>= 1; + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + if ((nv3->pramdac.general_control >> NV3_PRAMDAC_GENERAL_CONTROL_565_MODE) & 0x01) + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 16); + else + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 15); + + /*does 8bpp packed into 16 occur/ i would be surprised*/ +} + +/* Blit to the monitor from DFB, 32bpp */ +void nv3_render_current_bpp_dfb_32(uint32_t address) +{ + nv3_size_16_t size = {0}; + size.w = size.h = 1; + + nv3_position_16_t pos = nv3_render_get_dfb_position(address); + + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + if (nv3->nvbase.svga.bpp == 32) + { + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + *p = data; + } + /* Packed format */ + else if (nv3->nvbase.svga.bpp == 15 + || nv3->nvbase.svga.bpp == 16) + { + //pos.x >>= 1; + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, nv3->nvbase.svga.bpp); + *p++; + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, (data >> 16) & 0xFFFF, nv3->nvbase.svga.bpp); + } +} + + +/* Blit to the monitor from GPU, current bpp */ +void nv3_render_current_bpp(svga_t *svga, nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) +{ + /* Ensure that we are in the correct mode. Modified SVGA core code */ + nv3_render_ensure_mode(); + + switch (nv3->nvbase.svga.bpp) + { + case 4: + /* Uh we should never be here because we're in the SVGA mode */ + fatal("NV3 - Tried to render 4bpp in NV mode"); + break; + case 8: + nv3_render_8bpp(pos, size, grobj); + break; + case 15: + nv3_render_15bpp(pos, size, grobj); + break; + case 16: + nv3_render_16bpp(pos, size, grobj); + break; + case 32: + nv3_render_32bpp(pos, size, grobj); + break; + } + +} /* - Modified SVGA Core functions - Done, to facilitate the buffer changing around stuff. - - TODO: Do we need a custom 8bpp function? + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, indexed 8 bits per pixel format */ -void nv3_render_15bpp(svga_t *svga) +void nv3_render_8bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) { - int x; - uint32_t *p; - uint32_t dat; - uint32_t changed_addr; - uint32_t addr; + +} - /* "force_old_addr" code path removed, since we don't need it */ +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, 15 bits per pixel format +*/ - if ((svga->displine + svga->y_add) < 0) - return; +void nv3_render_15bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) +{ + if (!nv3) + return; - changed_addr = svga->remap_func(svga, svga->ma); + uint32_t vram_base; //acquired for the start of each line + uint32_t* p; + uint32_t data; + uint32_t start_x = pos.x; - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + for (uint32_t y = 0; y < size.h; y++) + { + /* re-set the vram address because we are basically "jumping" halfway across a line here */ + vram_base = nv3_render_get_vram_address(pos, grobj, true) & nv3->nvbase.svga.vram_display_mask; - if (!svga->remap_required) { - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); - *p++ = svga->conv_16to32(svga, dat >> 16, 15); + for (uint32_t x = 0; x < size.w; x++) + { + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); - *p++ = svga->conv_16to32(svga, dat >> 16, 15); - - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); - *p++ = svga->conv_16to32(svga, dat >> 16, 15); - - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); - *p++ = svga->conv_16to32(svga, dat >> 16, 15); - } - svga->ma += x << 1; - } else { - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { - addr = svga->remap_func(svga, svga->ma); - dat = *(uint32_t *) (&svga->vram[(addr) & svga->vram_display_mask]); - - *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); - *p++ = svga->conv_16to32(svga, dat >> 16, 15); - svga->ma += 4; - } + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; + + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 15); + + vram_base += 2; + pos.x++; } - svga->ma &= svga->vram_display_mask; + + pos.x = start_x; + pos.y++; } } +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, 16 bits per pixel format +*/ -void nv3_render_16bpp(svga_t *svga) -{ - int x; - uint32_t *p; - uint32_t dat; - uint32_t changed_addr; - uint32_t addr; +void nv3_render_16bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) +{ + if (!nv3) + return; - if ((svga->displine + svga->y_add) < 0) - return; + uint32_t vram_base; //acquired for the start of each line + uint32_t* p; + uint32_t data; + uint32_t start_x = pos.x; - changed_addr = svga->remap_func(svga, svga->ma); + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - /* "force_old_addr" code path removed, since we don't need it */ - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + for (uint32_t y = 0; y < size.h; y++) + { + /* re-get the vram address because we are basically "jumping" halfway across a line here */ + vram_base = nv3_render_get_vram_address(pos, grobj, true) & nv3->nvbase.svga.vram_display_mask; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + for (uint32_t x = 0; x < size.w; x++) + { + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - if (!svga->remap_required) { - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); - *p++ = svga->conv_16to32(svga, dat >> 16, 16); - - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); - *p++ = svga->conv_16to32(svga, dat >> 16, 16); - - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); - *p++ = svga->conv_16to32(svga, dat >> 16, 16); - - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); - *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); - *p++ = svga->conv_16to32(svga, dat >> 16, 16); - } - svga->ma += x << 1; - } else { - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { - addr = svga->remap_func(svga, svga->ma); - dat = *(uint32_t *) (&svga->vram[(addr) & svga->vram_display_mask]); - - *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); - *p++ = svga->conv_16to32(svga, dat >> 16, 16); - - svga->ma += 4; - } + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; + + /* should just "tip over" to the next line */ + *p = nv3->nvbase.svga.conv_16to32(&nv3->nvbase.svga, data & 0xFFFF, 15); + + vram_base += 2; + pos.x++; } - svga->ma &= svga->vram_display_mask; - } + + pos.x = start_x; + pos.y++; + } } +/* + Blit a certain region from the (destination buffer base + (position in vram)) to the 86Box monitor, 32 bits per pixel format +*/ -void nv3_render_32bpp(svga_t *svga) +void nv3_render_32bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) { - int x; - uint32_t *p; - uint32_t dat; - uint32_t changed_addr; - uint32_t addr; + if (!nv3) + return; - if ((svga->displine + svga->y_add) < 0) - return; + uint32_t vram_base; + uint32_t* p; + uint32_t data; + uint32_t start_x = pos.x; - /* "force_old_addr" code path removed, since we don't need it */ + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - changed_addr = svga->remap_func(svga, svga->ma); + for (uint32_t y = 0; y < size.h; y++) + { + /* re-get the vram address because we are basically "jumping" halfway across a line here */ + vram_base = nv3_render_get_vram_address(pos, grobj, true) & nv3->nvbase.svga.vram_display_mask; + - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + for (uint32_t x = 0; x < size.w; x++) + { + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - if (!svga->remap_required) { - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); - *p++ = svga_lookup_lut_ram(svga, dat & 0xffffff); - } - svga->ma += (x * 4); - } else { - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - addr = svga->remap_func(svga, svga->ma); - dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); - *p++ = svga_lookup_lut_ram(svga, dat & 0xffffff); - - svga->ma += 4; - } + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; + + /* should just "tip over" to the next line */ + *p = data; + + vram_base += 4; + pos.x++; } - svga->ma &= svga->vram_display_mask; + + pos.y++; + pos.x = start_x; } } diff --git a/src/video/nv/nv3/render/nv3_render_primitives.c b/src/video/nv/nv3/render/nv3_render_primitives.c index 487f41731..c89fd2d6e 100644 --- a/src/video/nv/nv3/render/nv3_render_primitives.c +++ b/src/video/nv/nv3/render/nv3_render_primitives.c @@ -119,6 +119,7 @@ void nv3_render_gdi_transparent_bitmap_blit(bool bit, bool clip, uint32_t color, else nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_d.x; } + } /* Originally written 23 March 2025, but then, redone, properly, on 30 March 2025 */ @@ -208,6 +209,7 @@ void nv3_render_gdi_transparent_bitmap(bool clip, uint32_t color, uint32_t bitma /* IF we're done, let's return */ if (!bits_remaining_in_bitmap) return; + } void nv3_render_gdi_1bpp_bitmap_blit(bool bit, uint32_t color0, uint32_t color1, nv3_grobj_t grobj) @@ -262,6 +264,7 @@ void nv3_render_gdi_1bpp_bitmap_blit(bool bit, uint32_t color0, uint32_t color1, } } + /* Originally written 23 March 2025, but then, redone, properly, on 30 March 2025 */ void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj) { diff --git a/src/video/nv/nv3/subsystems/nv3_pramdac.c b/src/video/nv/nv3/subsystems/nv3_pramdac.c index 0e41807a0..d1fb9f1c5 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramdac.c +++ b/src/video/nv/nv3/subsystems/nv3_pramdac.c @@ -51,6 +51,23 @@ void nv3_pramdac_init() // Polls the pixel clock. void nv3_pramdac_pixel_clock_poll(double real_time) { + /* Ignore in VGA mode */ + if (!nv3->nvbase.svga.override) + return; + + /* Figure out our refresh time. */ + if (!nv3->nvbase.refresh_time) + nv3->nvbase.refresh_time = (1/60.0); // rivatimers count in microseconds but present the info as seconds + + nv3->nvbase.refresh_clock += real_time; + + if (nv3->nvbase.refresh_clock > nv3->nvbase.refresh_time) + { + /* Update the screen because something changed */ + video_blit_memtoscreen(0, 0, xsize, ysize); + nv3->nvbase.refresh_clock = 0; + } + // TODO: ???? }