diff --git a/src/include/86box/nv/classes/vid_nv3_classes.h b/src/include/86box/nv/classes/vid_nv3_classes.h index 83d378031..5e564fe29 100644 --- a/src/include/86box/nv/classes/vid_nv3_classes.h +++ b/src/include/86box/nv/classes/vid_nv3_classes.h @@ -113,6 +113,11 @@ typedef enum nv3_pgraph_class_e #define NV3_RECTANGLE_MAX 16 #define NV3_RECTANGLE_END 0x0480 +// blit +#define NV3_BLIT_POSITION_IN 0x0300 +#define NV3_BLIT_POSITION_OUT 0x0304 +#define NV3_BLIT_SIZE 0x0308 + // image_from_cpu #define NV3_IMAGE_START_POSITION 0x0304 // starting position of image from cpu #define NV3_IMAGE_SIZE 0x0308 diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h index c5741f30c..e1cb0f65f 100644 --- a/src/include/86box/nv/render/vid_nv3_render.h +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -18,15 +18,25 @@ #pragma once /* Core */ -void nv3_render_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj); +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); +uint16_t nv3_render_read_pixel_16(nv3_position_16_t position, nv3_grobj_t grobj); +uint32_t nv3_render_read_pixel_32(nv3_position_16_t position, nv3_grobj_t grobj); + uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded); nv3_color_expanded_t nv3_render_expand_color(nv3_grobj_t grobj, uint32_t color); // 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. + + /* Pattern */ uint32_t nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1); /* Primitives */ void nv3_render_rect(nv3_position_16_t position, nv3_size_16_t size, uint32_t color, nv3_grobj_t grobj); -void nv3_render_chroma_test(nv3_grobj_t grobj); \ No newline at end of file +/* Chroma */ +void nv3_render_chroma_test(nv3_grobj_t grobj); + +/* Blit */ +void nv3_render_blit_screen2screen(nv3_grobj_t grobj); \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index ed8d9c4fc..aa59f7e69 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -569,10 +569,10 @@ extern const device_config_t nv3_config[]; #define NV3_PGRAPH_SRC_CANVAS_MAX 0x400554 // Maximum Source Canvas for Blit, Y=30:16, X=10:0 #define NV3_PGRAPH_DST_CANVAS_MIN 0x400558 // Minimum Destination Canvas for Blit, Y=30:16, X=10:0 #define NV3_PGRAPH_DST_CANVAS_MAX 0x40055C // Maximum Destination Canvas for Blit, Y=30:16, X=10:0 -#define NV3_PGRAPH_pattern_color_0_rgb 0x400600 -#define NV3_PGRAPH_pattern_color_0_alpha 0x400604 -#define NV3_PGRAPH_pattern_color_1_rgb 0x400608 -#define NV3_PGRAPH_pattern_color_1_alpha 0x40060C // pattern color +#define NV3_PGRAPH_PATTERN_COLOR_0_RGB 0x400600 +#define NV3_PGRAPH_PATTERN_COLOR_0_ALPHA 0x400604 +#define NV3_PGRAPH_PATTERN_COLOR_1_RGB 0x400608 +#define NV3_PGRAPH_PATTERN_COLOR_1_ALPHA 0x40060C // pattern color #define NV3_PGRAPH_PATTERN_BITMAP_HIGH 0x400610 // pattern bitmap [31:0] #define NV3_PGRAPH_PATTERN_BITMAP_LOW 0x400614 // pattern bitmap [63:32] #define NV3_PGRAPH_PATTERN_SHAPE 0x400618 @@ -1183,7 +1183,7 @@ typedef struct nv3_pgraph_s uint64_t pattern_bitmap; // pattern bitmap for blit. it's alwaus 64 bits to simplify pixel rendering code uint32_t pattern_shape; // may need to be an enum - 0=8x8, 1=64x1, 2=1x64 uint32_t plane_mask; // only 7:0 relevant - uint32_t chroma_key; // color key + uint32_t chroma_key; // color key uint32_t beta_factor; nv3_pgraph_dma_settings_t dma_settings; uint8_t rop; // Current GDI Ternary Render Operation diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 43e7cf2a0..2e6d3af08 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -128,7 +128,9 @@ add_library(vid OBJECT nv/nv3/classes/nv3_class_01c_image_in_memory.c nv/nv3/render/nv3_render_core.c - nv/nv3/render/nv3_render_primitives.c + nv/nv3/render/nv3_render_primitives.c + nv/nv3/render/nv3_render_blit.c + ) if(G100) 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 3ff52f68a..0f15e82d6 100644 --- a/src/video/nv/nv3/classes/nv3_class_010_blit.c +++ b/src/video/nv/nv3/classes/nv3_class_010_blit.c @@ -32,6 +32,22 @@ void nv3_class_010_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ { switch (method_id) { + case NV3_BLIT_POSITION_IN: + nv3->pgraph.blit.point_in.x = (param & 0xFFFF); + nv3->pgraph.blit.point_in.y = ((param >> 16) & 0xFFFF); + break; + case NV3_BLIT_POSITION_OUT: + nv3->pgraph.blit.point_out.x = (param & 0xFFFF); + nv3->pgraph.blit.point_out.y = ((param >> 16) & 0xFFFF); + break; + case NV3_BLIT_SIZE: + /* This is the last one*/ + nv3->pgraph.blit.size.w = (param & 0xFFFF); + nv3->pgraph.blit.size.h = ((param >> 16) & 0xFFFF); + + nv3_render_blit_screen2screen(grobj); + + break; default: nv_log("%s: Invalid or Unimplemented method 0x%04x", nv3_class_names[context.class_id & 0x1F], method_id); nv3_pgraph_interrupt_invalid(NV3_PGRAPH_INTR_1_SOFTWARE_METHOD_PENDING); diff --git a/src/video/nv/nv3/classes/nv3_class_011_image.c b/src/video/nv/nv3/classes/nv3_class_011_image.c index 9b4446cff..dc865243e 100644 --- a/src/video/nv/nv3/classes/nv3_class_011_image.c +++ b/src/video/nv/nv3/classes/nv3_class_011_image.c @@ -81,22 +81,22 @@ void nv3_class_011_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ //pixel3 pixel3 = param & 0xFF; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel3, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel3, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); pixel2 = (param >> 8) & 0xFF; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel2, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel2, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); pixel1 = (param >> 16) & 0xFF; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel1, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel1, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); pixel0 = (param >> 24) & 0xFF; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel0, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel0, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); @@ -104,12 +104,12 @@ void nv3_class_011_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ //2pixels packed into 1 case 16: pixel1 = (param) & 0xFFFF; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel1, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel1, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); pixel0 = (param >> 16) & 0xFFFF; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel0, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel0, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); @@ -117,7 +117,7 @@ void nv3_class_011_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ // just one case 32: pixel0 = param; - nv3_render_pixel(nv3->pgraph.image_current_position, pixel0, grobj); + nv3_render_write_pixel(nv3->pgraph.image_current_position, pixel0, grobj); nv3->pgraph.image_current_position.x++; nv3_class_011_check_line_bounds(); diff --git a/src/video/nv/nv3/render/nv3_render_blit.c b/src/video/nv/nv3/render/nv3_render_blit.c new file mode 100644 index 000000000..ce836520b --- /dev/null +++ b/src/video/nv/nv3/render/nv3_render_blit.c @@ -0,0 +1,92 @@ +/* +* 86Box A hypervisor and IBM PC system emulator that specializes in +* running old operating systems and software designed for IBM +* PC systems and compatibles from 1981 through fairly recent +* system designs based on the PCI bus. +* +* This file is part of the 86Box distribution. +* +* NV3 Core rendering code (Software version) +* +* +* +* Authors: Connor Hyde, I need a better email address ;^) +* +* Copyright 2024-2025 Connor Hyde +*/ + +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/plat.h> +#include <86box/rom.h> +#include <86box/video.h> +#include <86box/nv/vid_nv.h> +#include <86box/nv/vid_nv3.h> + +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; + + uint16_t end_x = (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); + + /* Read the old pixel */ + switch (nv3->nvbase.svga.bpp) + { + case 8: //8bpp + for (int32_t y = nv3->pgraph.blit.point_out.y; y < end_y; y++) + { + old_position.y++; + new_position.y++; + + for (int32_t x = nv3->pgraph.blit.point_out.x; x < end_x; x++) + { + old_position.x++; + new_position.x++; + + uint32_t pixel_to_copy = nv3_render_read_pixel_8(old_position, grobj) & 0xFF; + nv3_render_write_pixel(new_position, pixel_to_copy, grobj); + } + } + break; + case 16: //16bpp + for (int32_t y = nv3->pgraph.blit.point_out.y; y < end_y; y++) + { + old_position.y++; + new_position.y++; + + for (int32_t x = nv3->pgraph.blit.point_out.x; x < end_x; x++) + { + old_position.x++; + new_position.x++; + + uint32_t pixel_to_copy = nv3_render_read_pixel_16(old_position, grobj) & 0xFFFF; + nv3_render_write_pixel(new_position, pixel_to_copy, grobj); + } + } + break; + case 32: //32bpp + for (int32_t y = nv3->pgraph.blit.point_out.y; y < end_y; y++) + { + old_position.y++; + new_position.y++; + + for (int32_t x = nv3->pgraph.blit.point_out.x; x < end_x; x++) + { + old_position.x++; + new_position.x++; + + uint32_t pixel_to_copy = nv3_render_read_pixel_32(old_position, grobj); + nv3_render_write_pixel(new_position, pixel_to_copy, grobj); + } + } + break; + } +} \ 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 741f8e422..c7ffd5f44 100644 --- a/src/video/nv/nv3/render/nv3_render_core.c +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -194,13 +194,71 @@ uint32_t nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool nv3->pgraph.pattern_color_1_rgb.g = pattern_colour.g; nv3->pgraph.pattern_color_1_rgb.b = pattern_colour.b; } - - } +/* /* Combine the current buffer with the pitch to get the address in the framebuffer to draw from for a given position. */ +uint32_t nv3_render_get_vram_address(nv3_position_16_t position, nv3_grobj_t grobj) +{ + uint32_t vram_x = position.x; + uint32_t current_buffer = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER) & 0x03; + uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; + + // we have to multiply the x position by the number of bytes per pixel + switch (framebuffer_bpp) + { + case 8: + break; + case 16: + vram_x = position.x << 1; + break; + case 32: + vram_x = position.x << 2; + break; + } + + uint32_t pixel_addr_vram = vram_x + (nv3->pgraph.bpitch[current_buffer] * position.y) + nv3->pgraph.boffset[current_buffer]; + + pixel_addr_vram &= nv3->nvbase.svga.vram_mask; + + return pixel_addr_vram; +} + +/* Read an 8bpp pixel from the framebuffer. */ +uint8_t nv3_render_read_pixel_8(nv3_position_16_t position, nv3_grobj_t grobj) +{ + // hope you call it with the right bit + uint32_t vram_address = nv3_render_get_vram_address(position, grobj); + + return nv3->nvbase.svga.vram[vram_address]; +} + +/* Read an 16bpp pixel from the framebuffer. */ +uint16_t nv3_render_read_pixel_16(nv3_position_16_t position, nv3_grobj_t grobj) +{ + // hope you call it with the right bit + uint32_t vram_address = nv3_render_get_vram_address(position, grobj); + + uint16_t* vram_16 = (uint16_t*)(nv3->nvbase.svga.vram); + vram_address >>= 1; //convert to 16bit pointer + + return vram_16[vram_address]; +} + +/* Read an 16bpp pixel from the framebuffer. */ +uint32_t nv3_render_read_pixel_32(nv3_position_16_t position, nv3_grobj_t grobj) +{ + // hope you call it with the right bit + uint32_t vram_address = nv3_render_get_vram_address(position, grobj); + + uint32_t* vram_32 = (uint32_t*)(nv3->nvbase.svga.vram); + vram_address >>= 1; //convert to 16bit pointer + + return vram_32[vram_address]; +} + /* Plots a pixel. */ -void nv3_render_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj) +void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj) { uint8_t alpha = 0xFF; @@ -213,7 +271,7 @@ void nv3_render_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t gr #endif bool alpha_enabled = (grobj.grobj_0 >> NV3_PGRAPH_CONTEXT_SWITCH_ALPHA) & 0x01; - uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; // maybe y16 too? + uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; // maybe y16 too?z uint32_t current_buffer = (nv3->pgraph.context_switch >> NV3_PGRAPH_CONTEXT_SWITCH_SRC_BUFFER) & 0x03; /* doesn't seem*/ @@ -238,26 +296,7 @@ void nv3_render_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t gr /* TODO: Chroma Key, Pattern, Plane Mask...*/ - /* Combine the current buffer with the pitch to get the address in the framebuffer to draw from. */ - - uint32_t vram_x = position.x; - - // we have to multiply the x position by the number of bytes per pixel - switch (framebuffer_bpp) - { - case 8: - break; - case 16: - vram_x = position.x << 1; - break; - case 32: - vram_x = position.x << 2; - break; - } - - uint32_t pixel_addr_vram = vram_x + (nv3->pgraph.bpitch[current_buffer] * position.y) + nv3->pgraph.boffset[current_buffer]; - - pixel_addr_vram &= nv3->nvbase.svga.vram_mask; + uint32_t pixel_addr_vram = nv3_render_get_vram_address(position, grobj); uint32_t rop_src = 0, rop_dst = 0, rop_pattern = 0; uint8_t bit = 0x00; diff --git a/src/video/nv/nv3/render/nv3_render_primitives.c b/src/video/nv/nv3/render/nv3_render_primitives.c index e44636acb..f4bfdebf4 100644 --- a/src/video/nv/nv3/render/nv3_render_primitives.c +++ b/src/video/nv/nv3/render/nv3_render_primitives.c @@ -40,7 +40,7 @@ void nv3_render_rect(nv3_position_16_t position, nv3_size_16_t size, uint32_t co { current_pos.x = x; - nv3_render_pixel(current_pos, color, grobj); + nv3_render_write_pixel(current_pos, color, grobj); } } } \ 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 70aef4270..251ec7a5f 100644 --- a/src/video/nv/nv3/subsystems/nv3_pgraph.c +++ b/src/video/nv/nv3/subsystems/nv3_pgraph.c @@ -63,10 +63,10 @@ nv_register_t pgraph_registers[] = { { NV3_PGRAPH_SRC_CANVAS_MAX, "PGRAPH Source Canvas Maximum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, { NV3_PGRAPH_DST_CANVAS_MIN, "PGRAPH Destination Canvas Minimum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, { NV3_PGRAPH_DST_CANVAS_MAX, "PGRAPH Destination Canvas Maximum Coordinates (Bits 30:16 = Y, Bits 10:0 = X)", NULL, NULL}, - { NV3_PGRAPH_pattern_color_0_rgb, "PGRAPH Pattern Color 0_0 (Bits 29:20 = Red, Bits 19:10 = Green, Bits 9:0 = Blue)", NULL, NULL, }, - { NV3_PGRAPH_pattern_color_0_alpha, "PGRAPH Pattern Color 0_1 (Bits 7:0 = Alpha)", NULL, NULL, }, - { NV3_PGRAPH_pattern_color_1_rgb, "PGRAPH Pattern Color 1_0 (Bits 29:20 = Red, Bits 19:10 = Green, Bits 9:0 = Blue)", NULL, NULL, }, - { NV3_PGRAPH_pattern_color_1_alpha, "PGRAPH Pattern Color 1_1 (Bits 7:0 = Alpha)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_0_RGB, "PGRAPH Pattern Color 0_0 (Bits 29:20 = Red, Bits 19:10 = Green, Bits 9:0 = Blue)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_0_ALPHA, "PGRAPH Pattern Color 0_1 (Bits 7:0 = Alpha)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_1_RGB, "PGRAPH Pattern Color 1_0 (Bits 29:20 = Red, Bits 19:10 = Green, Bits 9:0 = Blue)", NULL, NULL, }, + { NV3_PGRAPH_PATTERN_COLOR_1_ALPHA, "PGRAPH Pattern Color 1_1 (Bits 7:0 = Alpha)", NULL, NULL, }, { NV3_PGRAPH_PATTERN_BITMAP_HIGH, "PGRAPH Pattern Bitmap (High 32bits)", NULL, NULL}, { NV3_PGRAPH_PATTERN_BITMAP_LOW, "PGRAPH Pattern Bitmap (Low 32bits)", NULL, NULL}, { NV3_PGRAPH_PATTERN_SHAPE, "PGRAPH Pattern Shape (1:0 - 0=8x8, 1=64x1, 2=1x64)", NULL, NULL}, @@ -185,16 +185,16 @@ uint32_t nv3_pgraph_read(uint32_t address) ret = *(uint32_t*)&nv3->pgraph.src_canvas_max; break; // Pattern - case NV3_PGRAPH_pattern_color_0_rgb: + case NV3_PGRAPH_PATTERN_COLOR_0_RGB: ret = *(uint32_t*)&nv3->pgraph.pattern_color_0_rgb; break; - case NV3_PGRAPH_pattern_color_0_alpha: + case NV3_PGRAPH_PATTERN_COLOR_0_ALPHA: ret = *(uint32_t*)&nv3->pgraph.pattern_color_0_alpha; break; - case NV3_PGRAPH_pattern_color_1_rgb: + case NV3_PGRAPH_PATTERN_COLOR_1_RGB: ret = *(uint32_t*)&nv3->pgraph.pattern_color_1_rgb; break; - case NV3_PGRAPH_pattern_color_1_alpha: + case NV3_PGRAPH_PATTERN_COLOR_1_ALPHA: ret = *(uint32_t*)&nv3->pgraph.pattern_color_1_alpha; break; case NV3_PGRAPH_PATTERN_BITMAP_HIGH: @@ -388,16 +388,16 @@ void nv3_pgraph_write(uint32_t address, uint32_t value) *(uint32_t*)&nv3->pgraph.src_canvas_max = value; break; // Pattern - case NV3_PGRAPH_pattern_color_0_rgb: + case NV3_PGRAPH_PATTERN_COLOR_0_RGB: *(uint32_t*)&nv3->pgraph.pattern_color_0_rgb = value; break; - case NV3_PGRAPH_pattern_color_0_alpha: + case NV3_PGRAPH_PATTERN_COLOR_0_ALPHA: *(uint32_t*)&nv3->pgraph.pattern_color_0_alpha = value; break; - case NV3_PGRAPH_pattern_color_1_rgb: + case NV3_PGRAPH_PATTERN_COLOR_1_RGB: *(uint32_t*)&nv3->pgraph.pattern_color_1_rgb = value; break; - case NV3_PGRAPH_pattern_color_1_alpha: + case NV3_PGRAPH_PATTERN_COLOR_1_ALPHA: *(uint32_t*)&nv3->pgraph.pattern_color_1_alpha = value; break; case NV3_PGRAPH_PATTERN_BITMAP_HIGH: