mirror of
https://github.com/86Box/86Box.git
synced 2026-02-23 01:48:21 -07:00
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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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:
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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: ????
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user