[GPU] Remove most hardcoded register/instruction layouts from common and D3D12 code
This commit is contained in:
@@ -1345,7 +1345,7 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
// Update system constants before uploading them.
|
||||
UpdateSystemConstantValues(
|
||||
memexport_used, primitive_two_faced, line_loop_closing_index,
|
||||
indexed ? index_buffer_info->endianness : Endian::kUnspecified,
|
||||
indexed ? index_buffer_info->endianness : Endian::kNone,
|
||||
adaptive_tessellation ? (index_buffer_info->guest_base & 0x1FFFFFFC) : 0,
|
||||
early_z, GetCurrentColorMask(pixel_shader), pipeline_render_targets);
|
||||
|
||||
@@ -1975,7 +1975,7 @@ void D3D12CommandProcessor::UpdateFixedFunctionState(bool primitive_two_faced) {
|
||||
|
||||
// Stencil reference value. Per-face reference not supported by Direct3D 12,
|
||||
// choose the back face one only if drawing only back faces.
|
||||
uint32_t stencil_ref_mask_reg;
|
||||
Register stencil_ref_mask_reg;
|
||||
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
|
||||
if (primitive_two_faced &&
|
||||
regs.Get<reg::RB_DEPTHCONTROL>().backface_enable &&
|
||||
@@ -2032,13 +2032,8 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
float rt_clamp[4][4];
|
||||
uint32_t rt_keep_masks[4][2];
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
static const uint32_t kColorInfoRegs[] = {
|
||||
XE_GPU_REG_RB_COLOR_INFO,
|
||||
XE_GPU_REG_RB_COLOR1_INFO,
|
||||
XE_GPU_REG_RB_COLOR2_INFO,
|
||||
XE_GPU_REG_RB_COLOR3_INFO,
|
||||
};
|
||||
auto color_info = regs.Get<reg::RB_COLOR_INFO>(kColorInfoRegs[i]);
|
||||
auto color_info = regs.Get<reg::RB_COLOR_INFO>(
|
||||
reg::RB_COLOR_INFO::rt_register_indices[i]);
|
||||
color_infos[i] = color_info;
|
||||
|
||||
if (IsROVUsedForEDRAM()) {
|
||||
@@ -2125,7 +2120,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
}
|
||||
// Alpha test.
|
||||
if (rb_colorcontrol.alpha_test_enable) {
|
||||
flags |= uint32_t(rb_colorcontrol.alpha_func.value())
|
||||
flags |= uint32_t(rb_colorcontrol.alpha_func)
|
||||
<< DxbcShaderTranslator::kSysFlag_AlphaPassIfLess_Shift;
|
||||
} else {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_AlphaPassIfLess |
|
||||
@@ -2149,7 +2144,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
flags |= DxbcShaderTranslator::kSysFlag_ROVDepthFloat24;
|
||||
}
|
||||
if (rb_depthcontrol.z_enable) {
|
||||
flags |= uint32_t(rb_depthcontrol.zfunc.value())
|
||||
flags |= uint32_t(rb_depthcontrol.zfunc)
|
||||
<< DxbcShaderTranslator::kSysFlag_ROVDepthPassIfLess_Shift;
|
||||
if (rb_depthcontrol.z_write_enable) {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_ROVDepthWrite;
|
||||
@@ -2350,7 +2345,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
// EDRAM pitch for ROV writing.
|
||||
if (IsROVUsedForEDRAM()) {
|
||||
uint32_t edram_pitch_tiles =
|
||||
((std::min(rb_surface_info.surface_pitch.value(), 2560u) *
|
||||
((std::min(rb_surface_info.surface_pitch, 2560u) *
|
||||
(rb_surface_info.msaa_samples >= MsaaSamples::k4X ? 2 : 1)) +
|
||||
79) /
|
||||
80;
|
||||
@@ -2408,14 +2403,8 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
4 * sizeof(float)) != 0;
|
||||
std::memcpy(system_constants_.edram_rt_clamp[i], rt_clamp[i],
|
||||
4 * sizeof(float));
|
||||
static const uint32_t kBlendControlRegs[] = {
|
||||
XE_GPU_REG_RB_BLENDCONTROL_0,
|
||||
XE_GPU_REG_RB_BLENDCONTROL_1,
|
||||
XE_GPU_REG_RB_BLENDCONTROL_2,
|
||||
XE_GPU_REG_RB_BLENDCONTROL_3,
|
||||
};
|
||||
uint32_t blend_factors_ops =
|
||||
regs[kBlendControlRegs[i]].u32 & 0x1FFF1FFF;
|
||||
regs[reg::RB_BLENDCONTROL::rt_register_indices[i]].u32 & 0x1FFF1FFF;
|
||||
dirty |= system_constants_.edram_rt_blend_factors_ops[i] !=
|
||||
blend_factors_ops;
|
||||
system_constants_.edram_rt_blend_factors_ops[i] = blend_factors_ops;
|
||||
@@ -2537,7 +2526,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
system_constants_.edram_stencil_back_write_mask =
|
||||
rb_stencilrefmask_bf.stencilwritemask;
|
||||
uint32_t stencil_func_ops_bf =
|
||||
(rb_depthcontrol.value >> 8) & ((1 << 12) - 1);
|
||||
(rb_depthcontrol.value >> 20) & ((1 << 12) - 1);
|
||||
dirty |= system_constants_.edram_stencil_back_func_ops !=
|
||||
stencil_func_ops_bf;
|
||||
system_constants_.edram_stencil_back_func_ops = stencil_func_ops_bf;
|
||||
|
||||
@@ -363,7 +363,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[5],
|
||||
PipelineDescription& description_out) {
|
||||
auto& regs = *register_file_;
|
||||
uint32_t pa_su_sc_mode_cntl = regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32;
|
||||
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
|
||||
bool primitive_two_faced = IsPrimitiveTwoFaced(tessellated, primitive_type);
|
||||
|
||||
// Initialize all unused fields to zero for comparison/hashing.
|
||||
@@ -381,7 +381,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
description_out.pixel_shader = pixel_shader;
|
||||
|
||||
// Index buffer strip cut value.
|
||||
if (pa_su_sc_mode_cntl & (1 << 21)) {
|
||||
if (pa_su_sc_mode_cntl.multi_prim_ib_ena) {
|
||||
// Not using 0xFFFF with 32-bit indices because in index buffers it will be
|
||||
// 0xFFFF0000 anyway due to endianness.
|
||||
description_out.strip_cut_index = index_format == IndexFormat::kInt32
|
||||
@@ -479,53 +479,60 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
// Xenos fill mode 1).
|
||||
// Here we also assume that only one side is culled - if two sides are culled,
|
||||
// the D3D12 command processor will drop such draw early.
|
||||
uint32_t cull_mode = primitive_two_faced ? (pa_su_sc_mode_cntl & 0x3) : 0;
|
||||
bool cull_front, cull_back;
|
||||
if (primitive_two_faced) {
|
||||
cull_front = pa_su_sc_mode_cntl.cull_front != 0;
|
||||
cull_back = pa_su_sc_mode_cntl.cull_back != 0;
|
||||
} else {
|
||||
cull_front = false;
|
||||
cull_back = false;
|
||||
}
|
||||
float poly_offset = 0.0f, poly_offset_scale = 0.0f;
|
||||
if (primitive_two_faced) {
|
||||
description_out.front_counter_clockwise = (pa_su_sc_mode_cntl & 0x4) == 0;
|
||||
if (cull_mode == 1) {
|
||||
description_out.front_counter_clockwise = pa_su_sc_mode_cntl.face == 0;
|
||||
if (cull_front) {
|
||||
description_out.cull_mode = PipelineCullMode::kFront;
|
||||
} else if (cull_mode == 2) {
|
||||
} else if (cull_back) {
|
||||
description_out.cull_mode = PipelineCullMode::kBack;
|
||||
} else {
|
||||
description_out.cull_mode = PipelineCullMode::kNone;
|
||||
}
|
||||
// With ROV, the depth bias is applied in the pixel shader because
|
||||
// per-sample depth is needed for MSAA.
|
||||
if (cull_mode != 1) {
|
||||
if (!cull_front) {
|
||||
// Front faces aren't culled.
|
||||
uint32_t fill_mode = (pa_su_sc_mode_cntl >> 5) & 0x7;
|
||||
if (fill_mode == 0 || fill_mode == 1) {
|
||||
// Direct3D 12, unfortunately, doesn't support point fill mode.
|
||||
if (pa_su_sc_mode_cntl.polymode_front_ptype !=
|
||||
xenos::PolygonType::kTriangles) {
|
||||
description_out.fill_mode_wireframe = 1;
|
||||
}
|
||||
if (!edram_rov_used_ && (pa_su_sc_mode_cntl & (1 << 11))) {
|
||||
if (!edram_rov_used_ && pa_su_sc_mode_cntl.poly_offset_front_enable) {
|
||||
poly_offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_OFFSET].f32;
|
||||
poly_offset_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32;
|
||||
}
|
||||
}
|
||||
if (cull_mode != 2) {
|
||||
if (!cull_back) {
|
||||
// Back faces aren't culled.
|
||||
uint32_t fill_mode = (pa_su_sc_mode_cntl >> 8) & 0x7;
|
||||
if (fill_mode == 0 || fill_mode == 1) {
|
||||
if (pa_su_sc_mode_cntl.polymode_back_ptype !=
|
||||
xenos::PolygonType::kTriangles) {
|
||||
description_out.fill_mode_wireframe = 1;
|
||||
}
|
||||
// Prefer front depth bias because in general, front faces are the ones
|
||||
// that are rendered (except for shadow volumes).
|
||||
if (!edram_rov_used_ && (pa_su_sc_mode_cntl & (1 << 12)) &&
|
||||
if (!edram_rov_used_ && pa_su_sc_mode_cntl.poly_offset_back_enable &&
|
||||
poly_offset == 0.0f && poly_offset_scale == 0.0f) {
|
||||
poly_offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_BACK_OFFSET].f32;
|
||||
poly_offset_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_BACK_SCALE].f32;
|
||||
}
|
||||
}
|
||||
if (((pa_su_sc_mode_cntl >> 3) & 0x3) == 0) {
|
||||
// Fill mode is disabled.
|
||||
if (pa_su_sc_mode_cntl.poly_mode == xenos::PolygonModeEnable::kDisabled) {
|
||||
description_out.fill_mode_wireframe = 0;
|
||||
}
|
||||
} else {
|
||||
// Filled front faces only.
|
||||
// Use front depth bias if POLY_OFFSET_PARA_ENABLED
|
||||
// (POLY_OFFSET_FRONT_ENABLED is for two-sided primitives).
|
||||
if (!edram_rov_used_ && (pa_su_sc_mode_cntl & (1 << 13))) {
|
||||
if (!edram_rov_used_ && pa_su_sc_mode_cntl.poly_offset_para_enable) {
|
||||
poly_offset = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_OFFSET].f32;
|
||||
poly_offset_scale = regs[XE_GPU_REG_PA_SU_POLY_OFFSET_FRONT_SCALE].f32;
|
||||
}
|
||||
@@ -543,8 +550,8 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
// of Duty 4 (vehicledamage map explosion decals) and Red Dead Redemption
|
||||
// (shadows - 2^17 is not enough, 2^18 hasn't been tested, but 2^19
|
||||
// eliminates the acne).
|
||||
if (((register_file_->values[XE_GPU_REG_RB_DEPTH_INFO].u32 >> 16) & 0x1) ==
|
||||
uint32_t(DepthRenderTargetFormat::kD24FS8)) {
|
||||
if (regs.Get<reg::RB_DEPTH_INFO>().depth_format ==
|
||||
DepthRenderTargetFormat::kD24FS8) {
|
||||
poly_offset *= float(1 << 19);
|
||||
} else {
|
||||
poly_offset *= float(1 << 23);
|
||||
@@ -564,48 +571,49 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
primitive_type == PrimitiveType::kQuadPatch)) {
|
||||
description_out.fill_mode_wireframe = 1;
|
||||
}
|
||||
// CLIP_DISABLE
|
||||
description_out.depth_clip =
|
||||
(regs[XE_GPU_REG_PA_CL_CLIP_CNTL].u32 & (1 << 16)) == 0;
|
||||
description_out.depth_clip = !regs.Get<reg::PA_CL_CLIP_CNTL>().clip_disable;
|
||||
if (edram_rov_used_) {
|
||||
description_out.rov_msaa =
|
||||
((regs[XE_GPU_REG_RB_SURFACE_INFO].u32 >> 16) & 0x3) != 0;
|
||||
regs.Get<reg::RB_SURFACE_INFO>().msaa_samples != MsaaSamples::k1X;
|
||||
} else {
|
||||
// Depth/stencil. No stencil, always passing depth test and no depth writing
|
||||
// means depth disabled.
|
||||
if (render_targets[4].format != DXGI_FORMAT_UNKNOWN) {
|
||||
uint32_t rb_depthcontrol = regs[XE_GPU_REG_RB_DEPTHCONTROL].u32;
|
||||
if (rb_depthcontrol & 0x2) {
|
||||
description_out.depth_func = (rb_depthcontrol >> 4) & 0x7;
|
||||
description_out.depth_write = (rb_depthcontrol & 0x4) != 0;
|
||||
auto rb_depthcontrol = regs.Get<reg::RB_DEPTHCONTROL>();
|
||||
if (rb_depthcontrol.z_enable) {
|
||||
description_out.depth_func = rb_depthcontrol.zfunc;
|
||||
description_out.depth_write = rb_depthcontrol.z_write_enable;
|
||||
} else {
|
||||
description_out.depth_func = 0b111;
|
||||
description_out.depth_func = CompareFunction::kAlways;
|
||||
}
|
||||
if (rb_depthcontrol & 0x1) {
|
||||
if (rb_depthcontrol.stencil_enable) {
|
||||
description_out.stencil_enable = 1;
|
||||
bool stencil_backface_enable =
|
||||
primitive_two_faced && (rb_depthcontrol & 0x80);
|
||||
uint32_t stencil_masks;
|
||||
primitive_two_faced && rb_depthcontrol.backface_enable;
|
||||
// Per-face masks not supported by Direct3D 12, choose the back face
|
||||
// ones only if drawing only back faces.
|
||||
if (stencil_backface_enable && cull_mode == 1) {
|
||||
stencil_masks = regs[XE_GPU_REG_RB_STENCILREFMASK_BF].u32;
|
||||
Register stencil_ref_mask_reg;
|
||||
if (stencil_backface_enable && cull_front) {
|
||||
stencil_ref_mask_reg = XE_GPU_REG_RB_STENCILREFMASK_BF;
|
||||
} else {
|
||||
stencil_masks = regs[XE_GPU_REG_RB_STENCILREFMASK].u32;
|
||||
stencil_ref_mask_reg = XE_GPU_REG_RB_STENCILREFMASK;
|
||||
}
|
||||
description_out.stencil_read_mask = (stencil_masks >> 8) & 0xFF;
|
||||
description_out.stencil_write_mask = (stencil_masks >> 16) & 0xFF;
|
||||
description_out.stencil_front_fail_op = (rb_depthcontrol >> 11) & 0x7;
|
||||
auto stencil_ref_mask =
|
||||
regs.Get<reg::RB_STENCILREFMASK>(stencil_ref_mask_reg);
|
||||
description_out.stencil_read_mask = stencil_ref_mask.stencilmask;
|
||||
description_out.stencil_write_mask = stencil_ref_mask.stencilwritemask;
|
||||
description_out.stencil_front_fail_op = rb_depthcontrol.stencilfail;
|
||||
description_out.stencil_front_depth_fail_op =
|
||||
(rb_depthcontrol >> 17) & 0x7;
|
||||
description_out.stencil_front_pass_op = (rb_depthcontrol >> 14) & 0x7;
|
||||
description_out.stencil_front_func = (rb_depthcontrol >> 8) & 0x7;
|
||||
rb_depthcontrol.stencilzfail;
|
||||
description_out.stencil_front_pass_op = rb_depthcontrol.stencilzpass;
|
||||
description_out.stencil_front_func = rb_depthcontrol.stencilfunc;
|
||||
if (stencil_backface_enable) {
|
||||
description_out.stencil_back_fail_op = (rb_depthcontrol >> 23) & 0x7;
|
||||
description_out.stencil_back_fail_op = rb_depthcontrol.stencilfail_bf;
|
||||
description_out.stencil_back_depth_fail_op =
|
||||
(rb_depthcontrol >> 29) & 0x7;
|
||||
description_out.stencil_back_pass_op = (rb_depthcontrol >> 26) & 0x7;
|
||||
description_out.stencil_back_func = (rb_depthcontrol >> 20) & 0x7;
|
||||
rb_depthcontrol.stencilzfail_bf;
|
||||
description_out.stencil_back_pass_op =
|
||||
rb_depthcontrol.stencilzpass_bf;
|
||||
description_out.stencil_back_func = rb_depthcontrol.stencilfunc_bf;
|
||||
} else {
|
||||
description_out.stencil_back_fail_op =
|
||||
description_out.stencil_front_fail_op;
|
||||
@@ -618,13 +626,13 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
}
|
||||
}
|
||||
// If not binding the DSV, ignore the format in the hash.
|
||||
if (description_out.depth_func != 0b111 || description_out.depth_write ||
|
||||
description_out.stencil_enable) {
|
||||
description_out.depth_format = DepthRenderTargetFormat(
|
||||
(regs[XE_GPU_REG_RB_DEPTH_INFO].u32 >> 16) & 1);
|
||||
if (description_out.depth_func != CompareFunction::kAlways ||
|
||||
description_out.depth_write || description_out.stencil_enable) {
|
||||
description_out.depth_format =
|
||||
regs.Get<reg::RB_DEPTH_INFO>().depth_format;
|
||||
}
|
||||
} else {
|
||||
description_out.depth_func = 0b111;
|
||||
description_out.depth_func = CompareFunction::kAlways;
|
||||
}
|
||||
if (early_z) {
|
||||
description_out.force_early_z = 1;
|
||||
@@ -684,38 +692,25 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
if (render_targets[i].format == DXGI_FORMAT_UNKNOWN) {
|
||||
break;
|
||||
}
|
||||
uint32_t guest_rt_index = render_targets[i].guest_render_target;
|
||||
uint32_t color_info, blendcontrol;
|
||||
switch (guest_rt_index) {
|
||||
case 1:
|
||||
color_info = regs[XE_GPU_REG_RB_COLOR1_INFO].u32;
|
||||
blendcontrol = regs[XE_GPU_REG_RB_BLENDCONTROL_1].u32;
|
||||
break;
|
||||
case 2:
|
||||
color_info = regs[XE_GPU_REG_RB_COLOR2_INFO].u32;
|
||||
blendcontrol = regs[XE_GPU_REG_RB_BLENDCONTROL_2].u32;
|
||||
break;
|
||||
case 3:
|
||||
color_info = regs[XE_GPU_REG_RB_COLOR3_INFO].u32;
|
||||
blendcontrol = regs[XE_GPU_REG_RB_BLENDCONTROL_3].u32;
|
||||
break;
|
||||
default:
|
||||
color_info = regs[XE_GPU_REG_RB_COLOR_INFO].u32;
|
||||
blendcontrol = regs[XE_GPU_REG_RB_BLENDCONTROL_0].u32;
|
||||
break;
|
||||
}
|
||||
PipelineRenderTarget& rt = description_out.render_targets[i];
|
||||
rt.used = 1;
|
||||
rt.format = RenderTargetCache::GetBaseColorFormat(
|
||||
ColorRenderTargetFormat((color_info >> 16) & 0xF));
|
||||
uint32_t guest_rt_index = render_targets[i].guest_render_target;
|
||||
auto color_info = regs.Get<reg::RB_COLOR_INFO>(
|
||||
reg::RB_COLOR_INFO::rt_register_indices[guest_rt_index]);
|
||||
rt.format =
|
||||
RenderTargetCache::GetBaseColorFormat(color_info.color_format);
|
||||
rt.write_mask = (color_mask >> (guest_rt_index * 4)) & 0xF;
|
||||
if (rt.write_mask) {
|
||||
rt.src_blend = kBlendFactorMap[blendcontrol & 0x1F];
|
||||
rt.dest_blend = kBlendFactorMap[(blendcontrol >> 8) & 0x1F];
|
||||
rt.blend_op = BlendOp((blendcontrol >> 5) & 0x7);
|
||||
rt.src_blend_alpha = kBlendFactorAlphaMap[(blendcontrol >> 16) & 0x1F];
|
||||
rt.dest_blend_alpha = kBlendFactorAlphaMap[(blendcontrol >> 24) & 0x1F];
|
||||
rt.blend_op_alpha = BlendOp((blendcontrol >> 21) & 0x7);
|
||||
auto blendcontrol = regs.Get<reg::RB_BLENDCONTROL>(
|
||||
reg::RB_BLENDCONTROL::rt_register_indices[guest_rt_index]);
|
||||
rt.src_blend = kBlendFactorMap[uint32_t(blendcontrol.color_srcblend)];
|
||||
rt.dest_blend = kBlendFactorMap[uint32_t(blendcontrol.color_destblend)];
|
||||
rt.blend_op = blendcontrol.color_comb_fcn;
|
||||
rt.src_blend_alpha =
|
||||
kBlendFactorAlphaMap[uint32_t(blendcontrol.alpha_srcblend)];
|
||||
rt.dest_blend_alpha =
|
||||
kBlendFactorAlphaMap[uint32_t(blendcontrol.alpha_destblend)];
|
||||
rt.blend_op_alpha = blendcontrol.alpha_comb_fcn;
|
||||
} else {
|
||||
rt.src_blend = PipelineBlendFactor::kOne;
|
||||
rt.dest_blend = PipelineBlendFactor::kZero;
|
||||
@@ -941,15 +936,17 @@ ID3D12PipelineState* PipelineCache::CreatePipelineState(
|
||||
|
||||
if (!edram_rov_used_) {
|
||||
// Depth/stencil.
|
||||
if (description.depth_func != 0b111 || description.depth_write) {
|
||||
if (description.depth_func != CompareFunction::kAlways ||
|
||||
description.depth_write) {
|
||||
state_desc.DepthStencilState.DepthEnable = TRUE;
|
||||
state_desc.DepthStencilState.DepthWriteMask =
|
||||
description.depth_write ? D3D12_DEPTH_WRITE_MASK_ALL
|
||||
: D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
// Comparison functions are the same in Direct3D 12 but plus one (minus
|
||||
// one, bit 0 for less, bit 1 for equal, bit 2 for greater).
|
||||
state_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC(
|
||||
uint32_t(D3D12_COMPARISON_FUNC_NEVER) + description.depth_func);
|
||||
state_desc.DepthStencilState.DepthFunc =
|
||||
D3D12_COMPARISON_FUNC(uint32_t(D3D12_COMPARISON_FUNC_NEVER) +
|
||||
uint32_t(description.depth_func));
|
||||
}
|
||||
if (description.stencil_enable) {
|
||||
state_desc.DepthStencilState.StencilEnable = TRUE;
|
||||
@@ -958,26 +955,30 @@ ID3D12PipelineState* PipelineCache::CreatePipelineState(
|
||||
state_desc.DepthStencilState.StencilWriteMask =
|
||||
description.stencil_write_mask;
|
||||
// Stencil operations are the same in Direct3D 12 too but plus one.
|
||||
state_desc.DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP(
|
||||
uint32_t(D3D12_STENCIL_OP_KEEP) + description.stencil_front_fail_op);
|
||||
state_desc.DepthStencilState.FrontFace.StencilFailOp =
|
||||
D3D12_STENCIL_OP(uint32_t(D3D12_STENCIL_OP_KEEP) +
|
||||
uint32_t(description.stencil_front_fail_op));
|
||||
state_desc.DepthStencilState.FrontFace.StencilDepthFailOp =
|
||||
D3D12_STENCIL_OP(uint32_t(D3D12_STENCIL_OP_KEEP) +
|
||||
description.stencil_front_depth_fail_op);
|
||||
state_desc.DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP(
|
||||
uint32_t(D3D12_STENCIL_OP_KEEP) + description.stencil_front_pass_op);
|
||||
uint32_t(description.stencil_front_depth_fail_op));
|
||||
state_desc.DepthStencilState.FrontFace.StencilPassOp =
|
||||
D3D12_STENCIL_OP(uint32_t(D3D12_STENCIL_OP_KEEP) +
|
||||
uint32_t(description.stencil_front_pass_op));
|
||||
state_desc.DepthStencilState.FrontFace.StencilFunc =
|
||||
D3D12_COMPARISON_FUNC(uint32_t(D3D12_COMPARISON_FUNC_NEVER) +
|
||||
description.stencil_front_func);
|
||||
state_desc.DepthStencilState.BackFace.StencilFailOp = D3D12_STENCIL_OP(
|
||||
uint32_t(D3D12_STENCIL_OP_KEEP) + description.stencil_back_fail_op);
|
||||
uint32_t(description.stencil_front_func));
|
||||
state_desc.DepthStencilState.BackFace.StencilFailOp =
|
||||
D3D12_STENCIL_OP(uint32_t(D3D12_STENCIL_OP_KEEP) +
|
||||
uint32_t(description.stencil_back_fail_op));
|
||||
state_desc.DepthStencilState.BackFace.StencilDepthFailOp =
|
||||
D3D12_STENCIL_OP(uint32_t(D3D12_STENCIL_OP_KEEP) +
|
||||
description.stencil_back_depth_fail_op);
|
||||
state_desc.DepthStencilState.BackFace.StencilPassOp = D3D12_STENCIL_OP(
|
||||
uint32_t(D3D12_STENCIL_OP_KEEP) + description.stencil_back_pass_op);
|
||||
uint32_t(description.stencil_back_depth_fail_op));
|
||||
state_desc.DepthStencilState.BackFace.StencilPassOp =
|
||||
D3D12_STENCIL_OP(uint32_t(D3D12_STENCIL_OP_KEEP) +
|
||||
uint32_t(description.stencil_back_pass_op));
|
||||
state_desc.DepthStencilState.BackFace.StencilFunc =
|
||||
D3D12_COMPARISON_FUNC(uint32_t(D3D12_COMPARISON_FUNC_NEVER) +
|
||||
description.stencil_back_func);
|
||||
uint32_t(description.stencil_back_func));
|
||||
}
|
||||
if (state_desc.DepthStencilState.DepthEnable ||
|
||||
state_desc.DepthStencilState.StencilEnable) {
|
||||
|
||||
@@ -152,21 +152,21 @@ class PipelineCache {
|
||||
uint32_t depth_clip : 1; // 15
|
||||
uint32_t rov_msaa : 1; // 16
|
||||
DepthRenderTargetFormat depth_format : 1; // 17
|
||||
uint32_t depth_func : 3; // 20
|
||||
CompareFunction depth_func : 3; // 20
|
||||
uint32_t depth_write : 1; // 21
|
||||
uint32_t stencil_enable : 1; // 22
|
||||
uint32_t stencil_read_mask : 8; // 30
|
||||
uint32_t force_early_z : 1; // 31
|
||||
|
||||
uint32_t stencil_write_mask : 8; // 8
|
||||
uint32_t stencil_front_fail_op : 3; // 11
|
||||
uint32_t stencil_front_depth_fail_op : 3; // 14
|
||||
uint32_t stencil_front_pass_op : 3; // 17
|
||||
uint32_t stencil_front_func : 3; // 20
|
||||
uint32_t stencil_back_fail_op : 3; // 23
|
||||
uint32_t stencil_back_depth_fail_op : 3; // 26
|
||||
uint32_t stencil_back_pass_op : 3; // 29
|
||||
uint32_t stencil_back_func : 3; // 32
|
||||
uint32_t stencil_write_mask : 8; // 8
|
||||
StencilOp stencil_front_fail_op : 3; // 11
|
||||
StencilOp stencil_front_depth_fail_op : 3; // 14
|
||||
StencilOp stencil_front_pass_op : 3; // 17
|
||||
CompareFunction stencil_front_func : 3; // 20
|
||||
StencilOp stencil_back_fail_op : 3; // 23
|
||||
StencilOp stencil_back_depth_fail_op : 3; // 26
|
||||
StencilOp stencil_back_pass_op : 3; // 29
|
||||
CompareFunction stencil_back_func : 3; // 32
|
||||
|
||||
PipelineRenderTarget render_targets[4];
|
||||
};
|
||||
|
||||
@@ -192,7 +192,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out, uint32_t& index_count_out) {
|
||||
bool index_32bit = index_format == IndexFormat::kInt32;
|
||||
auto& regs = *register_file_;
|
||||
bool reset = (regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32 & (1 << 21)) != 0;
|
||||
bool reset = regs.Get<reg::PA_SU_SC_MODE_CNTL>().multi_prim_ib_ena;
|
||||
// Swap the reset index because we will be comparing unswapped values to it.
|
||||
uint32_t reset_index = xenos::GpuSwap(
|
||||
regs[XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX].u32, index_endianness);
|
||||
|
||||
@@ -541,16 +541,17 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
|
||||
bool rov_used = command_processor_->IsROVUsedForEDRAM();
|
||||
|
||||
uint32_t rb_surface_info = regs[XE_GPU_REG_RB_SURFACE_INFO].u32;
|
||||
uint32_t surface_pitch = std::min(rb_surface_info & 0x3FFF, 2560u);
|
||||
auto rb_surface_info = regs.Get<reg::RB_SURFACE_INFO>();
|
||||
uint32_t surface_pitch = std::min(rb_surface_info.surface_pitch, 2560u);
|
||||
if (surface_pitch == 0) {
|
||||
// TODO(Triang3l): Do something if a memexport-only draw has 0 surface
|
||||
// pitch (never seen in any game so far, not sure if even legal).
|
||||
return false;
|
||||
}
|
||||
MsaaSamples msaa_samples = MsaaSamples((rb_surface_info >> 16) & 0x3);
|
||||
uint32_t msaa_samples_x = msaa_samples >= MsaaSamples::k4X ? 2 : 1;
|
||||
uint32_t msaa_samples_y = msaa_samples >= MsaaSamples::k2X ? 2 : 1;
|
||||
uint32_t msaa_samples_x =
|
||||
rb_surface_info.msaa_samples >= MsaaSamples::k4X ? 2 : 1;
|
||||
uint32_t msaa_samples_y =
|
||||
rb_surface_info.msaa_samples >= MsaaSamples::k2X ? 2 : 1;
|
||||
|
||||
// Extract color/depth info in an unified way.
|
||||
bool enabled[5];
|
||||
@@ -558,26 +559,27 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
uint32_t formats[5];
|
||||
bool formats_are_64bpp[5];
|
||||
uint32_t color_mask = command_processor_->GetCurrentColorMask(pixel_shader);
|
||||
uint32_t rb_color_info[4] = {
|
||||
regs[XE_GPU_REG_RB_COLOR_INFO].u32, regs[XE_GPU_REG_RB_COLOR1_INFO].u32,
|
||||
regs[XE_GPU_REG_RB_COLOR2_INFO].u32, regs[XE_GPU_REG_RB_COLOR3_INFO].u32};
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
enabled[i] = (color_mask & (0xF << (i * 4))) != 0;
|
||||
edram_bases[i] = std::min(rb_color_info[i] & 0xFFF, 2048u);
|
||||
formats[i] = uint32_t(GetBaseColorFormat(
|
||||
ColorRenderTargetFormat((rb_color_info[i] >> 16) & 0xF)));
|
||||
auto color_info = regs.Get<reg::RB_COLOR_INFO>(
|
||||
reg::RB_COLOR_INFO::rt_register_indices[i]);
|
||||
edram_bases[i] = std::min(color_info.color_base, 2048u);
|
||||
formats[i] = uint32_t(GetBaseColorFormat(color_info.color_format));
|
||||
formats_are_64bpp[i] =
|
||||
IsColorFormat64bpp(ColorRenderTargetFormat(formats[i]));
|
||||
}
|
||||
uint32_t rb_depthcontrol = regs[XE_GPU_REG_RB_DEPTHCONTROL].u32;
|
||||
uint32_t rb_depth_info = regs[XE_GPU_REG_RB_DEPTH_INFO].u32;
|
||||
auto rb_depthcontrol = regs.Get<reg::RB_DEPTHCONTROL>();
|
||||
auto rb_depth_info = regs.Get<reg::RB_DEPTH_INFO>();
|
||||
// 0x1 = stencil test, 0x2 = depth test.
|
||||
enabled[4] = (rb_depthcontrol & (0x1 | 0x2)) != 0;
|
||||
edram_bases[4] = std::min(rb_depth_info & 0xFFF, 2048u);
|
||||
formats[4] = (rb_depth_info >> 16) & 0x1;
|
||||
enabled[4] = rb_depthcontrol.stencil_enable || rb_depthcontrol.z_enable;
|
||||
edram_bases[4] = std::min(rb_depth_info.depth_base, 2048u);
|
||||
formats[4] = uint32_t(rb_depth_info.depth_format);
|
||||
formats_are_64bpp[4] = false;
|
||||
// Don't mark depth regions as dirty if not writing the depth.
|
||||
bool depth_readonly = (rb_depthcontrol & (0x1 | 0x4)) == 0;
|
||||
// TODO(Triang3l): Make a common function for checking if stencil writing is
|
||||
// really done?
|
||||
bool depth_readonly =
|
||||
!rb_depthcontrol.stencil_enable && !rb_depthcontrol.z_write_enable;
|
||||
|
||||
bool full_update = false;
|
||||
|
||||
@@ -590,7 +592,7 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
// in the beginning of the frame or after resolves by setting the current
|
||||
// pitch to 0.
|
||||
if (current_surface_pitch_ != surface_pitch ||
|
||||
current_msaa_samples_ != msaa_samples) {
|
||||
current_msaa_samples_ != rb_surface_info.msaa_samples) {
|
||||
full_update = true;
|
||||
}
|
||||
|
||||
@@ -632,26 +634,22 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
|
||||
// Get EDRAM usage of the current draw so dirty regions can be calculated.
|
||||
// See D3D12CommandProcessor::UpdateFixedFunctionState for more info.
|
||||
int16_t window_offset_y =
|
||||
(regs[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32 >> 16) & 0x7FFF;
|
||||
if (window_offset_y & 0x4000) {
|
||||
window_offset_y |= 0x8000;
|
||||
}
|
||||
uint32_t pa_cl_vte_cntl = regs[XE_GPU_REG_PA_CL_VTE_CNTL].u32;
|
||||
float viewport_scale_y = (pa_cl_vte_cntl & (1 << 2))
|
||||
int32_t window_offset_y =
|
||||
regs.Get<reg::PA_SC_WINDOW_OFFSET>().window_y_offset;
|
||||
auto pa_cl_vte_cntl = regs.Get<reg::PA_CL_VTE_CNTL>();
|
||||
float viewport_scale_y = pa_cl_vte_cntl.vport_y_scale_ena
|
||||
? regs[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32
|
||||
: 1280.0f;
|
||||
float viewport_offset_y = (pa_cl_vte_cntl & (1 << 3))
|
||||
float viewport_offset_y = pa_cl_vte_cntl.vport_y_offset_ena
|
||||
? regs[XE_GPU_REG_PA_CL_VPORT_YOFFSET].f32
|
||||
: std::abs(viewport_scale_y);
|
||||
if (regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32 & (1 << 16)) {
|
||||
if (regs.Get<reg::PA_SU_SC_MODE_CNTL>().vtx_window_offset_enable) {
|
||||
viewport_offset_y += float(window_offset_y);
|
||||
}
|
||||
uint32_t viewport_bottom = uint32_t(std::max(
|
||||
0.0f, std::ceil(viewport_offset_y + std::abs(viewport_scale_y))));
|
||||
uint32_t scissor_bottom =
|
||||
(regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR].u32 >> 16) & 0x7FFF;
|
||||
if (!(regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32 & (1u << 31))) {
|
||||
uint32_t scissor_bottom = regs.Get<reg::PA_SC_WINDOW_SCISSOR_BR>().br_y;
|
||||
if (!regs.Get<reg::PA_SC_WINDOW_SCISSOR_TL>().window_offset_disable) {
|
||||
scissor_bottom = std::max(int32_t(scissor_bottom) + window_offset_y, 0);
|
||||
}
|
||||
uint32_t dirty_bottom =
|
||||
@@ -769,7 +767,7 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
|
||||
ClearBindings();
|
||||
current_surface_pitch_ = surface_pitch;
|
||||
current_msaa_samples_ = msaa_samples;
|
||||
current_msaa_samples_ = rb_surface_info.msaa_samples;
|
||||
if (!rov_used) {
|
||||
current_edram_max_rows_ = edram_max_rows;
|
||||
}
|
||||
@@ -801,8 +799,8 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
#endif
|
||||
}
|
||||
XELOGGPU("RT Cache: %s update - pitch %u, samples %u, RTs to attach %u",
|
||||
full_update ? "Full" : "Partial", surface_pitch, msaa_samples,
|
||||
render_targets_to_attach);
|
||||
full_update ? "Full" : "Partial", surface_pitch,
|
||||
rb_surface_info.msaa_samples, render_targets_to_attach);
|
||||
|
||||
#if 0
|
||||
auto device =
|
||||
@@ -891,7 +889,7 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
if (!rov_used) {
|
||||
// Sample positions when loading depth must match sample positions when
|
||||
// drawing.
|
||||
command_processor_->SetSamplePositions(msaa_samples);
|
||||
command_processor_->SetSamplePositions(rb_surface_info.msaa_samples);
|
||||
|
||||
// Load the contents of the new render targets from the EDRAM buffer (will
|
||||
// change the state of the render targets to copy destination).
|
||||
@@ -1007,18 +1005,14 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
auto& regs = *register_file_;
|
||||
|
||||
// Get the render target properties.
|
||||
uint32_t rb_surface_info = regs[XE_GPU_REG_RB_SURFACE_INFO].u32;
|
||||
uint32_t surface_pitch = std::min(rb_surface_info & 0x3FFF, 2560u);
|
||||
auto rb_surface_info = regs.Get<reg::RB_SURFACE_INFO>();
|
||||
uint32_t surface_pitch = std::min(rb_surface_info.surface_pitch, 2560u);
|
||||
if (surface_pitch == 0) {
|
||||
return true;
|
||||
}
|
||||
MsaaSamples msaa_samples = MsaaSamples((rb_surface_info >> 16) & 0x3);
|
||||
uint32_t rb_copy_control = regs[XE_GPU_REG_RB_COPY_CONTROL].u32;
|
||||
// Depth info is always needed because color resolve may also clear depth.
|
||||
uint32_t rb_depth_info = regs[XE_GPU_REG_RB_DEPTH_INFO].u32;
|
||||
uint32_t depth_edram_base = rb_depth_info & 0xFFF;
|
||||
uint32_t depth_format = (rb_depth_info >> 16) & 0x1;
|
||||
uint32_t surface_index = rb_copy_control & 0x7;
|
||||
auto rb_depth_info = regs.Get<reg::RB_DEPTH_INFO>();
|
||||
uint32_t surface_index = regs.Get<reg::RB_COPY_CONTROL>().copy_src_select;
|
||||
if (surface_index > 4) {
|
||||
assert_always();
|
||||
return false;
|
||||
@@ -1027,43 +1021,28 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
uint32_t surface_edram_base;
|
||||
uint32_t surface_format;
|
||||
if (surface_is_depth) {
|
||||
surface_edram_base = depth_edram_base;
|
||||
surface_format = depth_format;
|
||||
surface_edram_base = rb_depth_info.depth_base;
|
||||
surface_format = uint32_t(rb_depth_info.depth_format);
|
||||
} else {
|
||||
uint32_t rb_color_info;
|
||||
switch (surface_index) {
|
||||
case 1:
|
||||
rb_color_info = regs[XE_GPU_REG_RB_COLOR1_INFO].u32;
|
||||
break;
|
||||
case 2:
|
||||
rb_color_info = regs[XE_GPU_REG_RB_COLOR2_INFO].u32;
|
||||
break;
|
||||
case 3:
|
||||
rb_color_info = regs[XE_GPU_REG_RB_COLOR3_INFO].u32;
|
||||
break;
|
||||
default:
|
||||
rb_color_info = regs[XE_GPU_REG_RB_COLOR_INFO].u32;
|
||||
break;
|
||||
}
|
||||
surface_edram_base = rb_color_info & 0xFFF;
|
||||
surface_format = uint32_t(GetBaseColorFormat(
|
||||
ColorRenderTargetFormat((rb_color_info >> 16) & 0xF)));
|
||||
auto color_info = regs.Get<reg::RB_COLOR_INFO>(
|
||||
reg::RB_COLOR_INFO::rt_register_indices[surface_index]);
|
||||
surface_edram_base = color_info.color_base;
|
||||
surface_format = uint32_t(GetBaseColorFormat(color_info.color_format));
|
||||
}
|
||||
|
||||
// Get the resolve region since both copying and clearing need it.
|
||||
// HACK: Vertices to use are always in vf0.
|
||||
auto fetch_group = reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(
|
||||
®s.values[XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0]);
|
||||
const auto& fetch = fetch_group->vertex_fetch_0;
|
||||
const auto& fetch = regs.Get<xenos::xe_gpu_vertex_fetch_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0);
|
||||
assert_true(fetch.type == 3);
|
||||
assert_true(fetch.endian == 2);
|
||||
assert_true(fetch.endian == Endian::k8in32);
|
||||
assert_true(fetch.size == 6);
|
||||
const uint8_t* src_vertex_address =
|
||||
memory->TranslatePhysical(fetch.address << 2);
|
||||
float vertices[6];
|
||||
// Most vertices have a negative half pixel offset applied, which we reverse.
|
||||
float vertex_offset =
|
||||
(regs[XE_GPU_REG_PA_SU_VTX_CNTL].u32 & 0x1) ? 0.0f : 0.5f;
|
||||
regs.Get<reg::PA_SU_VTX_CNTL>().pix_center ? 0.0f : 0.5f;
|
||||
for (uint32_t i = 0; i < 6; ++i) {
|
||||
vertices[i] =
|
||||
xenos::GpuSwap(xe::load<float>(src_vertex_address + i * sizeof(float)),
|
||||
@@ -1097,39 +1076,34 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
// vertices (-640,0)->(640,720), however, the destination texture pointer is
|
||||
// adjusted properly to the right half of the texture, and the source render
|
||||
// target has a pitch of 800).
|
||||
auto pa_sc_window_offset = regs.Get<reg::PA_SC_WINDOW_OFFSET>();
|
||||
D3D12_RECT rect;
|
||||
rect.left = LONG(std::min(std::min(vertices[0], vertices[2]), vertices[4]));
|
||||
rect.right = LONG(std::max(std::max(vertices[0], vertices[2]), vertices[4]));
|
||||
rect.top = LONG(std::min(std::min(vertices[1], vertices[3]), vertices[5]));
|
||||
rect.bottom = LONG(std::max(std::max(vertices[1], vertices[3]), vertices[5]));
|
||||
if (regs.Get<reg::PA_SU_SC_MODE_CNTL>().vtx_window_offset_enable) {
|
||||
rect.left += pa_sc_window_offset.window_x_offset;
|
||||
rect.right += pa_sc_window_offset.window_x_offset;
|
||||
rect.top += pa_sc_window_offset.window_y_offset;
|
||||
rect.bottom += pa_sc_window_offset.window_y_offset;
|
||||
}
|
||||
D3D12_RECT scissor;
|
||||
uint32_t window_scissor_tl = regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32;
|
||||
uint32_t window_scissor_br = regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR].u32;
|
||||
scissor.left = LONG(window_scissor_tl & 0x7FFF);
|
||||
scissor.right = LONG(window_scissor_br & 0x7FFF);
|
||||
scissor.top = LONG((window_scissor_tl >> 16) & 0x7FFF);
|
||||
scissor.bottom = LONG((window_scissor_br >> 16) & 0x7FFF);
|
||||
if (regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32 & (1 << 16)) {
|
||||
uint32_t pa_sc_window_offset = regs[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32;
|
||||
int16_t window_offset_x = pa_sc_window_offset & 0x7FFF;
|
||||
int16_t window_offset_y = (pa_sc_window_offset >> 16) & 0x7FFF;
|
||||
if (window_offset_x & 0x4000) {
|
||||
window_offset_x |= 0x8000;
|
||||
}
|
||||
if (window_offset_y & 0x4000) {
|
||||
window_offset_y |= 0x8000;
|
||||
}
|
||||
rect.left += window_offset_x;
|
||||
rect.right += window_offset_x;
|
||||
rect.top += window_offset_y;
|
||||
rect.bottom += window_offset_y;
|
||||
if (!(window_scissor_tl & (1u << 31))) {
|
||||
scissor.left = std::max(LONG(scissor.left + window_offset_x), LONG(0));
|
||||
scissor.right = std::max(LONG(scissor.right + window_offset_x), LONG(0));
|
||||
scissor.top = std::max(LONG(scissor.top + window_offset_y), LONG(0));
|
||||
scissor.bottom =
|
||||
std::max(LONG(scissor.bottom + window_offset_y), LONG(0));
|
||||
}
|
||||
auto pa_sc_window_scissor_tl = regs.Get<reg::PA_SC_WINDOW_SCISSOR_TL>();
|
||||
auto pa_sc_window_scissor_br = regs.Get<reg::PA_SC_WINDOW_SCISSOR_BR>();
|
||||
scissor.left = pa_sc_window_scissor_tl.tl_x;
|
||||
scissor.right = pa_sc_window_scissor_br.br_x;
|
||||
scissor.top = pa_sc_window_scissor_tl.tl_y;
|
||||
scissor.bottom = pa_sc_window_scissor_br.br_y;
|
||||
if (!pa_sc_window_scissor_tl.window_offset_disable) {
|
||||
scissor.left = std::max(
|
||||
LONG(scissor.left + pa_sc_window_offset.window_x_offset), LONG(0));
|
||||
scissor.right = std::max(
|
||||
LONG(scissor.right + pa_sc_window_offset.window_x_offset), LONG(0));
|
||||
scissor.top = std::max(
|
||||
LONG(scissor.top + pa_sc_window_offset.window_y_offset), LONG(0));
|
||||
scissor.bottom = std::max(
|
||||
LONG(scissor.bottom + pa_sc_window_offset.window_y_offset), LONG(0));
|
||||
}
|
||||
rect.left = std::max(rect.left, scissor.left);
|
||||
rect.right = std::min(rect.right, scissor.right);
|
||||
@@ -1140,9 +1114,9 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
"Resolve: (%d,%d)->(%d,%d) of RT %u (pitch %u, %u sample%s, format %u) "
|
||||
"at %u",
|
||||
rect.left, rect.top, rect.right, rect.bottom, surface_index,
|
||||
surface_pitch, 1 << uint32_t(msaa_samples),
|
||||
msaa_samples != MsaaSamples::k1X ? "s" : "", surface_format,
|
||||
surface_edram_base);
|
||||
surface_pitch, 1 << uint32_t(rb_surface_info.msaa_samples),
|
||||
rb_surface_info.msaa_samples != MsaaSamples::k1X ? "s" : "",
|
||||
surface_format, surface_edram_base);
|
||||
|
||||
if (rect.left >= rect.right || rect.top >= rect.bottom) {
|
||||
// Nothing to copy.
|
||||
@@ -1157,18 +1131,20 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
// GetEDRAMLayout in ResolveCopy and ResolveClear will perform the needed
|
||||
// clamping to the source render target size.
|
||||
|
||||
bool result =
|
||||
ResolveCopy(shared_memory, texture_cache, surface_edram_base,
|
||||
surface_pitch, msaa_samples, surface_is_depth, surface_format,
|
||||
rect, written_address_out, written_length_out);
|
||||
bool result = ResolveCopy(shared_memory, texture_cache, surface_edram_base,
|
||||
surface_pitch, rb_surface_info.msaa_samples,
|
||||
surface_is_depth, surface_format, rect,
|
||||
written_address_out, written_length_out);
|
||||
// Clear the color RT if needed.
|
||||
if (!surface_is_depth) {
|
||||
result &= ResolveClear(surface_edram_base, surface_pitch, msaa_samples,
|
||||
false, surface_format, rect);
|
||||
result &=
|
||||
ResolveClear(surface_edram_base, surface_pitch,
|
||||
rb_surface_info.msaa_samples, false, surface_format, rect);
|
||||
}
|
||||
// Clear the depth RT if needed (may be cleared alongside color).
|
||||
result &= ResolveClear(depth_edram_base, surface_pitch, msaa_samples, true,
|
||||
depth_format, rect);
|
||||
result &= ResolveClear(rb_depth_info.depth_base, surface_pitch,
|
||||
rb_surface_info.msaa_samples, true,
|
||||
uint32_t(rb_depth_info.depth_format), rect);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1183,19 +1159,18 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
|
||||
auto& regs = *register_file_;
|
||||
|
||||
uint32_t rb_copy_control = regs[XE_GPU_REG_RB_COPY_CONTROL].u32;
|
||||
xenos::CopyCommand copy_command =
|
||||
xenos::CopyCommand((rb_copy_control >> 20) & 0x3);
|
||||
if (copy_command != xenos::CopyCommand::kRaw &&
|
||||
copy_command != xenos::CopyCommand::kConvert) {
|
||||
auto rb_copy_control = regs.Get<reg::RB_COPY_CONTROL>();
|
||||
if (rb_copy_control.copy_command != xenos::CopyCommand::kRaw &&
|
||||
rb_copy_control.copy_command != xenos::CopyCommand::kConvert) {
|
||||
// TODO(Triang3l): Handle kConstantOne and kNull.
|
||||
assert_always();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto command_list = command_processor_->GetDeferredCommandList();
|
||||
|
||||
// Get format info.
|
||||
uint32_t rb_copy_dest_info = regs[XE_GPU_REG_RB_COPY_DEST_INFO].u32;
|
||||
auto rb_copy_dest_info = regs.Get<reg::RB_COPY_DEST_INFO>();
|
||||
TextureFormat src_texture_format;
|
||||
bool src_64bpp;
|
||||
if (is_depth) {
|
||||
@@ -1222,14 +1197,15 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
// The destination format is specified as k_8_8_8_8 when resolving depth, but
|
||||
// no format conversion is done for depth, so ignore it.
|
||||
TextureFormat dest_format =
|
||||
is_depth ? src_texture_format
|
||||
: GetBaseFormat(TextureFormat((rb_copy_dest_info >> 7) & 0x3F));
|
||||
is_depth
|
||||
? src_texture_format
|
||||
: GetBaseFormat(TextureFormat(rb_copy_dest_info.copy_dest_format));
|
||||
const FormatInfo* dest_format_info = FormatInfo::Get(dest_format);
|
||||
|
||||
// Get the destination region and clamp the source region to it.
|
||||
uint32_t rb_copy_dest_pitch = regs[XE_GPU_REG_RB_COPY_DEST_PITCH].u32;
|
||||
uint32_t dest_pitch = rb_copy_dest_pitch & 0x3FFF;
|
||||
uint32_t dest_height = (rb_copy_dest_pitch >> 16) & 0x3FFF;
|
||||
auto rb_copy_dest_pitch = regs.Get<reg::RB_COPY_DEST_PITCH>();
|
||||
uint32_t dest_pitch = rb_copy_dest_pitch.copy_dest_pitch;
|
||||
uint32_t dest_height = rb_copy_dest_pitch.copy_dest_height;
|
||||
if (dest_pitch == 0 || dest_height == 0) {
|
||||
// Nothing to copy.
|
||||
return true;
|
||||
@@ -1263,8 +1239,7 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
uint32_t dest_address = regs[XE_GPU_REG_RB_COPY_DEST_BASE].u32 & 0x1FFFFFFF;
|
||||
// An example of a 3D resolve destination is the color grading LUT (used
|
||||
// starting from the developer/publisher intro) in Dead Space 3.
|
||||
bool dest_3d = (rb_copy_dest_info & (1 << 3)) != 0;
|
||||
if (dest_3d) {
|
||||
if (rb_copy_dest_info.copy_dest_array) {
|
||||
dest_address += texture_util::GetTiledOffset3D(
|
||||
int(rect.left & ~LONG(31)), int(rect.top & ~LONG(31)), 0, dest_pitch,
|
||||
dest_height, xe::log2_floor(dest_format_info->bits_per_pixel >> 3));
|
||||
@@ -1279,21 +1254,20 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
// resolve to 8bpp or 16bpp textures at very odd locations.
|
||||
return false;
|
||||
}
|
||||
uint32_t dest_z = dest_3d ? ((rb_copy_dest_info >> 4) & 0x7) : 0;
|
||||
uint32_t dest_z =
|
||||
rb_copy_dest_info.copy_dest_array ? rb_copy_dest_info.copy_dest_slice : 0;
|
||||
|
||||
// See what samples we need and what we should do with them.
|
||||
xenos::CopySampleSelect sample_select =
|
||||
xenos::CopySampleSelect((rb_copy_control >> 4) & 0x7);
|
||||
xenos::CopySampleSelect sample_select = rb_copy_control.copy_sample_select;
|
||||
if (is_depth && sample_select > xenos::CopySampleSelect::k3) {
|
||||
assert_always();
|
||||
return false;
|
||||
}
|
||||
Endian128 dest_endian = Endian128(rb_copy_dest_info & 0x7);
|
||||
int32_t dest_exp_bias;
|
||||
if (is_depth) {
|
||||
dest_exp_bias = 0;
|
||||
} else {
|
||||
dest_exp_bias = int32_t((rb_copy_dest_info >> 16) << 26) >> 26;
|
||||
dest_exp_bias = rb_copy_dest_info.copy_dest_exp_bias;
|
||||
if (ColorRenderTargetFormat(src_format) ==
|
||||
ColorRenderTargetFormat::k_16_16 ||
|
||||
ColorRenderTargetFormat(src_format) ==
|
||||
@@ -1309,14 +1283,14 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
}
|
||||
}
|
||||
}
|
||||
bool dest_swap = !is_depth && ((rb_copy_dest_info >> 24) & 0x1);
|
||||
bool dest_swap = !is_depth && rb_copy_dest_info.copy_dest_swap;
|
||||
|
||||
XELOGGPU(
|
||||
"Resolve: Copying samples %u to 0x%.8X (%ux%u, %cD), destination Z %u, "
|
||||
"destination format %s, exponent bias %d, red and blue %sswapped",
|
||||
uint32_t(sample_select), dest_address, dest_pitch, dest_height,
|
||||
dest_3d ? '3' : '2', dest_z, dest_format_info->name, dest_exp_bias,
|
||||
dest_swap ? "" : "not ");
|
||||
rb_copy_dest_info.copy_dest_array ? '3' : '2', dest_z,
|
||||
dest_format_info->name, dest_exp_bias, dest_swap ? "" : "not ");
|
||||
|
||||
// There are 2 paths for resolving in this function - they don't necessarily
|
||||
// have to map directly to kRaw and kConvert CopyCommands.
|
||||
@@ -1344,7 +1318,7 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
resolution_scale_2x_ &&
|
||||
cvars::d3d12_resolution_scale_resolve_edge_clamp &&
|
||||
cvars::d3d12_half_pixel_offset &&
|
||||
!(regs[XE_GPU_REG_PA_SU_VTX_CNTL].u32 & 0x1);
|
||||
!regs.Get<reg::PA_SU_VTX_CNTL>().pix_center;
|
||||
if (sample_select <= xenos::CopySampleSelect::k3 &&
|
||||
src_texture_format == dest_format && dest_exp_bias == 0) {
|
||||
// *************************************************************************
|
||||
@@ -1363,7 +1337,7 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
uint32_t dest_size;
|
||||
uint32_t dest_modified_start = dest_address;
|
||||
uint32_t dest_modified_length;
|
||||
if (dest_3d) {
|
||||
if (rb_copy_dest_info.copy_dest_array) {
|
||||
// Depth granularity is 4 (though TiledAddress chaining is possible with 8
|
||||
// granularity).
|
||||
dest_size = texture_util::GetGuestMipSliceStorageSize(
|
||||
@@ -1442,8 +1416,10 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
assert_true(dest_pitch <= 8192);
|
||||
root_constants.tile_sample_dest_info =
|
||||
((dest_pitch + 31) >> 5) |
|
||||
(dest_3d ? (((dest_height + 31) >> 5) << 9) : 0) |
|
||||
(uint32_t(sample_select) << 18) | (uint32_t(dest_endian) << 20);
|
||||
(rb_copy_dest_info.copy_dest_array ? (((dest_height + 31) >> 5) << 9)
|
||||
: 0) |
|
||||
(uint32_t(sample_select) << 18) |
|
||||
(uint32_t(rb_copy_dest_info.copy_dest_endian) << 20);
|
||||
if (dest_swap) {
|
||||
root_constants.tile_sample_dest_info |= (1 << 23) | (src_format << 24);
|
||||
}
|
||||
@@ -1797,10 +1773,12 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
copy_buffer_state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
// dest_address already adjusted, so offsets are & 31.
|
||||
texture_cache->TileResolvedTexture(
|
||||
dest_format, dest_address, dest_pitch, dest_height, dest_3d,
|
||||
uint32_t(rect.left) & 31, uint32_t(rect.top) & 31, dest_z, copy_width,
|
||||
copy_height, dest_endian, copy_buffer, resolve_target->copy_buffer_size,
|
||||
resolve_target->footprint, &written_address_out, &written_length_out);
|
||||
dest_format, dest_address, dest_pitch, dest_height,
|
||||
rb_copy_dest_info.copy_dest_array != 0, uint32_t(rect.left) & 31,
|
||||
uint32_t(rect.top) & 31, dest_z, copy_width, copy_height,
|
||||
rb_copy_dest_info.copy_dest_endian, copy_buffer,
|
||||
resolve_target->copy_buffer_size, resolve_target->footprint,
|
||||
&written_address_out, &written_length_out);
|
||||
|
||||
// Done with the copy buffer.
|
||||
|
||||
@@ -1817,9 +1795,15 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base,
|
||||
auto& regs = *register_file_;
|
||||
|
||||
// Check if clearing is enabled.
|
||||
uint32_t rb_copy_control = regs[XE_GPU_REG_RB_COPY_CONTROL].u32;
|
||||
if (!(rb_copy_control & (is_depth ? (1 << 9) : (1 << 8)))) {
|
||||
return true;
|
||||
auto rb_copy_control = regs.Get<reg::RB_COPY_CONTROL>();
|
||||
if (is_depth) {
|
||||
if (!rb_copy_control.depth_clear_enable) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (!rb_copy_control.color_clear_enable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
XELOGGPU("Resolve: Clearing the %s render target",
|
||||
@@ -1886,7 +1870,7 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base,
|
||||
} else if (is_64bpp) {
|
||||
// TODO(Triang3l): Check which 32-bit portion is in which register.
|
||||
root_constants.clear_color_high = regs[XE_GPU_REG_RB_COLOR_CLEAR].u32;
|
||||
root_constants.clear_color_low = regs[XE_GPU_REG_RB_COLOR_CLEAR_LOW].u32;
|
||||
root_constants.clear_color_low = regs[XE_GPU_REG_RB_COLOR_CLEAR_LO].u32;
|
||||
command_processor_->SetComputePipeline(edram_clear_64bpp_pipeline_);
|
||||
} else {
|
||||
Register reg =
|
||||
|
||||
@@ -848,15 +848,13 @@ void TextureCache::RequestTextures(uint32_t used_vertex_texture_mask,
|
||||
continue;
|
||||
}
|
||||
TextureBinding& binding = texture_bindings_[index];
|
||||
uint32_t r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + index * 6;
|
||||
auto group =
|
||||
reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(®s.values[r]);
|
||||
const auto& fetch = regs.Get<xenos::xe_gpu_texture_fetch_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + index * 6);
|
||||
TextureKey old_key = binding.key;
|
||||
bool old_has_unsigned = binding.has_unsigned;
|
||||
bool old_has_signed = binding.has_signed;
|
||||
BindingInfoFromFetchConstant(group->texture_fetch, binding.key,
|
||||
&binding.swizzle, &binding.has_unsigned,
|
||||
&binding.has_signed);
|
||||
BindingInfoFromFetchConstant(fetch, binding.key, &binding.swizzle,
|
||||
&binding.has_unsigned, &binding.has_signed);
|
||||
texture_keys_in_sync_ |= index_bit;
|
||||
if (binding.key.IsInvalid()) {
|
||||
binding.texture = nullptr;
|
||||
@@ -1142,18 +1140,15 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
|
||||
TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
const D3D12Shader::SamplerBinding& binding) const {
|
||||
auto& regs = *register_file_;
|
||||
uint32_t r =
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + binding.fetch_constant * 6;
|
||||
auto group =
|
||||
reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(®s.values[r]);
|
||||
auto& fetch = group->texture_fetch;
|
||||
const auto& fetch = regs.Get<xenos::xe_gpu_texture_fetch_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + binding.fetch_constant * 6);
|
||||
|
||||
SamplerParameters parameters;
|
||||
|
||||
parameters.clamp_x = ClampMode(fetch.clamp_x);
|
||||
parameters.clamp_y = ClampMode(fetch.clamp_y);
|
||||
parameters.clamp_z = ClampMode(fetch.clamp_z);
|
||||
parameters.border_color = BorderColor(fetch.border_color);
|
||||
parameters.clamp_x = fetch.clamp_x;
|
||||
parameters.clamp_y = fetch.clamp_y;
|
||||
parameters.clamp_z = fetch.clamp_z;
|
||||
parameters.border_color = fetch.border_color;
|
||||
|
||||
uint32_t mip_min_level = fetch.mip_min_level;
|
||||
uint32_t mip_max_level = fetch.mip_max_level;
|
||||
@@ -1171,7 +1166,7 @@ TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
parameters.lod_bias = fetch.lod_bias;
|
||||
|
||||
AnisoFilter aniso_filter = binding.aniso_filter == AnisoFilter::kUseFetchConst
|
||||
? AnisoFilter(fetch.aniso_filter)
|
||||
? fetch.aniso_filter
|
||||
: binding.aniso_filter;
|
||||
aniso_filter = std::min(aniso_filter, AnisoFilter::kMax_16_1);
|
||||
parameters.aniso_filter = aniso_filter;
|
||||
@@ -1182,17 +1177,17 @@ TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
} else {
|
||||
TextureFilter mag_filter =
|
||||
binding.mag_filter == TextureFilter::kUseFetchConst
|
||||
? TextureFilter(fetch.mag_filter)
|
||||
? fetch.mag_filter
|
||||
: binding.mag_filter;
|
||||
parameters.mag_linear = mag_filter == TextureFilter::kLinear;
|
||||
TextureFilter min_filter =
|
||||
binding.min_filter == TextureFilter::kUseFetchConst
|
||||
? TextureFilter(fetch.min_filter)
|
||||
? fetch.min_filter
|
||||
: binding.min_filter;
|
||||
parameters.min_linear = min_filter == TextureFilter::kLinear;
|
||||
TextureFilter mip_filter =
|
||||
binding.mip_filter == TextureFilter::kUseFetchConst
|
||||
? TextureFilter(fetch.mip_filter)
|
||||
? fetch.mip_filter
|
||||
: binding.mip_filter;
|
||||
parameters.mip_linear = mip_filter == TextureFilter::kLinear;
|
||||
// TODO(Triang3l): Investigate mip_filter TextureFilter::kBaseMap.
|
||||
@@ -1586,13 +1581,12 @@ void TextureCache::CreateScaledResolveBufferRawUAV(
|
||||
|
||||
bool TextureCache::RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle,
|
||||
TextureFormat& format_out) {
|
||||
auto group = reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(
|
||||
®ister_file_->values[XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0]);
|
||||
auto& fetch = group->texture_fetch;
|
||||
auto& regs = *register_file_;
|
||||
const auto& fetch = regs.Get<xenos::xe_gpu_texture_fetch_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0);
|
||||
TextureKey key;
|
||||
uint32_t swizzle;
|
||||
BindingInfoFromFetchConstant(group->texture_fetch, key, &swizzle, nullptr,
|
||||
nullptr);
|
||||
BindingInfoFromFetchConstant(fetch, key, &swizzle, nullptr, nullptr);
|
||||
if (key.base_page == 0 || key.dimension != Dimension::k2D) {
|
||||
return false;
|
||||
}
|
||||
@@ -1733,7 +1727,7 @@ void TextureCache::BindingInfoFromFetchConstant(
|
||||
return;
|
||||
}
|
||||
|
||||
TextureFormat format = GetBaseFormat(TextureFormat(fetch.format));
|
||||
TextureFormat format = GetBaseFormat(fetch.format);
|
||||
|
||||
key_out.base_page = base_page;
|
||||
key_out.mip_page = mip_page;
|
||||
@@ -1745,7 +1739,7 @@ void TextureCache::BindingInfoFromFetchConstant(
|
||||
key_out.tiled = fetch.tiled;
|
||||
key_out.packed_mips = fetch.packed_mips;
|
||||
key_out.format = format;
|
||||
key_out.endianness = Endian(fetch.endianness);
|
||||
key_out.endianness = fetch.endianness;
|
||||
|
||||
if (swizzle_out != nullptr) {
|
||||
uint32_t swizzle = fetch.swizzle;
|
||||
@@ -1783,16 +1777,16 @@ void TextureCache::BindingInfoFromFetchConstant(
|
||||
}
|
||||
|
||||
if (has_unsigned_out != nullptr) {
|
||||
*has_unsigned_out = TextureSign(fetch.sign_x) != TextureSign::kSigned ||
|
||||
TextureSign(fetch.sign_y) != TextureSign::kSigned ||
|
||||
TextureSign(fetch.sign_z) != TextureSign::kSigned ||
|
||||
TextureSign(fetch.sign_w) != TextureSign::kSigned;
|
||||
*has_unsigned_out = fetch.sign_x != TextureSign::kSigned ||
|
||||
fetch.sign_y != TextureSign::kSigned ||
|
||||
fetch.sign_z != TextureSign::kSigned ||
|
||||
fetch.sign_w != TextureSign::kSigned;
|
||||
}
|
||||
if (has_signed_out != nullptr) {
|
||||
*has_signed_out = TextureSign(fetch.sign_x) == TextureSign::kSigned ||
|
||||
TextureSign(fetch.sign_y) == TextureSign::kSigned ||
|
||||
TextureSign(fetch.sign_z) == TextureSign::kSigned ||
|
||||
TextureSign(fetch.sign_w) == TextureSign::kSigned;
|
||||
*has_signed_out = fetch.sign_x == TextureSign::kSigned ||
|
||||
fetch.sign_y == TextureSign::kSigned ||
|
||||
fetch.sign_z == TextureSign::kSigned ||
|
||||
fetch.sign_w == TextureSign::kSigned;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user