/* * Copyright (C) 2011 Gilead Kutnick "Exophase" * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 * General Public License for more details. */ #include #include "common.h" #ifndef command_lengths const u8 command_lengths[256] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 3, 3, 3, 3, 6, 6, 6, 6, 4, 4, 4, 4, 8, 8, 8, 8, // 20 5, 5, 5, 5, 8, 8, 8, 8, 7, 7, 7, 7, 11, 11, 11, 11, // 30 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 40 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 50 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, // 60 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, // 70 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b0 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e0 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // f0 }; #endif void update_texture_ptr(psx_gpu_struct *psx_gpu) { u8 *texture_base; u8 *texture_ptr; switch((psx_gpu->render_state_base >> 8) & 0x3) { default: case TEXTURE_MODE_4BPP: texture_base = psx_gpu->texture_4bpp_cache[psx_gpu->current_texture_page]; texture_ptr = texture_base; texture_ptr += psx_gpu->texture_window_x & 0xF; texture_ptr += (psx_gpu->texture_window_y & 0xF) << 4; texture_ptr += (psx_gpu->texture_window_x >> 4) << 8; texture_ptr += (psx_gpu->texture_window_y >> 4) << 12; break; case TEXTURE_MODE_8BPP: if(psx_gpu->current_texture_page & 0x1) { texture_base = psx_gpu->texture_8bpp_odd_cache[psx_gpu->current_texture_page >> 1]; } else { texture_base = psx_gpu->texture_8bpp_even_cache[psx_gpu->current_texture_page >> 1]; } texture_ptr = texture_base; texture_ptr += psx_gpu->texture_window_x & 0xF; texture_ptr += (psx_gpu->texture_window_y & 0xF) << 4; texture_ptr += (psx_gpu->texture_window_x >> 4) << 8; texture_ptr += (psx_gpu->texture_window_y >> 4) << 12; break; case TEXTURE_MODE_16BPP: texture_base = (u8 *)(psx_gpu->vram_ptr); texture_base += (psx_gpu->current_texture_page & 0xF) * 128; texture_base += ((psx_gpu->current_texture_page >> 4) * 256) * 2048; texture_ptr = texture_base; texture_ptr += psx_gpu->texture_window_x * 2; texture_ptr += (psx_gpu->texture_window_y) * 2048; break; } psx_gpu->texture_page_base = texture_base; psx_gpu->texture_page_ptr = texture_ptr; } void set_texture(psx_gpu_struct *psx_gpu, u32 texture_settings) { texture_settings &= 0x1FF; if(psx_gpu->texture_settings != texture_settings) { u32 new_texture_page = texture_settings & 0x1F; u32 texture_mode = (texture_settings >> 7) & 0x3; u32 render_state_base = psx_gpu->render_state_base; flush_render_block_buffer(psx_gpu); render_state_base &= ~(0xF << 6); render_state_base |= ((texture_settings >> 5) & 0xF) << 6; psx_gpu->render_state_base = render_state_base; psx_gpu->current_texture_mask = 0x1 << new_texture_page; if(texture_mode == TEXTURE_MODE_8BPP) { // In 8bpp mode 256x256 takes up two pages. If it's on the right edge it // wraps back around to the left edge. u32 adjacent_texture_page = ((texture_settings + 1) & 0xF) | (texture_settings & 0x10); psx_gpu->current_texture_mask |= 0x1 << adjacent_texture_page; if((psx_gpu->last_8bpp_texture_page ^ new_texture_page) & 0x1) { u32 dirty_textures_8bpp_alternate_mask = psx_gpu->dirty_textures_8bpp_alternate_mask; psx_gpu->dirty_textures_8bpp_alternate_mask = psx_gpu->dirty_textures_8bpp_mask; psx_gpu->dirty_textures_8bpp_mask = dirty_textures_8bpp_alternate_mask; } psx_gpu->last_8bpp_texture_page = new_texture_page; } psx_gpu->current_texture_page = new_texture_page; psx_gpu->texture_settings = texture_settings; update_texture_ptr(psx_gpu); } } void set_clut(psx_gpu_struct *psx_gpu, u32 clut_settings) { if(psx_gpu->clut_settings != clut_settings) { flush_render_block_buffer(psx_gpu); psx_gpu->clut_settings = clut_settings; psx_gpu->clut_ptr = psx_gpu->vram_ptr + ((clut_settings & 0x7FFF) * 16); } } void set_triangle_color(psx_gpu_struct *psx_gpu, u32 triangle_color) { if(psx_gpu->triangle_color != triangle_color) { flush_render_block_buffer(psx_gpu); psx_gpu->triangle_color = triangle_color; } } static void do_fill(psx_gpu_struct *psx_gpu, u32 x, u32 y, u32 width, u32 height, u32 color) { x &= ~0xF; width = ((width + 0xF) & ~0xF); flush_render_block_buffer(psx_gpu); if(unlikely((x + width) > 1024)) { u32 width_a = 1024 - x; u32 width_b = width - width_a; if(unlikely((y + height) > 512)) { u32 height_a = 512 - y; u32 height_b = height - height_a; render_block_fill(psx_gpu, color, x, y, width_a, height_a); render_block_fill(psx_gpu, color, 0, y, width_b, height_a); render_block_fill(psx_gpu, color, x, 0, width_a, height_b); render_block_fill(psx_gpu, color, 0, 0, width_b, height_b); } else { render_block_fill(psx_gpu, color, x, y, width_a, height); render_block_fill(psx_gpu, color, 0, y, width_b, height); } } else { if(unlikely((y + height) > 512)) { u32 height_a = 512 - y; u32 height_b = height - height_a; render_block_fill(psx_gpu, color, x, y, width, height_a); render_block_fill(psx_gpu, color, x, 0, width, height_b); } else { render_block_fill(psx_gpu, color, x, y, width, height); } } } #define sign_extend_12bit(value) \ (((s32)((value) << 20)) >> 20) \ #define sign_extend_11bit(value) \ (((s32)((value) << 21)) >> 21) \ #define sign_extend_10bit(value) \ (((s32)((value) << 22)) >> 22) \ #define get_vertex_data_xy(vertex_number, offset16) \ vertexes[vertex_number].x = \ sign_extend_12bit(list_s16[offset16]) + psx_gpu->offset_x; \ vertexes[vertex_number].y = \ sign_extend_12bit(list_s16[(offset16) + 1]) + psx_gpu->offset_y; \ #define get_vertex_data_uv(vertex_number, offset16) \ vertexes[vertex_number].u = list_s16[offset16] & 0xFF; \ vertexes[vertex_number].v = (list_s16[offset16] >> 8) & 0xFF \ #define get_vertex_data_rgb(vertex_number, offset32) \ vertexes[vertex_number].r = list[offset32] & 0xFF; \ vertexes[vertex_number].g = (list[offset32] >> 8) & 0xFF; \ vertexes[vertex_number].b = (list[offset32] >> 16) & 0xFF \ #define get_vertex_data_xy_uv(vertex_number, offset16) \ get_vertex_data_xy(vertex_number, offset16); \ get_vertex_data_uv(vertex_number, (offset16) + 2) \ #define get_vertex_data_xy_rgb(vertex_number, offset16) \ get_vertex_data_rgb(vertex_number, (offset16) / 2); \ get_vertex_data_xy(vertex_number, (offset16) + 2); \ #define get_vertex_data_xy_uv_rgb(vertex_number, offset16) \ get_vertex_data_rgb(vertex_number, (offset16) / 2); \ get_vertex_data_xy(vertex_number, (offset16) + 2); \ get_vertex_data_uv(vertex_number, (offset16) + 4); \ #define set_vertex_color_constant(vertex_number, color) \ vertexes[vertex_number].r = color & 0xFF; \ vertexes[vertex_number].g = (color >> 8) & 0xFF; \ vertexes[vertex_number].b = (color >> 16) & 0xFF \ #define get_vertex_data_xy_rgb_constant(vertex_number, offset16, color) \ get_vertex_data_xy(vertex_number, offset16); \ set_vertex_color_constant(vertex_number, color) \ #ifndef SET_Ex #define SET_Ex(r, v) #endif vertex_struct vertexes[4] __attribute__((aligned(32))); u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) { u32 current_command = 0, command_length; u32 *list_start = list; u32 *list_end = list + (size / 4); for(; list < list_end; list += 1 + command_length) { s16 *list_s16 = (void *)list; current_command = *list >> 24; command_length = command_lengths[current_command]; if (list + 1 + command_length > list_end) { current_command = (u32)-1; break; } switch(current_command) { case 0x00: break; case 0x02: { u32 x = list_s16[2] & 0x3FF; u32 y = list_s16[3] & 0x1FF; u32 width = list_s16[4] & 0x3FF; u32 height = list_s16[5] & 0x1FF; u32 color = list[0] & 0xFFFFFF; do_fill(psx_gpu, x, y, width, height, color); break; } case 0x20 ... 0x23: { set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy(0, 2); get_vertex_data_xy(1, 4); get_vertex_data_xy(2, 6); render_triangle(psx_gpu, vertexes, current_command); break; } case 0x24 ... 0x27: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[9]); set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy_uv(0, 2); get_vertex_data_xy_uv(1, 6); get_vertex_data_xy_uv(2, 10); render_triangle(psx_gpu, vertexes, current_command); break; } case 0x28 ... 0x2B: { set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy(0, 2); get_vertex_data_xy(1, 4); get_vertex_data_xy(2, 6); get_vertex_data_xy(3, 8); render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); break; } case 0x2C ... 0x2F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[9]); set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy_uv(0, 2); get_vertex_data_xy_uv(1, 6); get_vertex_data_xy_uv(2, 10); get_vertex_data_xy_uv(3, 14); render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); break; } case 0x30 ... 0x33: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); get_vertex_data_xy_rgb(2, 8); render_triangle(psx_gpu, vertexes, current_command); break; } case 0x34: case 0x35: case 0x36: case 0x37: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); get_vertex_data_xy_uv_rgb(0, 0); get_vertex_data_xy_uv_rgb(1, 6); get_vertex_data_xy_uv_rgb(2, 12); render_triangle(psx_gpu, vertexes, current_command); break; } case 0x38: case 0x39: case 0x3A: case 0x3B: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); get_vertex_data_xy_rgb(2, 8); get_vertex_data_xy_rgb(3, 12); render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); break; } case 0x3C: case 0x3D: case 0x3E: case 0x3F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); get_vertex_data_xy_uv_rgb(0, 0); get_vertex_data_xy_uv_rgb(1, 6); get_vertex_data_xy_uv_rgb(2, 12); get_vertex_data_xy_uv_rgb(3, 18); render_triangle(psx_gpu, vertexes, current_command); render_triangle(psx_gpu, &(vertexes[1]), current_command); break; } case 0x40 ... 0x47: { vertexes[0].x = list_s16[2] + psx_gpu->offset_x; vertexes[0].y = list_s16[3] + psx_gpu->offset_y; vertexes[1].x = list_s16[4] + psx_gpu->offset_x; vertexes[1].y = list_s16[5] + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, list[0], 0); break; } case 0x48 ... 0x4F: { u32 num_vertexes = 1; u32 *list_position = &(list[2]); u32 xy = list[1]; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; xy = *list_position; while(1) { vertexes[0] = vertexes[1]; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, list[0], 0); list_position++; num_vertexes++; if(list_position >= list_end) { current_command = (u32)-1; goto breakloop; } xy = *list_position; if((xy & 0xF000F000) == 0x50005000) break; } command_length += (num_vertexes - 2); break; } case 0x50 ... 0x57: { vertexes[0].r = list[0] & 0xFF; vertexes[0].g = (list[0] >> 8) & 0xFF; vertexes[0].b = (list[0] >> 16) & 0xFF; vertexes[0].x = list_s16[2] + psx_gpu->offset_x; vertexes[0].y = list_s16[3] + psx_gpu->offset_y; vertexes[1].r = list[2] & 0xFF; vertexes[1].g = (list[2] >> 8) & 0xFF; vertexes[1].b = (list[2] >> 16) & 0xFF; vertexes[1].x = list_s16[6] + psx_gpu->offset_x; vertexes[1].y = list_s16[7] + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, 0, 0); break; } case 0x58 ... 0x5F: { u32 num_vertexes = 1; u32 *list_position = &(list[2]); u32 color = list[0]; u32 xy = list[1]; vertexes[1].r = color & 0xFF; vertexes[1].g = (color >> 8) & 0xFF; vertexes[1].b = (color >> 16) & 0xFF; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; color = list_position[0]; while(1) { xy = list_position[1]; vertexes[0] = vertexes[1]; vertexes[1].r = color & 0xFF; vertexes[1].g = (color >> 8) & 0xFF; vertexes[1].b = (color >> 16) & 0xFF; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, 0, 0); list_position += 2; num_vertexes++; if(list_position >= list_end) { current_command = (u32)-1; goto breakloop; } color = list_position[0]; if((color & 0xF000F000) == 0x50005000) break; } command_length += ((num_vertexes - 2) * 2); break; } case 0x60 ... 0x63: { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 width = list_s16[4] & 0x3FF; u32 height = list_s16[5] & 0x1FF; render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]); break; } case 0x64 ... 0x67: { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 uv = list_s16[4]; u32 width = list_s16[6] & 0x3FF; u32 height = list_s16[7] & 0x1FF; set_clut(psx_gpu, list_s16[5]); render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, width, height, current_command, list[0]); break; } case 0x68: case 0x69: case 0x6A: case 0x6B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]); break; } case 0x70: case 0x71: case 0x72: case 0x73: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]); break; } case 0x74: case 0x75: case 0x76: case 0x77: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 uv = list_s16[4]; set_clut(psx_gpu, list_s16[5]); render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 8, 8, current_command, list[0]); break; } case 0x78: case 0x79: case 0x7A: case 0x7B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]); break; } case 0x7C: case 0x7D: case 0x7E: case 0x7F: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 uv = list_s16[4]; set_clut(psx_gpu, list_s16[5]); render_sprite(psx_gpu, x, y, uv & 0xFF, (uv >> 8) & 0xFF, 16, 16, current_command, list[0]); break; } case 0x80: // vid -> vid { u32 sx = list_s16[2] & 0x3FF; u32 sy = list_s16[3] & 0x1FF; u32 dx = list_s16[4] & 0x3FF; u32 dy = list_s16[5] & 0x1FF; u32 w = ((list_s16[6] - 1) & 0x3FF) + 1; u32 h = ((list_s16[7] - 1) & 0x1FF) + 1; if (sx == dx && sy == dy && psx_gpu->mask_msb == 0) break; render_block_move(psx_gpu, sx, sy, dx, dy, w, h); break; } #ifdef PCSX case 0xA0: // sys -> vid case 0xC0: // vid -> sys goto breakloop; #else case 0xA0: // sys -> vid { u32 load_x = list_s16[2] & 0x3FF; u32 load_y = list_s16[3] & 0x1FF; u32 load_width = list_s16[4] & 0x3FF; u32 load_height = list_s16[5] & 0x1FF; u32 load_size = load_width * load_height; command_length += load_size / 2; if(load_size & 1) command_length++; render_block_copy(psx_gpu, (u16 *)&(list_s16[6]), load_x, load_y, load_width, load_height, load_width); break; } case 0xC0: // vid -> sys break; #endif case 0xE1: set_texture(psx_gpu, list[0]); if(list[0] & (1 << 9)) psx_gpu->render_state_base |= RENDER_STATE_DITHER; else psx_gpu->render_state_base &= ~RENDER_STATE_DITHER; psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1; SET_Ex(1, list[0]); break; case 0xE2: { // TODO: Clean u32 texture_window_settings = list[0]; u32 tmp, x, y, w, h; if(texture_window_settings != psx_gpu->texture_window_settings) { tmp = (texture_window_settings & 0x1F) | 0x20; for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1); tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20; for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1); tmp = 32 - (w >> 3); x = ((texture_window_settings >> 10) & tmp) << 3; tmp = 32 - (h >> 3); y = ((texture_window_settings >> 15) & tmp) << 3; flush_render_block_buffer(psx_gpu); psx_gpu->texture_window_settings = texture_window_settings; psx_gpu->texture_window_x = x; psx_gpu->texture_window_y = y; psx_gpu->texture_mask_width = w - 1; psx_gpu->texture_mask_height = h - 1; update_texture_ptr(psx_gpu); } SET_Ex(2, list[0]); break; } case 0xE3: { s16 viewport_start_x = list[0] & 0x3FF; s16 viewport_start_y = (list[0] >> 10) & 0x1FF; if(viewport_start_x == psx_gpu->viewport_start_x && viewport_start_y == psx_gpu->viewport_start_y) { break; } psx_gpu->viewport_start_x = viewport_start_x; psx_gpu->viewport_start_y = viewport_start_y; #ifdef TEXTURE_CACHE_4BPP psx_gpu->viewport_mask = texture_region_mask(psx_gpu->viewport_start_x, psx_gpu->viewport_start_y, psx_gpu->viewport_end_x, psx_gpu->viewport_end_y); #endif SET_Ex(3, list[0]); break; } case 0xE4: { s16 viewport_end_x = list[0] & 0x3FF; s16 viewport_end_y = (list[0] >> 10) & 0x1FF; if(viewport_end_x == psx_gpu->viewport_end_x && viewport_end_y == psx_gpu->viewport_end_y) { break; } psx_gpu->viewport_end_x = viewport_end_x; psx_gpu->viewport_end_y = viewport_end_y; #ifdef TEXTURE_CACHE_4BPP psx_gpu->viewport_mask = texture_region_mask(psx_gpu->viewport_start_x, psx_gpu->viewport_start_y, psx_gpu->viewport_end_x, psx_gpu->viewport_end_y); #endif SET_Ex(4, list[0]); break; } case 0xE5: { s32 offset_x = list[0] << 21; s32 offset_y = list[0] << 10; psx_gpu->offset_x = offset_x >> 21; psx_gpu->offset_y = offset_y >> 21; SET_Ex(5, list[0]); break; } case 0xE6: { u32 mask_settings = list[0]; u16 mask_msb = mask_settings << 15; if(list[0] & 0x2) psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE; else psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE; if(mask_msb != psx_gpu->mask_msb) { flush_render_block_buffer(psx_gpu); psx_gpu->mask_msb = mask_msb; } SET_Ex(6, list[0]); break; } default: break; } } breakloop: if (last_command != NULL) *last_command = current_command; return list - list_start; } #ifdef PCSX #define ENH_BUF_TABLE_STEP (1024 / sizeof(psx_gpu->enhancement_buf_by_x16)) static void update_enhancement_buf_table_from_hres(psx_gpu_struct *psx_gpu) { u32 b, x, s; b = 0; s = psx_gpu->enhancement_x_threshold; for (x = 0; x < sizeof(psx_gpu->enhancement_buf_by_x16); x++) { if (b < 3 && x * ENH_BUF_TABLE_STEP >= s - ENH_BUF_TABLE_STEP - 1) { s += psx_gpu->enhancement_x_threshold; b++; } psx_gpu->enhancement_buf_by_x16[x] = b; } } static void update_enhancement_buf_table_from_x(psx_gpu_struct *psx_gpu, u32 x0, u32 len) { u32 x, b; for (x = x0, b = 0; x >= len; b++) x -= len; if (b > 3) b = 3; memset(psx_gpu->enhancement_buf_by_x16 + x0 / ENH_BUF_TABLE_STEP, b, (len + ENH_BUF_TABLE_STEP - 1) / ENH_BUF_TABLE_STEP); } #define select_enhancement_buf(psx_gpu) \ psx_gpu->enhancement_current_buf_ptr = \ select_enhancement_buf_ptr(psx_gpu, psx_gpu->saved_viewport_start_x) #define enhancement_disable() { \ psx_gpu->vram_out_ptr = psx_gpu->vram_ptr; \ psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x; \ psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y; \ psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x; \ psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y; \ psx_gpu->uvrgb_phase = 0x8000; \ } #define enhancement_enable() { \ psx_gpu->vram_out_ptr = psx_gpu->enhancement_current_buf_ptr; \ psx_gpu->viewport_start_x = psx_gpu->saved_viewport_start_x * 2; \ psx_gpu->viewport_start_y = psx_gpu->saved_viewport_start_y * 2; \ psx_gpu->viewport_end_x = psx_gpu->saved_viewport_end_x * 2 + 1; \ psx_gpu->viewport_end_y = psx_gpu->saved_viewport_end_y * 2 + 1; \ psx_gpu->uvrgb_phase = 0x1000; \ } #define shift_vertices3(v) { \ v[0]->x *= 2; \ v[0]->y *= 2; \ v[1]->x *= 2; \ v[1]->y *= 2; \ v[2]->x *= 2; \ v[2]->y *= 2; \ } #define unshift_vertices3(v) { \ v[0]->x /= 2; \ v[0]->y /= 2; \ v[1]->x /= 2; \ v[1]->y /= 2; \ v[2]->x /= 2; \ v[2]->y /= 2; \ } #define shift_triangle_area() \ psx_gpu->triangle_area *= 4 extern void scale2x_tiles8(void *dst, const void *src, int w8, int h); #ifndef NEON_BUILD // TODO? void scale2x_tiles8(void *dst, const void *src, int w8, int h) { uint16_t* d = (uint16_t*)dst; const uint16_t* s = (const uint16_t*)src; while ( h-- ) { uint16_t* d_save = d; const uint16_t* s_save = s; int w = w8; while ( w-- ) { d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; d[ 0 ] = *s; d[ 1 ] = *s; d[ 1024 ] = *s; d[ 1025 ] = *s; d += 2; s++; } d = d_save + 2048; s = s_save + 1024; /* or 512? */ } } #endif static int disable_main_render; static void do_triangle_enhanced(psx_gpu_struct *psx_gpu, vertex_struct *vertexes, u32 current_command) { vertex_struct *vertex_ptrs[3]; if (!prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) return; if (!disable_main_render) render_triangle_p(psx_gpu, vertex_ptrs, current_command); enhancement_enable(); shift_vertices3(vertex_ptrs); shift_triangle_area(); render_triangle_p(psx_gpu, vertex_ptrs, current_command); } static void do_quad_enhanced(psx_gpu_struct *psx_gpu, vertex_struct *vertexes, u32 current_command) { vertex_struct *vertex_ptrs[3]; if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) { if (!disable_main_render) render_triangle_p(psx_gpu, vertex_ptrs, current_command); enhancement_enable(); shift_vertices3(vertex_ptrs); shift_triangle_area(); render_triangle_p(psx_gpu, vertex_ptrs, current_command); unshift_vertices3(vertex_ptrs); } enhancement_disable(); if (prepare_triangle(psx_gpu, &vertexes[1], vertex_ptrs)) { if (!disable_main_render) render_triangle_p(psx_gpu, vertex_ptrs, current_command); enhancement_enable(); shift_vertices3(vertex_ptrs); shift_triangle_area(); render_triangle_p(psx_gpu, vertex_ptrs, current_command); } } #if 0 #define fill_vertex(i, x_, y_, u_, v_, rgb_) \ vertexes[i].x = x_; \ vertexes[i].y = y_; \ vertexes[i].u = u_; \ vertexes[i].v = v_; \ vertexes[i].r = rgb_; \ vertexes[i].g = (rgb_) >> 8; \ vertexes[i].b = (rgb_) >> 16 static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y, u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb) { vertex_struct *vertex_ptrs[3]; u32 flags = (cmd_rgb >> 24); u32 color = cmd_rgb & 0xffffff; u32 render_state_base_saved = psx_gpu->render_state_base; int x1, y1; u8 u1, v1; flags &= (RENDER_FLAGS_MODULATE_TEXELS | RENDER_FLAGS_BLEND | RENDER_FLAGS_TEXTURE_MAP); set_triangle_color(psx_gpu, color); if(color == 0x808080) flags |= RENDER_FLAGS_MODULATE_TEXELS; psx_gpu->render_state_base &= ~RENDER_STATE_DITHER; enhancement_enable(); x1 = x + w; y1 = y + h; u1 = u + w; v1 = v + h; // FIXME.. if (u1 < u) u1 = 0xff; if (v1 < v) v1 = 0xff; // 0-2 // |/ // 1 fill_vertex(0, x, y, u, v, color); fill_vertex(1, x, y1, u, v1, color); fill_vertex(2, x1, y, u1, v, color); if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) { shift_vertices3(vertex_ptrs); shift_triangle_area(); render_triangle_p(psx_gpu, vertex_ptrs, flags); } // 0 // /| // 1-2 fill_vertex(0, x1, y, u1, v, color); fill_vertex(1, x, y1, u, v1, color); fill_vertex(2, x1, y1, u1, v1, color); if (prepare_triangle(psx_gpu, vertexes, vertex_ptrs)) { shift_vertices3(vertex_ptrs); shift_triangle_area(); render_triangle_p(psx_gpu, vertex_ptrs, flags); } psx_gpu->render_state_base = render_state_base_saved; } #else static void do_sprite_enhanced(psx_gpu_struct *psx_gpu, int x, int y, u32 u, u32 v, u32 w, u32 h, u32 cmd_rgb) { u32 flags = (cmd_rgb >> 24); u32 color = cmd_rgb & 0xffffff; render_sprite_4x(psx_gpu, x, y, u, v, w, h, flags, color); } #endif u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command) { u32 current_command = 0, command_length; u32 *list_start = list; u32 *list_end = list + (size / 4); psx_gpu->saved_viewport_start_x = psx_gpu->viewport_start_x; psx_gpu->saved_viewport_start_y = psx_gpu->viewport_start_y; psx_gpu->saved_viewport_end_x = psx_gpu->viewport_end_x; psx_gpu->saved_viewport_end_y = psx_gpu->viewport_end_y; select_enhancement_buf(psx_gpu); for(; list < list_end; list += 1 + command_length) { s16 *list_s16 = (void *)list; current_command = *list >> 24; command_length = command_lengths[current_command]; if (list + 1 + command_length > list_end) { current_command = (u32)-1; break; } enhancement_disable(); switch(current_command) { case 0x00: break; case 0x02: { u32 x = list_s16[2] & 0x3FF; u32 y = list_s16[3] & 0x1FF; u32 width = list_s16[4] & 0x3FF; u32 height = list_s16[5] & 0x1FF; u32 color = list[0] & 0xFFFFFF; x &= ~0xF; width = ((width + 0xF) & ~0xF); do_fill(psx_gpu, x, y, width, height, color); psx_gpu->vram_out_ptr = select_enhancement_buf_ptr(psx_gpu, x); x *= 2; y *= 2; width *= 2; height *= 2; render_block_fill_enh(psx_gpu, color, x, y, width, height); break; } case 0x20 ... 0x23: { set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy(0, 2); get_vertex_data_xy(1, 4); get_vertex_data_xy(2, 6); do_triangle_enhanced(psx_gpu, vertexes, current_command); break; } case 0x24 ... 0x27: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[9]); set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy_uv(0, 2); get_vertex_data_xy_uv(1, 6); get_vertex_data_xy_uv(2, 10); do_triangle_enhanced(psx_gpu, vertexes, current_command); break; } case 0x28 ... 0x2B: { set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy(0, 2); get_vertex_data_xy(1, 4); get_vertex_data_xy(2, 6); get_vertex_data_xy(3, 8); do_quad_enhanced(psx_gpu, vertexes, current_command); break; } case 0x2C ... 0x2F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[9]); set_triangle_color(psx_gpu, list[0] & 0xFFFFFF); get_vertex_data_xy_uv(0, 2); get_vertex_data_xy_uv(1, 6); get_vertex_data_xy_uv(2, 10); get_vertex_data_xy_uv(3, 14); do_quad_enhanced(psx_gpu, vertexes, current_command); break; } case 0x30 ... 0x33: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); get_vertex_data_xy_rgb(2, 8); do_triangle_enhanced(psx_gpu, vertexes, current_command); break; } case 0x34: case 0x35: case 0x36: case 0x37: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); get_vertex_data_xy_uv_rgb(0, 0); get_vertex_data_xy_uv_rgb(1, 6); get_vertex_data_xy_uv_rgb(2, 12); do_triangle_enhanced(psx_gpu, vertexes, current_command); break; } case 0x38: case 0x39: case 0x3A: case 0x3B: { get_vertex_data_xy_rgb(0, 0); get_vertex_data_xy_rgb(1, 4); get_vertex_data_xy_rgb(2, 8); get_vertex_data_xy_rgb(3, 12); do_quad_enhanced(psx_gpu, vertexes, current_command); break; } case 0x3C: case 0x3D: case 0x3E: case 0x3F: { set_clut(psx_gpu, list_s16[5]); set_texture(psx_gpu, list_s16[11]); get_vertex_data_xy_uv_rgb(0, 0); get_vertex_data_xy_uv_rgb(1, 6); get_vertex_data_xy_uv_rgb(2, 12); get_vertex_data_xy_uv_rgb(3, 18); do_quad_enhanced(psx_gpu, vertexes, current_command); break; } case 0x40 ... 0x47: { vertexes[0].x = list_s16[2] + psx_gpu->offset_x; vertexes[0].y = list_s16[3] + psx_gpu->offset_y; vertexes[1].x = list_s16[4] + psx_gpu->offset_x; vertexes[1].y = list_s16[5] + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, list[0], 0); enhancement_enable(); render_line(psx_gpu, vertexes, current_command, list[0], 1); break; } case 0x48 ... 0x4F: { u32 num_vertexes = 1; u32 *list_position = &(list[2]); u32 xy = list[1]; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; xy = *list_position; while(1) { vertexes[0] = vertexes[1]; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; enhancement_disable(); render_line(psx_gpu, vertexes, current_command, list[0], 0); enhancement_enable(); render_line(psx_gpu, vertexes, current_command, list[0], 1); list_position++; num_vertexes++; if(list_position >= list_end) { current_command = (u32)-1; goto breakloop; } xy = *list_position; if((xy & 0xF000F000) == 0x50005000) break; } command_length += (num_vertexes - 2); break; } case 0x50 ... 0x57: { vertexes[0].r = list[0] & 0xFF; vertexes[0].g = (list[0] >> 8) & 0xFF; vertexes[0].b = (list[0] >> 16) & 0xFF; vertexes[0].x = list_s16[2] + psx_gpu->offset_x; vertexes[0].y = list_s16[3] + psx_gpu->offset_y; vertexes[1].r = list[2] & 0xFF; vertexes[1].g = (list[2] >> 8) & 0xFF; vertexes[1].b = (list[2] >> 16) & 0xFF; vertexes[1].x = list_s16[6] + psx_gpu->offset_x; vertexes[1].y = list_s16[7] + psx_gpu->offset_y; render_line(psx_gpu, vertexes, current_command, 0, 0); enhancement_enable(); render_line(psx_gpu, vertexes, current_command, 0, 1); break; } case 0x58 ... 0x5F: { u32 num_vertexes = 1; u32 *list_position = &(list[2]); u32 color = list[0]; u32 xy = list[1]; vertexes[1].r = color & 0xFF; vertexes[1].g = (color >> 8) & 0xFF; vertexes[1].b = (color >> 16) & 0xFF; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; color = list_position[0]; while(1) { xy = list_position[1]; vertexes[0] = vertexes[1]; vertexes[1].r = color & 0xFF; vertexes[1].g = (color >> 8) & 0xFF; vertexes[1].b = (color >> 16) & 0xFF; vertexes[1].x = (xy & 0xFFFF) + psx_gpu->offset_x; vertexes[1].y = (xy >> 16) + psx_gpu->offset_y; enhancement_disable(); render_line(psx_gpu, vertexes, current_command, 0, 0); enhancement_enable(); render_line(psx_gpu, vertexes, current_command, 0, 1); list_position += 2; num_vertexes++; if(list_position >= list_end) { current_command = (u32)-1; goto breakloop; } color = list_position[0]; if((color & 0xF000F000) == 0x50005000) break; } command_length += ((num_vertexes - 2) * 2); break; } case 0x60 ... 0x63: { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u32 width = list_s16[4] & 0x3FF; u32 height = list_s16[5] & 0x1FF; render_sprite(psx_gpu, x, y, 0, 0, width, height, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, 0, 0, width, height, list[0]); break; } case 0x64 ... 0x67: { u32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); u32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u8 u = list_s16[4]; u8 v = list_s16[4] >> 8; u32 width = list_s16[6] & 0x3FF; u32 height = list_s16[7] & 0x1FF; set_clut(psx_gpu, list_s16[5]); render_sprite(psx_gpu, x, y, u, v, width, height, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, u, v, width, height, list[0]); break; } case 0x68: case 0x69: case 0x6A: case 0x6B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); render_sprite(psx_gpu, x, y, 0, 0, 1, 1, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, 0, 0, 1, 1, list[0]); break; } case 0x70: case 0x71: case 0x72: case 0x73: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); render_sprite(psx_gpu, x, y, 0, 0, 8, 8, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, 0, 0, 8, 8, list[0]); break; } case 0x74: case 0x75: case 0x76: case 0x77: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u8 u = list_s16[4]; u8 v = list_s16[4] >> 8; set_clut(psx_gpu, list_s16[5]); render_sprite(psx_gpu, x, y, u, v, 8, 8, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, u, v, 8, 8, list[0]); break; } case 0x78: case 0x79: case 0x7A: case 0x7B: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); render_sprite(psx_gpu, x, y, 0, 0, 16, 16, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, 0, 0, 16, 16, list[0]); break; } case 0x7C: case 0x7D: case 0x7E: case 0x7F: { s32 x = sign_extend_11bit(list_s16[2] + psx_gpu->offset_x); s32 y = sign_extend_11bit(list_s16[3] + psx_gpu->offset_y); u8 u = list_s16[4]; u8 v = list_s16[4] >> 8; set_clut(psx_gpu, list_s16[5]); render_sprite(psx_gpu, x, y, u, v, 16, 16, current_command, list[0]); do_sprite_enhanced(psx_gpu, x, y, u, v, 16, 16, list[0]); break; } case 0x80: // vid -> vid { u32 sx = list_s16[2] & 0x3FF; u32 sy = list_s16[3] & 0x1FF; u32 dx = list_s16[4] & 0x3FF; u32 dy = list_s16[5] & 0x1FF; u32 w = ((list_s16[6] - 1) & 0x3FF) + 1; u32 h = ((list_s16[7] - 1) & 0x1FF) + 1; u16 *buf; if (sx == dx && sy == dy && psx_gpu->mask_msb == 0) break; render_block_move(psx_gpu, sx, sy, dx, dy, w, h); if (dy + h > 512) h = 512 - dy; sx = sx & ~7; // FIXME? dx = dx * 2 & ~7; dy *= 2; w = (w + 7) / 8; buf = select_enhancement_buf_ptr(psx_gpu, dx / 2); scale2x_tiles8(buf + dy * 1024 + dx, psx_gpu->vram_ptr + sy * 1024 + sx, w, h); break; } case 0xA0: // sys -> vid case 0xC0: // vid -> sys goto breakloop; case 0xE1: set_texture(psx_gpu, list[0]); if(list[0] & (1 << 9)) psx_gpu->render_state_base |= RENDER_STATE_DITHER; else psx_gpu->render_state_base &= ~RENDER_STATE_DITHER; psx_gpu->display_area_draw_enable = (list[0] >> 10) & 0x1; SET_Ex(1, list[0]); break; case 0xE2: { // TODO: Clean u32 texture_window_settings = list[0]; u32 tmp, x, y, w, h; if(texture_window_settings != psx_gpu->texture_window_settings) { tmp = (texture_window_settings & 0x1F) | 0x20; for(w = 8; (tmp & 1) == 0; tmp >>= 1, w <<= 1); tmp = ((texture_window_settings >> 5) & 0x1f) | 0x20; for (h = 8; (tmp & 1) == 0; tmp >>= 1, h <<= 1); tmp = 32 - (w >> 3); x = ((texture_window_settings >> 10) & tmp) << 3; tmp = 32 - (h >> 3); y = ((texture_window_settings >> 15) & tmp) << 3; flush_render_block_buffer(psx_gpu); psx_gpu->texture_window_settings = texture_window_settings; psx_gpu->texture_window_x = x; psx_gpu->texture_window_y = y; psx_gpu->texture_mask_width = w - 1; psx_gpu->texture_mask_height = h - 1; update_texture_ptr(psx_gpu); } SET_Ex(2, list[0]); break; } case 0xE3: { s16 viewport_start_x = list[0] & 0x3FF; s16 viewport_start_y = (list[0] >> 10) & 0x1FF; u32 w; s32 d; if(viewport_start_x == psx_gpu->viewport_start_x && viewport_start_y == psx_gpu->viewport_start_y) { break; } psx_gpu->viewport_start_x = viewport_start_x; psx_gpu->viewport_start_y = viewport_start_y; psx_gpu->saved_viewport_start_x = viewport_start_x; psx_gpu->saved_viewport_start_y = viewport_start_y; w = (u32)psx_gpu->viewport_end_x - (u32)viewport_start_x + 1; d = psx_gpu->enhancement_x_threshold - w; if(-16 <= d && d <= 16) { update_enhancement_buf_table_from_x(psx_gpu, viewport_start_x, w); } select_enhancement_buf(psx_gpu); #ifdef TEXTURE_CACHE_4BPP psx_gpu->viewport_mask = texture_region_mask(psx_gpu->viewport_start_x, psx_gpu->viewport_start_y, psx_gpu->viewport_end_x, psx_gpu->viewport_end_y); #endif SET_Ex(3, list[0]); break; } case 0xE4: { s16 viewport_end_x = list[0] & 0x3FF; s16 viewport_end_y = (list[0] >> 10) & 0x1FF; u32 w; s32 d; if(viewport_end_x == psx_gpu->viewport_end_x && viewport_end_y == psx_gpu->viewport_end_y) { break; } psx_gpu->viewport_end_x = viewport_end_x; psx_gpu->viewport_end_y = viewport_end_y; psx_gpu->saved_viewport_end_x = viewport_end_x; psx_gpu->saved_viewport_end_y = viewport_end_y; w = (u32)viewport_end_x - (u32)psx_gpu->viewport_start_x + 1; d = psx_gpu->enhancement_x_threshold - w; if(-16 <= d && d <= 16) { update_enhancement_buf_table_from_x(psx_gpu, psx_gpu->viewport_start_x, w); } select_enhancement_buf(psx_gpu); #ifdef TEXTURE_CACHE_4BPP psx_gpu->viewport_mask = texture_region_mask(psx_gpu->viewport_start_x, psx_gpu->viewport_start_y, psx_gpu->viewport_end_x, psx_gpu->viewport_end_y); #endif SET_Ex(4, list[0]); break; } case 0xE5: { s32 offset_x = list[0] << 21; s32 offset_y = list[0] << 10; psx_gpu->offset_x = offset_x >> 21; psx_gpu->offset_y = offset_y >> 21; SET_Ex(5, list[0]); break; } case 0xE6: { u32 mask_settings = list[0]; u16 mask_msb = mask_settings << 15; if(list[0] & 0x2) psx_gpu->render_state_base |= RENDER_STATE_MASK_EVALUATE; else psx_gpu->render_state_base &= ~RENDER_STATE_MASK_EVALUATE; if(mask_msb != psx_gpu->mask_msb) { flush_render_block_buffer(psx_gpu); psx_gpu->mask_msb = mask_msb; } SET_Ex(6, list[0]); break; } default: break; } } enhancement_disable(); breakloop: if (last_command != NULL) *last_command = current_command; return list - list_start; } #endif /* PCSX */ // vim:shiftwidth=2:expandtab