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)

This commit is contained in:
starfrost013
2025-04-09 21:29:46 +01:00
parent c1506772de
commit 911a71c67f
9 changed files with 378 additions and 152 deletions

View File

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

View File

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

View File

@@ -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();
void nv3_pme_init(void);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: ????
}