diff --git a/src/xenia/gpu/registers.h b/src/xenia/gpu/registers.h index 2c710317b..3209a7063 100644 --- a/src/xenia/gpu/registers.h +++ b/src/xenia/gpu/registers.h @@ -30,6 +30,27 @@ namespace reg { ***************************************************/ +union COHER_STATUS_HOST { + xe::bf matching_contexts; + xe::bf rb_copy_dest_base_ena; + xe::bf dest_base_0_ena; + xe::bf dest_base_1_ena; + xe::bf dest_base_2_ena; + xe::bf dest_base_3_ena; + xe::bf dest_base_4_ena; + xe::bf dest_base_5_ena; + xe::bf dest_base_6_ena; + xe::bf dest_base_7_ena; + + xe::bf vc_action_ena; + xe::bf tc_action_ena; + xe::bf pglb_action_ena; + + xe::bf status; + + uint32_t value; +}; + union WAIT_UNTIL { xe::bf wait_re_vsync; xe::bf wait_fe_vsync; @@ -91,10 +112,26 @@ union PA_SU_SC_MODE_CNTL { uint32_t value; }; +// Setup Unit Vertex Control +union PA_SU_VTX_CNTL { + xe::bf pix_center; // 1 = half pixel offset + xe::bf round_mode; + xe::bf quant_mode; + + uint32_t value; +}; + +union PA_SC_MPASS_PS_CNTL { + xe::bf mpass_pix_vec_per_pass; + xe::bf mpass_ps_ena; + + uint32_t value; +}; + // Scanline converter viz query union PA_SC_VIZ_QUERY { xe::bf viz_query_ena; - xe::bf viz_query_id; + xe::bf viz_query_id; xe::bf kill_pix_post_early_z; uint32_t value; @@ -111,7 +148,9 @@ union PA_CL_CLIP_CNTL { xe::bf ucp_ena_4; xe::bf ucp_ena_5; + xe::bf ps_ucp_mode; xe::bf clip_disable; + xe::bf ucp_cull_only_ena; xe::bf boundary_edge_flag_ena; xe::bf dx_clip_space_def; xe::bf dis_clip_err_detect; @@ -156,8 +195,8 @@ union RB_MODECONTROL { union RB_SURFACE_INFO { xe::bf surface_pitch; - xe::bf msaa_samples; - xe::bf hiz_pitch; + xe::bf msaa_samples; + xe::bf hiz_pitch; uint32_t value; }; @@ -166,13 +205,6 @@ union RB_COLORCONTROL { xe::bf alpha_func; xe::bf alpha_test_enable; xe::bf alpha_to_mask_enable; - xe::bf blend_disable; - xe::bf fog_enable; - xe::bf vs_exports_fog; - xe::bf rop_code; - xe::bf dither_mode; - xe::bf dither_type; - xe::bf pixel_fog; xe::bf alpha_to_mask_offset0; xe::bf alpha_to_mask_offset1; @@ -185,7 +217,7 @@ union RB_COLORCONTROL { union RB_COLOR_INFO { xe::bf color_base; xe::bf color_format; - xe::bf unk_22; + xe::bf color_exp_bias; uint32_t value; }; @@ -197,6 +229,29 @@ union RB_DEPTH_INFO { uint32_t value; }; +union RB_COPY_CONTROL { + xe::bf copy_src_select; + xe::bf copy_sample_select; + xe::bf color_clear_enable; + xe::bf depth_clear_enable; + + xe::bf copy_command; + + uint32_t value; +}; + +union RB_COPY_DEST_INFO { + xe::bf copy_dest_endian; + xe::bf copy_dest_array; + xe::bf copy_dest_slice; + xe::bf copy_dest_format; + xe::bf copy_dest_number; + xe::bf copy_dest_exp_bias; + xe::bf copy_dest_swap; + + uint32_t value; +}; + } // namespace reg } // namespace gpu } // namespace xe diff --git a/src/xenia/gpu/vulkan/render_cache.cc b/src/xenia/gpu/vulkan/render_cache.cc index 659aadb1a..ef6f4b8b3 100644 --- a/src/xenia/gpu/vulkan/render_cache.cc +++ b/src/xenia/gpu/vulkan/render_cache.cc @@ -16,6 +16,7 @@ #include "xenia/base/memory.h" #include "xenia/base/profiling.h" #include "xenia/gpu/gpu_flags.h" +#include "xenia/gpu/registers.h" #include "xenia/gpu/vulkan/vulkan_gpu_flags.h" namespace xe { @@ -63,8 +64,7 @@ VkFormat DepthRenderTargetFormatToVkFormat(DepthRenderTargetFormat format) { case DepthRenderTargetFormat::kD24S8: return VK_FORMAT_D24_UNORM_S8_UINT; case DepthRenderTargetFormat::kD24FS8: - // TODO(benvanik): some way to emulate? resolve-time flag? - XELOGW("Unsupported EDRAM format kD24FS8 used"); + // Vulkan doesn't support 24-bit floats, so just promote it to 32-bit return VK_FORMAT_D32_SFLOAT_S8_UINT; default: return VK_FORMAT_UNDEFINED; @@ -296,6 +296,7 @@ CachedFramebuffer::CachedFramebuffer( VkFramebufferCreateInfo framebuffer_info; framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebuffer_info.pNext = nullptr; + framebuffer_info.flags = 0; framebuffer_info.renderPass = render_pass; framebuffer_info.attachmentCount = image_view_count; framebuffer_info.pAttachments = image_views; @@ -422,6 +423,8 @@ CachedRenderPass::CachedRenderPass(VkDevice device, DepthRenderTargetFormatToVkFormat(depth_config.format); // Single subpass that writes to our attachments. + // FIXME: "Multiple attachments that alias the same memory must not be used in + // a single subpass" VkSubpassDescription subpass_info; subpass_info.flags = 0; subpass_info.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; @@ -567,13 +570,14 @@ bool RenderCache::dirty() const { auto& cur_regs = shadow_registers_; bool dirty = false; - dirty |= cur_regs.rb_modecontrol != regs[XE_GPU_REG_RB_MODECONTROL].u32; - dirty |= cur_regs.rb_surface_info != regs[XE_GPU_REG_RB_SURFACE_INFO].u32; - dirty |= cur_regs.rb_color_info != regs[XE_GPU_REG_RB_COLOR_INFO].u32; - dirty |= cur_regs.rb_color1_info != regs[XE_GPU_REG_RB_COLOR1_INFO].u32; - dirty |= cur_regs.rb_color2_info != regs[XE_GPU_REG_RB_COLOR2_INFO].u32; - dirty |= cur_regs.rb_color3_info != regs[XE_GPU_REG_RB_COLOR3_INFO].u32; - dirty |= cur_regs.rb_depth_info != regs[XE_GPU_REG_RB_DEPTH_INFO].u32; + dirty |= cur_regs.rb_modecontrol.value != regs[XE_GPU_REG_RB_MODECONTROL].u32; + dirty |= + cur_regs.rb_surface_info.value != regs[XE_GPU_REG_RB_SURFACE_INFO].u32; + dirty |= cur_regs.rb_color_info.value != regs[XE_GPU_REG_RB_COLOR_INFO].u32; + dirty |= cur_regs.rb_color1_info.value != regs[XE_GPU_REG_RB_COLOR1_INFO].u32; + dirty |= cur_regs.rb_color2_info.value != regs[XE_GPU_REG_RB_COLOR2_INFO].u32; + dirty |= cur_regs.rb_color3_info.value != regs[XE_GPU_REG_RB_COLOR3_INFO].u32; + dirty |= cur_regs.rb_depth_info.value != regs[XE_GPU_REG_RB_DEPTH_INFO].u32; dirty |= cur_regs.pa_sc_window_scissor_tl != regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32; dirty |= cur_regs.pa_sc_window_scissor_br != @@ -597,13 +601,20 @@ const RenderState* RenderCache::BeginRenderPass(VkCommandBuffer command_buffer, CachedFramebuffer* framebuffer = nullptr; auto& regs = shadow_registers_; bool dirty = false; - dirty |= SetShadowRegister(®s.rb_modecontrol, XE_GPU_REG_RB_MODECONTROL); - dirty |= SetShadowRegister(®s.rb_surface_info, XE_GPU_REG_RB_SURFACE_INFO); - dirty |= SetShadowRegister(®s.rb_color_info, XE_GPU_REG_RB_COLOR_INFO); - dirty |= SetShadowRegister(®s.rb_color1_info, XE_GPU_REG_RB_COLOR1_INFO); - dirty |= SetShadowRegister(®s.rb_color2_info, XE_GPU_REG_RB_COLOR2_INFO); - dirty |= SetShadowRegister(®s.rb_color3_info, XE_GPU_REG_RB_COLOR3_INFO); - dirty |= SetShadowRegister(®s.rb_depth_info, XE_GPU_REG_RB_DEPTH_INFO); + dirty |= + SetShadowRegister(®s.rb_modecontrol.value, XE_GPU_REG_RB_MODECONTROL); + dirty |= SetShadowRegister(®s.rb_surface_info.value, + XE_GPU_REG_RB_SURFACE_INFO); + dirty |= + SetShadowRegister(®s.rb_color_info.value, XE_GPU_REG_RB_COLOR_INFO); + dirty |= + SetShadowRegister(®s.rb_color1_info.value, XE_GPU_REG_RB_COLOR1_INFO); + dirty |= + SetShadowRegister(®s.rb_color2_info.value, XE_GPU_REG_RB_COLOR2_INFO); + dirty |= + SetShadowRegister(®s.rb_color3_info.value, XE_GPU_REG_RB_COLOR3_INFO); + dirty |= + SetShadowRegister(®s.rb_depth_info.value, XE_GPU_REG_RB_DEPTH_INFO); dirty |= SetShadowRegister(®s.pa_sc_window_scissor_tl, XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL); dirty |= SetShadowRegister(®s.pa_sc_window_scissor_br, @@ -696,13 +707,12 @@ bool RenderCache::ParseConfiguration(RenderConfiguration* config) { // RB_MODECONTROL // Rough mode control (color, color+depth, etc). - config->mode_control = static_cast(regs.rb_modecontrol & 0x7); + config->mode_control = regs.rb_modecontrol.edram_mode; // RB_SURFACE_INFO // http://fossies.org/dox/MesaLib-10.3.5/fd2__gmem_8c_source.html - config->surface_pitch_px = regs.rb_surface_info & 0x3FFF; - config->surface_msaa = - static_cast((regs.rb_surface_info >> 16) & 0x3); + config->surface_pitch_px = regs.rb_surface_info.surface_pitch; + config->surface_msaa = regs.rb_surface_info.msaa_samples; // TODO(benvanik): verify min/max so we don't go out of bounds. // TODO(benvanik): has to be a good way to get height. @@ -721,14 +731,13 @@ bool RenderCache::ParseConfiguration(RenderConfiguration* config) { // Color attachment configuration. if (config->mode_control == ModeControl::kColorDepth) { - uint32_t color_info[4] = { + reg::RB_COLOR_INFO color_info[4] = { regs.rb_color_info, regs.rb_color1_info, regs.rb_color2_info, regs.rb_color3_info, }; for (int i = 0; i < 4; ++i) { - config->color[i].edram_base = color_info[i] & 0xFFF; - config->color[i].format = - static_cast((color_info[i] >> 16) & 0xF); + config->color[i].edram_base = color_info[i].color_base; + config->color[i].format = color_info[i].color_format; // We don't support GAMMA formats, so switch them to what we do support. switch (config->color[i].format) { case ColorRenderTargetFormat::k_8_8_8_8_GAMMA: @@ -741,10 +750,6 @@ bool RenderCache::ParseConfiguration(RenderConfiguration* config) { config->color[i].format = ColorRenderTargetFormat::k_2_10_10_10_FLOAT; break; } - - // Make sure all unknown bits are unset. - // RDR sets bit 0x00400000 - // assert_zero(color_info[i] & ~0x000F0FFF); } } else { for (int i = 0; i < 4; ++i) { @@ -757,12 +762,8 @@ bool RenderCache::ParseConfiguration(RenderConfiguration* config) { // Depth/stencil attachment configuration. if (config->mode_control == ModeControl::kColorDepth || config->mode_control == ModeControl::kDepth) { - config->depth_stencil.edram_base = regs.rb_depth_info & 0xFFF; - config->depth_stencil.format = - static_cast((regs.rb_depth_info >> 16) & 0x1); - - // Make sure all unknown bits are unset. - // assert_zero(regs.rb_depth_info & ~0x00010FFF); + config->depth_stencil.edram_base = regs.rb_depth_info.depth_base; + config->depth_stencil.format = regs.rb_depth_info.depth_format; } else { config->depth_stencil.edram_base = 0; config->depth_stencil.format = DepthRenderTargetFormat::kD24S8; @@ -872,6 +873,27 @@ bool RenderCache::ConfigureRenderPass(VkCommandBuffer command_buffer, return true; } +VkImageView RenderCache::FindTileView(uint32_t base, uint32_t pitch, + MsaaSamples samples, bool color_or_depth, + uint32_t format) { + uint32_t tile_width = samples == MsaaSamples::k4X ? 40 : 80; + uint32_t tile_height = samples != MsaaSamples::k1X ? 8 : 16; + + TileViewKey key; + key.tile_offset = base; + key.tile_width = xe::round_up(pitch, tile_width) / tile_width; + key.tile_height = 160; + key.color_or_depth = color_or_depth ? 1 : 0; + key.msaa_samples = 0; + key.edram_format = static_cast(format); + auto view = FindTileView(key); + if (view) { + return view->image_view; + } + + return nullptr; +} + CachedTileView* RenderCache::FindOrCreateTileView( VkCommandBuffer command_buffer, const TileViewKey& view_key) { auto tile_view = FindTileView(view_key); diff --git a/src/xenia/gpu/vulkan/render_cache.h b/src/xenia/gpu/vulkan/render_cache.h index c9f0adf98..9f6a72dc8 100644 --- a/src/xenia/gpu/vulkan/render_cache.h +++ b/src/xenia/gpu/vulkan/render_cache.h @@ -11,6 +11,7 @@ #define XENIA_GPU_VULKAN_RENDER_CACHE_H_ #include "xenia/gpu/register_file.h" +#include "xenia/gpu/registers.h" #include "xenia/gpu/shader.h" #include "xenia/gpu/texture_info.h" #include "xenia/gpu/vulkan/vulkan_shader.h" @@ -268,6 +269,9 @@ class RenderCache { // with an already open pass. bool dirty() const; + VkImageView FindTileView(uint32_t base, uint32_t pitch, MsaaSamples samples, + bool color_or_depth, uint32_t format); + // Begins a render pass targeting the state-specified framebuffer formats. // The command buffer will be transitioned into the render pass phase. const RenderState* BeginRenderPass(VkCommandBuffer command_buffer, @@ -353,13 +357,13 @@ class RenderCache { // If the registers don't change between passes we can quickly reuse the // previous one. struct ShadowRegisters { - uint32_t rb_modecontrol; - uint32_t rb_surface_info; - uint32_t rb_color_info; - uint32_t rb_color1_info; - uint32_t rb_color2_info; - uint32_t rb_color3_info; - uint32_t rb_depth_info; + reg::RB_MODECONTROL rb_modecontrol; + reg::RB_SURFACE_INFO rb_surface_info; + reg::RB_COLOR_INFO rb_color_info; + reg::RB_COLOR_INFO rb_color1_info; + reg::RB_COLOR_INFO rb_color2_info; + reg::RB_COLOR_INFO rb_color3_info; + reg::RB_DEPTH_INFO rb_depth_info; uint32_t pa_sc_window_scissor_tl; uint32_t pa_sc_window_scissor_br;