#define select_enhancement_buf_ptr(psx_gpu, x) \ ((psx_gpu)->enhancement_buf_ptr + \ ((psx_gpu)->enhancement_buf_by_x16[(x) / 16] << 20)) #ifndef NEON_BUILD void setup_sprite_16bpp_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v, s32 width, s32 height, u32 color) { u32 left_offset = u & 0x7; u32 width_rounded = width + left_offset + 7; u16 *fb_ptr = psx_gpu->vram_out_ptr + (y * 1024) + (s32)(x - left_offset * 2); u32 right_width = width_rounded & 0x7; u32 block_width = width_rounded / 8; u32 fb_ptr_pitch = (2048 + 16) - (block_width * 16); u32 left_mask_bits = ~(0xFFFF << (left_offset * 2)); u32 right_mask_bits = 0xFFFC << (right_width * 2); u32 texture_offset_base = u + (v * 1024); u32 texture_mask = psx_gpu->texture_mask_width | (psx_gpu->texture_mask_height * 1024); u32 blocks_remaining; u32 num_blocks = psx_gpu->num_blocks; block_struct *block = psx_gpu->blocks + num_blocks; u16 *texture_page_ptr = psx_gpu->texture_page_ptr; u16 *texture_block_ptr; texture_offset_base &= ~0x7; sprites_16bpp++; if(block_width == 1) { u32 mask_bits = left_mask_bits | right_mask_bits; u32 mask_bits_a = mask_bits & 0xFF; u32 mask_bits_b = mask_bits >> 8; vec_8x16u texels; vec_8x16u texels_wide; while(height) { num_blocks += 4; sprite_blocks += 4; if(num_blocks > MAX_BLOCKS) { flush_render_block_buffer(psx_gpu); num_blocks = 4; block = psx_gpu->blocks; } texture_block_ptr = texture_page_ptr + (texture_offset_base & texture_mask); load_128b(texels, texture_block_ptr); zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low); block->texels = texels_wide; block->draw_mask_bits = mask_bits_a; block->fb_ptr = fb_ptr; block++; block->texels = texels_wide; block->draw_mask_bits = mask_bits_a; block->fb_ptr = fb_ptr + 1024; block++; zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high); block->texels = texels_wide; block->draw_mask_bits = mask_bits_b; block->fb_ptr = fb_ptr + 8; block++; block->texels = texels_wide; block->draw_mask_bits = mask_bits_b; block->fb_ptr = fb_ptr + 8 + 1024; block++; texture_offset_base += 1024; fb_ptr += 2048; height--; psx_gpu->num_blocks = num_blocks; } } else { u32 texture_offset; u32 left_mask_bits_a = left_mask_bits & 0xFF; u32 left_mask_bits_b = left_mask_bits >> 8; u32 right_mask_bits_a = right_mask_bits & 0xFF; u32 right_mask_bits_b = right_mask_bits >> 8; vec_8x16u texels; vec_8x16u texels_wide; while(height) { blocks_remaining = block_width - 2; num_blocks += block_width * 4; sprite_blocks += block_width * 4; if(num_blocks > MAX_BLOCKS) { flush_render_block_buffer(psx_gpu); num_blocks = block_width * 4; block = psx_gpu->blocks; } texture_offset = texture_offset_base; texture_offset_base += 1024; texture_block_ptr = texture_page_ptr + (texture_offset & texture_mask); load_128b(texels, texture_block_ptr); zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low); block->texels = texels_wide; block->draw_mask_bits = left_mask_bits_a; block->fb_ptr = fb_ptr; block++; block->texels = texels_wide; block->draw_mask_bits = left_mask_bits_a; block->fb_ptr = fb_ptr + 1024; block++; zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high); block->texels = texels_wide; block->draw_mask_bits = left_mask_bits_b; block->fb_ptr = fb_ptr + 8; block++; block->texels = texels_wide; block->draw_mask_bits = left_mask_bits_b; block->fb_ptr = fb_ptr + 8 + 1024; block++; texture_offset += 8; fb_ptr += 16; while(blocks_remaining) { texture_block_ptr = texture_page_ptr + (texture_offset & texture_mask); load_128b(texels, texture_block_ptr); zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low); block->texels = texels_wide; block->draw_mask_bits = 0; block->fb_ptr = fb_ptr; block++; block->texels = texels_wide; block->draw_mask_bits = 0; block->fb_ptr = fb_ptr + 1024; block++; zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high); block->texels = texels_wide; block->draw_mask_bits = 0; block->fb_ptr = fb_ptr + 8; block++; block->texels = texels_wide; block->draw_mask_bits = 0; block->fb_ptr = fb_ptr + 8 + 1024; block++; texture_offset += 8; fb_ptr += 16; blocks_remaining--; } texture_block_ptr = texture_page_ptr + (texture_offset & texture_mask); load_128b(texels, texture_block_ptr); zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.low, texels.low); block->texels = texels_wide; block->draw_mask_bits = right_mask_bits_a; block->fb_ptr = fb_ptr; block++; block->texels = texels_wide; block->draw_mask_bits = right_mask_bits_a; block->fb_ptr = fb_ptr + 1024; block++; zip_4x32b(vector_cast(vec_4x32u, texels_wide), texels.high, texels.high); block->texels = texels_wide; block->draw_mask_bits = right_mask_bits_b; block->fb_ptr = fb_ptr + 8; block++; block->texels = texels_wide; block->draw_mask_bits = right_mask_bits_b; block->fb_ptr = fb_ptr + 8 + 1024; block++; fb_ptr += fb_ptr_pitch; height--; psx_gpu->num_blocks = num_blocks; } } } #endif static void setup_sprite_untextured_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, s32 u, s32 v, s32 width, s32 height, u32 color) { setup_sprite_untextured(psx_gpu, x, y, u, v, width * 2, height * 2, color); } #define setup_sprite_blocks_switch_textured_4x(texture_mode) \ setup_sprite_##texture_mode##_4x \ #define setup_sprite_blocks_switch_untextured_4x(texture_mode) \ setup_sprite_untextured_4x \ #define setup_sprite_blocks_switch_4x(texturing, texture_mode) \ setup_sprite_blocks_switch_##texturing##_4x(texture_mode) \ #define render_sprite_blocks_switch_block_modulation_4x(texture_mode, \ blend_mode, mask_evaluate, shading, dithering, texturing, blending, \ modulation) \ { \ setup_sprite_blocks_switch_4x(texturing, texture_mode), \ texture_sprite_blocks_switch_##texturing(texture_mode), \ shade_blocks_switch(unshaded, texturing, modulation, undithered, blending, \ mask_evaluate), \ blend_blocks_switch(texturing, blending, blend_mode, mask_evaluate) \ } \ #define render_sprite_blocks_switch_block_blending_4x(texture_mode, \ blend_mode, mask_evaluate, shading, dithering, texturing, blending) \ render_sprite_blocks_switch_block_modulation_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithering, texturing, blending, modulated), \ render_sprite_blocks_switch_block_modulation_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithering, texturing, blending, unmodulated) \ #define render_sprite_blocks_switch_block_texturing_4x(texture_mode, \ blend_mode, mask_evaluate, shading, dithering, texturing) \ render_sprite_blocks_switch_block_blending_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithering, texturing, unblended), \ render_sprite_blocks_switch_block_blending_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithering, texturing, blended) \ #define render_sprite_blocks_switch_block_dithering_4x(texture_mode, \ blend_mode, mask_evaluate, shading, dithering) \ render_sprite_blocks_switch_block_texturing_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithering, untextured), \ render_sprite_blocks_switch_block_texturing_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithering, textured) \ #define render_sprite_blocks_switch_block_shading_4x(texture_mode, blend_mode, \ mask_evaluate, shading) \ render_sprite_blocks_switch_block_dithering_4x(texture_mode, blend_mode, \ mask_evaluate, shading, undithered), \ render_sprite_blocks_switch_block_dithering_4x(texture_mode, blend_mode, \ mask_evaluate, shading, dithered) \ #define render_sprite_blocks_switch_block_mask_evaluate_4x(texture_mode, \ blend_mode, mask_evaluate) \ render_sprite_blocks_switch_block_shading_4x(texture_mode, blend_mode, \ mask_evaluate, unshaded), \ render_sprite_blocks_switch_block_shading_4x(texture_mode, blend_mode, \ mask_evaluate, shaded) \ #define render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, \ blend_mode) \ render_sprite_blocks_switch_block_mask_evaluate_4x(texture_mode, blend_mode, \ off), \ render_sprite_blocks_switch_block_mask_evaluate_4x(texture_mode, blend_mode, \ on) \ #define render_sprite_blocks_switch_block_texture_mode_4x(texture_mode) \ render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, average), \ render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, add), \ render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, subtract), \ render_sprite_blocks_switch_block_blend_mode_4x(texture_mode, add_fourth) \ #define render_sprite_blocks_switch_block_4x() \ render_sprite_blocks_switch_block_texture_mode_4x(4bpp), \ render_sprite_blocks_switch_block_texture_mode_4x(8bpp), \ render_sprite_blocks_switch_block_texture_mode_4x(16bpp), \ render_sprite_blocks_switch_block_texture_mode_4x(4bpp) \ render_block_handler_struct render_sprite_block_handlers_4x[] = { render_sprite_blocks_switch_block_4x() }; void render_sprite_4x(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v, s32 width, s32 height, u32 flags, u32 color) { s32 x_right = x + width - 1; s32 y_bottom = y + height - 1; #ifdef PROFILE sprites++; #endif if(x < psx_gpu->viewport_start_x) { u32 clip = psx_gpu->viewport_start_x - x; x += clip; u += clip; width -= clip; } if(y < psx_gpu->viewport_start_y) { s32 clip = psx_gpu->viewport_start_y - y; y += clip; v += clip; height -= clip; } if(x_right > psx_gpu->viewport_end_x) width -= x_right - psx_gpu->viewport_end_x; if(y_bottom > psx_gpu->viewport_end_y) height -= y_bottom - psx_gpu->viewport_end_y; if((width <= 0) || (height <= 0)) return; psx_gpu->vram_out_ptr = select_enhancement_buf_ptr(psx_gpu, x); x *= 2; y *= 2; #ifdef PROFILE span_pixels += width * height; spans += height; #endif u32 render_state = flags & (RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND | RENDER_FLAGS_TEXTURE_MAP); render_state |= (psx_gpu->render_state_base & ~RENDER_STATE_DITHER); if((psx_gpu->render_state != render_state) || (psx_gpu->primitive_type != PRIMITIVE_TYPE_SPRITE)) { psx_gpu->render_state = render_state; flush_render_block_buffer(psx_gpu); #ifdef PROFILE state_changes++; #endif } psx_gpu->primitive_type = PRIMITIVE_TYPE_SPRITE; color &= 0xFFFFFF; if(psx_gpu->triangle_color != color) { flush_render_block_buffer(psx_gpu); psx_gpu->triangle_color = color; } if(color == 0x808080) render_state |= RENDER_FLAGS_MODULATE_TEXELS; render_block_handler_struct *render_block_handler = &(render_sprite_block_handlers_4x[render_state]); psx_gpu->render_block_handler = render_block_handler; ((setup_sprite_function_type *)render_block_handler->setup_blocks) (psx_gpu, x, y, u, v, width, height, color); }