diff --git a/hw/xbox/nv2a/pgraph/gl/blit.c b/hw/xbox/nv2a/pgraph/blit.c similarity index 79% rename from hw/xbox/nv2a/pgraph/gl/blit.c rename to hw/xbox/nv2a/pgraph/blit.c index 6850ffb7c7d..ca5ab1d9289 100644 --- a/hw/xbox/nv2a/pgraph/gl/blit.c +++ b/hw/xbox/nv2a/pgraph/blit.c @@ -1,223 +1,223 @@ -/* - * Geforce NV2A PGRAPH OpenGL Renderer - * - * Copyright (c) 2012 espes - * Copyright (c) 2015 Jannik Vogel - * Copyright (c) 2018-2024 Matt Borgerson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/xbox/nv2a/nv2a_int.h" -#include "renderer.h" - -static void perform_blit(int operation, uint8_t *source, uint8_t *dest, - size_t width, size_t height, size_t width_bytes, - size_t source_pitch, size_t dest_pitch, - BetaState *beta) -{ - if (operation == NV09F_SET_OPERATION_SRCCOPY) { - for (unsigned int y = 0; y < height; y++) { - memmove(dest, source, width_bytes); - source += source_pitch; - dest += dest_pitch; - } - } else if (operation == NV09F_SET_OPERATION_BLEND_AND) { - uint32_t max_beta_mult = 0x7f80; - uint32_t beta_mult = beta->beta >> 16; - uint32_t inv_beta_mult = max_beta_mult - beta_mult; - - for (unsigned int y = 0; y < height; y++) { - uint8_t *s = source; - uint8_t *d = dest; - for (unsigned int x = 0; x < width; x++) { - for (unsigned int ch = 0; ch < 3; ch++) { - uint32_t a = s[x * 4 + ch] * beta_mult; - uint32_t b = d[x * 4 + ch] * inv_beta_mult; - d[x * 4 + ch] = (a + b) / max_beta_mult; - } - } - source += source_pitch; - dest += dest_pitch; - } - } else { - fprintf(stderr, "Unknown blit operation: 0x%x\n", operation); - assert(false && "Unknown blit operation"); - } -} - -static void patch_alpha(uint8_t *dest, size_t width_pixels, size_t height, - size_t dest_pitch, uint8_t alpha_val) -{ - for (unsigned int y = 0; y < height; y++) { - uint8_t *d = dest; - for (unsigned int x = 0; x < width_pixels; x++) { - d[x * 4 + 3] = alpha_val; - } - dest += dest_pitch; - } -} - -void pgraph_gl_image_blit(NV2AState *d) -{ - PGRAPHState *pg = &d->pgraph; - ContextSurfaces2DState *context_surfaces = &pg->context_surfaces_2d; - ImageBlitState *image_blit = &pg->image_blit; - BetaState *beta = &pg->beta; - - pgraph_gl_surface_update(d, false, true, true); - - assert(context_surfaces->object_instance == image_blit->context_surfaces); - - unsigned int bytes_per_pixel; - switch (context_surfaces->color_format) { - case NV062_SET_COLOR_FORMAT_LE_Y8: - bytes_per_pixel = 1; - break; - case NV062_SET_COLOR_FORMAT_LE_R5G6B5: - bytes_per_pixel = 2; - break; - case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8: - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8_Z8R8G8B8: - case NV062_SET_COLOR_FORMAT_LE_Y32: - bytes_per_pixel = 4; - break; - default: - fprintf(stderr, "Unknown blit surface format: 0x%x\n", - context_surfaces->color_format); - assert(false); - break; - } - - hwaddr source_dma_len; - uint8_t *source = (uint8_t *)nv_dma_map( - d, context_surfaces->dma_image_source, &source_dma_len); - assert(context_surfaces->source_offset < source_dma_len); - source += context_surfaces->source_offset; - hwaddr source_addr = source - d->vram_ptr; - - hwaddr dest_dma_len; - uint8_t *dest = (uint8_t *)nv_dma_map(d, context_surfaces->dma_image_dest, - &dest_dma_len); - assert(context_surfaces->dest_offset < dest_dma_len); - dest += context_surfaces->dest_offset; - hwaddr dest_addr = dest - d->vram_ptr; - - SurfaceBinding *surf_src = pgraph_gl_surface_get(d, source_addr); - if (surf_src) { - pgraph_gl_surface_download_if_dirty(d, surf_src); - } - - hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch + - image_blit->in_x * bytes_per_pixel; - hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch + - image_blit->out_x * bytes_per_pixel; - - size_t max_row_pixels = - MIN(context_surfaces->source_pitch, context_surfaces->dest_pitch) / - bytes_per_pixel; - size_t row_pixels = MIN(max_row_pixels, image_blit->width); - - hwaddr dest_size = (image_blit->height - 1) * context_surfaces->dest_pitch + - image_blit->width * bytes_per_pixel; - - uint8_t *source_row = source + source_offset; - uint8_t *dest_row = dest + dest_offset; - size_t row_bytes = row_pixels * bytes_per_pixel; - - size_t adjusted_height = image_blit->height; - size_t leftover_bytes = 0; - - hwaddr clipped_dest_size = - nv_clip_gpu_tile_blit(d, dest_addr + dest_offset, dest_size); - - if (clipped_dest_size < dest_size) { - adjusted_height = clipped_dest_size / context_surfaces->dest_pitch; - size_t consumed_bytes = adjusted_height * context_surfaces->dest_pitch; - - leftover_bytes = clipped_dest_size - consumed_bytes; - } - - SurfaceBinding *surf_dest = pgraph_gl_surface_get(d, dest_addr); - if (surf_dest) { - if (adjusted_height < surf_dest->height || - row_pixels < surf_dest->width) { - pgraph_gl_surface_download_if_dirty(d, surf_dest); - } else { - // The blit will completely replace the surface so any pending - // download should be discarded. - surf_dest->download_pending = false; - surf_dest->draw_dirty = false; - } - surf_dest->upload_pending = true; - pg->draw_time++; - } - - NV2A_DPRINTF(" blit 0x%tx -> 0x%tx (Size: %llu, Clipped Height: %zu)\n", - source_addr, dest_addr, dest_size, adjusted_height); - - if (adjusted_height > 0) { - perform_blit(image_blit->operation, source_row, dest_row, row_pixels, - adjusted_height, row_bytes, context_surfaces->source_pitch, - context_surfaces->dest_pitch, beta); - } - - if (leftover_bytes > 0) { - uint8_t *src = - source_row + adjusted_height * context_surfaces->source_pitch; - uint8_t *dest = - dest_row + adjusted_height * context_surfaces->dest_pitch; - - perform_blit(image_blit->operation, src, dest, - leftover_bytes / bytes_per_pixel, 1, leftover_bytes, - context_surfaces->source_pitch, - context_surfaces->dest_pitch, beta); - } - - bool needs_alpha_patching; - uint8_t alpha_override; - switch (context_surfaces->color_format) { - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8: - needs_alpha_patching = true; - alpha_override = 0xff; - break; - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8_Z8R8G8B8: - needs_alpha_patching = true; - alpha_override = 0; - break; - default: - needs_alpha_patching = false; - alpha_override = 0; - } - - if (needs_alpha_patching) { - if (adjusted_height > 0) { - patch_alpha(dest_row, row_pixels, adjusted_height, - context_surfaces->dest_pitch, alpha_override); - } - - if (leftover_bytes > 0) { - uint8_t *dest = - dest_row + adjusted_height * context_surfaces->dest_pitch; - patch_alpha(dest, leftover_bytes / 4, 1, 0, alpha_override); - } - } - - dest_addr += dest_offset; - memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size, - DIRTY_MEMORY_VGA); - memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size, - DIRTY_MEMORY_NV2A_TEX); -} +/* + * Geforce NV2A PGRAPH Renderer + * + * Copyright (c) 2012 espes + * Copyright (c) 2015 Jannik Vogel + * Copyright (c) 2018-2024 Matt Borgerson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "hw/xbox/nv2a/nv2a_int.h" + +static void perform_blit(int operation, uint8_t *source, uint8_t *dest, + size_t width, size_t height, size_t width_bytes, + size_t source_pitch, size_t dest_pitch, + BetaState *beta) +{ + if (operation == NV09F_SET_OPERATION_SRCCOPY) { + for (unsigned int y = 0; y < height; y++) { + memmove(dest, source, width_bytes); + source += source_pitch; + dest += dest_pitch; + } + } else if (operation == NV09F_SET_OPERATION_BLEND_AND) { + uint32_t max_beta_mult = 0x7f80; + uint32_t beta_mult = beta->beta >> 16; + uint32_t inv_beta_mult = max_beta_mult - beta_mult; + + for (unsigned int y = 0; y < height; y++) { + uint8_t *s = source; + uint8_t *d = dest; + for (unsigned int x = 0; x < width; x++) { + for (unsigned int ch = 0; ch < 3; ch++) { + uint32_t a = s[x * 4 + ch] * beta_mult; + uint32_t b = d[x * 4 + ch] * inv_beta_mult; + d[x * 4 + ch] = (a + b) / max_beta_mult; + } + } + source += source_pitch; + dest += dest_pitch; + } + } else { + fprintf(stderr, "Unknown blit operation: 0x%x\n", operation); + assert(false && "Unknown blit operation"); + } +} + +static void patch_alpha(uint8_t *dest, size_t width_pixels, size_t height, + size_t dest_pitch, uint8_t alpha_val) +{ + for (unsigned int y = 0; y < height; y++) { + uint8_t *d = dest; + for (unsigned int x = 0; x < width_pixels; x++) { + d[x * 4 + 3] = alpha_val; + } + dest += dest_pitch; + } +} +void pgraph_common_image_blit(NV2AState *d) + +{ + PGRAPHState *pg = &d->pgraph; + ContextSurfaces2DState *context_surfaces = &pg->context_surfaces_2d; + ImageBlitState *image_blit = &pg->image_blit; + BetaState *beta = &pg->beta; + + pg->renderer->ops.surface_update(d, false, true, true); + + assert(context_surfaces->object_instance == image_blit->context_surfaces); + + unsigned int bytes_per_pixel; + switch (context_surfaces->color_format) { + case NV062_SET_COLOR_FORMAT_LE_Y8: + bytes_per_pixel = 1; + break; + case NV062_SET_COLOR_FORMAT_LE_R5G6B5: + bytes_per_pixel = 2; + break; + case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: + case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8: + case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8_Z8R8G8B8: + case NV062_SET_COLOR_FORMAT_LE_Y32: + bytes_per_pixel = 4; + break; + default: + fprintf(stderr, "Unknown blit surface format: 0x%x\n", + context_surfaces->color_format); + assert(false); + break; + } + + hwaddr source_dma_len, dest_dma_len; + + uint8_t *source = (uint8_t *)nv_dma_map( + d, context_surfaces->dma_image_source, &source_dma_len); + assert(context_surfaces->source_offset < source_dma_len); + source += context_surfaces->source_offset; + + uint8_t *dest = (uint8_t *)nv_dma_map(d, context_surfaces->dma_image_dest, + &dest_dma_len); + assert(context_surfaces->dest_offset < dest_dma_len); + dest += context_surfaces->dest_offset; + + hwaddr source_addr = source - d->vram_ptr; + hwaddr dest_addr = dest - d->vram_ptr; + + SurfaceBinding *surf_src = pg->renderer->ops.surface_get(d, source_addr); + if (surf_src) { + pg->renderer->ops.surface_download_if_dirty(d, surf_src); + } + + hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch + + image_blit->in_x * bytes_per_pixel; + hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch + + image_blit->out_x * bytes_per_pixel; + + size_t max_row_pixels = + MIN(context_surfaces->source_pitch, context_surfaces->dest_pitch) / + bytes_per_pixel; + size_t row_pixels = MIN(max_row_pixels, image_blit->width); + + hwaddr dest_size = (image_blit->height - 1) * context_surfaces->dest_pitch + + image_blit->width * bytes_per_pixel; + + uint8_t *source_row = source + source_offset; + uint8_t *dest_row = dest + dest_offset; + size_t row_bytes = row_pixels * bytes_per_pixel; + + size_t adjusted_height = image_blit->height; + size_t leftover_bytes = 0; + + hwaddr clipped_dest_size = + nv_clip_gpu_tile_blit(d, dest_addr + dest_offset, dest_size); + + if (clipped_dest_size < dest_size) { + adjusted_height = clipped_dest_size / context_surfaces->dest_pitch; + size_t consumed_bytes = adjusted_height * context_surfaces->dest_pitch; + + leftover_bytes = clipped_dest_size - consumed_bytes; + } + + SurfaceBinding *surf_dest = pg->renderer->ops.surface_get(d, dest_addr); + if (surf_dest) { + if (adjusted_height < surf_dest->height || + row_pixels < surf_dest->width) { + pg->renderer->ops.surface_download_if_dirty(d, surf_dest); + } else { + // The blit will completely replace the surface so any pending + // download should be discarded. + surf_dest->download_pending = false; + surf_dest->draw_dirty = false; + } + surf_dest->upload_pending = true; + pg->draw_time++; + } + + NV2A_DPRINTF(" blit 0x%tx -> 0x%tx (Size: %llu, Clipped Height: %zu)\n", + source_addr, dest_addr, dest_size, adjusted_height); + + if (adjusted_height > 0) { + perform_blit(image_blit->operation, source_row, dest_row, row_pixels, + adjusted_height, row_bytes, context_surfaces->source_pitch, + context_surfaces->dest_pitch, beta); + } + + if (leftover_bytes > 0) { + uint8_t *src = + source_row + adjusted_height * context_surfaces->source_pitch; + uint8_t *dest = + dest_row + adjusted_height * context_surfaces->dest_pitch; + + perform_blit(image_blit->operation, src, dest, + leftover_bytes / bytes_per_pixel, 1, leftover_bytes, + context_surfaces->source_pitch, + context_surfaces->dest_pitch, beta); + } + + bool needs_alpha_patching; + uint8_t alpha_override; + switch (context_surfaces->color_format) { + case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8: + needs_alpha_patching = true; + alpha_override = 0xff; + break; + case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8_Z8R8G8B8: + needs_alpha_patching = true; + alpha_override = 0; + break; + default: + needs_alpha_patching = false; + alpha_override = 0; + } + + if (needs_alpha_patching) { + if (adjusted_height > 0) { + patch_alpha(dest_row, row_pixels, adjusted_height, + context_surfaces->dest_pitch, alpha_override); + } + + if (leftover_bytes > 0) { + uint8_t *dest = + dest_row + adjusted_height * context_surfaces->dest_pitch; + patch_alpha(dest, leftover_bytes / 4, 1, 0, alpha_override); + } +} + + dest_addr += dest_offset; + memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size, + DIRTY_MEMORY_VGA); + memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size, + DIRTY_MEMORY_NV2A_TEX); +} diff --git a/hw/xbox/nv2a/pgraph/gl/meson.build b/hw/xbox/nv2a/pgraph/gl/meson.build index c19a542adbd..74150a57499 100644 --- a/hw/xbox/nv2a/pgraph/gl/meson.build +++ b/hw/xbox/nv2a/pgraph/gl/meson.build @@ -1,5 +1,4 @@ specific_ss.add([sdl, gloffscreen, files( - 'blit.c', 'debug.c', 'display.c', 'draw.c', diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.c b/hw/xbox/nv2a/pgraph/gl/renderer.c index e9e2109779e..f4c675803fc 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.c +++ b/hw/xbox/nv2a/pgraph/gl/renderer.c @@ -23,6 +23,7 @@ #include "hw/xbox/nv2a/pgraph/pgraph.h" #include "debug.h" #include "renderer.h" +#include "hw/xbox/nv2a/pgraph/surface.h" GloContext *g_nv2a_context_render; GloContext *g_nv2a_context_display; @@ -196,7 +197,6 @@ static PGRAPHRenderer pgraph_gl_renderer = { .flip_stall = pgraph_gl_flip_stall, .flush_draw = pgraph_gl_flush_draw, .get_report = pgraph_gl_get_report, - .image_blit = pgraph_gl_image_blit, .pre_savevm_trigger = pgraph_gl_pre_savevm_trigger, .pre_savevm_wait = pgraph_gl_pre_savevm_wait, .pre_shutdown_trigger = pgraph_gl_pre_shutdown_trigger, @@ -204,6 +204,8 @@ static PGRAPHRenderer pgraph_gl_renderer = { .process_pending = pgraph_gl_process_pending, .process_pending_reports = pgraph_gl_process_pending_reports, .surface_update = pgraph_gl_surface_update, + .surface_get = pgraph_gl_surface_get, + .surface_download_if_dirty = pgraph_gl_surface_download_if_dirty, .set_surface_scale_factor = pgraph_gl_set_surface_scale_factor, .get_surface_scale_factor = pgraph_gl_get_surface_scale_factor, .get_framebuffer_surface = pgraph_gl_get_framebuffer_surface, diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 9b9d9bfb029..f71901ef7a8 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -256,7 +256,6 @@ void pgraph_gl_draw_begin(NV2AState *d); void pgraph_gl_draw_end(NV2AState *d); void pgraph_gl_flush_draw(NV2AState *d); void pgraph_gl_get_report(NV2AState *d, uint32_t parameter); -void pgraph_gl_image_blit(NV2AState *d); void pgraph_gl_mark_textures_possibly_dirty(NV2AState *d, hwaddr addr, hwaddr size); void pgraph_gl_process_pending_reports(NV2AState *d); void pgraph_gl_surface_flush(NV2AState *d); diff --git a/hw/xbox/nv2a/pgraph/meson.build b/hw/xbox/nv2a/pgraph/meson.build index fc52f609ebd..4a7bdfa3aae 100644 --- a/hw/xbox/nv2a/pgraph/meson.build +++ b/hw/xbox/nv2a/pgraph/meson.build @@ -1,4 +1,5 @@ specific_ss.add(files( + 'blit.c', 'pgraph.c', 'profile.c', 'rdi.c', diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index b34685866cf..e6acc74811c 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -762,7 +762,7 @@ int pgraph_method(NV2AState *d, unsigned int subchannel, image_blit->height = parameter >> 16; if (image_blit->width && image_blit->height) { - d->pgraph.renderer->ops.image_blit(d); + pgraph_common_image_blit(d); } break; default: diff --git a/hw/xbox/nv2a/pgraph/pgraph.h b/hw/xbox/nv2a/pgraph/pgraph.h index 0449270b55e..85356c623e7 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.h +++ b/hw/xbox/nv2a/pgraph/pgraph.h @@ -38,6 +38,7 @@ typedef struct NV2AState NV2AState; typedef struct PGRAPHNullState PGRAPHNullState; typedef struct PGRAPHGLState PGRAPHGLState; typedef struct PGRAPHVkState PGRAPHVkState; +typedef struct SurfaceBinding SurfaceBinding; typedef struct VertexAttribute { bool dma_select; @@ -119,7 +120,6 @@ typedef struct PGRAPHRenderer { void (*flip_stall)(NV2AState *d); void (*flush_draw)(NV2AState *d); void (*get_report)(NV2AState *d, uint32_t parameter); - void (*image_blit)(NV2AState *d); void (*pre_savevm_trigger)(NV2AState *d); void (*pre_savevm_wait)(NV2AState *d); void (*pre_shutdown_trigger)(NV2AState *d); @@ -128,6 +128,8 @@ typedef struct PGRAPHRenderer { void (*process_pending_reports)(NV2AState *d); void (*surface_flush)(NV2AState *d); void (*surface_update)(NV2AState *d, bool upload, bool color_write, bool zeta_write); + void *(*surface_get)(NV2AState *d, hwaddr addr); + void (*surface_download_if_dirty)(NV2AState *d, void *surface); void (*set_surface_scale_factor)(NV2AState *d, unsigned int scale); unsigned int (*get_surface_scale_factor)(NV2AState *d); int (*get_framebuffer_surface)(NV2AState *d); diff --git a/hw/xbox/nv2a/pgraph/vk/blit.c b/hw/xbox/nv2a/pgraph/vk/blit.c deleted file mode 100644 index 9df86bf539c..00000000000 --- a/hw/xbox/nv2a/pgraph/vk/blit.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Geforce NV2A PGRAPH Vulkan Renderer - * - * Copyright (c) 2024 Matt Borgerson - * - * Based on GL implementation: - * - * Copyright (c) 2012 espes - * Copyright (c) 2015 Jannik Vogel - * Copyright (c) 2018-2024 Matt Borgerson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/xbox/nv2a/nv2a_int.h" -#include "renderer.h" - -static void perform_blit(int operation, uint8_t *source, uint8_t *dest, - size_t width, size_t height, size_t width_bytes, - size_t source_pitch, size_t dest_pitch, - BetaState *beta) -{ - if (operation == NV09F_SET_OPERATION_SRCCOPY) { - for (unsigned int y = 0; y < height; y++) { - memmove(dest, source, width_bytes); - source += source_pitch; - dest += dest_pitch; - } - } else if (operation == NV09F_SET_OPERATION_BLEND_AND) { - uint32_t max_beta_mult = 0x7f80; - uint32_t beta_mult = beta->beta >> 16; - uint32_t inv_beta_mult = max_beta_mult - beta_mult; - - for (unsigned int y = 0; y < height; y++) { - uint8_t *s = source; - uint8_t *d = dest; - for (unsigned int x = 0; x < width; x++) { - for (unsigned int ch = 0; ch < 3; ch++) { - uint32_t a = s[x * 4 + ch] * beta_mult; - uint32_t b = d[x * 4 + ch] * inv_beta_mult; - d[x * 4 + ch] = (a + b) / max_beta_mult; - } - } - source += source_pitch; - dest += dest_pitch; - } - } else { - fprintf(stderr, "Unknown blit operation: 0x%x\n", operation); - assert(false && "Unknown blit operation"); - } -} - -static void patch_alpha(uint8_t *dest, size_t width_pixels, size_t height, - size_t dest_pitch, uint8_t alpha_val) -{ - for (unsigned int y = 0; y < height; y++) { - uint8_t *d = dest; - for (unsigned int x = 0; x < width_pixels; x++) { - d[x * 4 + 3] = alpha_val; - } - dest += dest_pitch; - } -} - -void pgraph_vk_image_blit(NV2AState *d) -{ - PGRAPHState *pg = &d->pgraph; - ContextSurfaces2DState *context_surfaces = &pg->context_surfaces_2d; - ImageBlitState *image_blit = &pg->image_blit; - BetaState *beta = &pg->beta; - - pgraph_vk_surface_update(d, false, true, true); - - assert(context_surfaces->object_instance == image_blit->context_surfaces); - - unsigned int bytes_per_pixel; - switch (context_surfaces->color_format) { - case NV062_SET_COLOR_FORMAT_LE_Y8: - bytes_per_pixel = 1; - break; - case NV062_SET_COLOR_FORMAT_LE_R5G6B5: - bytes_per_pixel = 2; - break; - case NV062_SET_COLOR_FORMAT_LE_A8R8G8B8: - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8: - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8_Z8R8G8B8: - case NV062_SET_COLOR_FORMAT_LE_Y32: - bytes_per_pixel = 4; - break; - default: - fprintf(stderr, "Unknown blit surface format: 0x%x\n", - context_surfaces->color_format); - assert(false); - break; - } - - hwaddr source_dma_len; - uint8_t *source = (uint8_t *)nv_dma_map( - d, context_surfaces->dma_image_source, &source_dma_len); - assert(context_surfaces->source_offset < source_dma_len); - source += context_surfaces->source_offset; - hwaddr source_addr = source - d->vram_ptr; - - hwaddr dest_dma_len; - uint8_t *dest = (uint8_t *)nv_dma_map(d, context_surfaces->dma_image_dest, - &dest_dma_len); - assert(context_surfaces->dest_offset < dest_dma_len); - dest += context_surfaces->dest_offset; - hwaddr dest_addr = dest - d->vram_ptr; - - SurfaceBinding *surf_src = pgraph_vk_surface_get(d, source_addr); - if (surf_src) { - pgraph_vk_surface_download_if_dirty(d, surf_src); - } - - hwaddr source_offset = image_blit->in_y * context_surfaces->source_pitch + - image_blit->in_x * bytes_per_pixel; - hwaddr dest_offset = image_blit->out_y * context_surfaces->dest_pitch + - image_blit->out_x * bytes_per_pixel; - - size_t max_row_pixels = - MIN(context_surfaces->source_pitch, context_surfaces->dest_pitch) / - bytes_per_pixel; - size_t row_pixels = MIN(max_row_pixels, image_blit->width); - - hwaddr dest_size = (image_blit->height - 1) * context_surfaces->dest_pitch + - image_blit->width * bytes_per_pixel; - - uint8_t *source_row = source + source_offset; - uint8_t *dest_row = dest + dest_offset; - size_t row_bytes = row_pixels * bytes_per_pixel; - - size_t adjusted_height = image_blit->height; - size_t leftover_bytes = 0; - - hwaddr clipped_dest_size = - nv_clip_gpu_tile_blit(d, dest_addr + dest_offset, dest_size); - - if (clipped_dest_size < dest_size) { - adjusted_height = clipped_dest_size / context_surfaces->dest_pitch; - size_t consumed_bytes = adjusted_height * context_surfaces->dest_pitch; - - leftover_bytes = clipped_dest_size - consumed_bytes; - } - - SurfaceBinding *surf_dest = pgraph_vk_surface_get(d, dest_addr); - if (surf_dest) { - if (adjusted_height < surf_dest->height || - row_pixels < surf_dest->width) { - pgraph_vk_surface_download_if_dirty(d, surf_dest); - } else { - // The blit will completely replace the surface so any pending - // download should be discarded. - surf_dest->download_pending = false; - surf_dest->draw_dirty = false; - } - surf_dest->upload_pending = true; - pg->draw_time++; - } - - NV2A_DPRINTF(" blit 0x%tx -> 0x%tx (Size: %llu, Clipped Height: %zu)\n", - source_addr, dest_addr, dest_size, adjusted_height); - - if (adjusted_height > 0) { - perform_blit(image_blit->operation, source_row, dest_row, row_pixels, - adjusted_height, row_bytes, context_surfaces->source_pitch, - context_surfaces->dest_pitch, beta); - } - - if (leftover_bytes > 0) { - uint8_t *src = - source_row + adjusted_height * context_surfaces->source_pitch; - uint8_t *dest = - dest_row + adjusted_height * context_surfaces->dest_pitch; - - perform_blit(image_blit->operation, src, dest, - leftover_bytes / bytes_per_pixel, 1, leftover_bytes, - context_surfaces->source_pitch, - context_surfaces->dest_pitch, beta); - } - - bool needs_alpha_patching; - uint8_t alpha_override; - switch (context_surfaces->color_format) { - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8: - needs_alpha_patching = true; - alpha_override = 0xff; - break; - case NV062_SET_COLOR_FORMAT_LE_X8R8G8B8_Z8R8G8B8: - needs_alpha_patching = true; - alpha_override = 0; - break; - default: - needs_alpha_patching = false; - alpha_override = 0; - } - - if (needs_alpha_patching) { - if (adjusted_height > 0) { - patch_alpha(dest_row, row_pixels, adjusted_height, - context_surfaces->dest_pitch, alpha_override); - } - - if (leftover_bytes > 0) { - uint8_t *dest = - dest_row + adjusted_height * context_surfaces->dest_pitch; - patch_alpha(dest, leftover_bytes / 4, 1, 0, alpha_override); - } - } - - dest_addr += dest_offset; - memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size, - DIRTY_MEMORY_VGA); - memory_region_set_client_dirty(d->vram, dest_addr, clipped_dest_size, - DIRTY_MEMORY_NV2A_TEX); -} diff --git a/hw/xbox/nv2a/pgraph/vk/meson.build b/hw/xbox/nv2a/pgraph/vk/meson.build index b5d75e2faa4..eaf395f6eba 100644 --- a/hw/xbox/nv2a/pgraph/vk/meson.build +++ b/hw/xbox/nv2a/pgraph/vk/meson.build @@ -2,7 +2,6 @@ if vulkan.found() specific_ss.add([sdl, volk, libglslang, vma, vulkan, spirv_reflect, gloffscreen, files( - 'blit.c', 'buffer.c', 'command.c', 'debug.c', diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.c b/hw/xbox/nv2a/pgraph/vk/renderer.c index 4272bbceb6d..226b634da07 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.c +++ b/hw/xbox/nv2a/pgraph/vk/renderer.c @@ -19,7 +19,7 @@ #include "hw/xbox/nv2a/nv2a_int.h" #include "renderer.h" - +#include "hw/xbox/nv2a/pgraph/surface.h" #include "gloffscreen.h" #if HAVE_EXTERNAL_MEMORY @@ -218,7 +218,6 @@ static PGRAPHRenderer pgraph_vk_renderer = { .flip_stall = pgraph_vk_flip_stall, .flush_draw = pgraph_vk_flush_draw, .get_report = pgraph_vk_get_report, - .image_blit = pgraph_vk_image_blit, .pre_savevm_trigger = pgraph_vk_pre_savevm_trigger, .pre_savevm_wait = pgraph_vk_pre_savevm_wait, .pre_shutdown_trigger = pgraph_vk_pre_shutdown_trigger, @@ -226,6 +225,8 @@ static PGRAPHRenderer pgraph_vk_renderer = { .process_pending = pgraph_vk_process_pending, .process_pending_reports = pgraph_vk_process_pending_reports, .surface_update = pgraph_vk_surface_update, + .surface_get = pgraph_vk_surface_get, + .surface_download_if_dirty = pgraph_vk_surface_download_if_dirty, .set_surface_scale_factor = pgraph_vk_set_surface_scale_factor, .get_surface_scale_factor = pgraph_vk_get_surface_scale_factor, .get_framebuffer_surface = pgraph_vk_get_framebuffer_surface, diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 8cf9e4d6638..9295fa43e00 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -591,8 +591,6 @@ void pgraph_vk_ensure_not_in_render_pass(PGRAPHState *pg); VkCommandBuffer pgraph_vk_begin_nondraw_commands(PGRAPHState *pg); void pgraph_vk_end_nondraw_commands(PGRAPHState *pg, VkCommandBuffer cmd); -// blit.c -void pgraph_vk_image_blit(NV2AState *d); // gpuprops.c void pgraph_vk_determine_gpu_properties(NV2AState *d);