From d470c9067913e6791ca7a128f7fb2de47675acf1 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Tue, 12 Aug 2025 20:57:36 +0100 Subject: [PATCH] Partially fix S2SB. Makes Windows 95 behave a lot better! --- src/include/86box/nv/render/vid_nv3_render.h | 3 + src/include/86box/nv/vid_nv3.h | 80 ++++++++---- src/include/86box/utils/video_stdlib.h | 3 + .../classes/nv3_class_01c_image_in_memory.c | 2 +- src/video/nv/nv3/nv3_core_arbiter.c | 16 +-- src/video/nv/nv3/render/nv3_render_blit.c | 4 +- src/video/nv/nv3/render/nv3_render_core.c | 116 ++++++++++++++++-- src/video/nv/nv3/subsystems/nv3_pgraph.c | 8 +- 8 files changed, 186 insertions(+), 46 deletions(-) diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h index 9c7af77ab..e0b28edd0 100644 --- a/src/include/86box/nv/render/vid_nv3_render.h +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -39,6 +39,9 @@ uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded); nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj); // Convert a colour to full RGB10 format from the current working format. uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t color); // Convert a colour from the current working format to RGB10 format. +/* ROP */ +uint8_t nv3_render_translate_nvrop(nv3_grobj_t grobj, uint32_t rop); + /* Pattern */ void nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1); diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index 8e3bd87da..48170bfcd 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -607,24 +607,58 @@ extern const device_config_t nv3t_config[]; // Confi #define NV3_PGRAPH_INTR_EN_0 0x400140 // Interrupt Control for PGRAPH #1 //todo: add what this does #define NV3_PGRAPH_INTR_EN_1 0x400144 // Interrupt Control for PGRAPH #2 (it can receive two at onc) -#define NV3_PGRAPH_CONTEXT_SWITCH 0x400180 // Holds the current PGRAPH context, switched by context switching +#define NV3_PGRAPH_CTX_SWITCH 0x400180 // Holds the current PGRAPH context, switched by context switching /* Contextual information for pgraph */ -#define NV3_PGRAPH_CONTEXT_SWITCH_COLOR_FORMAT 2 // Holds the current color format used for drawing operations. -#define NV3_PGRAPH_CONTEXT_SWITCH_ALPHA 3 // Holds a boolean if alpha transparency is currently enabled in drawing operations. -#define NV3_PGRAPH_CONTEXT_SWITCH_MONO_FORMAT 8 // Holds the current color format used for monochome drawing operations. -#define NV3_PGRAPH_CONTEXT_SWITCH_DAC_BYPASS 9 // Holds if PRAMDAC should be bypassed, and an external DAC drawn. -#define NV3_PGRAPH_CONTEXT_SWITCH_Z_WRITE 12 // Holds if we should write back to the zbuffer. -#define NV3_PGRAPH_CONTEXT_SWITCH_CHROMA_KEY 13 // Holds the current chroma mask used for drawing operations. -#define NV3_PGRAPH_CONTEXT_SWITCH_PLANE_MASK 14 // Holds the current plane mask used for drawing operations. -#define NV3_PGRAPH_CONTEXT_SWITCH_USER_CLIP 15 // Holds the user-specified clipping information used for drawing operations. -#define NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER 16 // Holds the buffer ID used for drawing operation (i.e. which bpixel/bpitch/boffset index to use) -#define NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER0_ENABLED 20 // Holds a boolean indicating if buffer 0 can be used as the destination for a drawing operation. -#define NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER1_ENABLED 21 // Holds a boolean indicating if buffer 1 can be used as the destination for a drawing operation. -#define NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER2_ENABLED 22 // Holds a boolean indicating if buffer 2 can be used as the destination for a drawing operation. -#define NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER3_ENABLED 23 // Holds a boolean indicating if buffer 3 can be used as the destination for a drawing operation. -#define NV3_PGRAPH_CONTEXT_SWITCH_PATCH_CONFIG 24 // Something to do with an operation to do during a patchcord? -#define NV3_PGRAPH_CONTEXT_SWITCH_VOLATILE 31 // HUH +#define NV3_PGRAPH_CTX_SWITCH_COLOR_FORMAT 0 // Holds the current color format used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_ALPHA 3 // Holds a boolean indicating in if alpha transparency is currently enabled in drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_MONO_FORMAT 8 // Holds the current color format used for monochome drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_DAC_BYPASS 9 // Holds if PRAMDAC should be bypassed, and an external DAC drawn. +#define NV3_PGRAPH_CTX_SWITCH_Z_WRITE 12 // Holds if we should write back to the zbuffer. +#define NV3_PGRAPH_CTX_SWITCH_CHROMA_KEY 13 // Holds the current chroma mask used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_PLANE_MASK 14 // Holds the current plane mask used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_USER_CLIP 15 // Holds the user-specified clipping information used for drawing operations. +#define NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER 16 // Holds the buffer ID used for drawing operation (i.e. which bpixel/bpitch/boffset index to use) +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER0_ENABLED 20 // Holds a boolean indicating if buffer 0 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER1_ENABLED 21 // Holds a boolean indicating if buffer 1 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER2_ENABLED 22 // Holds a boolean indicating if buffer 2 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_DST_BUFFER3_ENABLED 23 // Holds a boolean indicating if buffer 3 can be used as the destination for a drawing operation. +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG 24 // ROP type + +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0 0x0 // Reserved +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_DST_SRC 0x1 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_DST 0x2 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_SRC 0x3 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_DST 0x4 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_SRC 0x5 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_DST 0x6 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_SRC0 0x7 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_SRC1 0x8 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_SRC_PAT 0x9 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_SRC 0xA +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_PAT 0xB +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_SRC 0xC +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_PAT 0xD +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_PAT_SRC 0xE +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD1 0xF +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_DST 0x10 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_DST_SRC 0x11 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_DST 0x12 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_PAT 0x13 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_PAT_SRC 0x14 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_PAT 0x15 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD2 0x16 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS 0x17 // Ignore +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD0 0x18 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_SRC_DST 0x19 +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_DST_SRC 0x1A +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD1 0x1B +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD2 0x1C +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_SRC 0x1D +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD3 0x1E +#define NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD4 0x1F + +#define NV3_PGRAPH_CTX_SWITCH_VOLATILE 31 // HUH #define NV3_PGRAPH_CONTEXT_CONTROL 0x400190 // DMA context control #define NV3_PGRAPH_CONTEXT_USER 0x400194 // Current DMA context state, may rename @@ -1166,10 +1200,10 @@ typedef struct nv3_pramdac_s } nv3_pramdac_t; /* Holds DMA channel context information */ -typedef struct nv3_pgraph_context_switch_s +typedef struct NV3_PGRAPH_CTX_SWITCH_s { /* TODO */ -} nv3_pgraph_context_switch_t; +} NV3_PGRAPH_CTX_SWITCH_t; typedef struct nv3_pgraph_context_control_s { @@ -1251,10 +1285,10 @@ typedef enum nv3_pgraph_bpixel_format_e typedef enum nv3_pgraph_destination_buffer_e { - pgraph_dest_buffer0 = (1 << NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER0_ENABLED), - pgraph_dest_buffer1 = (1 << NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER1_ENABLED), - pgraph_dest_buffer2 = (1 << NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER2_ENABLED), - pgraph_dest_buffer3 = (1 << NV3_PGRAPH_CONTEXT_SWITCH_DST_BUFFER3_ENABLED), + pgraph_dest_buffer0 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER0_ENABLED), + pgraph_dest_buffer1 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER1_ENABLED), + pgraph_dest_buffer2 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER2_ENABLED), + pgraph_dest_buffer3 = (1 << NV3_PGRAPH_CTX_SWITCH_DST_BUFFER3_ENABLED), } nv3_pgraph_destination_buffer; // Graphics Subsystem @@ -1273,7 +1307,7 @@ typedef struct nv3_pgraph_s uint32_t context_switch; // TODO: Make this a struct, it's just going to be enormous lol. nv3_pgraph_context_control_t context_control; - nv3_pgraph_context_switch_t context_user_submit; + NV3_PGRAPH_CTX_SWITCH_t context_user_submit; nv3_pgraph_context_user_t context_user; uint32_t context_cache[NV3_PGRAPH_CONTEXT_CACHE_SIZE]; // DMA context cache (nv3_pgraph_context_user_t array?) diff --git a/src/include/86box/utils/video_stdlib.h b/src/include/86box/utils/video_stdlib.h index 4434ef43f..0d4b148d6 100644 --- a/src/include/86box/utils/video_stdlib.h +++ b/src/include/86box/utils/video_stdlib.h @@ -17,4 +17,7 @@ /* ROP */ + +#define VIDEO_ROP_SRC_COPY 0xCC + int32_t video_rop_gdi_ternary(int32_t rop, int32_t src, int32_t dst, int32_t pattern); \ No newline at end of file diff --git a/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c b/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c index eb7f266d2..12ac3fe6b 100644 --- a/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c +++ b/src/video/nv/nv3/classes/nv3_class_01c_image_in_memory.c @@ -31,7 +31,7 @@ void nv3_class_01c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_t context, nv3_grobj_t grobj) { /* We need this for a lot of methods, so may as well store it here. */ - uint32_t src_buffer_id = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER) & 0x03; + uint32_t src_buffer_id = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER) & 0x03; switch (method_id) diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c index e23386cac..3399ca9fe 100644 --- a/src/video/nv/nv3/nv3_core_arbiter.c +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -108,11 +108,11 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address) else { //nvplay stuff - #ifdef ENABLE_NV_LOG_ULTRA - warning("MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning unmapped pattern]\n", address); - #else + //#ifdef ENABLE_NV_LOG_ULTRA + //warning("MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning unmapped pattern]\n", address); + //#else nv_log("MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning unmapped pattern]\n", address); - #endif + //#endif // The real hardware returns a garbage pattern return 0x00; @@ -181,11 +181,11 @@ void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value) else { //nvplay stuff - #ifdef ENABLE_NV_LOG_ULTRA - warning("MMIO write arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address); - #else + //#ifdef ENABLE_NV_LOG_ULTRA + //warning("MMIO write arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address); + //#else nv_log("MMIO write arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address); - #endif + //#endif return; } diff --git a/src/video/nv/nv3/render/nv3_render_blit.c b/src/video/nv/nv3/render/nv3_render_blit.c index 0896bd199..92b657cd0 100644 --- a/src/video/nv/nv3/render/nv3_render_blit.c +++ b/src/video/nv/nv3/render/nv3_render_blit.c @@ -121,12 +121,12 @@ uint32_t nv3_s2sb_line_buffer[NV3_MAX_HORIZONTAL_SIZE*NV3_MAX_VERTICAL_SIZE] = { void nv3_render_blit_screen2screen_for_buffer(nv3_grobj_t grobj, uint32_t dst_buffer) { -if (nv3->pgraph.blit.size.x < NV3_MAX_HORIZONTAL_SIZE + if (nv3->pgraph.blit.size.x < NV3_MAX_HORIZONTAL_SIZE && nv3->pgraph.blit.size.y < NV3_MAX_VERTICAL_SIZE) memset(&nv3_s2sb_line_buffer, 0x00, (sizeof(uint32_t) * nv3->pgraph.blit.size.y) * (sizeof(uint32_t) * nv3->pgraph.blit.size.x)); /* First calculate our source and destination buffer */ - uint32_t src_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER) & 0x03; + uint32_t src_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER) & 0x03; nv3_coord_16_t in_position = nv3->pgraph.blit.point_in; nv3_coord_16_t out_position = nv3->pgraph.blit.point_out; diff --git a/src/video/nv/nv3/render/nv3_render_core.c b/src/video/nv/nv3/render/nv3_render_core.c index 862d83371..db7bdb06d 100644 --- a/src/video/nv/nv3/render/nv3_render_core.c +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -44,7 +44,7 @@ nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj) // grobj0 = seems to share the format of PGRAPH_CONTEXT_SWITCH register. uint8_t format = (grobj.grobj_0 & 0x07); - bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_ALPHA) & 0x01; + bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_ALPHA) & 0x01; nv3_color_expanded_t color_final; // set the pixel format @@ -119,7 +119,7 @@ nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj) uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t color) { uint8_t format = (grobj.grobj_0 & 0x07); - bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_ALPHA) & 0x01; + bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_ALPHA) & 0x01; nv_log_verbose_only("Downconverting Colour 0x%08x using pgraph_pixel_format 0x%x alpha enabled=%d\n", color, format, alpha_enabled); @@ -168,7 +168,7 @@ uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t co /* Runs the chroma key/color key test */ bool nv3_render_chroma_test(uint32_t color, nv3_grobj_t grobj) { - bool chroma_enabled = ((grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_CHROMA_KEY) & 0x01); + bool chroma_enabled = ((grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_CHROMA_KEY) & 0x01); if (!chroma_enabled) return true; @@ -239,7 +239,7 @@ uint32_t nv3_render_get_vram_address(nv3_coord_16_t position, nv3_grobj_t grobj) { uint32_t vram_x = position.x; uint32_t vram_y = position.y; - uint32_t current_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER) & 0x03; + uint32_t current_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_SRC_BUFFER) & 0x03; uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; @@ -359,7 +359,7 @@ uint32_t nv3_render_read_pixel_32(nv3_coord_16_t position, nv3_grobj_t grobj) void nv3_render_write_pixel_to_buffer(nv3_coord_16_t position, uint32_t color, nv3_grobj_t grobj, uint32_t buffer) { - bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_ALPHA) & 0x01; + bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_ALPHA) & 0x01; int32_t clip_end_x = nv3->pgraph.clip_start.x + nv3->pgraph.clip_size.x; int32_t clip_end_y = nv3->pgraph.clip_start.y + nv3->pgraph.clip_size.y; @@ -428,6 +428,9 @@ void nv3_render_write_pixel_to_buffer(nv3_coord_16_t position, uint32_t color, n We use the pixel format of the destination buffer to achieve this (thanks frostbite2000) */ + // translate the patch config to GDI rop + uint32_t final_rop = nv3_render_translate_nvrop(grobj, nv3->pgraph.rop); + uint32_t destination_format = (nv3->pgraph.bpixel[buffer]) & 0x03; switch (destination_format) @@ -435,7 +438,7 @@ void nv3_render_write_pixel_to_buffer(nv3_coord_16_t position, uint32_t color, n case bpixel_fmt_8bit: rop_src = color & 0xFF; rop_dst = nv3->nvbase.svga.vram[pixel_addr_vram]; - nv3->nvbase.svga.vram[pixel_addr_vram] = video_rop_gdi_ternary(nv3->pgraph.rop, rop_src, rop_dst, rop_pattern) & 0xFF; + nv3->nvbase.svga.vram[pixel_addr_vram] = video_rop_gdi_ternary(final_rop, rop_src, rop_dst, rop_pattern) & 0xFF; nv3->nvbase.svga.changedvram[pixel_addr_vram >> 12] = changeframecount; @@ -464,7 +467,7 @@ void nv3_render_write_pixel_to_buffer(nv3_coord_16_t position, uint32_t color, n rop_dst = vram_16[pixel_addr_vram]; - vram_16[pixel_addr_vram] = video_rop_gdi_ternary(nv3->pgraph.rop, rop_src, rop_dst, rop_pattern) & 0xFFFF; + vram_16[pixel_addr_vram] = video_rop_gdi_ternary(final_rop, rop_src, rop_dst, rop_pattern) & 0xFFFF; nv3->nvbase.svga.changedvram[pixel_addr_vram >> 11] = changeframecount; @@ -477,7 +480,7 @@ void nv3_render_write_pixel_to_buffer(nv3_coord_16_t position, uint32_t color, n rop_src = color; rop_dst = vram_32[pixel_addr_vram]; - vram_32[pixel_addr_vram] = video_rop_gdi_ternary(nv3->pgraph.rop, rop_src, rop_dst, rop_pattern); + vram_32[pixel_addr_vram] = video_rop_gdi_ternary(final_rop, rop_src, rop_dst, rop_pattern); nv3->nvbase.svga.changedvram[pixel_addr_vram >> 10] = changeframecount; @@ -789,3 +792,100 @@ void nv3_render_32bpp(uint32_t vram_start, nv3_coord_16_t screen_size) } } } + +// Translate an "NV-ROP" into a GDI Ternary ROP +uint8_t nv3_render_translate_nvrop(nv3_grobj_t grobj, uint32_t rop) +{ + // Credit to envytools for this function: + // https://github.com/envytools/envytools/blob/f102b82381f3f11cee113d16374c87091db039d9/nvhw/pgraph.c + // How does one even go about reverse engineering this (I'm sure the behaviour is simpler when you don't have to translate this but...) Marcelina is a legend. + + uint32_t patch_config_rop = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG) & 0x1F; + + /* || patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0*/ + + // TODO: Blending + if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS) // 0x00 is used for "nothing here" it seems. + return VIDEO_ROP_SRC_COPY; + + uint8_t res = 0; + + int32_t swizzle[3]; + + if (patch_config_rop < 8) { + swizzle[0] = patch_config_rop >> 0 & 1; + swizzle[1] = patch_config_rop >> 1 & 1; + swizzle[2] = patch_config_rop >> 2 & 1; + } else if (patch_config_rop < 0x10) { + swizzle[0] = (patch_config_rop >> 0 & 1) + 1; + swizzle[1] = (patch_config_rop >> 1 & 1) + 1; + swizzle[2] = (patch_config_rop >> 2 & 1) + 1; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_DST) { + swizzle[0] = 0, swizzle[1] = 1, swizzle[2] = 2; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_DST_SRC) { + swizzle[0] = 1, swizzle[1] = 0, swizzle[2] = 2; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_PAT_DST) { + swizzle[0] = 0, swizzle[1] = 2, swizzle[2] = 1; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_DST_PAT) { + swizzle[0] = 2, swizzle[1] = 0, swizzle[2] = 1; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_PAT_SRC) { + swizzle[0] = 1, swizzle[1] = 2, swizzle[2] = 0; + } else if (patch_config_rop == NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_DST_SRC_PAT) { + swizzle[0] = 2, swizzle[1] = 1, swizzle[2] = 0; + } else { + warning("NV3 ROP: Invalid patch configuration %02x!", rop); + } + if (patch_config_rop == 0) { + if (rop & 0x01) + res |= 0x11; + if (rop & 0x16) + res |= 0x44; + if (rop & 0x68) + res |= 0x22; + if (rop & 0x80) + res |= 0x88; + } else if (patch_config_rop == 0xf) { + if (rop & 0x01) + res |= 0x03; + if (rop & 0x16) + res |= 0x0c; + if (rop & 0x68) + res |= 0x30; + if (rop & 0x80) + res |= 0xc0; + } else { + int32_t i; + for (i = 0; i < 8; i++) { + int32_t s0 = i >> swizzle[0] & 1; + int32_t s1 = i >> swizzle[1] & 1; + int32_t s2 = i >> swizzle[2] & 1; + int32_t s = s2 << 2 | s1 << 1 | s0; + if (rop >> s & 1) + res |= 1 << i; + } + } + return res; + + /* + uint32_t patch_config = (grobj.grobj_0 >> NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG) & 0x1F; + + // Wtf do these even do? + switch (patch_config) + { + // don't do anything + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_SRC_BYPASS: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD0: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD1: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_RSVD2: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD0: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD1: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD2: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD3: + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_BLEND_RSVD4: + return src; + case NV3_PGRAPH_CTX_SWITCH_PATCH_CONFIG_PAT_SRC_DST: // S2SB + break; + + } + */ +} \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pgraph.c b/src/video/nv/nv3/subsystems/nv3_pgraph.c index dbca46216..3ad9fa2a1 100644 --- a/src/video/nv/nv3/subsystems/nv3_pgraph.c +++ b/src/video/nv/nv3/subsystems/nv3_pgraph.c @@ -51,7 +51,7 @@ nv_register_t pgraph_registers[] = { { NV3_PGRAPH_INTR_EN_0, "PGRAPH Interrupt Enable 0", NULL, NULL }, { NV3_PGRAPH_INTR_1, "PGRAPH Interrupt Status 1", NULL, NULL }, { NV3_PGRAPH_INTR_EN_1, "PGRAPH Interrupt Enable 1", NULL, NULL }, - { NV3_PGRAPH_CONTEXT_SWITCH, "PGRAPH DMA Context Switch", NULL, NULL }, + { NV3_PGRAPH_CTX_SWITCH, "PGRAPH DMA Context Switch", NULL, NULL }, { NV3_PGRAPH_CONTEXT_CONTROL, "PGRAPH DMA Context Control", NULL, NULL }, { NV3_PGRAPH_CONTEXT_USER, "PGRAPH DMA Context User", NULL, NULL }, //{ NV3_PGRAPH_CONTEXT_CACHE(0), "PGRAPH DMA Context Cache", NULL, NULL }, @@ -156,7 +156,7 @@ uint32_t nv3_pgraph_read(uint32_t address) // In the future, these will most likely have their own functions... // Context Swithcing (THIS IS CONTROLLED BY PFIFO!) - case NV3_PGRAPH_CONTEXT_SWITCH: + case NV3_PGRAPH_CTX_SWITCH: ret = nv3->pgraph.context_switch; break; case NV3_PGRAPH_CONTEXT_CONTROL: @@ -359,7 +359,7 @@ void nv3_pgraph_write(uint32_t address, uint32_t value) // In the future, these will most likely have their own functions... // Context Swithcing (THIS IS CONTROLLED BY PFIFO!) - case NV3_PGRAPH_CONTEXT_SWITCH: + case NV3_PGRAPH_CTX_SWITCH: nv3->pgraph.context_switch = value; break; case NV3_PGRAPH_CONTEXT_CONTROL: @@ -625,7 +625,7 @@ void nv3_pgraph_submit(uint32_t param, uint16_t method, uint8_t channel, uint8_t switch (method) { default: - // Object Method orchestration + // Object Method arbitration nv3_pgraph_arbitrate_method(param, method, channel, subchannel, class_id, context); break; }