[GPU] Move all xenos.h to gpu::xenos, disambiguate Dimension/TextureDimension
This commit is contained in:
@@ -673,7 +673,8 @@ void D3D12CommandProcessor::ReleaseScratchGPUBuffer(
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12CommandProcessor::SetSamplePositions(MsaaSamples sample_positions) {
|
||||
void D3D12CommandProcessor::SetSamplePositions(
|
||||
xenos::MsaaSamples sample_positions) {
|
||||
if (current_sample_positions_ == sample_positions) {
|
||||
return;
|
||||
}
|
||||
@@ -696,10 +697,10 @@ void D3D12CommandProcessor::SetSamplePositions(MsaaSamples sample_positions) {
|
||||
// work a little bit better for tall stairs.
|
||||
// FIXME(Triang3l): This is currently even uglier than without custom
|
||||
// sample positions.
|
||||
if (sample_positions >= MsaaSamples::k2X) {
|
||||
if (sample_positions >= xenos::MsaaSamples::k2X) {
|
||||
// Sample 1 is lower-left on Xenos, but upper-right in Direct3D 12.
|
||||
D3D12_SAMPLE_POSITION d3d_sample_positions[4];
|
||||
if (sample_positions >= MsaaSamples::k4X) {
|
||||
if (sample_positions >= xenos::MsaaSamples::k4X) {
|
||||
// Upper-left.
|
||||
d3d_sample_positions[0].X = -2 + 4;
|
||||
d3d_sample_positions[0].Y = -6 + 4;
|
||||
@@ -1657,7 +1658,7 @@ void D3D12CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC swap_texture_srv_desc;
|
||||
TextureFormat frontbuffer_format;
|
||||
xenos::TextureFormat frontbuffer_format;
|
||||
ID3D12Resource* swap_texture_resource = texture_cache_->RequestSwapTexture(
|
||||
swap_texture_srv_desc, frontbuffer_format);
|
||||
if (swap_texture_resource) {
|
||||
@@ -1667,8 +1668,8 @@ void D3D12CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||
// executable, which initializes the normal gamma ramp for 8_8_8_8 output
|
||||
// and the PWL gamma ramp for 2_10_10_10.
|
||||
bool use_pwl_gamma_ramp =
|
||||
frontbuffer_format == TextureFormat::k_2_10_10_10 ||
|
||||
frontbuffer_format == TextureFormat::k_2_10_10_10_AS_16_16_16_16;
|
||||
frontbuffer_format == xenos::TextureFormat::k_2_10_10_10 ||
|
||||
frontbuffer_format == xenos::TextureFormat::k_2_10_10_10_AS_16_16_16_16;
|
||||
|
||||
bool descriptors_obtained;
|
||||
ui::d3d12::util::DescriptorCPUGPUHandlePair descriptor_swap_texture;
|
||||
@@ -1757,7 +1758,7 @@ void D3D12CommandProcessor::OnPrimaryBufferEnd() {
|
||||
}
|
||||
}
|
||||
|
||||
Shader* D3D12CommandProcessor::LoadShader(ShaderType shader_type,
|
||||
Shader* D3D12CommandProcessor::LoadShader(xenos::ShaderType shader_type,
|
||||
uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) {
|
||||
@@ -1765,7 +1766,7 @@ Shader* D3D12CommandProcessor::LoadShader(ShaderType shader_type,
|
||||
dword_count);
|
||||
}
|
||||
|
||||
bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
||||
uint32_t index_count,
|
||||
IndexBufferInfo* index_buffer_info,
|
||||
bool major_mode_explicit) {
|
||||
@@ -1833,7 +1834,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
!pixel_shader->memexport_stream_constants().empty();
|
||||
bool memexport_used = memexport_used_vertex || memexport_used_pixel;
|
||||
|
||||
bool primitive_two_faced = IsPrimitiveTwoFaced(tessellated, primitive_type);
|
||||
bool primitive_two_faced =
|
||||
xenos::IsPrimitiveTwoFaced(tessellated, primitive_type);
|
||||
auto sq_program_cntl = regs.Get<reg::SQ_PROGRAM_CNTL>();
|
||||
auto pa_su_sc_mode_cntl = regs.Get<reg::PA_SU_SC_MODE_CNTL>();
|
||||
if (!memexport_used_vertex &&
|
||||
@@ -1856,18 +1858,18 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
|
||||
// Set up primitive topology.
|
||||
bool indexed = index_buffer_info != nullptr && index_buffer_info->guest_base;
|
||||
PrimitiveType primitive_type_converted;
|
||||
xenos::PrimitiveType primitive_type_converted;
|
||||
D3D_PRIMITIVE_TOPOLOGY primitive_topology;
|
||||
if (tessellated) {
|
||||
primitive_type_converted = primitive_type;
|
||||
switch (primitive_type_converted) {
|
||||
// TODO(Triang3l): Support all kinds of patches if found in games.
|
||||
case PrimitiveType::kTriangleList:
|
||||
case PrimitiveType::kTrianglePatch:
|
||||
case xenos::PrimitiveType::kTriangleList:
|
||||
case xenos::PrimitiveType::kTrianglePatch:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST;
|
||||
break;
|
||||
case PrimitiveType::kQuadList:
|
||||
case PrimitiveType::kQuadPatch:
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
case xenos::PrimitiveType::kQuadPatch:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
|
||||
break;
|
||||
default:
|
||||
@@ -1877,23 +1879,23 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
primitive_type_converted =
|
||||
PrimitiveConverter::GetReplacementPrimitiveType(primitive_type);
|
||||
switch (primitive_type_converted) {
|
||||
case PrimitiveType::kPointList:
|
||||
case xenos::PrimitiveType::kPointList:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
break;
|
||||
case PrimitiveType::kLineList:
|
||||
case xenos::PrimitiveType::kLineList:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
break;
|
||||
case PrimitiveType::kLineStrip:
|
||||
case xenos::PrimitiveType::kLineStrip:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
break;
|
||||
case PrimitiveType::kTriangleList:
|
||||
case PrimitiveType::kRectangleList:
|
||||
case xenos::PrimitiveType::kTriangleList:
|
||||
case xenos::PrimitiveType::kRectangleList:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
break;
|
||||
case PrimitiveType::kTriangleStrip:
|
||||
case xenos::PrimitiveType::kTriangleStrip:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
break;
|
||||
case PrimitiveType::kQuadList:
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
|
||||
break;
|
||||
default:
|
||||
@@ -1905,7 +1907,7 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
deferred_command_list_->D3DIASetPrimitiveTopology(primitive_topology);
|
||||
}
|
||||
uint32_t line_loop_closing_index;
|
||||
if (primitive_type == PrimitiveType::kLineLoop && !indexed &&
|
||||
if (primitive_type == xenos::PrimitiveType::kLineLoop && !indexed &&
|
||||
index_count >= 3) {
|
||||
// Add a vertex to close the loop, and make the vertex shader replace its
|
||||
// index (before adding the offset) with 0 to fetch the first vertex again.
|
||||
@@ -1929,7 +1931,7 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
auto rb_colorcontrol = regs.Get<reg::RB_COLORCONTROL>();
|
||||
early_z = pixel_shader->implicit_early_z_allowed() &&
|
||||
(!rb_colorcontrol.alpha_test_enable ||
|
||||
rb_colorcontrol.alpha_func == CompareFunction::kAlways) &&
|
||||
rb_colorcontrol.alpha_func == xenos::CompareFunction::kAlways) &&
|
||||
!rb_colorcontrol.alpha_to_mask_enable;
|
||||
} else {
|
||||
early_z = true;
|
||||
@@ -1940,8 +1942,9 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
ID3D12RootSignature* root_signature;
|
||||
if (!pipeline_cache_->ConfigurePipeline(
|
||||
vertex_shader, pixel_shader, primitive_type_converted,
|
||||
indexed ? index_buffer_info->format : IndexFormat::kInt16, early_z,
|
||||
pipeline_render_targets, &pipeline_handle, &root_signature)) {
|
||||
indexed ? index_buffer_info->format : xenos::IndexFormat::kInt16,
|
||||
early_z, pipeline_render_targets, &pipeline_handle,
|
||||
&root_signature)) {
|
||||
return false;
|
||||
}
|
||||
if (current_cached_pipeline_ != pipeline_handle) {
|
||||
@@ -1957,7 +1960,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::kNone,
|
||||
indexed ? index_buffer_info->endianness : xenos::Endian::kNone,
|
||||
used_texture_mask, early_z, GetCurrentColorMask(pixel_shader),
|
||||
pipeline_render_targets);
|
||||
|
||||
@@ -2032,7 +2035,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
GetSupportedMemExportFormatSize(memexport_stream.format);
|
||||
if (memexport_format_size == 0) {
|
||||
XELOGE("Unsupported memexport format {}",
|
||||
FormatInfo::Get(TextureFormat(uint32_t(memexport_stream.format)))
|
||||
FormatInfo::Get(
|
||||
xenos::TextureFormat(uint32_t(memexport_stream.format)))
|
||||
->name);
|
||||
return false;
|
||||
}
|
||||
@@ -2074,7 +2078,8 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
GetSupportedMemExportFormatSize(memexport_stream.format);
|
||||
if (memexport_format_size == 0) {
|
||||
XELOGE("Unsupported memexport format {}",
|
||||
FormatInfo::Get(TextureFormat(uint32_t(memexport_stream.format)))
|
||||
FormatInfo::Get(
|
||||
xenos::TextureFormat(uint32_t(memexport_stream.format)))
|
||||
->name);
|
||||
return false;
|
||||
}
|
||||
@@ -2114,16 +2119,18 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||
|
||||
// Actually draw.
|
||||
if (indexed) {
|
||||
uint32_t index_size = index_buffer_info->format == IndexFormat::kInt32
|
||||
? sizeof(uint32_t)
|
||||
: sizeof(uint16_t);
|
||||
uint32_t index_size =
|
||||
index_buffer_info->format == xenos::IndexFormat::kInt32
|
||||
? sizeof(uint32_t)
|
||||
: sizeof(uint16_t);
|
||||
assert_false(index_buffer_info->guest_base & (index_size - 1));
|
||||
uint32_t index_base =
|
||||
index_buffer_info->guest_base & 0x1FFFFFFF & ~(index_size - 1);
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
index_buffer_view.Format = index_buffer_info->format == IndexFormat::kInt32
|
||||
? DXGI_FORMAT_R32_UINT
|
||||
: DXGI_FORMAT_R16_UINT;
|
||||
index_buffer_view.Format =
|
||||
index_buffer_info->format == xenos::IndexFormat::kInt32
|
||||
? DXGI_FORMAT_R32_UINT
|
||||
: DXGI_FORMAT_R16_UINT;
|
||||
PrimitiveConverter::ConversionResult conversion_result;
|
||||
uint32_t converted_index_count;
|
||||
if (tessellated) {
|
||||
@@ -2455,7 +2462,7 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
|
||||
ff_scissor_update_needed_ = true;
|
||||
ff_blend_factor_update_needed_ = true;
|
||||
ff_stencil_ref_update_needed_ = true;
|
||||
current_sample_positions_ = MsaaSamples::k1X;
|
||||
current_sample_positions_ = xenos::MsaaSamples::k1X;
|
||||
current_cached_pipeline_ = nullptr;
|
||||
current_external_pipeline_ = nullptr;
|
||||
current_graphics_root_signature_ = nullptr;
|
||||
@@ -2703,9 +2710,10 @@ void D3D12CommandProcessor::UpdateFixedFunctionState(bool primitive_two_faced) {
|
||||
pixel_size_x = 1;
|
||||
pixel_size_y = 1;
|
||||
} else {
|
||||
MsaaSamples msaa_samples = regs.Get<reg::RB_SURFACE_INFO>().msaa_samples;
|
||||
pixel_size_x = msaa_samples >= MsaaSamples::k4X ? 2 : 1;
|
||||
pixel_size_y = msaa_samples >= MsaaSamples::k2X ? 2 : 1;
|
||||
xenos::MsaaSamples msaa_samples =
|
||||
regs.Get<reg::RB_SURFACE_INFO>().msaa_samples;
|
||||
pixel_size_x = msaa_samples >= xenos::MsaaSamples::k4X ? 2 : 1;
|
||||
pixel_size_y = msaa_samples >= xenos::MsaaSamples::k2X ? 2 : 1;
|
||||
}
|
||||
if (texture_cache_->IsResolutionScale2X()) {
|
||||
pixel_size_x *= 2;
|
||||
@@ -2849,7 +2857,7 @@ void D3D12CommandProcessor::UpdateFixedFunctionState(bool primitive_two_faced) {
|
||||
|
||||
void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
bool shared_memory_is_uav, bool primitive_two_faced,
|
||||
uint32_t line_loop_closing_index, Endian index_endian,
|
||||
uint32_t line_loop_closing_index, xenos::Endian index_endian,
|
||||
uint32_t used_texture_mask, bool early_z, uint32_t color_mask,
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[4]) {
|
||||
auto& regs = *register_file_;
|
||||
@@ -2990,13 +2998,13 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
// Gamma writing.
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
if (color_infos[i].color_format ==
|
||||
ColorRenderTargetFormat::k_8_8_8_8_GAMMA) {
|
||||
xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_Color0Gamma << i;
|
||||
}
|
||||
}
|
||||
if (edram_rov_used_ && depth_stencil_enabled) {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_ROVDepthStencil;
|
||||
if (rb_depth_info.depth_format == DepthRenderTargetFormat::kD24FS8) {
|
||||
if (rb_depth_info.depth_format == xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
flags |= DxbcShaderTranslator::kSysFlag_ROVDepthFloat24;
|
||||
}
|
||||
if (rb_depthcontrol.z_enable) {
|
||||
@@ -3199,9 +3207,9 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
// Log2 of sample count, for scaling VPOS with SSAA (without ROV) and for
|
||||
// EDRAM address calculation with MSAA (with ROV).
|
||||
uint32_t sample_count_log2_x =
|
||||
rb_surface_info.msaa_samples >= MsaaSamples::k4X ? 1 : 0;
|
||||
rb_surface_info.msaa_samples >= xenos::MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t sample_count_log2_y =
|
||||
rb_surface_info.msaa_samples >= MsaaSamples::k2X ? 1 : 0;
|
||||
rb_surface_info.msaa_samples >= xenos::MsaaSamples::k2X ? 1 : 0;
|
||||
dirty |= system_constants_.sample_count_log2[0] != sample_count_log2_x;
|
||||
dirty |= system_constants_.sample_count_log2[1] != sample_count_log2_y;
|
||||
system_constants_.sample_count_log2[0] = sample_count_log2_x;
|
||||
@@ -3220,7 +3228,7 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
if (edram_rov_used_) {
|
||||
uint32_t edram_pitch_tiles =
|
||||
((rb_surface_info.surface_pitch *
|
||||
(rb_surface_info.msaa_samples >= MsaaSamples::k4X ? 2 : 1)) +
|
||||
(rb_surface_info.msaa_samples >= xenos::MsaaSamples::k4X ? 2 : 1)) +
|
||||
79) /
|
||||
80;
|
||||
dirty |= system_constants_.edram_pitch_tiles != edram_pitch_tiles;
|
||||
@@ -3232,8 +3240,9 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
|
||||
reg::RB_COLOR_INFO color_info = color_infos[i];
|
||||
// Exponent bias is in bits 20:25 of RB_COLOR_INFO.
|
||||
int32_t color_exp_bias = color_info.color_exp_bias;
|
||||
if (color_info.color_format == ColorRenderTargetFormat::k_16_16 ||
|
||||
color_info.color_format == ColorRenderTargetFormat::k_16_16_16_16) {
|
||||
if (color_info.color_format == xenos::ColorRenderTargetFormat::k_16_16 ||
|
||||
color_info.color_format ==
|
||||
xenos::ColorRenderTargetFormat::k_16_16_16_16) {
|
||||
// On the Xbox 360, k_16_16_EDRAM and k_16_16_16_16_EDRAM internally have
|
||||
// -32...32 range and expect shaders to give -32...32 values, but they're
|
||||
// emulated using normalized RG16/RGBA16 when not using the ROV, so the
|
||||
@@ -4239,28 +4248,28 @@ bool D3D12CommandProcessor::UpdateBindings(
|
||||
}
|
||||
|
||||
uint32_t D3D12CommandProcessor::GetSupportedMemExportFormatSize(
|
||||
ColorFormat format) {
|
||||
xenos::ColorFormat format) {
|
||||
switch (format) {
|
||||
case ColorFormat::k_8_8_8_8:
|
||||
case ColorFormat::k_2_10_10_10:
|
||||
case xenos::ColorFormat::k_8_8_8_8:
|
||||
case xenos::ColorFormat::k_2_10_10_10:
|
||||
// TODO(Triang3l): Investigate how k_8_8_8_8_A works - not supported in the
|
||||
// texture cache currently.
|
||||
// case ColorFormat::k_8_8_8_8_A:
|
||||
case ColorFormat::k_10_11_11:
|
||||
case ColorFormat::k_11_11_10:
|
||||
case ColorFormat::k_16_16:
|
||||
case ColorFormat::k_16_16_FLOAT:
|
||||
case ColorFormat::k_32_FLOAT:
|
||||
case ColorFormat::k_8_8_8_8_AS_16_16_16_16:
|
||||
case ColorFormat::k_2_10_10_10_AS_16_16_16_16:
|
||||
case ColorFormat::k_10_11_11_AS_16_16_16_16:
|
||||
case ColorFormat::k_11_11_10_AS_16_16_16_16:
|
||||
// case xenos::ColorFormat::k_8_8_8_8_A:
|
||||
case xenos::ColorFormat::k_10_11_11:
|
||||
case xenos::ColorFormat::k_11_11_10:
|
||||
case xenos::ColorFormat::k_16_16:
|
||||
case xenos::ColorFormat::k_16_16_FLOAT:
|
||||
case xenos::ColorFormat::k_32_FLOAT:
|
||||
case xenos::ColorFormat::k_8_8_8_8_AS_16_16_16_16:
|
||||
case xenos::ColorFormat::k_2_10_10_10_AS_16_16_16_16:
|
||||
case xenos::ColorFormat::k_10_11_11_AS_16_16_16_16:
|
||||
case xenos::ColorFormat::k_11_11_10_AS_16_16_16_16:
|
||||
return 1;
|
||||
case ColorFormat::k_16_16_16_16:
|
||||
case ColorFormat::k_16_16_16_16_FLOAT:
|
||||
case ColorFormat::k_32_32_FLOAT:
|
||||
case xenos::ColorFormat::k_16_16_16_16:
|
||||
case xenos::ColorFormat::k_16_16_16_16_FLOAT:
|
||||
case xenos::ColorFormat::k_32_32_FLOAT:
|
||||
return 2;
|
||||
case ColorFormat::k_32_32_32_32_FLOAT:
|
||||
case xenos::ColorFormat::k_32_32_32_32_FLOAT:
|
||||
return 4;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -158,7 +158,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
||||
|
||||
// Sets the current SSAA sample positions, needs to be done before setting
|
||||
// render targets or copying to depth render targets.
|
||||
void SetSamplePositions(MsaaSamples sample_positions);
|
||||
void SetSamplePositions(xenos::MsaaSamples sample_positions);
|
||||
|
||||
// Returns a pipeline state object with deferred creation by its handle. May
|
||||
// return nullptr if failed to create the pipeline state object.
|
||||
@@ -206,11 +206,11 @@ class D3D12CommandProcessor : public CommandProcessor {
|
||||
|
||||
void OnPrimaryBufferEnd() override;
|
||||
|
||||
Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||
Shader* LoadShader(xenos::ShaderType shader_type, uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) override;
|
||||
|
||||
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
|
||||
bool IssueDraw(xenos::PrimitiveType primitive_type, uint32_t index_count,
|
||||
IndexBufferInfo* index_buffer_info,
|
||||
bool major_mode_explicit) override;
|
||||
bool IssueCopy() override;
|
||||
@@ -336,7 +336,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
||||
void UpdateFixedFunctionState(bool primitive_two_faced);
|
||||
void UpdateSystemConstantValues(
|
||||
bool shared_memory_is_uav, bool primitive_two_faced,
|
||||
uint32_t line_loop_closing_index, Endian index_endian,
|
||||
uint32_t line_loop_closing_index, xenos::Endian index_endian,
|
||||
uint32_t used_texture_mask, bool early_z, uint32_t color_mask,
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[4]);
|
||||
bool UpdateBindings(const D3D12Shader* vertex_shader,
|
||||
@@ -348,7 +348,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
||||
// for instance).
|
||||
// TODO(Triang3l): Check if any game uses memexport with formats smaller than
|
||||
// 32 bits per element.
|
||||
static uint32_t GetSupportedMemExportFormatSize(ColorFormat format);
|
||||
static uint32_t GetSupportedMemExportFormatSize(xenos::ColorFormat format);
|
||||
|
||||
// Returns a buffer for reading GPU data back to the CPU. Assuming
|
||||
// synchronizing immediately after use. Always in COPY_DEST state.
|
||||
@@ -524,7 +524,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
||||
bool ff_stencil_ref_update_needed_;
|
||||
|
||||
// Current SSAA sample positions (to be updated by the render target cache).
|
||||
MsaaSamples current_sample_positions_;
|
||||
xenos::MsaaSamples current_sample_positions_;
|
||||
|
||||
// Currently bound pipeline, either a graphics pipeline from the pipeline
|
||||
// cache (with potentially deferred creation - current_external_pipeline_ is
|
||||
|
||||
@@ -25,7 +25,7 @@ constexpr uint32_t D3D12Shader::kMaxTextureBindings;
|
||||
constexpr uint32_t D3D12Shader::kMaxSamplerBindingIndexBits;
|
||||
constexpr uint32_t D3D12Shader::kMaxSamplerBindings;
|
||||
|
||||
D3D12Shader::D3D12Shader(ShaderType shader_type, uint64_t data_hash,
|
||||
D3D12Shader::D3D12Shader(xenos::ShaderType shader_type, uint64_t data_hash,
|
||||
const uint32_t* dword_ptr, uint32_t dword_count)
|
||||
: Shader(shader_type, data_hash, dword_ptr, dword_count) {}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "xenia/gpu/dxbc_shader_translator.h"
|
||||
#include "xenia/gpu/shader.h"
|
||||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/ui/d3d12/d3d12_provider.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -22,7 +23,7 @@ namespace d3d12 {
|
||||
|
||||
class D3D12Shader : public Shader {
|
||||
public:
|
||||
D3D12Shader(ShaderType shader_type, uint64_t data_hash,
|
||||
D3D12Shader(xenos::ShaderType shader_type, uint64_t data_hash,
|
||||
const uint32_t* dword_ptr, uint32_t dword_count);
|
||||
|
||||
void SetTexturesAndSamplers(
|
||||
@@ -53,7 +54,7 @@ class D3D12Shader : public Shader {
|
||||
uint32_t fetch_constant;
|
||||
// Stacked and 3D are separate TextureBindings, even for bindless for null
|
||||
// descriptor handling simplicity.
|
||||
TextureDimension dimension;
|
||||
xenos::FetchOpDimension dimension;
|
||||
bool is_signed;
|
||||
};
|
||||
// Safe to hash and compare with memcmp for layout hashing.
|
||||
@@ -70,10 +71,10 @@ class D3D12Shader : public Shader {
|
||||
struct SamplerBinding {
|
||||
uint32_t bindless_descriptor_index;
|
||||
uint32_t fetch_constant;
|
||||
TextureFilter mag_filter;
|
||||
TextureFilter min_filter;
|
||||
TextureFilter mip_filter;
|
||||
AnisoFilter aniso_filter;
|
||||
xenos::TextureFilter mag_filter;
|
||||
xenos::TextureFilter min_filter;
|
||||
xenos::TextureFilter mip_filter;
|
||||
xenos::AnisoFilter aniso_filter;
|
||||
};
|
||||
const SamplerBinding* GetSamplerBindings(uint32_t& count_out) const {
|
||||
count_out = uint32_t(sampler_bindings_.size());
|
||||
|
||||
@@ -25,16 +25,16 @@ class D3D12TraceViewer : public TraceViewer {
|
||||
return std::unique_ptr<gpu::GraphicsSystem>(new D3D12GraphicsSystem());
|
||||
}
|
||||
|
||||
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
|
||||
uint32_t base,
|
||||
ColorRenderTargetFormat format) override {
|
||||
uintptr_t GetColorRenderTarget(
|
||||
uint32_t pitch, xenos::MsaaSamples samples, uint32_t base,
|
||||
xenos::ColorRenderTargetFormat format) override {
|
||||
// TODO(Triang3l): EDRAM viewer.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t GetDepthRenderTarget(uint32_t pitch, MsaaSamples samples,
|
||||
uint32_t base,
|
||||
DepthRenderTargetFormat format) override {
|
||||
uintptr_t GetDepthRenderTarget(
|
||||
uint32_t pitch, xenos::MsaaSamples samples, uint32_t base,
|
||||
xenos::DepthRenderTargetFormat format) override {
|
||||
// TODO(Triang3l): EDRAM viewer.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ bool PipelineCache::IsCreatingPipelineStates() {
|
||||
return !creation_queue_.empty() || creation_threads_busy_ != 0;
|
||||
}
|
||||
|
||||
D3D12Shader* PipelineCache::LoadShader(ShaderType shader_type,
|
||||
D3D12Shader* PipelineCache::LoadShader(xenos::ShaderType shader_type,
|
||||
uint32_t guest_address,
|
||||
const uint32_t* host_address,
|
||||
uint32_t dword_count) {
|
||||
@@ -760,7 +760,7 @@ Shader::HostVertexShaderType PipelineCache::GetHostVertexShaderTypeIfValid()
|
||||
xenos::TessellationMode tessellation_mode =
|
||||
regs.Get<reg::VGT_HOS_CNTL>().tess_mode;
|
||||
switch (vgt_draw_initiator.prim_type) {
|
||||
case PrimitiveType::kTriangleList:
|
||||
case xenos::PrimitiveType::kTriangleList:
|
||||
// Also supported by triangle strips and fans according to:
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt
|
||||
// Would need to convert those to triangle lists, but haven't seen any
|
||||
@@ -779,7 +779,7 @@ Shader::HostVertexShaderType PipelineCache::GetHostVertexShaderTypeIfValid()
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PrimitiveType::kQuadList:
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
switch (tessellation_mode) {
|
||||
// Also supported by quad strips according to:
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt
|
||||
@@ -794,11 +794,11 @@ Shader::HostVertexShaderType PipelineCache::GetHostVertexShaderTypeIfValid()
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PrimitiveType::kTrianglePatch:
|
||||
case xenos::PrimitiveType::kTrianglePatch:
|
||||
// - Banjo-Kazooie: Nuts & Bolts - water - adaptive.
|
||||
// - Halo 3 - water - adaptive.
|
||||
return Shader::HostVertexShaderType::kTriangleDomainPatchIndexed;
|
||||
case PrimitiveType::kQuadPatch:
|
||||
case xenos::PrimitiveType::kQuadPatch:
|
||||
// - Fable II - continuous.
|
||||
// - Viva Pinata - garden ground - adaptive.
|
||||
return Shader::HostVertexShaderType::kQuadDomainPatchIndexed;
|
||||
@@ -866,7 +866,8 @@ bool PipelineCache::EnsureShadersTranslated(
|
||||
|
||||
bool PipelineCache::ConfigurePipeline(
|
||||
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
|
||||
PrimitiveType primitive_type, IndexFormat index_format, bool early_z,
|
||||
xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format,
|
||||
bool early_z,
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[5],
|
||||
void** pipeline_state_handle_out,
|
||||
ID3D12RootSignature** root_signature_out) {
|
||||
@@ -966,7 +967,7 @@ bool PipelineCache::TranslateShader(
|
||||
}
|
||||
|
||||
const char* host_shader_type;
|
||||
if (shader->type() == ShaderType::kVertex) {
|
||||
if (shader->type() == xenos::ShaderType::kVertex) {
|
||||
switch (shader->host_vertex_shader_type()) {
|
||||
case Shader::HostVertexShaderType::kLineDomainCPIndexed:
|
||||
host_shader_type = "control-point-indexed line domain";
|
||||
@@ -1128,7 +1129,7 @@ bool PipelineCache::TranslateShader(
|
||||
// Create a version of the shader with early depth/stencil forced by Xenia
|
||||
// itself when it's safe to do so or when EARLY_Z_ENABLE is set in
|
||||
// RB_DEPTHCONTROL.
|
||||
if (shader->type() == ShaderType::kPixel && !edram_rov_used_ &&
|
||||
if (shader->type() == xenos::ShaderType::kPixel && !edram_rov_used_ &&
|
||||
!shader->writes_depth()) {
|
||||
shader->SetForcedEarlyZShaderObject(
|
||||
std::move(DxbcShaderTranslator::ForceEarlyDepthStencil(
|
||||
@@ -1147,7 +1148,7 @@ bool PipelineCache::TranslateShader(
|
||||
// Dump shader files if desired.
|
||||
if (!cvars::dump_shaders.empty()) {
|
||||
shader->Dump(cvars::dump_shaders,
|
||||
(shader->type() == ShaderType::kPixel)
|
||||
(shader->type() == xenos::ShaderType::kPixel)
|
||||
? (edram_rov_used_ ? "d3d12_rov" : "d3d12_rtv")
|
||||
: "d3d12");
|
||||
}
|
||||
@@ -1157,7 +1158,8 @@ bool PipelineCache::TranslateShader(
|
||||
|
||||
bool PipelineCache::GetCurrentStateDescription(
|
||||
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
|
||||
PrimitiveType primitive_type, IndexFormat index_format, bool early_z,
|
||||
xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format,
|
||||
bool early_z,
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[5],
|
||||
PipelineRuntimeDescription& runtime_description_out) {
|
||||
PipelineDescription& description_out = runtime_description_out.description;
|
||||
@@ -1187,7 +1189,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
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
|
||||
description_out.strip_cut_index = index_format == xenos::IndexFormat::kInt32
|
||||
? PipelineStripCutIndex::kFFFFFFFF
|
||||
: PipelineStripCutIndex::kFFFF;
|
||||
} else {
|
||||
@@ -1203,16 +1205,16 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
description_out.host_vertex_shader_type = host_vertex_shader_type;
|
||||
if (host_vertex_shader_type == Shader::HostVertexShaderType::kVertex) {
|
||||
switch (primitive_type) {
|
||||
case PrimitiveType::kPointList:
|
||||
case xenos::PrimitiveType::kPointList:
|
||||
description_out.primitive_topology_type_or_tessellation_mode =
|
||||
uint32_t(PipelinePrimitiveTopologyType::kPoint);
|
||||
break;
|
||||
case PrimitiveType::kLineList:
|
||||
case PrimitiveType::kLineStrip:
|
||||
case PrimitiveType::kLineLoop:
|
||||
case xenos::PrimitiveType::kLineList:
|
||||
case xenos::PrimitiveType::kLineStrip:
|
||||
case xenos::PrimitiveType::kLineLoop:
|
||||
// Quads are emulated as line lists with adjacency.
|
||||
case PrimitiveType::kQuadList:
|
||||
case PrimitiveType::k2DLineStrip:
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
case xenos::PrimitiveType::k2DLineStrip:
|
||||
description_out.primitive_topology_type_or_tessellation_mode =
|
||||
uint32_t(PipelinePrimitiveTopologyType::kLine);
|
||||
break;
|
||||
@@ -1222,14 +1224,14 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
break;
|
||||
}
|
||||
switch (primitive_type) {
|
||||
case PrimitiveType::kPointList:
|
||||
case xenos::PrimitiveType::kPointList:
|
||||
description_out.geometry_shader = PipelineGeometryShader::kPointList;
|
||||
break;
|
||||
case PrimitiveType::kRectangleList:
|
||||
case xenos::PrimitiveType::kRectangleList:
|
||||
description_out.geometry_shader =
|
||||
PipelineGeometryShader::kRectangleList;
|
||||
break;
|
||||
case PrimitiveType::kQuadList:
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
description_out.geometry_shader = PipelineGeometryShader::kQuadList;
|
||||
break;
|
||||
default:
|
||||
@@ -1241,7 +1243,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
uint32_t(regs.Get<reg::VGT_HOS_CNTL>().tess_mode);
|
||||
}
|
||||
|
||||
bool primitive_two_faced = IsPrimitiveTwoFaced(
|
||||
bool primitive_two_faced = xenos::IsPrimitiveTwoFaced(
|
||||
host_vertex_shader_type != Shader::HostVertexShaderType::kVertex,
|
||||
primitive_type);
|
||||
|
||||
@@ -1332,7 +1334,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
// (shadows - 2^17 is not enough, 2^18 hasn't been tested, but 2^19
|
||||
// eliminates the acne).
|
||||
if (regs.Get<reg::RB_DEPTH_INFO>().depth_format ==
|
||||
DepthRenderTargetFormat::kD24FS8) {
|
||||
xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
poly_offset *= float(1 << 19);
|
||||
} else {
|
||||
poly_offset *= float(1 << 23);
|
||||
@@ -1353,8 +1355,8 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
}
|
||||
description_out.depth_clip = !regs.Get<reg::PA_CL_CLIP_CNTL>().clip_disable;
|
||||
if (edram_rov_used_) {
|
||||
description_out.rov_msaa =
|
||||
regs.Get<reg::RB_SURFACE_INFO>().msaa_samples != MsaaSamples::k1X;
|
||||
description_out.rov_msaa = regs.Get<reg::RB_SURFACE_INFO>().msaa_samples !=
|
||||
xenos::MsaaSamples::k1X;
|
||||
} else {
|
||||
// Depth/stencil. No stencil, always passing depth test and no depth writing
|
||||
// means depth disabled.
|
||||
@@ -1364,7 +1366,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
description_out.depth_func = rb_depthcontrol.zfunc;
|
||||
description_out.depth_write = rb_depthcontrol.z_write_enable;
|
||||
} else {
|
||||
description_out.depth_func = CompareFunction::kAlways;
|
||||
description_out.depth_func = xenos::CompareFunction::kAlways;
|
||||
}
|
||||
if (rb_depthcontrol.stencil_enable) {
|
||||
description_out.stencil_enable = 1;
|
||||
@@ -1406,13 +1408,13 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
}
|
||||
}
|
||||
// If not binding the DSV, ignore the format in the hash.
|
||||
if (description_out.depth_func != CompareFunction::kAlways ||
|
||||
if (description_out.depth_func != xenos::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 = CompareFunction::kAlways;
|
||||
description_out.depth_func = xenos::CompareFunction::kAlways;
|
||||
}
|
||||
if (early_z) {
|
||||
description_out.force_early_z = 1;
|
||||
@@ -1495,10 +1497,10 @@ bool PipelineCache::GetCurrentStateDescription(
|
||||
} else {
|
||||
rt.src_blend = PipelineBlendFactor::kOne;
|
||||
rt.dest_blend = PipelineBlendFactor::kZero;
|
||||
rt.blend_op = BlendOp::kAdd;
|
||||
rt.blend_op = xenos::BlendOp::kAdd;
|
||||
rt.src_blend_alpha = PipelineBlendFactor::kOne;
|
||||
rt.dest_blend_alpha = PipelineBlendFactor::kZero;
|
||||
rt.blend_op_alpha = BlendOp::kAdd;
|
||||
rt.blend_op_alpha = xenos::BlendOp::kAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1725,7 +1727,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12PipelineState(
|
||||
|
||||
if (!edram_rov_used_) {
|
||||
// Depth/stencil.
|
||||
if (description.depth_func != CompareFunction::kAlways ||
|
||||
if (description.depth_func != xenos::CompareFunction::kAlways ||
|
||||
description.depth_write) {
|
||||
state_desc.DepthStencilState.DepthEnable = TRUE;
|
||||
state_desc.DepthStencilState.DepthWriteMask =
|
||||
@@ -1812,10 +1814,10 @@ ID3D12PipelineState* PipelineCache::CreateD3D12PipelineState(
|
||||
// Call of Duty 4 - GPU performance is better when not blending.
|
||||
if (rt.src_blend != PipelineBlendFactor::kOne ||
|
||||
rt.dest_blend != PipelineBlendFactor::kZero ||
|
||||
rt.blend_op != BlendOp::kAdd ||
|
||||
rt.blend_op != xenos::BlendOp::kAdd ||
|
||||
rt.src_blend_alpha != PipelineBlendFactor::kOne ||
|
||||
rt.dest_blend_alpha != PipelineBlendFactor::kZero ||
|
||||
rt.blend_op_alpha != BlendOp::kAdd) {
|
||||
rt.blend_op_alpha != xenos::BlendOp::kAdd) {
|
||||
blend_desc.BlendEnable = TRUE;
|
||||
blend_desc.SrcBlend = kBlendFactorMap[uint32_t(rt.src_blend)];
|
||||
blend_desc.DestBlend = kBlendFactorMap[uint32_t(rt.dest_blend)];
|
||||
|
||||
@@ -56,7 +56,7 @@ class PipelineCache {
|
||||
void EndSubmission();
|
||||
bool IsCreatingPipelineStates();
|
||||
|
||||
D3D12Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
|
||||
D3D12Shader* LoadShader(xenos::ShaderType shader_type, uint32_t guest_address,
|
||||
const uint32_t* host_address, uint32_t dword_count);
|
||||
|
||||
// Returns the host vertex shader type for the current draw if it's valid and
|
||||
@@ -70,7 +70,8 @@ class PipelineCache {
|
||||
|
||||
bool ConfigurePipeline(
|
||||
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
|
||||
PrimitiveType primitive_type, IndexFormat index_format, bool early_z,
|
||||
xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format,
|
||||
bool early_z,
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[5],
|
||||
void** pipeline_state_handle_out,
|
||||
ID3D12RootSignature** root_signature_out);
|
||||
@@ -87,7 +88,7 @@ class PipelineCache {
|
||||
uint64_t ucode_data_hash;
|
||||
|
||||
uint32_t ucode_dword_count : 16;
|
||||
ShaderType type : 1;
|
||||
xenos::ShaderType type : 1;
|
||||
Shader::HostVertexShaderType host_vertex_shader_type : 3;
|
||||
|
||||
reg::SQ_PROGRAM_CNTL sq_program_cntl;
|
||||
@@ -155,15 +156,15 @@ class PipelineCache {
|
||||
|
||||
// Update PipelineDescription::kVersion if anything is changed!
|
||||
XEPACKEDSTRUCT(PipelineRenderTarget, {
|
||||
uint32_t used : 1; // 1
|
||||
ColorRenderTargetFormat format : 4; // 5
|
||||
PipelineBlendFactor src_blend : 4; // 9
|
||||
PipelineBlendFactor dest_blend : 4; // 13
|
||||
BlendOp blend_op : 3; // 16
|
||||
PipelineBlendFactor src_blend_alpha : 4; // 20
|
||||
PipelineBlendFactor dest_blend_alpha : 4; // 24
|
||||
BlendOp blend_op_alpha : 3; // 27
|
||||
uint32_t write_mask : 4; // 31
|
||||
uint32_t used : 1; // 1
|
||||
xenos::ColorRenderTargetFormat format : 4; // 5
|
||||
PipelineBlendFactor src_blend : 4; // 9
|
||||
PipelineBlendFactor dest_blend : 4; // 13
|
||||
xenos::BlendOp blend_op : 3; // 16
|
||||
PipelineBlendFactor src_blend_alpha : 4; // 20
|
||||
PipelineBlendFactor dest_blend_alpha : 4; // 24
|
||||
xenos::BlendOp blend_op_alpha : 3; // 27
|
||||
uint32_t write_mask : 4; // 31
|
||||
});
|
||||
|
||||
XEPACKEDSTRUCT(PipelineDescription, {
|
||||
@@ -180,28 +181,28 @@ class PipelineCache {
|
||||
// xenos::TessellationMode for a domain shader.
|
||||
uint32_t primitive_topology_type_or_tessellation_mode : 2; // 7
|
||||
// Zero for non-kVertex host_vertex_shader_type.
|
||||
PipelineGeometryShader geometry_shader : 2; // 9
|
||||
uint32_t fill_mode_wireframe : 1; // 10
|
||||
PipelineCullMode cull_mode : 2; // 12
|
||||
uint32_t front_counter_clockwise : 1; // 13
|
||||
uint32_t depth_clip : 1; // 14
|
||||
uint32_t rov_msaa : 1; // 15
|
||||
DepthRenderTargetFormat depth_format : 1; // 16
|
||||
CompareFunction depth_func : 3; // 19
|
||||
uint32_t depth_write : 1; // 20
|
||||
uint32_t stencil_enable : 1; // 21
|
||||
uint32_t stencil_read_mask : 8; // 29
|
||||
uint32_t force_early_z : 1; // 30
|
||||
PipelineGeometryShader geometry_shader : 2; // 9
|
||||
uint32_t fill_mode_wireframe : 1; // 10
|
||||
PipelineCullMode cull_mode : 2; // 12
|
||||
uint32_t front_counter_clockwise : 1; // 13
|
||||
uint32_t depth_clip : 1; // 14
|
||||
uint32_t rov_msaa : 1; // 15
|
||||
xenos::DepthRenderTargetFormat depth_format : 1; // 16
|
||||
xenos::CompareFunction depth_func : 3; // 19
|
||||
uint32_t depth_write : 1; // 20
|
||||
uint32_t stencil_enable : 1; // 21
|
||||
uint32_t stencil_read_mask : 8; // 29
|
||||
uint32_t force_early_z : 1; // 30
|
||||
|
||||
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
|
||||
uint32_t stencil_write_mask : 8; // 8
|
||||
xenos::StencilOp stencil_front_fail_op : 3; // 11
|
||||
xenos::StencilOp stencil_front_depth_fail_op : 3; // 14
|
||||
xenos::StencilOp stencil_front_pass_op : 3; // 17
|
||||
xenos::CompareFunction stencil_front_func : 3; // 20
|
||||
xenos::StencilOp stencil_back_fail_op : 3; // 23
|
||||
xenos::StencilOp stencil_back_depth_fail_op : 3; // 26
|
||||
xenos::StencilOp stencil_back_pass_op : 3; // 29
|
||||
xenos::CompareFunction stencil_back_func : 3; // 32
|
||||
|
||||
PipelineRenderTarget render_targets[4];
|
||||
|
||||
@@ -228,7 +229,8 @@ class PipelineCache {
|
||||
|
||||
bool GetCurrentStateDescription(
|
||||
D3D12Shader* vertex_shader, D3D12Shader* pixel_shader,
|
||||
PrimitiveType primitive_type, IndexFormat index_format, bool early_z,
|
||||
xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format,
|
||||
bool early_z,
|
||||
const RenderTargetCache::PipelineRenderTarget render_targets[5],
|
||||
PipelineRuntimeDescription& runtime_description_out);
|
||||
|
||||
|
||||
@@ -173,16 +173,16 @@ void PrimitiveConverter::BeginFrame() {
|
||||
memory_regions_used_ = 0;
|
||||
}
|
||||
|
||||
PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType(
|
||||
PrimitiveType type) {
|
||||
xenos::PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType(
|
||||
xenos::PrimitiveType type) {
|
||||
switch (type) {
|
||||
case PrimitiveType::kTriangleFan:
|
||||
return PrimitiveType::kTriangleList;
|
||||
case PrimitiveType::kLineLoop:
|
||||
return PrimitiveType::kLineStrip;
|
||||
case PrimitiveType::kQuadList:
|
||||
case xenos::PrimitiveType::kTriangleFan:
|
||||
return xenos::PrimitiveType::kTriangleList;
|
||||
case xenos::PrimitiveType::kLineLoop:
|
||||
return xenos::PrimitiveType::kLineStrip;
|
||||
case xenos::PrimitiveType::kQuadList:
|
||||
if (cvars::d3d12_convert_quads_to_triangles) {
|
||||
return PrimitiveType::kTriangleList;
|
||||
return xenos::PrimitiveType::kTriangleList;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -192,10 +192,10 @@ PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType(
|
||||
}
|
||||
|
||||
PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
PrimitiveType source_type, uint32_t address, uint32_t index_count,
|
||||
IndexFormat index_format, Endian index_endianness,
|
||||
xenos::PrimitiveType source_type, uint32_t address, uint32_t index_count,
|
||||
xenos::IndexFormat index_format, xenos::Endian index_endianness,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out, uint32_t& index_count_out) {
|
||||
bool index_32bit = index_format == IndexFormat::kInt32;
|
||||
bool index_32bit = index_format == xenos::IndexFormat::kInt32;
|
||||
auto& regs = *register_file_;
|
||||
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.
|
||||
@@ -207,22 +207,22 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
uint32_t reset_index_host = index_32bit ? 0xFFFFFFFFu : 0xFFFFu;
|
||||
|
||||
// Degenerate line loops are just lines.
|
||||
if (source_type == PrimitiveType::kLineLoop && index_count <= 2) {
|
||||
source_type = PrimitiveType::kLineStrip;
|
||||
if (source_type == xenos::PrimitiveType::kLineLoop && index_count <= 2) {
|
||||
source_type = xenos::PrimitiveType::kLineStrip;
|
||||
}
|
||||
|
||||
// Check if need to convert at all.
|
||||
if (source_type == PrimitiveType::kTriangleStrip ||
|
||||
source_type == PrimitiveType::kLineStrip) {
|
||||
if (source_type == xenos::PrimitiveType::kTriangleStrip ||
|
||||
source_type == xenos::PrimitiveType::kLineStrip) {
|
||||
if (!reset || reset_index == reset_index_host) {
|
||||
return ConversionResult::kConversionNotNeeded;
|
||||
}
|
||||
} else if (source_type == PrimitiveType::kQuadList) {
|
||||
} else if (source_type == xenos::PrimitiveType::kQuadList) {
|
||||
if (!cvars::d3d12_convert_quads_to_triangles) {
|
||||
return ConversionResult::kConversionNotNeeded;
|
||||
}
|
||||
} else if (source_type != PrimitiveType::kTriangleFan &&
|
||||
source_type != PrimitiveType::kLineLoop) {
|
||||
} else if (source_type != xenos::PrimitiveType::kTriangleFan &&
|
||||
source_type != xenos::PrimitiveType::kLineLoop) {
|
||||
return ConversionResult::kConversionNotNeeded;
|
||||
}
|
||||
|
||||
@@ -232,10 +232,10 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
|
||||
// Exit early for clearly empty draws, without even reading the memory.
|
||||
uint32_t index_count_min;
|
||||
if (source_type == PrimitiveType::kLineStrip ||
|
||||
source_type == PrimitiveType::kLineLoop) {
|
||||
if (source_type == xenos::PrimitiveType::kLineStrip ||
|
||||
source_type == xenos::PrimitiveType::kLineLoop) {
|
||||
index_count_min = 2;
|
||||
} else if (source_type == PrimitiveType::kQuadList) {
|
||||
} else if (source_type == xenos::PrimitiveType::kQuadList) {
|
||||
index_count_min = 4;
|
||||
} else {
|
||||
index_count_min = 3;
|
||||
@@ -308,15 +308,16 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
// Optimization specific to primitive types - if reset index not found in the
|
||||
// source index buffer, can set this to false and use a faster way of copying.
|
||||
bool reset_actually_used = reset;
|
||||
if (source_type == PrimitiveType::kTriangleFan) {
|
||||
if (source_type == xenos::PrimitiveType::kTriangleFan) {
|
||||
// Triangle fans are not supported by Direct3D 12 at all.
|
||||
conversion_needed = true;
|
||||
trace_writer_->WriteMemoryRead(address, index_buffer_size);
|
||||
if (reset) {
|
||||
uint32_t current_fan_index_count = 0;
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
uint32_t index =
|
||||
index_format == IndexFormat::kInt32 ? source_32[i] : source_16[i];
|
||||
uint32_t index = index_format == xenos::IndexFormat::kInt32
|
||||
? source_32[i]
|
||||
: source_16[i];
|
||||
if (index == reset_index) {
|
||||
current_fan_index_count = 0;
|
||||
continue;
|
||||
@@ -328,8 +329,8 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
} else {
|
||||
converted_index_count = 3 * (index_count - 2);
|
||||
}
|
||||
} else if (source_type == PrimitiveType::kTriangleStrip ||
|
||||
source_type == PrimitiveType::kLineStrip) {
|
||||
} else if (source_type == xenos::PrimitiveType::kTriangleStrip ||
|
||||
source_type == xenos::PrimitiveType::kLineStrip) {
|
||||
converted_index_count = index_count;
|
||||
// Check if the restart index is used at all in this buffer because reading
|
||||
// vertices from a default heap is faster than from an upload heap.
|
||||
@@ -348,7 +349,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
check_source = source;
|
||||
uint32_t check_indices_remaining = index_count;
|
||||
alignas(16) uint64_t check_result[2];
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
while (check_indices_remaining != 0 && (check_source_uintptr & 15)) {
|
||||
--check_indices_remaining;
|
||||
if (*(check_source_32++) == reset_index) {
|
||||
@@ -402,7 +403,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
if (source_32[i] == reset_index) {
|
||||
conversion_needed = true;
|
||||
@@ -418,15 +419,16 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
}
|
||||
#endif // XE_ARCH_AMD64
|
||||
} else if (source_type == PrimitiveType::kLineLoop) {
|
||||
} else if (source_type == xenos::PrimitiveType::kLineLoop) {
|
||||
conversion_needed = true;
|
||||
trace_writer_->WriteMemoryRead(address, index_buffer_size);
|
||||
if (reset) {
|
||||
reset_actually_used = false;
|
||||
uint32_t current_strip_index_count = 0;
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
uint32_t index =
|
||||
index_format == IndexFormat::kInt32 ? source_32[i] : source_16[i];
|
||||
uint32_t index = index_format == xenos::IndexFormat::kInt32
|
||||
? source_32[i]
|
||||
: source_16[i];
|
||||
if (index == reset_index) {
|
||||
reset_actually_used = true;
|
||||
// Loop strips with more than 2 vertices.
|
||||
@@ -444,7 +446,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
} else {
|
||||
converted_index_count = index_count + 1;
|
||||
}
|
||||
} else if (source_type == PrimitiveType::kQuadList) {
|
||||
} else if (source_type == xenos::PrimitiveType::kQuadList) {
|
||||
conversion_needed = true;
|
||||
trace_writer_->WriteMemoryRead(address, index_buffer_size);
|
||||
converted_index_count = (index_count >> 2) * 6;
|
||||
@@ -471,13 +473,13 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
return ConversionResult::kFailed;
|
||||
}
|
||||
|
||||
if (source_type == PrimitiveType::kTriangleFan) {
|
||||
if (source_type == xenos::PrimitiveType::kTriangleFan) {
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/direct3d9/triangle-fans
|
||||
// Ordered as (v1, v2, v0), (v2, v3, v0).
|
||||
if (reset) {
|
||||
uint32_t current_fan_index_count = 0;
|
||||
uint32_t current_fan_first_index = 0;
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
uint32_t* target_32 = reinterpret_cast<uint32_t*>(target);
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
uint32_t index = source_32[i];
|
||||
@@ -513,7 +515,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
uint32_t* target_32 = reinterpret_cast<uint32_t*>(target);
|
||||
for (uint32_t i = 2; i < index_count; ++i) {
|
||||
*(target_32++) = source_32[i - 1];
|
||||
@@ -529,8 +531,8 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (source_type == PrimitiveType::kTriangleStrip ||
|
||||
source_type == PrimitiveType::kLineStrip) {
|
||||
} else if (source_type == xenos::PrimitiveType::kTriangleStrip ||
|
||||
source_type == xenos::PrimitiveType::kLineStrip) {
|
||||
#if XE_ARCH_AMD64
|
||||
// Replace the reset index with the maximum representable value - vector OR
|
||||
// gives 0 or 0xFFFF/0xFFFFFFFF, which is exactly what is needed.
|
||||
@@ -549,7 +551,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
target_aligned_uintptr =
|
||||
reinterpret_cast<uintptr_t>(target) & ~(uintptr_t(15));
|
||||
uint32_t vector_count = (address_last >> 4) - (address >> 4) + 1;
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
__m128i reset_index_vector = _mm_set1_epi32(reset_index);
|
||||
for (uint32_t i = 0; i < vector_count; ++i) {
|
||||
__m128i indices_vector = _mm_load_si128(source_aligned_128++);
|
||||
@@ -569,7 +571,7 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
uint32_t index = source_32[i];
|
||||
reinterpret_cast<uint32_t*>(target)[i] =
|
||||
@@ -583,11 +585,11 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
}
|
||||
#endif // XE_ARCH_AMD64
|
||||
} else if (source_type == PrimitiveType::kLineLoop) {
|
||||
} else if (source_type == xenos::PrimitiveType::kLineLoop) {
|
||||
if (reset_actually_used) {
|
||||
uint32_t current_strip_index_count = 0;
|
||||
uint32_t current_strip_first_index = 0;
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
uint32_t* target_32 = reinterpret_cast<uint32_t*>(target);
|
||||
for (uint32_t i = 0; i < index_count; ++i) {
|
||||
uint32_t index = source_32[i];
|
||||
@@ -635,16 +637,16 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
} else {
|
||||
std::memcpy(target, source, index_count * index_size);
|
||||
if (converted_index_count > index_count) {
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
reinterpret_cast<uint32_t*>(target)[index_count] = source_32[0];
|
||||
} else {
|
||||
reinterpret_cast<uint16_t*>(target)[index_count] = source_16[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (source_type == PrimitiveType::kQuadList) {
|
||||
} else if (source_type == xenos::PrimitiveType::kQuadList) {
|
||||
uint32_t quad_count = index_count >> 4;
|
||||
if (index_format == IndexFormat::kInt32) {
|
||||
if (index_format == xenos::IndexFormat::kInt32) {
|
||||
uint32_t* target_32 = reinterpret_cast<uint32_t*>(target);
|
||||
for (uint32_t i = 0; i < quad_count; ++i) {
|
||||
uint32_t quad_index = i << 2;
|
||||
@@ -680,13 +682,14 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
|
||||
}
|
||||
|
||||
void* PrimitiveConverter::AllocateIndices(
|
||||
IndexFormat format, uint32_t count, uint32_t simd_offset,
|
||||
xenos::IndexFormat format, uint32_t count, uint32_t simd_offset,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out) {
|
||||
if (count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t size = count * (format == IndexFormat::kInt32 ? sizeof(uint32_t)
|
||||
: sizeof(uint16_t));
|
||||
uint32_t size =
|
||||
count * (format == xenos::IndexFormat::kInt32 ? sizeof(uint32_t)
|
||||
: sizeof(uint16_t));
|
||||
// 16-align all index data because SIMD is used to replace the reset index
|
||||
// (without that, 4-alignment would be required anyway to mix 16-bit and
|
||||
// 32-bit indices in one buffer page).
|
||||
@@ -703,7 +706,7 @@ void* PrimitiveConverter::AllocateIndices(
|
||||
nullptr, nullptr, &gpu_address);
|
||||
if (mapping == nullptr) {
|
||||
XELOGE("Failed to allocate space for {} converted {}-bit vertex indices",
|
||||
count, format == IndexFormat::kInt32 ? 32 : 16);
|
||||
count, format == xenos::IndexFormat::kInt32 ? 32 : 16);
|
||||
return nullptr;
|
||||
}
|
||||
gpu_address_out = gpu_address + simd_offset;
|
||||
@@ -732,18 +735,18 @@ PrimitiveConverter::MemoryInvalidationCallbackThunk(
|
||||
}
|
||||
|
||||
D3D12_GPU_VIRTUAL_ADDRESS PrimitiveConverter::GetStaticIndexBuffer(
|
||||
PrimitiveType source_type, uint32_t index_count,
|
||||
xenos::PrimitiveType source_type, uint32_t index_count,
|
||||
uint32_t& index_count_out) const {
|
||||
if (index_count > kMaxNonIndexedVertices) {
|
||||
assert_always();
|
||||
return D3D12_GPU_VIRTUAL_ADDRESS(0);
|
||||
}
|
||||
if (source_type == PrimitiveType::kTriangleFan) {
|
||||
if (source_type == xenos::PrimitiveType::kTriangleFan) {
|
||||
index_count_out = (std::max(index_count, uint32_t(2)) - 2) * 3;
|
||||
return static_ib_gpu_address_ +
|
||||
kStaticIBTriangleFanOffset * sizeof(uint16_t);
|
||||
}
|
||||
if (source_type == PrimitiveType::kQuadList &&
|
||||
if (source_type == xenos::PrimitiveType::kQuadList &&
|
||||
cvars::d3d12_convert_quads_to_triangles) {
|
||||
index_count_out = (index_count >> 2) * 6;
|
||||
return static_ib_gpu_address_ + kStaticIBQuadOffset * sizeof(uint16_t);
|
||||
|
||||
@@ -51,7 +51,8 @@ class PrimitiveConverter {
|
||||
void BeginFrame();
|
||||
|
||||
// Returns the primitive type that the original type will be converted to.
|
||||
static PrimitiveType GetReplacementPrimitiveType(PrimitiveType type);
|
||||
static xenos::PrimitiveType GetReplacementPrimitiveType(
|
||||
xenos::PrimitiveType type);
|
||||
|
||||
enum class ConversionResult {
|
||||
// Converted to a transient buffer.
|
||||
@@ -69,10 +70,10 @@ class PrimitiveConverter {
|
||||
// buffer will be in the GENERIC_READ state (it's in an upload heap). Only
|
||||
// writing to the outputs if returning kConverted. The restart index will be
|
||||
// handled internally from the register values.
|
||||
ConversionResult ConvertPrimitives(PrimitiveType source_type,
|
||||
ConversionResult ConvertPrimitives(xenos::PrimitiveType source_type,
|
||||
uint32_t address, uint32_t index_count,
|
||||
IndexFormat index_format,
|
||||
Endian index_endianness,
|
||||
xenos::IndexFormat index_format,
|
||||
xenos::Endian index_endianness,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out,
|
||||
uint32_t& index_count_out);
|
||||
|
||||
@@ -80,7 +81,7 @@ class PrimitiveConverter {
|
||||
// primitives in INDEX_BUFFER state, for non-indexed drawing. Returns 0 if
|
||||
// conversion is not available (can draw natively).
|
||||
D3D12_GPU_VIRTUAL_ADDRESS GetStaticIndexBuffer(
|
||||
PrimitiveType source_type, uint32_t index_count,
|
||||
xenos::PrimitiveType source_type, uint32_t index_count,
|
||||
uint32_t& index_count_out) const;
|
||||
|
||||
// Callback for invalidating buffers mid-frame.
|
||||
@@ -93,7 +94,7 @@ class PrimitiveConverter {
|
||||
// simd_offset is source address & 15 - if SIMD is used, the source and the
|
||||
// target must have the same alignment within one register. 0 is optimal when
|
||||
// not using SIMD.
|
||||
void* AllocateIndices(IndexFormat format, uint32_t count,
|
||||
void* AllocateIndices(xenos::IndexFormat format, uint32_t count,
|
||||
uint32_t simd_offset,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out);
|
||||
|
||||
@@ -135,8 +136,8 @@ class PrimitiveConverter {
|
||||
uint64_t value;
|
||||
struct {
|
||||
uint32_t address; // 32
|
||||
PrimitiveType source_type : 6; // 38
|
||||
IndexFormat format : 1; // 39
|
||||
xenos::PrimitiveType source_type : 6; // 38
|
||||
xenos::IndexFormat format : 1; // 39
|
||||
uint32_t count : 16; // 55
|
||||
uint32_t reset : 1; // 56
|
||||
};
|
||||
|
||||
@@ -579,9 +579,9 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
return false;
|
||||
}
|
||||
uint32_t msaa_samples_x =
|
||||
rb_surface_info.msaa_samples >= MsaaSamples::k4X ? 2 : 1;
|
||||
rb_surface_info.msaa_samples >= xenos::MsaaSamples::k4X ? 2 : 1;
|
||||
uint32_t msaa_samples_y =
|
||||
rb_surface_info.msaa_samples >= MsaaSamples::k2X ? 2 : 1;
|
||||
rb_surface_info.msaa_samples >= xenos::MsaaSamples::k2X ? 2 : 1;
|
||||
|
||||
// Extract color/depth info in an unified way.
|
||||
bool enabled[5];
|
||||
@@ -596,7 +596,7 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
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]));
|
||||
IsColorFormat64bpp(xenos::ColorRenderTargetFormat(formats[i]));
|
||||
}
|
||||
auto rb_depthcontrol = regs.Get<reg::RB_DEPTHCONTROL>();
|
||||
auto rb_depth_info = regs.Get<reg::RB_DEPTH_INFO>();
|
||||
@@ -968,7 +968,7 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
render_target->state = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
current_pipeline_render_targets_[rtv_count].guest_render_target = i;
|
||||
current_pipeline_render_targets_[rtv_count].format =
|
||||
GetColorDXGIFormat(ColorRenderTargetFormat(formats[i]));
|
||||
GetColorDXGIFormat(xenos::ColorRenderTargetFormat(formats[i]));
|
||||
++rtv_count;
|
||||
}
|
||||
for (uint32_t i = rtv_count; i < 4; ++i) {
|
||||
@@ -985,7 +985,7 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
|
||||
D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
depth_render_target->state = D3D12_RESOURCE_STATE_DEPTH_WRITE;
|
||||
current_pipeline_render_targets_[4].format =
|
||||
GetDepthDXGIFormat(DepthRenderTargetFormat(formats[4]));
|
||||
GetDepthDXGIFormat(xenos::DepthRenderTargetFormat(formats[4]));
|
||||
} else {
|
||||
current_pipeline_render_targets_[4].format = DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
@@ -1094,7 +1094,7 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
const auto& fetch = regs.Get<xenos::xe_gpu_vertex_fetch_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0);
|
||||
assert_true(fetch.type == xenos::FetchConstantType::kVertex);
|
||||
assert_true(fetch.endian == Endian::k8in32);
|
||||
assert_true(fetch.endian == xenos::Endian::k8in32);
|
||||
assert_true(fetch.size == 6);
|
||||
trace_writer_->WriteMemoryRead(fetch.address << 2, fetch.size << 2);
|
||||
const uint8_t* src_vertex_address =
|
||||
@@ -1106,7 +1106,7 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
for (uint32_t i = 0; i < 6; ++i) {
|
||||
vertices[i] =
|
||||
xenos::GpuSwap(xe::load<float>(src_vertex_address + i * sizeof(float)),
|
||||
Endian(fetch.endian)) +
|
||||
xenos::Endian(fetch.endian)) +
|
||||
vertex_offset;
|
||||
}
|
||||
// Xenos only supports rectangle copies (luckily).
|
||||
@@ -1175,7 +1175,7 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
"at {}",
|
||||
rect.left, rect.top, rect.right, rect.bottom, surface_index,
|
||||
surface_pitch, 1 << uint32_t(rb_surface_info.msaa_samples),
|
||||
rb_surface_info.msaa_samples != MsaaSamples::k1X ? "s" : "",
|
||||
rb_surface_info.msaa_samples != xenos::MsaaSamples::k1X ? "s" : "",
|
||||
surface_format, surface_edram_base);
|
||||
|
||||
if (rect.left >= rect.right || rect.top >= rect.bottom) {
|
||||
@@ -1211,8 +1211,9 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
|
||||
bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
TextureCache* texture_cache,
|
||||
uint32_t edram_base, uint32_t surface_pitch,
|
||||
MsaaSamples msaa_samples, bool is_depth,
|
||||
uint32_t src_format, const D3D12_RECT& rect,
|
||||
xenos::MsaaSamples msaa_samples,
|
||||
bool is_depth, uint32_t src_format,
|
||||
const D3D12_RECT& rect,
|
||||
uint32_t& written_address_out,
|
||||
uint32_t& written_length_out) {
|
||||
written_address_out = written_length_out = 0;
|
||||
@@ -1231,35 +1232,35 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
|
||||
// Get format info.
|
||||
auto rb_copy_dest_info = regs.Get<reg::RB_COPY_DEST_INFO>();
|
||||
TextureFormat src_texture_format;
|
||||
xenos::TextureFormat src_texture_format;
|
||||
bool src_64bpp;
|
||||
if (is_depth) {
|
||||
src_texture_format =
|
||||
DepthRenderTargetToTextureFormat(DepthRenderTargetFormat(src_format));
|
||||
src_texture_format = DepthRenderTargetToTextureFormat(
|
||||
xenos::DepthRenderTargetFormat(src_format));
|
||||
src_64bpp = false;
|
||||
} else {
|
||||
// Force k_16_16 and k_16_16_16_16 RTs to be always resolved via drawing,
|
||||
// because resolving to a k_16_16 or a k_16_16_16_16 texture should result
|
||||
// in unsigned texture data, unlike the render target which is signed.
|
||||
if (ColorRenderTargetFormat(src_format) ==
|
||||
ColorRenderTargetFormat::k_16_16) {
|
||||
src_texture_format = TextureFormat::k_16_16_EDRAM;
|
||||
} else if (ColorRenderTargetFormat(src_format) ==
|
||||
ColorRenderTargetFormat::k_16_16_16_16) {
|
||||
src_texture_format = TextureFormat::k_16_16_16_16_EDRAM;
|
||||
if (xenos::ColorRenderTargetFormat(src_format) ==
|
||||
xenos::ColorRenderTargetFormat::k_16_16) {
|
||||
src_texture_format = xenos::TextureFormat::k_16_16_EDRAM;
|
||||
} else if (xenos::ColorRenderTargetFormat(src_format) ==
|
||||
xenos::ColorRenderTargetFormat::k_16_16_16_16) {
|
||||
src_texture_format = xenos::TextureFormat::k_16_16_16_16_EDRAM;
|
||||
} else {
|
||||
src_texture_format = GetBaseFormat(ColorRenderTargetToTextureFormat(
|
||||
ColorRenderTargetFormat(src_format)));
|
||||
xenos::ColorRenderTargetFormat(src_format)));
|
||||
}
|
||||
src_64bpp = IsColorFormat64bpp(ColorRenderTargetFormat(src_format));
|
||||
src_64bpp = IsColorFormat64bpp(xenos::ColorRenderTargetFormat(src_format));
|
||||
}
|
||||
assert_true(src_texture_format != TextureFormat::kUnknown);
|
||||
assert_true(src_texture_format != xenos::TextureFormat::kUnknown);
|
||||
// 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.copy_dest_format));
|
||||
xenos::TextureFormat dest_format =
|
||||
is_depth ? src_texture_format
|
||||
: GetBaseFormat(
|
||||
xenos::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.
|
||||
@@ -1328,10 +1329,10 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
dest_exp_bias = 0;
|
||||
} else {
|
||||
dest_exp_bias = rb_copy_dest_info.copy_dest_exp_bias;
|
||||
if (ColorRenderTargetFormat(src_format) ==
|
||||
ColorRenderTargetFormat::k_16_16 ||
|
||||
ColorRenderTargetFormat(src_format) ==
|
||||
ColorRenderTargetFormat::k_16_16_16_16) {
|
||||
if (xenos::ColorRenderTargetFormat(src_format) ==
|
||||
xenos::ColorRenderTargetFormat::k_16_16 ||
|
||||
xenos::ColorRenderTargetFormat(src_format) ==
|
||||
xenos::ColorRenderTargetFormat::k_16_16_16_16) {
|
||||
// On the Xbox 360, k_16_16_EDRAM and k_16_16_16_16_EDRAM internally have
|
||||
// -32...32 range, but they're emulated using normalized RG16/RGBA16, so
|
||||
// sampling the host render target gives 1/32 of what is actually stored
|
||||
@@ -1505,9 +1506,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
edram_base | (resolution_scale_log2 << 13) |
|
||||
(resolution_scale_edge_clamp ? (1 << 14) : 0) |
|
||||
(is_depth ? (1 << 15) : 0) | (surface_pitch_tiles << 16);
|
||||
if (msaa_samples >= MsaaSamples::k2X) {
|
||||
if (msaa_samples >= xenos::MsaaSamples::k2X) {
|
||||
root_constants.base_samples_2x_depth_pitch |= 1 << 11;
|
||||
if (msaa_samples >= MsaaSamples::k4X) {
|
||||
if (msaa_samples >= xenos::MsaaSamples::k4X) {
|
||||
root_constants.base_samples_2x_depth_pitch |= 1 << 12;
|
||||
}
|
||||
}
|
||||
@@ -1520,9 +1521,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
command_processor_->SubmitBarriers();
|
||||
// 1 group per destination 80x16 region.
|
||||
uint32_t group_count_x = row_width_ss_div_80, group_count_y = rows;
|
||||
if (msaa_samples >= MsaaSamples::k2X) {
|
||||
if (msaa_samples >= xenos::MsaaSamples::k2X) {
|
||||
group_count_y = (group_count_y + 1) >> 1;
|
||||
if (msaa_samples >= MsaaSamples::k4X) {
|
||||
if (msaa_samples >= xenos::MsaaSamples::k4X) {
|
||||
group_count_x = (group_count_x + 1) >> 1;
|
||||
}
|
||||
}
|
||||
@@ -1648,9 +1649,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
load_root_constants.base_samples_2x_depth_pitch =
|
||||
edram_base | (resolution_scale_log2 << 13) |
|
||||
(surface_pitch_tiles << 16);
|
||||
if (msaa_samples >= MsaaSamples::k2X) {
|
||||
if (msaa_samples >= xenos::MsaaSamples::k2X) {
|
||||
load_root_constants.base_samples_2x_depth_pitch |= 1 << 11;
|
||||
if (msaa_samples >= MsaaSamples::k4X) {
|
||||
if (msaa_samples >= xenos::MsaaSamples::k4X) {
|
||||
load_root_constants.base_samples_2x_depth_pitch |= 1 << 12;
|
||||
}
|
||||
}
|
||||
@@ -1713,8 +1714,8 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
command_list->D3DSetGraphicsRootSignature(resolve_root_signature_);
|
||||
|
||||
ResolveRootConstants resolve_root_constants;
|
||||
uint32_t samples_x_log2 = msaa_samples >= MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t samples_y_log2 = msaa_samples >= MsaaSamples::k2X ? 1 : 0;
|
||||
uint32_t samples_x_log2 = msaa_samples >= xenos::MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t samples_y_log2 = msaa_samples >= xenos::MsaaSamples::k2X ? 1 : 0;
|
||||
resolve_root_constants.rect_samples_lw =
|
||||
(copy_rect.left << (samples_x_log2 + resolution_scale_log2)) |
|
||||
(copy_width << (16 + samples_x_log2 + resolution_scale_log2));
|
||||
@@ -1728,10 +1729,10 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
samples_y_log2 | (samples_x_log2 << 1) |
|
||||
(resolution_scale_edge_clamp ? (1 << 6) : 0) |
|
||||
((uint32_t(dest_exp_bias) & 0x3F) << 7);
|
||||
if (msaa_samples == MsaaSamples::k1X) {
|
||||
if (msaa_samples == xenos::MsaaSamples::k1X) {
|
||||
// No offset.
|
||||
resolve_root_constants.resolve_info |= (1 << 2) | (1 << 4);
|
||||
} else if (msaa_samples == MsaaSamples::k2X) {
|
||||
} else if (msaa_samples == xenos::MsaaSamples::k2X) {
|
||||
// -0.5 or +0.5 samples vertical offset if getting only one sample.
|
||||
if (sample_select == xenos::CopySampleSelect::k0) {
|
||||
resolve_root_constants.resolve_info |= (0 << 2) | (1 << 4);
|
||||
@@ -1772,26 +1773,26 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC rt_srv_desc;
|
||||
rt_srv_desc.Format =
|
||||
GetColorDXGIFormat(ColorRenderTargetFormat(src_format));
|
||||
GetColorDXGIFormat(xenos::ColorRenderTargetFormat(src_format));
|
||||
rt_srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
UINT swizzle = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
if (dest_swap) {
|
||||
switch (ColorRenderTargetFormat(src_format)) {
|
||||
case ColorRenderTargetFormat::k_8_8_8_8:
|
||||
case ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT:
|
||||
case ColorRenderTargetFormat::k_16_16_16_16:
|
||||
case ColorRenderTargetFormat::k_16_16_16_16_FLOAT:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
switch (xenos::ColorRenderTargetFormat(src_format)) {
|
||||
case xenos::ColorRenderTargetFormat::k_8_8_8_8:
|
||||
case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_16_16_16_16:
|
||||
case xenos::ColorRenderTargetFormat::k_16_16_16_16_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
swizzle = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dest_format == TextureFormat::k_6_5_5) {
|
||||
if (dest_format == xenos::TextureFormat::k_6_5_5) {
|
||||
// Green bits of the resolve target used for blue, and blue bits used for
|
||||
// green.
|
||||
swizzle = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
@@ -1810,7 +1811,7 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
command_list->D3DSetGraphicsRootDescriptorTable(1, descriptor_rt.second);
|
||||
|
||||
command_processor_->SubmitBarriers();
|
||||
command_processor_->SetSamplePositions(MsaaSamples::k1X);
|
||||
command_processor_->SetSamplePositions(xenos::MsaaSamples::k1X);
|
||||
command_processor_->SetExternalGraphicsPipeline(resolve_pipeline);
|
||||
command_list->D3DOMSetRenderTargets(1, &resolve_target->rtv_handle, TRUE,
|
||||
nullptr);
|
||||
@@ -1881,8 +1882,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
|
||||
|
||||
bool RenderTargetCache::ResolveClear(uint32_t edram_base,
|
||||
uint32_t surface_pitch,
|
||||
MsaaSamples msaa_samples, bool is_depth,
|
||||
uint32_t format, const D3D12_RECT& rect) {
|
||||
xenos::MsaaSamples msaa_samples,
|
||||
bool is_depth, uint32_t format,
|
||||
const D3D12_RECT& rect) {
|
||||
auto& regs = *register_file_;
|
||||
|
||||
// Check if clearing is enabled.
|
||||
@@ -1902,7 +1904,7 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base,
|
||||
|
||||
// Calculate the layout.
|
||||
bool is_64bpp =
|
||||
!is_depth && IsColorFormat64bpp(ColorRenderTargetFormat(format));
|
||||
!is_depth && IsColorFormat64bpp(xenos::ColorRenderTargetFormat(format));
|
||||
D3D12_RECT clear_rect = rect;
|
||||
uint32_t surface_pitch_tiles, row_width_ss_div_80, rows;
|
||||
if (!GetEDRAMLayout(surface_pitch, msaa_samples, is_64bpp, edram_base,
|
||||
@@ -1911,8 +1913,8 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base,
|
||||
// Nothing to clear.
|
||||
return true;
|
||||
}
|
||||
uint32_t samples_x_log2 = msaa_samples >= MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t samples_y_log2 = msaa_samples >= MsaaSamples::k2X ? 1 : 0;
|
||||
uint32_t samples_x_log2 = msaa_samples >= xenos::MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t samples_y_log2 = msaa_samples >= xenos::MsaaSamples::k2X ? 1 : 0;
|
||||
|
||||
// Get transient data needed for clearing.
|
||||
ui::d3d12::util::DescriptorCPUGPUHandlePair descriptor_edram;
|
||||
@@ -1941,7 +1943,8 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base,
|
||||
(surface_pitch_tiles << 16);
|
||||
// When ROV is used, there's no 32-bit depth buffer.
|
||||
if (!edram_rov_used_ && is_depth &&
|
||||
DepthRenderTargetFormat(format) == DepthRenderTargetFormat::kD24FS8) {
|
||||
xenos::DepthRenderTargetFormat(format) ==
|
||||
xenos::DepthRenderTargetFormat::kD24FS8) {
|
||||
root_constants.clear_depth24 = regs[XE_GPU_REG_RB_DEPTH_CLEAR].u32;
|
||||
// 20e4 [0,2), based on CFloat24 from d3dref9.dll and on 6e4 in DirectXTex.
|
||||
uint32_t depth24 = root_constants.clear_depth24 >> 8;
|
||||
@@ -2222,42 +2225,42 @@ void RenderTargetCache::WriteEDRAMRawUAVDescriptor(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
|
||||
ColorRenderTargetFormat RenderTargetCache::GetBaseColorFormat(
|
||||
ColorRenderTargetFormat format) {
|
||||
xenos::ColorRenderTargetFormat RenderTargetCache::GetBaseColorFormat(
|
||||
xenos::ColorRenderTargetFormat format) {
|
||||
switch (format) {
|
||||
case ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
|
||||
return ColorRenderTargetFormat::k_8_8_8_8;
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
return ColorRenderTargetFormat::k_2_10_10_10;
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
return ColorRenderTargetFormat::k_2_10_10_10_FLOAT;
|
||||
case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
|
||||
return xenos::ColorRenderTargetFormat::k_8_8_8_8;
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
return xenos::ColorRenderTargetFormat::k_2_10_10_10;
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
return xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT;
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_FORMAT RenderTargetCache::GetColorDXGIFormat(
|
||||
ColorRenderTargetFormat format) {
|
||||
xenos::ColorRenderTargetFormat format) {
|
||||
switch (format) {
|
||||
case ColorRenderTargetFormat::k_8_8_8_8:
|
||||
case ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
|
||||
case xenos::ColorRenderTargetFormat::k_8_8_8_8:
|
||||
case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case ColorRenderTargetFormat::k_2_10_10_10:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10:
|
||||
return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT:
|
||||
case ColorRenderTargetFormat::k_16_16_16_16_FLOAT:
|
||||
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_16_16_16_16_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case ColorRenderTargetFormat::k_16_16:
|
||||
case xenos::ColorRenderTargetFormat::k_16_16:
|
||||
return DXGI_FORMAT_R16G16_SNORM;
|
||||
case ColorRenderTargetFormat::k_16_16_16_16:
|
||||
case xenos::ColorRenderTargetFormat::k_16_16_16_16:
|
||||
return DXGI_FORMAT_R16G16B16A16_SNORM;
|
||||
case ColorRenderTargetFormat::k_16_16_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_16_16_FLOAT:
|
||||
return DXGI_FORMAT_R16G16_FLOAT;
|
||||
case ColorRenderTargetFormat::k_32_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_32_FLOAT:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
case ColorRenderTargetFormat::k_32_32_FLOAT:
|
||||
case xenos::ColorRenderTargetFormat::k_32_32_FLOAT:
|
||||
return DXGI_FORMAT_R32G32_FLOAT;
|
||||
default:
|
||||
break;
|
||||
@@ -2412,7 +2415,7 @@ void RenderTargetCache::CommitEDRAMBufferUAVWrites(bool force) {
|
||||
|
||||
void RenderTargetCache::ClearBindings() {
|
||||
current_surface_pitch_ = 0;
|
||||
current_msaa_samples_ = MsaaSamples::k1X;
|
||||
current_msaa_samples_ = xenos::MsaaSamples::k1X;
|
||||
current_edram_max_rows_ = 0;
|
||||
std::memset(current_bindings_, 0, sizeof(current_bindings_));
|
||||
apply_to_command_list_ = true;
|
||||
@@ -2481,8 +2484,9 @@ bool RenderTargetCache::GetResourceDesc(RenderTargetKey key,
|
||||
return false;
|
||||
}
|
||||
DXGI_FORMAT dxgi_format =
|
||||
key.is_depth ? GetDepthDXGIFormat(DepthRenderTargetFormat(key.format))
|
||||
: GetColorDXGIFormat(ColorRenderTargetFormat(key.format));
|
||||
key.is_depth
|
||||
? GetDepthDXGIFormat(xenos::DepthRenderTargetFormat(key.format))
|
||||
: GetColorDXGIFormat(xenos::ColorRenderTargetFormat(key.format));
|
||||
if (dxgi_format == DXGI_FORMAT_UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
@@ -2651,7 +2655,7 @@ RenderTargetCache::RenderTarget* RenderTargetCache::FindOrCreateRenderTarget(
|
||||
}
|
||||
|
||||
bool RenderTargetCache::GetEDRAMLayout(
|
||||
uint32_t pitch_pixels, MsaaSamples msaa_samples, bool is_64bpp,
|
||||
uint32_t pitch_pixels, xenos::MsaaSamples msaa_samples, bool is_64bpp,
|
||||
uint32_t& base_in_out, D3D12_RECT& rect_in_out, uint32_t& pitch_tiles_out,
|
||||
uint32_t& row_width_ss_div_80_out, uint32_t& rows_out) {
|
||||
if (pitch_pixels == 0 || rect_in_out.right <= 0 || rect_in_out.bottom <= 0 ||
|
||||
@@ -2667,8 +2671,8 @@ bool RenderTargetCache::GetEDRAMLayout(
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t samples_x_log2 = msaa_samples >= MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t samples_y_log2 = msaa_samples >= MsaaSamples::k2X ? 1 : 0;
|
||||
uint32_t samples_x_log2 = msaa_samples >= xenos::MsaaSamples::k4X ? 1 : 0;
|
||||
uint32_t samples_y_log2 = msaa_samples >= xenos::MsaaSamples::k2X ? 1 : 0;
|
||||
uint32_t sample_size_log2 = is_64bpp ? 1 : 0;
|
||||
|
||||
uint32_t pitch_tiles = (((pitch_pixels << samples_x_log2) + 79) / 80)
|
||||
@@ -2711,14 +2715,16 @@ bool RenderTargetCache::GetEDRAMLayout(
|
||||
RenderTargetCache::EDRAMLoadStoreMode RenderTargetCache::GetLoadStoreMode(
|
||||
bool is_depth, uint32_t format) {
|
||||
if (is_depth) {
|
||||
return DepthRenderTargetFormat(format) == DepthRenderTargetFormat::kD24FS8
|
||||
return xenos::DepthRenderTargetFormat(format) ==
|
||||
xenos::DepthRenderTargetFormat::kD24FS8
|
||||
? EDRAMLoadStoreMode::kDepthFloat
|
||||
: EDRAMLoadStoreMode::kDepthUnorm;
|
||||
}
|
||||
ColorRenderTargetFormat color_format = ColorRenderTargetFormat(format);
|
||||
if (color_format == ColorRenderTargetFormat::k_2_10_10_10_FLOAT ||
|
||||
xenos::ColorRenderTargetFormat color_format =
|
||||
xenos::ColorRenderTargetFormat(format);
|
||||
if (color_format == xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT ||
|
||||
color_format ==
|
||||
ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16) {
|
||||
xenos::ColorRenderTargetFormat::k_2_10_10_10_FLOAT_AS_16_16_16_16) {
|
||||
return EDRAMLoadStoreMode::kColor7e3;
|
||||
}
|
||||
return IsColorFormat64bpp(color_format) ? EDRAMLoadStoreMode::kColor64bpp
|
||||
@@ -2824,7 +2830,7 @@ void RenderTargetCache::StoreRenderTargetsToEDRAM() {
|
||||
// Calculate the dispatch width.
|
||||
uint32_t surface_pitch_ss =
|
||||
current_surface_pitch_ *
|
||||
(current_msaa_samples_ >= MsaaSamples::k4X ? 2 : 1);
|
||||
(current_msaa_samples_ >= xenos::MsaaSamples::k4X ? 2 : 1);
|
||||
uint32_t surface_pitch_tiles = (surface_pitch_ss + 79) / 80;
|
||||
assert_true(surface_pitch_tiles != 0);
|
||||
|
||||
@@ -2854,7 +2860,7 @@ void RenderTargetCache::StoreRenderTargetsToEDRAM() {
|
||||
uint32_t rt_pitch_tiles = surface_pitch_tiles;
|
||||
if (!render_target->key.is_depth &&
|
||||
IsColorFormat64bpp(
|
||||
ColorRenderTargetFormat(render_target->key.format))) {
|
||||
xenos::ColorRenderTargetFormat(render_target->key.format))) {
|
||||
rt_pitch_tiles *= 2;
|
||||
}
|
||||
// TODO(Triang3l): log2(sample count, resolution scale).
|
||||
@@ -2975,7 +2981,7 @@ void RenderTargetCache::LoadRenderTargetsFromEDRAM(
|
||||
uint32_t edram_pitch_tiles = render_target->key.width_ss_div_80;
|
||||
if (!render_target->key.is_depth &&
|
||||
IsColorFormat64bpp(
|
||||
ColorRenderTargetFormat(render_target->key.format))) {
|
||||
xenos::ColorRenderTargetFormat(render_target->key.format))) {
|
||||
edram_pitch_tiles *= 2;
|
||||
}
|
||||
// Clamp the height if somehow requested a render target that is too large.
|
||||
|
||||
@@ -290,20 +290,21 @@ class RenderTargetCache {
|
||||
|
||||
// Totally necessary to rely on the base format - Too Human switches between
|
||||
// 2_10_10_10_FLOAT and 2_10_10_10_FLOAT_AS_16_16_16_16 every draw.
|
||||
static ColorRenderTargetFormat GetBaseColorFormat(
|
||||
ColorRenderTargetFormat format);
|
||||
static inline bool IsColorFormat64bpp(ColorRenderTargetFormat format) {
|
||||
return format == ColorRenderTargetFormat::k_16_16_16_16 ||
|
||||
format == ColorRenderTargetFormat::k_16_16_16_16_FLOAT ||
|
||||
format == ColorRenderTargetFormat::k_32_32_FLOAT;
|
||||
static xenos::ColorRenderTargetFormat GetBaseColorFormat(
|
||||
xenos::ColorRenderTargetFormat format);
|
||||
static inline bool IsColorFormat64bpp(xenos::ColorRenderTargetFormat format) {
|
||||
return format == xenos::ColorRenderTargetFormat::k_16_16_16_16 ||
|
||||
format == xenos::ColorRenderTargetFormat::k_16_16_16_16_FLOAT ||
|
||||
format == xenos::ColorRenderTargetFormat::k_32_32_FLOAT;
|
||||
}
|
||||
static DXGI_FORMAT GetColorDXGIFormat(ColorRenderTargetFormat format);
|
||||
static DXGI_FORMAT GetColorDXGIFormat(xenos::ColorRenderTargetFormat format);
|
||||
// Nvidia may have higher performance with 24-bit depth, AMD should have no
|
||||
// performance difference, but with EDRAM loads/stores less conversion should
|
||||
// be performed by the shaders if D24S8 is emulated as D24_UNORM_S8_UINT, and
|
||||
// it's probably more accurate.
|
||||
static inline DXGI_FORMAT GetDepthDXGIFormat(DepthRenderTargetFormat format) {
|
||||
return format == DepthRenderTargetFormat::kD24FS8
|
||||
static inline DXGI_FORMAT GetDepthDXGIFormat(
|
||||
xenos::DepthRenderTargetFormat format) {
|
||||
return format == xenos::DepthRenderTargetFormat::kD24FS8
|
||||
? DXGI_FORMAT_D32_FLOAT_S8X24_UINT
|
||||
: DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
}
|
||||
@@ -396,8 +397,8 @@ class RenderTargetCache {
|
||||
uint32_t edram_dirty_rows;
|
||||
union {
|
||||
uint32_t format;
|
||||
ColorRenderTargetFormat color_format;
|
||||
DepthRenderTargetFormat depth_format;
|
||||
xenos::ColorRenderTargetFormat color_format;
|
||||
xenos::DepthRenderTargetFormat depth_format;
|
||||
};
|
||||
RenderTarget* render_target;
|
||||
};
|
||||
@@ -472,9 +473,10 @@ class RenderTargetCache {
|
||||
// rectangle is within the bounds of EDRAM and is not empty, but if it returns
|
||||
// false, the output values may not be written, so the return value must be
|
||||
// checked.
|
||||
static bool GetEDRAMLayout(uint32_t pitch_pixels, MsaaSamples msaa_samples,
|
||||
bool is_64bpp, uint32_t& base_in_out,
|
||||
D3D12_RECT& rect_in_out, uint32_t& pitch_tiles_out,
|
||||
static bool GetEDRAMLayout(uint32_t pitch_pixels,
|
||||
xenos::MsaaSamples msaa_samples, bool is_64bpp,
|
||||
uint32_t& base_in_out, D3D12_RECT& rect_in_out,
|
||||
uint32_t& pitch_tiles_out,
|
||||
uint32_t& row_width_ss_div_80_out,
|
||||
uint32_t& rows_out);
|
||||
|
||||
@@ -493,13 +495,13 @@ class RenderTargetCache {
|
||||
// Performs the copying part of a resolve.
|
||||
bool ResolveCopy(SharedMemory* shared_memory, TextureCache* texture_cache,
|
||||
uint32_t edram_base, uint32_t surface_pitch,
|
||||
MsaaSamples msaa_samples, bool is_depth, uint32_t src_format,
|
||||
const D3D12_RECT& rect, uint32_t& written_address_out,
|
||||
uint32_t& written_length_out);
|
||||
xenos::MsaaSamples msaa_samples, bool is_depth,
|
||||
uint32_t src_format, const D3D12_RECT& rect,
|
||||
uint32_t& written_address_out, uint32_t& written_length_out);
|
||||
// Performs the clearing part of a resolve.
|
||||
bool ResolveClear(uint32_t edram_base, uint32_t surface_pitch,
|
||||
MsaaSamples msaa_samples, bool is_depth, uint32_t format,
|
||||
const D3D12_RECT& rect);
|
||||
xenos::MsaaSamples msaa_samples, bool is_depth,
|
||||
uint32_t format, const D3D12_RECT& rect);
|
||||
|
||||
ID3D12PipelineState* GetResolvePipeline(DXGI_FORMAT dest_format);
|
||||
// Returns any available resolve target placed at least at
|
||||
@@ -646,7 +648,7 @@ class RenderTargetCache {
|
||||
std::unordered_multimap<uint32_t, RenderTarget*> render_targets_;
|
||||
|
||||
uint32_t current_surface_pitch_ = 0;
|
||||
MsaaSamples current_msaa_samples_ = MsaaSamples::k1X;
|
||||
xenos::MsaaSamples current_msaa_samples_ = xenos::MsaaSamples::k1X;
|
||||
// current_edram_max_rows_ is for RTV/DSV only (render target texture size).
|
||||
uint32_t current_edram_max_rows_ = 0;
|
||||
RenderTargetBinding current_bindings_[5] = {};
|
||||
|
||||
@@ -1362,7 +1362,7 @@ void TextureCache::EndFrame() {
|
||||
XELOGE("Unsupported texture formats used in the frame:");
|
||||
unsupported_header_written = true;
|
||||
}
|
||||
XELOGE("* {}{}{}{}", FormatInfo::Get(TextureFormat(i))->name,
|
||||
XELOGE("* {}{}{}{}", FormatInfo::Get(xenos::TextureFormat(i))->name,
|
||||
unsupported_features & kUnsupportedResourceBit ? " resource" : "",
|
||||
unsupported_features & kUnsupportedUnormBit ? " unorm" : "",
|
||||
unsupported_features & kUnsupportedSnormBit ? " snorm" : "");
|
||||
@@ -1595,15 +1595,16 @@ void TextureCache::WriteActiveTextureBindfulSRV(
|
||||
} else {
|
||||
NullSRVDescriptorIndex null_descriptor_index;
|
||||
switch (host_shader_binding.dimension) {
|
||||
case TextureDimension::k3D:
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
null_descriptor_index = NullSRVDescriptorIndex::k3D;
|
||||
break;
|
||||
case TextureDimension::kCube:
|
||||
case xenos::FetchOpDimension::kCube:
|
||||
null_descriptor_index = NullSRVDescriptorIndex::kCube;
|
||||
break;
|
||||
default:
|
||||
assert_true(host_shader_binding.dimension == TextureDimension::k1D ||
|
||||
host_shader_binding.dimension == TextureDimension::k2D);
|
||||
assert_true(
|
||||
host_shader_binding.dimension == xenos::FetchOpDimension::k1D ||
|
||||
host_shader_binding.dimension == xenos::FetchOpDimension::k2D);
|
||||
null_descriptor_index = NullSRVDescriptorIndex::k2DArray;
|
||||
}
|
||||
source_handle = provider->OffsetViewDescriptor(
|
||||
@@ -1637,17 +1638,18 @@ uint32_t TextureCache::GetActiveTextureBindlessSRVIndex(
|
||||
}
|
||||
if (descriptor_index == UINT32_MAX) {
|
||||
switch (host_shader_binding.dimension) {
|
||||
case TextureDimension::k3D:
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
descriptor_index =
|
||||
uint32_t(D3D12CommandProcessor::SystemBindlessView::kNullTexture3D);
|
||||
break;
|
||||
case TextureDimension::kCube:
|
||||
case xenos::FetchOpDimension::kCube:
|
||||
descriptor_index = uint32_t(
|
||||
D3D12CommandProcessor::SystemBindlessView::kNullTextureCube);
|
||||
break;
|
||||
default:
|
||||
assert_true(host_shader_binding.dimension == TextureDimension::k1D ||
|
||||
host_shader_binding.dimension == TextureDimension::k2D);
|
||||
assert_true(
|
||||
host_shader_binding.dimension == xenos::FetchOpDimension::k1D ||
|
||||
host_shader_binding.dimension == xenos::FetchOpDimension::k2D);
|
||||
descriptor_index = uint32_t(
|
||||
D3D12CommandProcessor::SystemBindlessView::kNullTexture2DArray);
|
||||
}
|
||||
@@ -1674,31 +1676,32 @@ TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
nullptr, binding.mip_filter);
|
||||
parameters.mip_min_level = mip_min_level;
|
||||
|
||||
AnisoFilter aniso_filter = binding.aniso_filter == AnisoFilter::kUseFetchConst
|
||||
? fetch.aniso_filter
|
||||
: binding.aniso_filter;
|
||||
aniso_filter = std::min(aniso_filter, AnisoFilter::kMax_16_1);
|
||||
xenos::AnisoFilter aniso_filter =
|
||||
binding.aniso_filter == xenos::AnisoFilter::kUseFetchConst
|
||||
? fetch.aniso_filter
|
||||
: binding.aniso_filter;
|
||||
aniso_filter = std::min(aniso_filter, xenos::AnisoFilter::kMax_16_1);
|
||||
parameters.aniso_filter = aniso_filter;
|
||||
if (aniso_filter != AnisoFilter::kDisabled) {
|
||||
if (aniso_filter != xenos::AnisoFilter::kDisabled) {
|
||||
parameters.mag_linear = 1;
|
||||
parameters.min_linear = 1;
|
||||
parameters.mip_linear = 1;
|
||||
} else {
|
||||
TextureFilter mag_filter =
|
||||
binding.mag_filter == TextureFilter::kUseFetchConst
|
||||
xenos::TextureFilter mag_filter =
|
||||
binding.mag_filter == xenos::TextureFilter::kUseFetchConst
|
||||
? fetch.mag_filter
|
||||
: binding.mag_filter;
|
||||
parameters.mag_linear = mag_filter == TextureFilter::kLinear;
|
||||
TextureFilter min_filter =
|
||||
binding.min_filter == TextureFilter::kUseFetchConst
|
||||
parameters.mag_linear = mag_filter == xenos::TextureFilter::kLinear;
|
||||
xenos::TextureFilter min_filter =
|
||||
binding.min_filter == xenos::TextureFilter::kUseFetchConst
|
||||
? fetch.min_filter
|
||||
: binding.min_filter;
|
||||
parameters.min_linear = min_filter == TextureFilter::kLinear;
|
||||
TextureFilter mip_filter =
|
||||
binding.mip_filter == TextureFilter::kUseFetchConst
|
||||
parameters.min_linear = min_filter == xenos::TextureFilter::kLinear;
|
||||
xenos::TextureFilter mip_filter =
|
||||
binding.mip_filter == xenos::TextureFilter::kUseFetchConst
|
||||
? fetch.mip_filter
|
||||
: binding.mip_filter;
|
||||
parameters.mip_linear = mip_filter == TextureFilter::kLinear;
|
||||
parameters.mip_linear = mip_filter == xenos::TextureFilter::kLinear;
|
||||
}
|
||||
|
||||
return parameters;
|
||||
@@ -1707,7 +1710,7 @@ TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
void TextureCache::WriteSampler(SamplerParameters parameters,
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle) const {
|
||||
D3D12_SAMPLER_DESC desc;
|
||||
if (parameters.aniso_filter != AnisoFilter::kDisabled) {
|
||||
if (parameters.aniso_filter != xenos::AnisoFilter::kDisabled) {
|
||||
desc.Filter = D3D12_FILTER_ANISOTROPIC;
|
||||
desc.MaxAnisotropy = 1u << (uint32_t(parameters.aniso_filter) - 1);
|
||||
} else {
|
||||
@@ -1747,7 +1750,7 @@ void TextureCache::WriteSampler(SamplerParameters parameters,
|
||||
desc.MipLODBias = 0.0f;
|
||||
desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
||||
// TODO(Triang3l): Border colors k_ACBYCR_BLACK and k_ACBCRY_BLACK.
|
||||
if (parameters.border_color == BorderColor::k_AGBR_White) {
|
||||
if (parameters.border_color == xenos::BorderColor::k_AGBR_White) {
|
||||
desc.BorderColor[0] = 1.0f;
|
||||
desc.BorderColor[1] = 1.0f;
|
||||
desc.BorderColor[2] = 1.0f;
|
||||
@@ -1799,10 +1802,10 @@ void TextureCache::MarkRangeAsResolved(uint32_t start_unscaled,
|
||||
}
|
||||
|
||||
bool TextureCache::TileResolvedTexture(
|
||||
TextureFormat format, uint32_t texture_base, uint32_t texture_pitch,
|
||||
xenos::TextureFormat format, uint32_t texture_base, uint32_t texture_pitch,
|
||||
uint32_t texture_height, bool is_3d, uint32_t offset_x, uint32_t offset_y,
|
||||
uint32_t offset_z, uint32_t resolve_width, uint32_t resolve_height,
|
||||
Endian128 endian, ID3D12Resource* buffer, uint32_t buffer_size,
|
||||
xenos::Endian128 endian, ID3D12Resource* buffer, uint32_t buffer_size,
|
||||
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint,
|
||||
uint32_t* written_address_out, uint32_t* written_length_out) {
|
||||
if (written_address_out) {
|
||||
@@ -2085,14 +2088,16 @@ void TextureCache::CreateScaledResolveBufferRawUAV(
|
||||
}
|
||||
|
||||
ID3D12Resource* TextureCache::RequestSwapTexture(
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC& srv_desc_out, TextureFormat& format_out) {
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC& srv_desc_out,
|
||||
xenos::TextureFormat& format_out) {
|
||||
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(fetch, key, &swizzle, nullptr);
|
||||
if (key.base_page == 0 || key.dimension != Dimension::k2D) {
|
||||
if (key.base_page == 0 ||
|
||||
key.dimension != xenos::DataDimension::k2DOrStacked) {
|
||||
return nullptr;
|
||||
}
|
||||
Texture* texture = FindOrCreateTexture(key);
|
||||
@@ -2120,8 +2125,8 @@ ID3D12Resource* TextureCache::RequestSwapTexture(
|
||||
return texture->resource;
|
||||
}
|
||||
|
||||
bool TextureCache::IsDecompressionNeeded(TextureFormat format, uint32_t width,
|
||||
uint32_t height) {
|
||||
bool TextureCache::IsDecompressionNeeded(xenos::TextureFormat format,
|
||||
uint32_t width, uint32_t height) {
|
||||
DXGI_FORMAT dxgi_format_uncompressed =
|
||||
host_formats_[uint32_t(format)].dxgi_format_uncompressed;
|
||||
if (dxgi_format_uncompressed == DXGI_FORMAT_UNKNOWN) {
|
||||
@@ -2154,7 +2159,8 @@ void TextureCache::BindingInfoFromFetchConstant(
|
||||
(xenos::XE_GPU_SWIZZLE_0 << 6) | (xenos::XE_GPU_SWIZZLE_0 << 9);
|
||||
}
|
||||
if (swizzled_signs_out != nullptr) {
|
||||
*swizzled_signs_out = uint8_t(TextureSign::kUnsigned) * uint8_t(0b01010101);
|
||||
*swizzled_signs_out =
|
||||
uint8_t(xenos::TextureSign::kUnsigned) * uint8_t(0b01010101);
|
||||
}
|
||||
|
||||
switch (fetch.type) {
|
||||
@@ -2190,7 +2196,7 @@ void TextureCache::BindingInfoFromFetchConstant(
|
||||
// No texture data at all.
|
||||
return;
|
||||
}
|
||||
if (fetch.dimension == Dimension::k1D && width > 8192) {
|
||||
if (fetch.dimension == xenos::DataDimension::k1D && width > 8192) {
|
||||
XELOGE(
|
||||
"1D texture is too wide ({}) - ignoring! "
|
||||
"Report the game to Xenia developers",
|
||||
@@ -2198,7 +2204,7 @@ void TextureCache::BindingInfoFromFetchConstant(
|
||||
return;
|
||||
}
|
||||
|
||||
TextureFormat format = GetBaseFormat(fetch.format);
|
||||
xenos::TextureFormat format = GetBaseFormat(fetch.format);
|
||||
|
||||
key_out.base_page = base_page;
|
||||
key_out.mip_page = mip_page;
|
||||
@@ -2305,7 +2311,7 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
||||
kUnsupportedResourceBit;
|
||||
return nullptr;
|
||||
}
|
||||
if (key.dimension == Dimension::k3D) {
|
||||
if (key.dimension == xenos::DataDimension::k3D) {
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
|
||||
} else {
|
||||
// 1D textures are treated as 2D for simplicity.
|
||||
@@ -2357,7 +2363,8 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
||||
texture_used_last_ = texture;
|
||||
texture->mip_offsets[0] = 0;
|
||||
uint32_t width_blocks, height_blocks, depth_blocks;
|
||||
uint32_t array_size = key.dimension != Dimension::k3D ? key.depth : 1;
|
||||
uint32_t array_size =
|
||||
key.dimension != xenos::DataDimension::k3D ? key.depth : 1;
|
||||
if (key.base_page != 0) {
|
||||
texture_util::GetGuestMipBlocks(key.dimension, key.width, key.height,
|
||||
key.depth, key.format, 0, width_blocks,
|
||||
@@ -2491,13 +2498,13 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
||||
}
|
||||
|
||||
// Get the guest layout.
|
||||
Dimension dimension = texture->key.dimension;
|
||||
bool is_3d = dimension == Dimension::k3D;
|
||||
xenos::DataDimension dimension = texture->key.dimension;
|
||||
bool is_3d = dimension == xenos::DataDimension::k3D;
|
||||
uint32_t width = texture->key.width;
|
||||
uint32_t height = texture->key.height;
|
||||
uint32_t depth = is_3d ? texture->key.depth : 1;
|
||||
uint32_t slice_count = is_3d ? 1 : texture->key.depth;
|
||||
TextureFormat guest_format = texture->key.format;
|
||||
xenos::TextureFormat guest_format = texture->key.format;
|
||||
const FormatInfo* guest_format_info = FormatInfo::Get(guest_format);
|
||||
uint32_t block_width = guest_format_info->block_width;
|
||||
uint32_t block_height = guest_format_info->block_height;
|
||||
@@ -2871,7 +2878,7 @@ uint32_t TextureCache::FindOrCreateTextureDescriptor(Texture& texture,
|
||||
// Create a new bindless or cached descriptor if supported.
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc;
|
||||
|
||||
TextureFormat format = texture.key.format;
|
||||
xenos::TextureFormat format = texture.key.format;
|
||||
if (IsSignedVersionSeparate(format) &&
|
||||
texture.key.signed_separate != uint32_t(is_signed)) {
|
||||
// Not the version with the needed signedness.
|
||||
@@ -2892,8 +2899,8 @@ uint32_t TextureCache::FindOrCreateTextureDescriptor(Texture& texture,
|
||||
|
||||
uint32_t mip_levels = texture.key.mip_max_level + 1;
|
||||
switch (texture.key.dimension) {
|
||||
case Dimension::k1D:
|
||||
case Dimension::k2D:
|
||||
case xenos::DataDimension::k1D:
|
||||
case xenos::DataDimension::k2DOrStacked:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.MostDetailedMip = 0;
|
||||
desc.Texture2DArray.MipLevels = mip_levels;
|
||||
@@ -2902,13 +2909,13 @@ uint32_t TextureCache::FindOrCreateTextureDescriptor(Texture& texture,
|
||||
desc.Texture2DArray.PlaneSlice = 0;
|
||||
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
case Dimension::k3D:
|
||||
case xenos::DataDimension::k3D:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
desc.Texture3D.MostDetailedMip = 0;
|
||||
desc.Texture3D.MipLevels = mip_levels;
|
||||
desc.Texture3D.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
case Dimension::kCube:
|
||||
case xenos::DataDimension::kCube:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
desc.TextureCube.MostDetailedMip = 0;
|
||||
desc.TextureCube.MipLevels = mip_levels;
|
||||
|
||||
@@ -61,9 +61,9 @@ class TextureCache {
|
||||
struct {
|
||||
// Physical 4 KB page with the base mip level, disregarding A/C/E address
|
||||
// range prefix.
|
||||
uint32_t base_page : 17; // 17 total
|
||||
Dimension dimension : 2; // 19
|
||||
uint32_t width : 13; // 32
|
||||
uint32_t base_page : 17; // 17 total
|
||||
xenos::DataDimension dimension : 2; // 19
|
||||
uint32_t width : 13; // 32
|
||||
|
||||
uint32_t height : 13; // 45
|
||||
uint32_t tiled : 1; // 46
|
||||
@@ -72,10 +72,10 @@ class TextureCache {
|
||||
uint32_t mip_page : 17; // 64
|
||||
|
||||
// Layers for stacked and 3D, 6 for cube, 1 for other dimensions.
|
||||
uint32_t depth : 10; // 74
|
||||
uint32_t mip_max_level : 4; // 78
|
||||
TextureFormat format : 6; // 84
|
||||
Endian endianness : 2; // 86
|
||||
uint32_t depth : 10; // 74
|
||||
uint32_t mip_max_level : 4; // 78
|
||||
xenos::TextureFormat format : 6; // 84
|
||||
xenos::Endian endianness : 2; // 86
|
||||
// Whether this texture is signed and has a different host representation
|
||||
// than an unsigned view of the same guest texture.
|
||||
uint32_t signed_separate : 1; // 87
|
||||
@@ -137,15 +137,15 @@ class TextureCache {
|
||||
// for binding checking validity whether samplers are up to date.
|
||||
union SamplerParameters {
|
||||
struct {
|
||||
ClampMode clamp_x : 3; // 3
|
||||
ClampMode clamp_y : 3; // 6
|
||||
ClampMode clamp_z : 3; // 9
|
||||
BorderColor border_color : 2; // 11
|
||||
xenos::ClampMode clamp_x : 3; // 3
|
||||
xenos::ClampMode clamp_y : 3; // 6
|
||||
xenos::ClampMode clamp_z : 3; // 9
|
||||
xenos::BorderColor border_color : 2; // 11
|
||||
// For anisotropic, these are true.
|
||||
uint32_t mag_linear : 1; // 12
|
||||
uint32_t min_linear : 1; // 13
|
||||
uint32_t mip_linear : 1; // 14
|
||||
AnisoFilter aniso_filter : 3; // 17
|
||||
xenos::AnisoFilter aniso_filter : 3; // 17
|
||||
uint32_t mip_min_level : 4; // 21
|
||||
// Maximum mip level is in the texture resource itself.
|
||||
};
|
||||
@@ -221,15 +221,15 @@ class TextureCache {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle) const;
|
||||
|
||||
void MarkRangeAsResolved(uint32_t start_unscaled, uint32_t length_unscaled);
|
||||
static inline DXGI_FORMAT GetResolveDXGIFormat(TextureFormat format) {
|
||||
static inline DXGI_FORMAT GetResolveDXGIFormat(xenos::TextureFormat format) {
|
||||
return host_formats_[uint32_t(format)].dxgi_format_resolve_tile;
|
||||
}
|
||||
// The source buffer must be in the non-pixel-shader SRV state.
|
||||
bool TileResolvedTexture(TextureFormat format, uint32_t texture_base,
|
||||
bool TileResolvedTexture(xenos::TextureFormat format, uint32_t texture_base,
|
||||
uint32_t texture_pitch, uint32_t texture_height,
|
||||
bool is_3d, uint32_t offset_x, uint32_t offset_y,
|
||||
uint32_t offset_z, uint32_t resolve_width,
|
||||
uint32_t resolve_height, Endian128 endian,
|
||||
uint32_t resolve_height, xenos::Endian128 endian,
|
||||
ID3D12Resource* buffer, uint32_t buffer_size,
|
||||
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint,
|
||||
uint32_t* written_address_out,
|
||||
@@ -256,7 +256,8 @@ class TextureCache {
|
||||
// description of its SRV. May call LoadTextureData, so the same restrictions
|
||||
// (such as about descriptor heap change possibility) apply.
|
||||
ID3D12Resource* RequestSwapTexture(
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC& srv_desc_out, TextureFormat& format_out);
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC& srv_desc_out,
|
||||
xenos::TextureFormat& format_out);
|
||||
|
||||
private:
|
||||
enum class LoadMode {
|
||||
@@ -498,16 +499,16 @@ class TextureCache {
|
||||
// Whether the signed version of the texture has a different representation on
|
||||
// the host than its unsigned version (for example, if it's a fixed-point
|
||||
// texture emulated with a larger host pixel format).
|
||||
static inline bool IsSignedVersionSeparate(TextureFormat format) {
|
||||
static inline bool IsSignedVersionSeparate(xenos::TextureFormat format) {
|
||||
const HostFormat& host_format = host_formats_[uint32_t(format)];
|
||||
return host_format.load_mode_snorm != LoadMode::kUnknown &&
|
||||
host_format.load_mode_snorm != host_format.load_mode;
|
||||
}
|
||||
// Whether decompression is needed on the host (Direct3D only allows creation
|
||||
// of block-compressed textures with 4x4-aligned dimensions on PC).
|
||||
static bool IsDecompressionNeeded(TextureFormat format, uint32_t width,
|
||||
static bool IsDecompressionNeeded(xenos::TextureFormat format, uint32_t width,
|
||||
uint32_t height);
|
||||
static inline DXGI_FORMAT GetDXGIResourceFormat(TextureFormat format,
|
||||
static inline DXGI_FORMAT GetDXGIResourceFormat(xenos::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
const HostFormat& host_format = host_formats_[uint32_t(format)];
|
||||
@@ -518,7 +519,7 @@ class TextureCache {
|
||||
static inline DXGI_FORMAT GetDXGIResourceFormat(TextureKey key) {
|
||||
return GetDXGIResourceFormat(key.format, key.width, key.height);
|
||||
}
|
||||
static inline DXGI_FORMAT GetDXGIUnormFormat(TextureFormat format,
|
||||
static inline DXGI_FORMAT GetDXGIUnormFormat(xenos::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
const HostFormat& host_format = host_formats_[uint32_t(format)];
|
||||
@@ -540,16 +541,17 @@ class TextureCache {
|
||||
uint32_t* host_swizzle_out, uint8_t* swizzled_signs_out);
|
||||
|
||||
static constexpr bool AreDimensionsCompatible(
|
||||
TextureDimension binding_dimension, Dimension resource_dimension) {
|
||||
xenos::FetchOpDimension binding_dimension,
|
||||
xenos::DataDimension resource_dimension) {
|
||||
switch (binding_dimension) {
|
||||
case TextureDimension::k1D:
|
||||
case TextureDimension::k2D:
|
||||
return resource_dimension == Dimension::k1D ||
|
||||
resource_dimension == Dimension::k2D;
|
||||
case TextureDimension::k3D:
|
||||
return resource_dimension == Dimension::k3D;
|
||||
case TextureDimension::kCube:
|
||||
return resource_dimension == Dimension::kCube;
|
||||
case xenos::FetchOpDimension::k1D:
|
||||
case xenos::FetchOpDimension::k2D:
|
||||
return resource_dimension == xenos::DataDimension::k1D ||
|
||||
resource_dimension == xenos::DataDimension::k2DOrStacked;
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
return resource_dimension == xenos::DataDimension::k3D;
|
||||
case xenos::FetchOpDimension::kCube:
|
||||
return resource_dimension == xenos::DataDimension::kCube;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user