diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 0a08debf2..0698ff00f 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -509,48 +509,6 @@ D3D12CommandProcessor::GetSystemBindlessViewHandlePair( view_bindless_heap_gpu_start_, uint32_t(view))); } -ui::d3d12::util::DescriptorCpuGpuHandlePair -D3D12CommandProcessor::GetSharedMemoryUintPow2BindlessSRVHandlePair( - uint32_t element_size_bytes_pow2) const { - SystemBindlessView view; - switch (element_size_bytes_pow2) { - case 2: - view = SystemBindlessView::kSharedMemoryR32UintSRV; - break; - case 3: - view = SystemBindlessView::kSharedMemoryR32G32UintSRV; - break; - case 4: - view = SystemBindlessView::kSharedMemoryR32G32B32A32UintSRV; - break; - default: - assert_unhandled_case(element_size_bytes_pow2); - view = SystemBindlessView::kSharedMemoryR32UintSRV; - } - return GetSystemBindlessViewHandlePair(view); -} - -ui::d3d12::util::DescriptorCpuGpuHandlePair -D3D12CommandProcessor::GetSharedMemoryUintPow2BindlessUAVHandlePair( - uint32_t element_size_bytes_pow2) const { - SystemBindlessView view; - switch (element_size_bytes_pow2) { - case 2: - view = SystemBindlessView::kSharedMemoryR32UintUAV; - break; - case 3: - view = SystemBindlessView::kSharedMemoryR32G32UintUAV; - break; - case 4: - view = SystemBindlessView::kSharedMemoryR32G32B32A32UintUAV; - break; - default: - assert_unhandled_case(element_size_bytes_pow2); - view = SystemBindlessView::kSharedMemoryR32UintUAV; - } - return GetSystemBindlessViewHandlePair(view); -} - ui::d3d12::util::DescriptorCpuGpuHandlePair D3D12CommandProcessor::GetEdramUintPow2BindlessSRVHandlePair( uint32_t element_size_bytes_pow2) const { @@ -1503,46 +1461,10 @@ bool D3D12CommandProcessor::SetupContext() { shared_memory_->WriteRawSRVDescriptor(provider.OffsetViewDescriptor( view_bindless_heap_cpu_start_, uint32_t(SystemBindlessView::kSharedMemoryRawSRV))); - // kSharedMemoryR32UintSRV. - shared_memory_->WriteUintPow2SRVDescriptor( - provider.OffsetViewDescriptor( - view_bindless_heap_cpu_start_, - uint32_t(SystemBindlessView::kSharedMemoryR32UintSRV)), - 2); - // kSharedMemoryR32G32UintSRV. - shared_memory_->WriteUintPow2SRVDescriptor( - provider.OffsetViewDescriptor( - view_bindless_heap_cpu_start_, - uint32_t(SystemBindlessView::kSharedMemoryR32G32UintSRV)), - 3); - // kSharedMemoryR32G32B32A32UintSRV. - shared_memory_->WriteUintPow2SRVDescriptor( - provider.OffsetViewDescriptor( - view_bindless_heap_cpu_start_, - uint32_t(SystemBindlessView::kSharedMemoryR32G32B32A32UintSRV)), - 4); // kSharedMemoryRawUAV. shared_memory_->WriteRawUAVDescriptor(provider.OffsetViewDescriptor( view_bindless_heap_cpu_start_, uint32_t(SystemBindlessView::kSharedMemoryRawUAV))); - // kSharedMemoryR32UintUAV. - shared_memory_->WriteUintPow2UAVDescriptor( - provider.OffsetViewDescriptor( - view_bindless_heap_cpu_start_, - uint32_t(SystemBindlessView::kSharedMemoryR32UintUAV)), - 2); - // kSharedMemoryR32G32UintUAV. - shared_memory_->WriteUintPow2UAVDescriptor( - provider.OffsetViewDescriptor( - view_bindless_heap_cpu_start_, - uint32_t(SystemBindlessView::kSharedMemoryR32G32UintUAV)), - 3); - // kSharedMemoryR32G32B32A32UintUAV. - shared_memory_->WriteUintPow2UAVDescriptor( - provider.OffsetViewDescriptor( - view_bindless_heap_cpu_start_, - uint32_t(SystemBindlessView::kSharedMemoryR32G32B32A32UintUAV)), - 4); // kEdramRawSRV. render_target_cache_->WriteEdramRawSRVDescriptor( provider.OffsetViewDescriptor( @@ -2646,7 +2568,6 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, if (host_render_targets_used) { bound_depth_and_color_render_target_bits = render_target_cache_->GetLastUpdateBoundRenderTargets( - render_target_cache_->gamma_render_target_as_srgb(), bound_depth_and_color_render_target_formats); } else { bound_depth_and_color_render_target_bits = 0; @@ -2979,8 +2900,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, // Invalidate textures in memexported memory and watch for changes. for (const draw_util::MemExportRange& memexport_range : memexport_ranges_) { shared_memory_->RangeWrittenByGpu( - memexport_range.base_address_dwords << 2, memexport_range.size_bytes, - false); + memexport_range.base_address_dwords << 2, memexport_range.size_bytes); } if (GetGPUSetting(GPUSetting::ReadbackMemexport)) { // Read the exported data on the CPU. @@ -3785,7 +3705,8 @@ XE_NOINLINE void D3D12CommandProcessor::UpdateSystemConstantValues_Impl( flags |= uint32_t(alpha_test_function) << DxbcShaderTranslator::kSysFlag_AlphaPassIfLess_Shift; // Gamma writing. - if (!render_target_cache_->gamma_render_target_as_srgb()) { + if (!(edram_rov_used || + render_target_cache_->gamma_render_target_as_unorm16())) { for (uint32_t i = 0; i < 4; ++i) { if (color_infos[i].color_format == xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { @@ -3952,9 +3873,7 @@ XE_NOINLINE void D3D12CommandProcessor::UpdateSystemConstantValues_Impl( } // Texture signedness / gamma. - bool gamma_render_target_as_srgb = - render_target_cache_->gamma_render_target_as_srgb(); - uint32_t textures_resolved = 0; + uint32_t textures_resolution_scaled = 0; uint32_t textures_remaining = used_texture_mask; uint32_t texture_index; while (xe::bit_scan_forward(textures_remaining, &texture_index)) { @@ -3974,14 +3893,14 @@ XE_NOINLINE void D3D12CommandProcessor::UpdateSystemConstantValues_Impl( texture_signs_uint = (texture_signs_uint & ~texture_signs_mask) | texture_signs_shifted; // cache misses here, we're accessing the texture bindings out of order - textures_resolved |= - uint32_t(texture_cache_->IsActiveTextureResolved(texture_index)) + textures_resolution_scaled |= + uint32_t(texture_cache_->IsActiveTextureResolutionScaled(texture_index)) << texture_index; } - update_dirty_uint32_cmp(system_constants_.textures_resolved, - textures_resolved); - system_constants_.textures_resolved = textures_resolved; + update_dirty_uint32_cmp(system_constants_.textures_resolution_scaled, + textures_resolution_scaled); + system_constants_.textures_resolution_scaled = textures_resolution_scaled; // Log2 of sample count, for alpha to mask and with ROV, for EDRAM address // calculation with MSAA. diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index a8a389bcd..bd70565fe 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -160,13 +160,6 @@ class D3D12CommandProcessor final : public CommandProcessor { kNullRawSRV = kNullRawSRVAndSharedMemoryRawUAVStart, kSharedMemoryRawUAV, - kSharedMemoryR32UintSRV, - kSharedMemoryR32G32UintSRV, - kSharedMemoryR32G32B32A32UintSRV, - kSharedMemoryR32UintUAV, - kSharedMemoryR32G32UintUAV, - kSharedMemoryR32G32B32A32UintUAV, - kEdramRawSRV, kEdramR32UintSRV, kEdramR32G32UintSRV, @@ -192,12 +185,6 @@ class D3D12CommandProcessor final : public CommandProcessor { ui::d3d12::util::DescriptorCpuGpuHandlePair GetSystemBindlessViewHandlePair( SystemBindlessView view) const; ui::d3d12::util::DescriptorCpuGpuHandlePair - GetSharedMemoryUintPow2BindlessSRVHandlePair( - uint32_t element_size_bytes_pow2) const; - ui::d3d12::util::DescriptorCpuGpuHandlePair - GetSharedMemoryUintPow2BindlessUAVHandlePair( - uint32_t element_size_bytes_pow2) const; - ui::d3d12::util::DescriptorCpuGpuHandlePair GetEdramUintPow2BindlessSRVHandlePair(uint32_t element_size_bytes_pow2) const; ui::d3d12::util::DescriptorCpuGpuHandlePair GetEdramUintPow2BindlessUAVHandlePair(uint32_t element_size_bytes_pow2) const; diff --git a/src/xenia/gpu/d3d12/d3d12_render_target_cache.cc b/src/xenia/gpu/d3d12/d3d12_render_target_cache.cc index ffc5ee24c..74616f810 100644 --- a/src/xenia/gpu/d3d12/d3d12_render_target_cache.cc +++ b/src/xenia/gpu/d3d12/d3d12_render_target_cache.cc @@ -274,6 +274,7 @@ bool D3D12RenderTargetCache::Initialize() { return false; } edram_buffer_->SetName(L"EDRAM Buffer"); + edram_buffer_gpu_address_ = edram_buffer_->GetGPUVirtualAddress(); edram_buffer_modification_status_ = EdramBufferModificationStatus::kUnmodified; @@ -364,31 +365,15 @@ bool D3D12RenderTargetCache::Initialize() { resolve_copy_root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Parameter 1 is the destination (shared memory). - D3D12_DESCRIPTOR_RANGE resolve_copy_dest_range; - resolve_copy_dest_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - resolve_copy_dest_range.NumDescriptors = 1; - resolve_copy_dest_range.BaseShaderRegister = 0; - resolve_copy_dest_range.RegisterSpace = 0; - resolve_copy_dest_range.OffsetInDescriptorsFromTableStart = 0; - resolve_copy_root_parameters[1].ParameterType = - D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - resolve_copy_root_parameters[1].DescriptorTable.NumDescriptorRanges = 1; - resolve_copy_root_parameters[1].DescriptorTable.pDescriptorRanges = - &resolve_copy_dest_range; + resolve_copy_root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + resolve_copy_root_parameters[1].Descriptor.ShaderRegister = 0; + resolve_copy_root_parameters[1].Descriptor.RegisterSpace = 0; resolve_copy_root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Parameter 2 is the source (EDRAM). - D3D12_DESCRIPTOR_RANGE resolve_copy_source_range; - resolve_copy_source_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - resolve_copy_source_range.NumDescriptors = 1; - resolve_copy_source_range.BaseShaderRegister = 0; - resolve_copy_source_range.RegisterSpace = 0; - resolve_copy_source_range.OffsetInDescriptorsFromTableStart = 0; - resolve_copy_root_parameters[2].ParameterType = - D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - resolve_copy_root_parameters[2].DescriptorTable.NumDescriptorRanges = 1; - resolve_copy_root_parameters[2].DescriptorTable.pDescriptorRanges = - &resolve_copy_source_range; + resolve_copy_root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; + resolve_copy_root_parameters[2].Descriptor.ShaderRegister = 0; + resolve_copy_root_parameters[2].Descriptor.RegisterSpace = 0; resolve_copy_root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; D3D12_ROOT_SIGNATURE_DESC resolve_copy_root_signature_desc; @@ -456,7 +441,7 @@ bool D3D12RenderTargetCache::Initialize() { if (path_ == Path::kHostRenderTargets) { // Host render targets. - gamma_render_target_as_srgb_ = cvars::gamma_render_target_as_srgb; + gamma_render_target_as_unorm16_ = cvars::gamma_render_target_as_unorm16; depth_float24_round_ = cvars::depth_float24_round; depth_float24_convert_in_pixel_shader_ = @@ -499,6 +484,17 @@ bool D3D12RenderTargetCache::Initialize() { break; } } + if (msaa_2x_supported_ && gamma_render_target_as_unorm16_) { + multisample_quality_levels.Format = DXGI_FORMAT_R16G16B16A16_UNORM; + multisample_quality_levels.NumQualityLevels = 0; + if (FAILED(device->CheckFeatureSupport( + D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + &multisample_quality_levels, + sizeof(multisample_quality_levels))) || + !multisample_quality_levels.NumQualityLevels) { + msaa_2x_supported_ = false; + } + } } else { msaa_2x_supported_ = false; } @@ -573,20 +569,11 @@ bool D3D12RenderTargetCache::Initialize() { &host_depth_store_root_source_range; host_depth_store_root_source.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Destination. - D3D12_DESCRIPTOR_RANGE host_depth_store_root_dest_range; - host_depth_store_root_dest_range.RangeType = - D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - host_depth_store_root_dest_range.NumDescriptors = 1; - host_depth_store_root_dest_range.BaseShaderRegister = 0; - host_depth_store_root_dest_range.RegisterSpace = 0; - host_depth_store_root_dest_range.OffsetInDescriptorsFromTableStart = 0; D3D12_ROOT_PARAMETER& host_depth_store_root_dest = host_depth_store_root_parameters[kHostDepthStoreRootParameterDest]; - host_depth_store_root_dest.ParameterType = - D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - host_depth_store_root_dest.DescriptorTable.NumDescriptorRanges = 1; - host_depth_store_root_dest.DescriptorTable.pDescriptorRanges = - &host_depth_store_root_dest_range; + host_depth_store_root_dest.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + host_depth_store_root_dest.Descriptor.ShaderRegister = 0; + host_depth_store_root_dest.Descriptor.RegisterSpace = 0; host_depth_store_root_dest.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Root signature. D3D12_ROOT_SIGNATURE_DESC host_depth_store_root_desc; @@ -834,12 +821,6 @@ bool D3D12RenderTargetCache::Initialize() { dump_root_stencil_range.BaseShaderRegister = 1; dump_root_stencil_range.RegisterSpace = 0; dump_root_stencil_range.OffsetInDescriptorsFromTableStart = 0; - D3D12_DESCRIPTOR_RANGE dump_root_edram_range; - dump_root_edram_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - dump_root_edram_range.NumDescriptors = 1; - dump_root_edram_range.BaseShaderRegister = 0; - dump_root_edram_range.RegisterSpace = 0; - dump_root_edram_range.OffsetInDescriptorsFromTableStart = 0; D3D12_ROOT_PARAMETER dump_root_color_parameters[kDumpRootParameterColorCount]; D3D12_ROOT_PARAMETER @@ -892,11 +873,9 @@ bool D3D12RenderTargetCache::Initialize() { D3D12_ROOT_PARAMETER& dump_root_edram = i ? dump_root_depth_parameters[kDumpRootParameterDepthEdram] : dump_root_color_parameters[kDumpRootParameterColorEdram]; - dump_root_edram.ParameterType = - D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - dump_root_edram.DescriptorTable.NumDescriptorRanges = 1; - dump_root_edram.DescriptorTable.pDescriptorRanges = - &dump_root_edram_range; + dump_root_edram.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + dump_root_edram.Descriptor.ShaderRegister = 0; + dump_root_edram.Descriptor.RegisterSpace = 0; dump_root_edram.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; } D3D12_ROOT_SIGNATURE_DESC dump_root_desc; @@ -1014,8 +993,8 @@ bool D3D12RenderTargetCache::Initialize() { } else if (path_ == Path::kPixelShaderInterlock) { // Pixel shader interlock (rasterizer-ordered view). - // Blending is done in linear space directly in shaders. - gamma_render_target_as_srgb_ = false; + // Piecewise linear gamma is 8-bit with programmable blending. + gamma_render_target_as_unorm16_ = false; // Always true float24 depth rounded to the nearest even. depth_float24_round_ = true; @@ -1038,18 +1017,10 @@ bool D3D12RenderTargetCache::Initialize() { resolve_rov_clear_root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Parameter 1 is the destination (EDRAM). - D3D12_DESCRIPTOR_RANGE resolve_rov_clear_dest_range; - resolve_rov_clear_dest_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - resolve_rov_clear_dest_range.NumDescriptors = 1; - resolve_rov_clear_dest_range.BaseShaderRegister = 0; - resolve_rov_clear_dest_range.RegisterSpace = 0; - resolve_rov_clear_dest_range.OffsetInDescriptorsFromTableStart = 0; resolve_rov_clear_root_parameters[1].ParameterType = - D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - resolve_rov_clear_root_parameters[1].DescriptorTable.NumDescriptorRanges = - 1; - resolve_rov_clear_root_parameters[1].DescriptorTable.pDescriptorRanges = - &resolve_rov_clear_dest_range; + D3D12_ROOT_PARAMETER_TYPE_UAV; + resolve_rov_clear_root_parameters[1].Descriptor.ShaderRegister = 0; + resolve_rov_clear_root_parameters[1].Descriptor.RegisterSpace = 0; resolve_rov_clear_root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; D3D12_ROOT_SIGNATURE_DESC resolve_rov_clear_root_signature_desc; @@ -1397,95 +1368,52 @@ bool D3D12RenderTargetCache::Resolve(const Memory& memory, resolve_info.copy_dest_extent_length); } if (copy_dest_committed) { - // Write the descriptors and transition the resources. - // Full shared memory without resolution scaling, range of the scaled - // resolve buffer with scaling because only at least 128 * 2^20 R32 - // elements must be addressable - // (D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP). - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor_dest; - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor_source; - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptors[2]; - if (command_processor_.RequestOneUseSingleViewDescriptors( - bindless_resources_used_ ? uint32_t(draw_resolution_scaled) : 2, - descriptors)) { - if (bindless_resources_used_) { - if (draw_resolution_scaled) { - descriptor_dest = descriptors[0]; - } else { - descriptor_dest = - command_processor_ - .GetSharedMemoryUintPow2BindlessUAVHandlePair( - copy_shader_info.dest_bpe_log2); - } - if (copy_shader_info.source_is_raw) { - descriptor_source = - command_processor_.GetSystemBindlessViewHandlePair( - D3D12CommandProcessor::SystemBindlessView::kEdramRawSRV); - } else { - descriptor_source = - command_processor_.GetEdramUintPow2BindlessSRVHandlePair( - copy_shader_info.source_bpe_log2); - } - } else { - descriptor_dest = descriptors[0]; - if (!draw_resolution_scaled) { - shared_memory.WriteUintPow2UAVDescriptor( - descriptor_dest.first, copy_shader_info.dest_bpe_log2); - } - descriptor_source = descriptors[1]; - if (copy_shader_info.source_is_raw) { - WriteEdramRawSRVDescriptor(descriptor_source.first); - } else { - WriteEdramUintPow2SRVDescriptor(descriptor_source.first, - copy_shader_info.source_bpe_log2); - } - } - if (draw_resolution_scaled) { - texture_cache.CreateCurrentScaledResolveRangeUintPow2UAV( - descriptor_dest.first, copy_shader_info.dest_bpe_log2); - texture_cache.TransitionCurrentScaledResolveRange( - D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - } else { - shared_memory.UseForWriting(); - } - TransitionEdramBuffer(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + command_list.D3DSetComputeRootSignature(resolve_copy_root_signature_); - // Submit the resolve. - command_list.D3DSetComputeRootSignature(resolve_copy_root_signature_); - command_list.D3DSetComputeRootDescriptorTable( - 2, descriptor_source.second); - command_list.D3DSetComputeRootDescriptorTable(1, - descriptor_dest.second); - if (draw_resolution_scaled) { - command_list.D3DSetComputeRoot32BitConstants( - 0, - sizeof(copy_shader_constants.dest_relative) / sizeof(uint32_t), - ©_shader_constants.dest_relative, 0); - } else { - command_list.D3DSetComputeRoot32BitConstants( - 0, sizeof(copy_shader_constants) / sizeof(uint32_t), - ©_shader_constants, 0); - } - command_processor_.SetExternalPipeline( - resolve_copy_pipelines_[size_t(copy_shader)]); - command_processor_.SubmitBarriers(); - command_list.D3DDispatch(copy_group_count_x, copy_group_count_y, 1); + // Source. + TransitionEdramBuffer(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + command_list.D3DSetComputeRootShaderResourceView( + 2, edram_buffer_gpu_address_); - // Order the resolve with other work using the destination as a UAV. - if (draw_resolution_scaled) { - texture_cache.MarkCurrentScaledResolveRangeUAVWritesCommitNeeded(); - } else { - shared_memory.MarkUAVWritesCommitNeeded(); - } + // Destination and constants. + if (draw_resolution_scaled) { + texture_cache.TransitionCurrentScaledResolveRange( + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + command_list.D3DSetComputeRootUnorderedAccessView( + 1, texture_cache.GetCurrentScaledResolveRangeGPUAddress()); - // Invalidate textures and mark the range as scaled if needed. - texture_cache.MarkRangeAsResolved( - resolve_info.copy_dest_extent_start, - resolve_info.copy_dest_extent_length); - written_address_out = resolve_info.copy_dest_extent_start; - written_length_out = resolve_info.copy_dest_extent_length; - copied = true; + command_list.D3DSetComputeRoot32BitConstants( + 0, sizeof(copy_shader_constants.dest_relative) / sizeof(uint32_t), + ©_shader_constants.dest_relative, 0); + } else { + shared_memory.UseForWriting(); + command_list.D3DSetComputeRootUnorderedAccessView( + 1, shared_memory.GetGPUAddress()); + + command_list.D3DSetComputeRoot32BitConstants( + 0, sizeof(copy_shader_constants) / sizeof(uint32_t), + ©_shader_constants, 0); } + + // Dispatch the resolve. + command_processor_.SetExternalPipeline( + resolve_copy_pipelines_[size_t(copy_shader)]); + command_processor_.SubmitBarriers(); + command_list.D3DDispatch(copy_group_count_x, copy_group_count_y, 1); + + // Order the resolve with other work using the destination as a UAV. + if (draw_resolution_scaled) { + texture_cache.MarkCurrentScaledResolveRangeUAVWritesCommitNeeded(); + } else { + shared_memory.MarkUAVWritesCommitNeeded(); + } + + // Invalidate textures and mark the range as scaled if needed. + texture_cache.MarkRangeAsResolved(resolve_info.copy_dest_extent_start, + resolve_info.copy_dest_extent_length); + written_address_out = resolve_info.copy_dest_extent_start; + written_length_out = resolve_info.copy_dest_extent_length; + copied = true; } else { XELOGE( "D3D12RenderTargetCache: Failed to obtain the resolve destination " @@ -1522,76 +1450,57 @@ bool D3D12RenderTargetCache::Resolve(const Memory& memory, cleared = true; } break; case Path::kPixelShaderInterlock: { - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor_edram; - bool descriptor_edram_obtained; - if (bindless_resources_used_) { - descriptor_edram = command_processor_.GetSystemBindlessViewHandlePair( - D3D12CommandProcessor::SystemBindlessView :: - kEdramR32G32B32A32UintUAV); - descriptor_edram_obtained = true; - } else { - descriptor_edram_obtained = - command_processor_.RequestOneUseSingleViewDescriptors( - 1, &descriptor_edram); - if (descriptor_edram_obtained) { - WriteEdramUintPow2UAVDescriptor(descriptor_edram.first, 4); - } + TransitionEdramBuffer(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + // Should be safe to only commit once (if was UAV / ROV previously - if + // there was nothing to copy, only to clear, for some reason, for + // instance), overlap of the depth and the color ranges is highly + // unlikely. + CommitEdramBufferUAVWrites(); + command_list.D3DSetComputeRootSignature( + resolve_rov_clear_root_signature_); + command_list.D3DSetComputeRootUnorderedAccessView( + 1, edram_buffer_gpu_address_); + std::pair clear_group_count = + resolve_info.GetClearShaderGroupCount(draw_resolution_scale_x(), + draw_resolution_scale_y()); + assert_true(clear_group_count.first && clear_group_count.second); + if (clear_depth) { + draw_util::ResolveClearShaderConstants depth_clear_constants; + resolve_info.GetDepthClearShaderConstants(depth_clear_constants); + command_list.D3DSetComputeRoot32BitConstants( + 0, sizeof(depth_clear_constants) / sizeof(uint32_t), + &depth_clear_constants, 0); + command_processor_.SetExternalPipeline( + resolve_rov_clear_32bpp_pipeline_); + command_processor_.SubmitBarriers(); + command_list.D3DDispatch(clear_group_count.first, + clear_group_count.second, 1); } - if (descriptor_edram_obtained) { - TransitionEdramBuffer(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - // Should be safe to only commit once (if was UAV / ROV previously - - // if there was nothing to copy, only to clear, for some reason, for - // instance), overlap of the depth and the color ranges is highly - // unlikely. - CommitEdramBufferUAVWrites(); - command_list.D3DSetComputeRootSignature( - resolve_rov_clear_root_signature_); - command_list.D3DSetComputeRootDescriptorTable( - 1, descriptor_edram.second); - std::pair clear_group_count = - resolve_info.GetClearShaderGroupCount(draw_resolution_scale_x(), - draw_resolution_scale_y()); - assert_true(clear_group_count.first && clear_group_count.second); + if (clear_color) { + draw_util::ResolveClearShaderConstants color_clear_constants; + resolve_info.GetColorClearShaderConstants(color_clear_constants); if (clear_depth) { - draw_util::ResolveClearShaderConstants depth_clear_constants; - resolve_info.GetDepthClearShaderConstants(depth_clear_constants); + // Non-RT-specific constants have already been set. command_list.D3DSetComputeRoot32BitConstants( - 0, sizeof(depth_clear_constants) / sizeof(uint32_t), - &depth_clear_constants, 0); - command_processor_.SetExternalPipeline( - resolve_rov_clear_32bpp_pipeline_); - command_processor_.SubmitBarriers(); - command_list.D3DDispatch(clear_group_count.first, - clear_group_count.second, 1); + 0, sizeof(color_clear_constants.rt_specific) / sizeof(uint32_t), + &color_clear_constants.rt_specific, + offsetof(draw_util::ResolveClearShaderConstants, rt_specific) / + sizeof(uint32_t)); + } else { + command_list.D3DSetComputeRoot32BitConstants( + 0, sizeof(color_clear_constants) / sizeof(uint32_t), + &color_clear_constants, 0); } - if (clear_color) { - draw_util::ResolveClearShaderConstants color_clear_constants; - resolve_info.GetColorClearShaderConstants(color_clear_constants); - if (clear_depth) { - // Non-RT-specific constants have already been set. - command_list.D3DSetComputeRoot32BitConstants( - 0, - sizeof(color_clear_constants.rt_specific) / sizeof(uint32_t), - &color_clear_constants.rt_specific, - offsetof(draw_util::ResolveClearShaderConstants, - rt_specific) / - sizeof(uint32_t)); - } else { - command_list.D3DSetComputeRoot32BitConstants( - 0, sizeof(color_clear_constants) / sizeof(uint32_t), - &color_clear_constants, 0); - } - command_processor_.SetExternalPipeline( - resolve_info.color_edram_info.format_is_64bpp - ? resolve_rov_clear_64bpp_pipeline_ - : resolve_rov_clear_32bpp_pipeline_); - command_processor_.SubmitBarriers(); - command_list.D3DDispatch(clear_group_count.first, - clear_group_count.second, 1); - } - MarkEdramBufferModified(); - cleared = true; + command_processor_.SetExternalPipeline( + resolve_info.color_edram_info.format_is_64bpp + ? resolve_rov_clear_64bpp_pipeline_ + : resolve_rov_clear_32bpp_pipeline_); + command_processor_.SubmitBarriers(); + command_list.D3DDispatch(clear_group_count.first, + clear_group_count.second, 1); } + MarkEdramBufferModified(); + cleared = true; } break; default: assert_unhandled_case(GetPath()); @@ -1775,12 +1684,10 @@ DXGI_FORMAT D3D12RenderTargetCache::GetColorResourceDXGIFormat( // compression. switch (format) { case xenos::ColorRenderTargetFormat::k_8_8_8_8: - case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: - if (gamma_render_target_as_srgb_) { - // Can toggle between UNORM and UNORM_SRGB for the same data. - return DXGI_FORMAT_R8G8B8A8_TYPELESS; - } return DXGI_FORMAT_R8G8B8A8_UNORM; + case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: + return gamma_render_target_as_unorm16_ ? DXGI_FORMAT_R16G16B16A16_UNORM + : DXGI_FORMAT_R8G8B8A8_UNORM; 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; @@ -1813,11 +1720,6 @@ DXGI_FORMAT D3D12RenderTargetCache::GetColorResourceDXGIFormat( DXGI_FORMAT D3D12RenderTargetCache::GetColorDrawDXGIFormat( xenos::ColorRenderTargetFormat format) const { switch (format) { - case xenos::ColorRenderTargetFormat::k_8_8_8_8: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: - return gamma_render_target_as_srgb_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB - : DXGI_FORMAT_R8G8B8A8_UNORM; case xenos::ColorRenderTargetFormat::k_16_16: return DXGI_FORMAT_R16G16_SNORM; case xenos::ColorRenderTargetFormat::k_16_16_16_16: @@ -1911,6 +1813,10 @@ DXGI_FORMAT D3D12RenderTargetCache::GetDepthSRVStencilDXGIFormat( } } +bool D3D12RenderTargetCache::IsGammaFormatHostStorageSeparate() const { + return gamma_render_target_as_unorm16_; +} + RenderTargetCache::RenderTarget* D3D12RenderTargetCache::CreateRenderTarget( RenderTargetKey key) { ID3D12Device* device = command_processor_.GetD3D12Provider().GetDevice(); @@ -1991,7 +1897,6 @@ RenderTargetCache::RenderTarget* D3D12RenderTargetCache::CreateRenderTarget( } D3D12_CPU_DESCRIPTOR_HANDLE descriptor_draw_handle = descriptor_draw.GetHandle(); - ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_draw_srgb; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_load_separate; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_srv_stencil; D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; @@ -2050,23 +1955,6 @@ RenderTargetCache::RenderTarget* D3D12RenderTargetCache::CreateRenderTarget( } device->CreateRenderTargetView(resource.Get(), &rtv_desc, descriptor_draw_handle); - // sRGB drawing RTV. - switch (key.GetColorFormat()) { - case xenos::ColorRenderTargetFormat::k_8_8_8_8: - case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: - if (gamma_render_target_as_srgb_) { - descriptor_draw_srgb = descriptor_pool.AllocateDescriptor(); - if (!descriptor_draw_srgb.IsValid()) { - return nullptr; - } - rtv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - device->CreateRenderTargetView(resource.Get(), &rtv_desc, - descriptor_draw_srgb.GetHandle()); - } - break; - default: - break; - } // Ownership transfer RTV. DXGI_FORMAT load_format = GetColorOwnershipTransferDXGIFormat(key.GetColorFormat()); @@ -2087,9 +1975,8 @@ RenderTargetCache::RenderTarget* D3D12RenderTargetCache::CreateRenderTarget( return new D3D12RenderTarget( key, resource.Get(), std::move(descriptor_draw), - std::move(descriptor_draw_srgb), std::move(descriptor_load_separate), - std::move(descriptor_srv), std::move(descriptor_srv_stencil), - resource_state); + std::move(descriptor_load_separate), std::move(descriptor_srv), + std::move(descriptor_srv_stencil), resource_state); } bool D3D12RenderTargetCache::IsHostDepthEncodingDifferent( @@ -3430,15 +3317,25 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) { if (dest_is_64bpp) { // Handle construction of 64bpp color, either from two 32-bit samples in r0 - // and r1, or from one 64bpp sample in r1. Using r2.x as temporary when + // and r1, or from one 64bpp sample in r1. Using r2.xy as temporary when // needed. // If color_packed_in_r0x_and_r1x, use the generic path for combining two // 32-bit samples - as raw in r0.x and r1.x - into the destination. bool color_packed_in_r0x_and_r1x = false; if (source_is_color) { switch (source_color_format) { - case xenos::ColorRenderTargetFormat::k_8_8_8_8: case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: { + // 8_8_8_8_GAMMA is represented by linear stored in + // R16G16B16A16_UNORM. + for (uint32_t i = 0; i < 2; ++i) { + for (uint32_t j = 0; j < 3; ++j) { + DxbcShaderTranslator::PreSaturatedLinearToPWLGamma(a, i, j, i, j, + 2, 0, 2, 1); + } + } + } + [[fallthrough]]; + case xenos::ColorRenderTargetFormat::k_8_8_8_8: { color_packed_in_r0x_and_r1x = true; for (uint32_t i = 0; i < 2; ++i) { a.OpMAd(dxbc::Dest::R(i), dxbc::Src::R(i), dxbc::Src::LF(255.0f), @@ -3589,7 +3486,14 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) { switch (source_color_format) { case xenos::ColorRenderTargetFormat::k_8_8_8_8: case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: { + // 8_8_8_8_GAMMA is represented by linear stored in + // R16G16B16A16_UNORM. if (dest_is_stencil_bit) { + if (source_color_format == + xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { + DxbcShaderTranslator::PreSaturatedLinearToPWLGamma(a, 1, 0, 1, 0, + 2, 0, 2, 1); + } a.OpMAd(dxbc::Dest::R(1, 0b0001), dxbc::Src::R(1, dxbc::Src::kXXXX), dxbc::Src::LF(255.0f), dxbc::Src::LF(0.5f)); a.OpFToU(dxbc::Dest::R(1, 0b0001), @@ -3599,18 +3503,38 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) { xenos::ColorRenderTargetFormat::k_8_8_8_8 || dest_color_format == xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA)) { - // Same format - passthrough. + // Same format - only perform color space conversion. + if (dest_color_format != source_color_format) { + if (dest_color_format == + xenos::ColorRenderTargetFormat::k_8_8_8_8) { + for (uint32_t i = 0; i < 3; ++i) { + DxbcShaderTranslator::PreSaturatedLinearToPWLGamma( + a, 1, i, 1, i, 2, 0, 2, 1); + } + } else { + for (uint32_t i = 0; i < 3; ++i) { + DxbcShaderTranslator::PWLGammaToLinear(a, 1, i, 1, i, true, 2, + 0, 2, 1); + } + } + } a.OpMov(dxbc::Dest::O(0), dxbc::Src::R(1)); } else if (mode.output == TransferOutput::kDepth) { - // When need only depth, not stencil, skip the red component. - a.OpMAd(dxbc::Dest::R( - 1, osgn_parameter_index_sv_stencil_ref != UINT32_MAX - ? 0b1111 - : 0b1110), - dxbc::Src::R(1), dxbc::Src::LF(255.0f), - dxbc::Src::LF(0.5f)); + // When need only depth, not stencil, skipping the red component. + if (source_color_format == + xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { + for (uint32_t i = shader_uses_stencil_reference_output ? 0 : 1; + i < 3; ++i) { + DxbcShaderTranslator::PreSaturatedLinearToPWLGamma( + a, 1, i, 1, i, 2, 0, 2, 1); + } + } + a.OpMAd( + dxbc::Dest::R( + 1, shader_uses_stencil_reference_output ? 0b1111 : 0b1110), + dxbc::Src::R(1), dxbc::Src::LF(255.0f), dxbc::Src::LF(0.5f)); a.OpFToU(dxbc::Dest::R(1, 0b1110), dxbc::Src::R(1)); - if (osgn_parameter_index_sv_stencil_ref != UINT32_MAX) { + if (shader_uses_stencil_reference_output) { // Write the red component to the stencil reference. a.OpFToU(dxbc::Dest::OStencilRef(), dxbc::Src::R(1, dxbc::Src::kXXXX)); @@ -3626,6 +3550,13 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) { dxbc::Src::R(1, dxbc::Src::kYYYY)); } else { color_packed_in_r1x = true; + if (source_color_format == + xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { + for (uint32_t i = 0; i < 3; ++i) { + DxbcShaderTranslator::PreSaturatedLinearToPWLGamma( + a, 1, i, 1, i, 2, 0, 2, 1); + } + } a.OpMAd(dxbc::Dest::R(1), dxbc::Src::R(1), dxbc::Src::LF(255.0f), dxbc::Src::LF(0.5f)); a.OpFToU(dxbc::Dest::R(1), dxbc::Src::R(1)); @@ -3769,8 +3700,7 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) { // this is the end of the shader. if (color_packed_in_r1x) { switch (dest_color_format) { - case xenos::ColorRenderTargetFormat::k_8_8_8_8: - case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: { + case xenos::ColorRenderTargetFormat::k_8_8_8_8: { a.OpUBFE(dxbc::Dest::R(1), dxbc::Src::LU(8), dxbc::Src::LU(0, 8, 16, 24), dxbc::Src::R(1, dxbc::Src::kXXXX)); @@ -3778,6 +3708,26 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) { a.OpMul(dxbc::Dest::O(0), dxbc::Src::R(1), dxbc::Src::LF(1.0f / 255.0f)); } break; + case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: { + // 8_8_8_8_GAMMA is represented by linear stored in + // R16G16B16A16_UNORM. + a.OpUBFE(dxbc::Dest::R(1), dxbc::Src::LU(8), + dxbc::Src::LU(0, 8, 16, 24), + dxbc::Src::R(1, dxbc::Src::kXXXX)); + a.OpUToF(dxbc::Dest::R(1), dxbc::Src::R(1)); + a.OpMul(dxbc::Dest::R(1, 0b0111), dxbc::Src::R(1), + dxbc::Src::LF(1.0f / 255.0f)); + a.OpMul(dxbc::Dest::O(0, 0b1000), dxbc::Src::R(1), + dxbc::Src::LF(1.0f / 255.0f)); + for (uint32_t i = 0; i < 3; ++i) { + DxbcShaderTranslator::PWLGammaToLinear(a, 1, i, 1, i, true, 0, + 0, 0, 1); + } + // TODO(Triang3l): The `mov` can be eliminated by passing the + // destination to `PWLGammaToLinear` as `dxbc::Dest` rather than + // just the register index. + a.OpMov(dxbc::Dest::O(0, 0b0111), dxbc::Src::R(1)); + } break; case xenos::ColorRenderTargetFormat::k_2_10_10_10: case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10: { a.OpUBFE(dxbc::Dest::R(1), dxbc::Src::LU(10, 10, 10, 2), @@ -4499,38 +4449,19 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears( continue; } if (!host_depth_store_set_up) { - // Bindings. - // 0 - source. - // 1 - EDRAM if bindful. + // Source descriptor. ui::d3d12::util::DescriptorCpuGpuHandlePair - host_depth_store_descriptors[2]; + host_depth_store_descriptor_source; if (!command_processor_.RequestOneUseSingleViewDescriptors( - 1 + uint32_t(!bindless_resources_used_), - host_depth_store_descriptors)) { + 1, &host_depth_store_descriptor_source)) { continue; } command_list.D3DSetComputeRootSignature( host_depth_store_root_signature_); - // Destination (EDRAM uint4 buffer). - if (bindless_resources_used_) { - command_list.D3DSetComputeRootDescriptorTable( - kHostDepthStoreRootParameterDest, - command_processor_.GetEdramUintPow2BindlessUAVHandlePair(4) - .second); - } else { - const ui::d3d12::util::DescriptorCpuGpuHandlePair& - host_depth_store_descriptor_dest = - host_depth_store_descriptors[1]; - WriteEdramUintPow2UAVDescriptor( - host_depth_store_descriptor_dest.first, 4); - command_list.D3DSetComputeRootDescriptorTable( - kHostDepthStoreRootParameterDest, - host_depth_store_descriptor_dest.second); - } + // Destination (EDRAM buffer). + command_list.D3DSetComputeRootUnorderedAccessView( + kHostDepthStoreRootParameterDest, edram_buffer_gpu_address_); // Depth source texture. - const ui::d3d12::util::DescriptorCpuGpuHandlePair& - host_depth_store_descriptor_source = - host_depth_store_descriptors[0]; device->CopyDescriptorsSimple( 1, host_depth_store_descriptor_source.first, dest_d3d12_rt.descriptor_srv().GetHandle(), @@ -5358,13 +5289,24 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears( float color_clear_value[4] = {}; bool clear_via_drawing = false; switch (dest_rt_key.GetColorFormat()) { - case xenos::ColorRenderTargetFormat::k_8_8_8_8: - case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: { + case xenos::ColorRenderTargetFormat::k_8_8_8_8: { for (uint32_t j = 0; j < 4; ++j) { color_clear_value[j] = ((clear_value >> (j * 8)) & 0xFF) * (1.0f / 0xFF); } } break; + case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: { + // 8_8_8_8_GAMMA is represented by linear stored in + // R16G16B16A16_UNORM. + for (uint32_t j = 0; j < 4; ++j) { + color_clear_value[j] = + ((clear_value >> (j * 8)) & 0xFF) * (1.0f / 0xFF); + } + for (uint32_t j = 0; j < 3; ++j) { + color_clear_value[j] = + xenos::PWLGammaToLinear(color_clear_value[j]); + } + } break; case xenos::ColorRenderTargetFormat::k_2_10_10_10: case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10: { for (uint32_t j = 0; j < 3; ++j) { @@ -5509,17 +5451,6 @@ void D3D12RenderTargetCache::SetCommandListRenderTargets( } } } - uint32_t render_targets_are_srgb; - if (gamma_render_target_as_srgb_) { - render_targets_are_srgb = last_update_accumulated_color_targets_are_gamma(); - if (are_current_command_list_render_targets_srgb_ != - render_targets_are_srgb) { - are_current_command_list_render_targets_srgb_ = render_targets_are_srgb; - are_current_command_list_render_targets_valid_ = false; - } - } else { - render_targets_are_srgb = 0; - } if (!are_current_command_list_render_targets_valid_) { std::memcpy(current_command_list_render_targets_, depth_and_color_render_targets, @@ -5546,10 +5477,7 @@ void D3D12RenderTargetCache::SetCommandListRenderTargets( : null_rtv_descriptor_ss_.GetHandle(); } auto& d3d12_rt = *static_cast(render_target); - rtv_handles[rtv_count++] = - (render_targets_are_srgb & (uint32_t(1) << i)) - ? d3d12_rt.descriptor_draw_srgb().GetHandle() - : d3d12_rt.descriptor_draw().GetHandle(); + rtv_handles[rtv_count++] = d3d12_rt.descriptor_draw().GetHandle(); } command_processor_.GetDeferredCommandList().D3DOMSetRenderTargets( rtv_count, rtv_handles, false, @@ -5702,7 +5630,7 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( // Bindings. // - Texture2D/Texture2DMS xe_edram_dump_source : t0 // - Optionally, Texture2D/Texture2DMS xe_edram_dump_stencil : t1 - // - RWBuffer xe_edram : u0 + // - RWByteAddressBuffer xe_edram : u0 // - Constant buffers uint32_t rdef_binding_count = 1 + key.is_depth + 1 + kDumpCbufferCount; // Names. @@ -5775,13 +5703,10 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( dxbc::RdefInputBind& rdef_binding_edram = rdef_bindings[rdef_binding_index++]; rdef_binding_edram.name_ptr = rdef_xe_edram_name_ptr; - rdef_binding_edram.type = dxbc::RdefInputType::kUAVRWTyped; - rdef_binding_edram.return_type = dxbc::ResourceReturnType::kUInt; + rdef_binding_edram.type = dxbc::RdefInputType::kUAVRWByteAddress; + rdef_binding_edram.return_type = dxbc::ResourceReturnType::kMixed; rdef_binding_edram.dimension = dxbc::RdefDimension::kUAVBuffer; - rdef_binding_edram.sample_count = UINT32_MAX; rdef_binding_edram.bind_count = 1; - rdef_binding_edram.flags = - format_is_64bpp ? dxbc::kRdefInputFlags2Component : 0; // xe_edram_dump_offsets dxbc::RdefInputBind& rdef_binding_offsets = rdef_bindings[rdef_binding_index++]; @@ -5906,10 +5831,7 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( dxbc::Src::T(dxbc::Src::Dcl, 1, 1, 1)); } // EDRAM buffer. - a.OpDclUnorderedAccessViewTyped( - dxbc::ResourceDimension::kBuffer, 0, - dxbc::ResourceReturnTypeX4Token(dxbc::ResourceReturnType::kUInt), - dxbc::Src::U(dxbc::Src::Dcl, 0, 0, 0)); + a.OpDclUnorderedAccessViewRaw(0, dxbc::Src::U(dxbc::Src::Dcl, 0, 0, 0)); a.OpDclInput(dxbc::Dest::VThreadID(0b0011)); // r0 - addressing before the load, then addressing and conversion scratch // r1 - addressing scratch before the load, then data @@ -6042,6 +5964,9 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( a.OpIAdd(dxbc::Dest::R(0, 0b0100), dxbc::Src::R(0, dxbc::Src::kZZZZ), dxbc::Src::R(1, dxbc::Src::kXXXX)); } + // Convert the destination address from samples to bytes. + a.OpIShL(dxbc::Dest::R(0, 0b0100), dxbc::Src::R(0, dxbc::Src::kZZZZ), + dxbc::Src::LU(format_is_64bpp ? 3 : 2)); // Extract the source texture base tile index to r1.x. // r0.x = X sample position within the tile @@ -6236,7 +6161,6 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( } else { switch (key.GetColorFormat()) { case xenos::ColorRenderTargetFormat::k_8_8_8_8: - case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: if (!source_is_uint) { a.OpMAd(dxbc::Dest::R(1), dxbc::Src::R(1), dxbc::Src::LF(255.0f), dxbc::Src::LF(0.5f)); @@ -6248,6 +6172,22 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( dxbc::Src::R(1, dxbc::Src::kXXXX)); } break; + case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: + // 8_8_8_8_GAMMA is represented by linear stored in R16G16B16A16_UNORM. + assert_false(source_is_uint); + for (uint32_t i = 0; i < 3; ++i) { + DxbcShaderTranslator::PreSaturatedLinearToPWLGamma(a, 1, i, 1, i, 0, + 0, 0, 1); + } + a.OpMAd(dxbc::Dest::R(1), dxbc::Src::R(1), dxbc::Src::LF(255.0f), + dxbc::Src::LF(0.5f)); + a.OpFToU(dxbc::Dest::R(1), dxbc::Src::R(1)); + for (uint32_t i = 1; i < 4; ++i) { + a.OpBFI(dxbc::Dest::R(1, 0b0001), dxbc::Src::LU(8), + dxbc::Src::LU(i * 8), dxbc::Src::R(1).Select(i), + dxbc::Src::R(1, dxbc::Src::kXXXX)); + } + break; case xenos::ColorRenderTargetFormat::k_2_10_10_10: case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10: if (!source_is_uint) { @@ -6310,9 +6250,8 @@ ID3D12PipelineState* D3D12RenderTargetCache::GetOrCreateDumpPipeline( } // Write the sample to the destination address stored in r0.z. - a.OpStoreUAVTyped( - dxbc::Dest::U(0, 0), dxbc::Src::R(0, dxbc::Src::kZZZZ), 1, - dxbc::Src::R(1, format_is_64bpp ? 0b0100 : dxbc::Src::kXXXX)); + a.OpStoreRaw(dxbc::Dest::U(0, 0, format_is_64bpp ? 0b0011 : 0b0001), + dxbc::Src::R(0, dxbc::Src::kZZZZ), dxbc::Src::R(1)); a.OpRet(); @@ -6455,29 +6394,8 @@ void D3D12RenderTargetCache::DumpRenderTargets(uint32_t dump_base, pipeline_key.is_depth = rt_key.is_depth; dump_invocations_.emplace_back(rectangle, pipeline_key); } - // 32bpp and 64bpp. - size_t edram_uav_indices[2] = {SIZE_MAX, SIZE_MAX}; - const ui::d3d12::D3D12Provider& provider = - command_processor_.GetD3D12Provider(); - if (!bindless_resources_used_) { - if (any_sources_32bpp_64bpp[0]) { - edram_uav_indices[0] = current_temporary_descriptors_cpu_.size(); - current_temporary_descriptors_cpu_.push_back( - provider.OffsetViewDescriptor( - edram_buffer_descriptor_heap_start_, - uint32_t(EdramBufferDescriptorIndex::kR32UintUAV))); - } - if (any_sources_32bpp_64bpp[1]) { - edram_uav_indices[1] = current_temporary_descriptors_cpu_.size(); - current_temporary_descriptors_cpu_.push_back( - provider.OffsetViewDescriptor( - edram_buffer_descriptor_heap_start_, - uint32_t(EdramBufferDescriptorIndex::kR32G32UintUAV))); - } - } // Copy source descriptors to a shader-visible heap. - ID3D12Device* device = provider.GetDevice(); uint32_t descriptor_count = uint32_t(current_temporary_descriptors_cpu_.size()); current_temporary_descriptors_gpu_.resize(descriptor_count); @@ -6485,6 +6403,7 @@ void D3D12RenderTargetCache::DumpRenderTargets(uint32_t dump_base, descriptor_count, current_temporary_descriptors_gpu_.data())) { return; } + ID3D12Device* device = command_processor_.GetD3D12Provider().GetDevice(); for (uint32_t i = 0; i < descriptor_count; ++i) { device->CopyDescriptorsSimple(1, current_temporary_descriptors_gpu_[i].first, @@ -6499,6 +6418,8 @@ void D3D12RenderTargetCache::DumpRenderTargets(uint32_t dump_base, DeferredCommandList& command_list = command_processor_.GetDeferredCommandList(); ID3D12RootSignature* last_root_signature = nullptr; + // `root_parameters_set` doesn't include the EDRAM buffer, which is never + // changed. uint32_t root_parameters_set = 0; uint32_t last_descriptor_index_source = UINT32_MAX; uint32_t last_descriptor_index_stencil = UINT32_MAX; @@ -6523,35 +6444,10 @@ void D3D12RenderTargetCache::DumpRenderTargets(uint32_t dump_base, last_root_signature = root_signature; command_list.D3DSetComputeRootSignature(root_signature); root_parameters_set = 0; - } - - DumpRootParameter root_parameter_edram = pipeline_key.is_depth - ? kDumpRootParameterDepthEdram - : kDumpRootParameterColorEdram; - uint32_t root_parameter_edram_bit = uint32_t(1) << root_parameter_edram; - bool format_is_64bpp = rt_key.Is64bpp(); - if (last_edram_uav_is_64bpp != format_is_64bpp) { - last_edram_uav_is_64bpp = format_is_64bpp; - root_parameters_set &= ~root_parameter_edram_bit; - } - if (!(root_parameters_set & root_parameter_edram_bit)) { - D3D12_GPU_DESCRIPTOR_HANDLE descriptor_handle_edram; - if (bindless_resources_used_) { - descriptor_handle_edram = command_processor_ - .GetEdramUintPow2BindlessUAVHandlePair( - 2 + uint32_t(last_edram_uav_is_64bpp)) - .second; - } else { - assert_true(edram_uav_indices[size_t(last_edram_uav_is_64bpp)] != - SIZE_MAX); - descriptor_handle_edram = - current_temporary_descriptors_gpu_[edram_uav_indices[size_t( - last_edram_uav_is_64bpp)]] - .second; - } - command_list.D3DSetComputeRootDescriptorTable(root_parameter_edram, - descriptor_handle_edram); - root_parameters_set |= root_parameter_edram_bit; + command_list.D3DSetComputeRootUnorderedAccessView( + pipeline_key.is_depth ? kDumpRootParameterDepthEdram + : kDumpRootParameterColorEdram, + edram_buffer_gpu_address_); } DumpRootParameter root_parameter_pitches = @@ -6612,6 +6508,7 @@ void D3D12RenderTargetCache::DumpRenderTargets(uint32_t dump_base, uint32_t(1) << kDumpRootParameterOffsets; DumpOffsets offsets; offsets.source_base_tiles = rt_key.base_tiles; + bool format_is_64bpp = rt_key.Is64bpp(); ResolveCopyDumpRectangle::Dispatch dispatches[ResolveCopyDumpRectangle::kMaxDispatches]; uint32_t dispatch_count = diff --git a/src/xenia/gpu/d3d12/d3d12_render_target_cache.h b/src/xenia/gpu/d3d12/d3d12_render_target_cache.h index d89e28e71..c0bb7420a 100644 --- a/src/xenia/gpu/d3d12/d3d12_render_target_cache.h +++ b/src/xenia/gpu/d3d12/d3d12_render_target_cache.h @@ -95,8 +95,8 @@ class D3D12RenderTargetCache final : public RenderTargetCache { // For host render targets. - bool gamma_render_target_as_srgb() const { - return gamma_render_target_as_srgb_; + bool gamma_render_target_as_unorm16() const { + return gamma_render_target_as_unorm16_; } // Using R16G16[B16A16]_SNORM, which are -1...1, not the needed -32...32. @@ -129,6 +129,8 @@ class D3D12RenderTargetCache final : public RenderTargetCache { xenos::DepthRenderTargetFormat format); protected: + bool IsGammaFormatHostStorageSeparate() const override; + uint32_t GetMaxRenderTargetWidth() const override { return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; } @@ -178,6 +180,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { // copied to a different buffer - the same range may have ROV-owned color and // host float32 depth at the same time). ID3D12Resource* edram_buffer_ = nullptr; + D3D12_GPU_VIRTUAL_ADDRESS edram_buffer_gpu_address_ = 0; D3D12_RESOURCE_STATES edram_buffer_state_; EdramBufferModificationStatus edram_buffer_modification_status_ = EdramBufferModificationStatus::kUnmodified; @@ -225,16 +228,13 @@ class D3D12RenderTargetCache final : public RenderTargetCache { class D3D12RenderTarget final : public RenderTarget { public: - // descriptor_draw_srgb is only used for k_8_8_8_8 render targets when host - // sRGB (gamma_render_target_as_srgb) is used. descriptor_load is present - // when the DXGI formats are different for drawing and bit-exact loading - // (for NaN pattern preservation across EDRAM tile ownership transfers in - // floating-point formats, and to distinguish between two -1 representations - // in snorm formats). + // descriptor_load is present when the DXGI formats are different for + // drawing and bit-exact loading (for NaN pattern preservation across EDRAM + // tile ownership transfers in floating-point formats, and to distinguish + // between two -1 representations in snorm formats). D3D12RenderTarget( RenderTargetKey key, ID3D12Resource* resource, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_draw, - ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_draw_srgb, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_load_separate, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_srv, @@ -243,7 +243,6 @@ class D3D12RenderTargetCache final : public RenderTargetCache { : RenderTarget(key), resource_(resource), descriptor_draw_(std::move(descriptor_draw)), - descriptor_draw_srgb_(std::move(descriptor_draw_srgb)), descriptor_load_separate_(std::move(descriptor_load_separate)), descriptor_srv_(std::move(descriptor_srv)), descriptor_srv_stencil_(std::move(descriptor_srv_stencil)), @@ -254,10 +253,6 @@ class D3D12RenderTargetCache final : public RenderTargetCache { const { return descriptor_draw_; } - const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_draw_srgb() - const { - return descriptor_draw_srgb_; - } const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_srv() const { return descriptor_srv_; @@ -297,7 +292,6 @@ class D3D12RenderTargetCache final : public RenderTargetCache { private: Microsoft::WRL::ComPtr resource_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_draw_; - ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_draw_srgb_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_load_separate_; // Texture SRV non-shader-visible descriptors, to prepare shader-visible // descriptors faster, by copying rather than by creating every time. @@ -617,7 +611,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { // May be different for different sources. kDumpRootParameterColorPitches = kDumpRootParameterSource + 1, - // Only changed between 32bpp and 64bpp. + // Not changed. kDumpRootParameterColorEdram, kDumpRootParameterColorCount, @@ -718,7 +712,7 @@ class D3D12RenderTargetCache final : public RenderTargetCache { bool use_stencil_reference_output_ = false; - bool gamma_render_target_as_srgb_ = false; + bool gamma_render_target_as_unorm16_ = false; bool depth_float24_round_ = false; bool depth_float24_convert_in_pixel_shader_ = false; @@ -753,7 +747,6 @@ class D3D12RenderTargetCache final : public RenderTargetCache { const RenderTarget* const* current_command_list_render_targets_[1 + xenos::kMaxColorRenderTargets]; - uint32_t are_current_command_list_render_targets_srgb_ = 0; bool are_current_command_list_render_targets_valid_ = false; // Temporary storage for descriptors used in PerformTransfersAndResolveClears diff --git a/src/xenia/gpu/d3d12/d3d12_shared_memory.cc b/src/xenia/gpu/d3d12/d3d12_shared_memory.cc index 84f14787a..4a10c3e62 100644 --- a/src/xenia/gpu/d3d12/d3d12_shared_memory.cc +++ b/src/xenia/gpu/d3d12/d3d12_shared_memory.cc @@ -107,47 +107,11 @@ bool D3D12SharedMemory::Initialize() { provider.OffsetViewDescriptor(buffer_descriptor_heap_start_, uint32_t(BufferDescriptorIndex::kRawSRV)), buffer_, kBufferSize); - ui::d3d12::util::CreateBufferTypedSRV( - device, - provider.OffsetViewDescriptor( - buffer_descriptor_heap_start_, - uint32_t(BufferDescriptorIndex::kR32UintSRV)), - buffer_, DXGI_FORMAT_R32_UINT, kBufferSize >> 2); - ui::d3d12::util::CreateBufferTypedSRV( - device, - provider.OffsetViewDescriptor( - buffer_descriptor_heap_start_, - uint32_t(BufferDescriptorIndex::kR32G32UintSRV)), - buffer_, DXGI_FORMAT_R32G32_UINT, kBufferSize >> 3); - ui::d3d12::util::CreateBufferTypedSRV( - device, - provider.OffsetViewDescriptor( - buffer_descriptor_heap_start_, - uint32_t(BufferDescriptorIndex::kR32G32B32A32UintSRV)), - buffer_, DXGI_FORMAT_R32G32B32A32_UINT, kBufferSize >> 4); ui::d3d12::util::CreateBufferRawUAV( device, provider.OffsetViewDescriptor(buffer_descriptor_heap_start_, uint32_t(BufferDescriptorIndex::kRawUAV)), buffer_, kBufferSize); - ui::d3d12::util::CreateBufferTypedUAV( - device, - provider.OffsetViewDescriptor( - buffer_descriptor_heap_start_, - uint32_t(BufferDescriptorIndex::kR32UintUAV)), - buffer_, DXGI_FORMAT_R32_UINT, kBufferSize >> 2); - ui::d3d12::util::CreateBufferTypedUAV( - device, - provider.OffsetViewDescriptor( - buffer_descriptor_heap_start_, - uint32_t(BufferDescriptorIndex::kR32G32UintUAV)), - buffer_, DXGI_FORMAT_R32G32_UINT, kBufferSize >> 3); - ui::d3d12::util::CreateBufferTypedUAV( - device, - provider.OffsetViewDescriptor( - buffer_descriptor_heap_start_, - uint32_t(BufferDescriptorIndex::kR32G32B32A32UintUAV)), - buffer_, DXGI_FORMAT_R32G32B32A32_UINT, kBufferSize >> 4); upload_buffer_pool_ = std::make_unique( provider, xe::align(ui::d3d12::D3D12UploadBufferPool::kDefaultPageSize, @@ -233,60 +197,6 @@ void D3D12SharedMemory::WriteRawUAVDescriptor( D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); } -void D3D12SharedMemory::WriteUintPow2SRVDescriptor( - D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2) { - BufferDescriptorIndex descriptor_index; - switch (element_size_bytes_pow2) { - case 2: - descriptor_index = BufferDescriptorIndex::kR32UintSRV; - break; - case 3: - descriptor_index = BufferDescriptorIndex::kR32G32UintSRV; - break; - case 4: - descriptor_index = BufferDescriptorIndex::kR32G32B32A32UintSRV; - break; - default: - assert_unhandled_case(element_size_bytes_pow2); - return; - } - const ui::d3d12::D3D12Provider& provider = - command_processor_.GetD3D12Provider(); - ID3D12Device* device = provider.GetDevice(); - device->CopyDescriptorsSimple( - 1, handle, - provider.OffsetViewDescriptor(buffer_descriptor_heap_start_, - uint32_t(descriptor_index)), - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); -} - -void D3D12SharedMemory::WriteUintPow2UAVDescriptor( - D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2) { - BufferDescriptorIndex descriptor_index; - switch (element_size_bytes_pow2) { - case 2: - descriptor_index = BufferDescriptorIndex::kR32UintUAV; - break; - case 3: - descriptor_index = BufferDescriptorIndex::kR32G32UintUAV; - break; - case 4: - descriptor_index = BufferDescriptorIndex::kR32G32B32A32UintUAV; - break; - default: - assert_unhandled_case(element_size_bytes_pow2); - return; - } - const ui::d3d12::D3D12Provider& provider = - command_processor_.GetD3D12Provider(); - ID3D12Device* device = provider.GetDevice(); - device->CopyDescriptorsSimple( - 1, handle, - provider.OffsetViewDescriptor(buffer_descriptor_heap_start_, - uint32_t(descriptor_index)), - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); -} - bool D3D12SharedMemory::InitializeTraceSubmitDownloads() { ResetTraceDownload(); PrepareForTraceDownload(); @@ -453,7 +363,7 @@ bool D3D12SharedMemory::UploadRanges( return false; } MakeRangeValid(upload_range_start << page_size_log2(), - uint32_t(upload_buffer_size), false, false); + uint32_t(upload_buffer_size), false); if (upload_buffer_size < (1ULL << 32) && upload_buffer_size > 8192) { memory::vastcpy( diff --git a/src/xenia/gpu/d3d12/d3d12_shared_memory.h b/src/xenia/gpu/d3d12/d3d12_shared_memory.h index 73cff2e7b..60c44c8ef 100644 --- a/src/xenia/gpu/d3d12/d3d12_shared_memory.h +++ b/src/xenia/gpu/d3d12/d3d12_shared_memory.h @@ -76,12 +76,6 @@ class D3D12SharedMemory : public SharedMemory { void WriteRawSRVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle); void WriteRawUAVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle); - // Due to the D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP limitation, the - // smallest supported formats are 32-bit. - void WriteUintPow2SRVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle, - uint32_t element_size_bytes_pow2); - void WriteUintPow2UAVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle, - uint32_t element_size_bytes_pow2); // Returns true if any downloads were submitted to the command processor. bool InitializeTraceSubmitDownloads(); @@ -110,13 +104,7 @@ class D3D12SharedMemory : public SharedMemory { // rather than creation). enum class BufferDescriptorIndex : uint32_t { kRawSRV, - kR32UintSRV, - kR32G32UintSRV, - kR32G32B32A32UintSRV, kRawUAV, - kR32UintUAV, - kR32G32UintUAV, - kR32G32B32A32UintUAV, kCount, }; diff --git a/src/xenia/gpu/d3d12/d3d12_texture_cache.cc b/src/xenia/gpu/d3d12/d3d12_texture_cache.cc index 4a14af244..a4de12e35 100644 --- a/src/xenia/gpu/d3d12/d3d12_texture_cache.cc +++ b/src/xenia/gpu/d3d12/d3d12_texture_cache.cc @@ -151,26 +151,14 @@ bool D3D12TextureCache::Initialize() { root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Parameter 1 is the source (may be changed multiple times for the same // destination). - D3D12_DESCRIPTOR_RANGE root_dest_range; - root_dest_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - root_dest_range.NumDescriptors = 1; - root_dest_range.BaseShaderRegister = 0; - root_dest_range.RegisterSpace = 0; - root_dest_range.OffsetInDescriptorsFromTableStart = 0; - root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - root_parameters[1].DescriptorTable.NumDescriptorRanges = 1; - root_parameters[1].DescriptorTable.pDescriptorRanges = &root_dest_range; + root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; + root_parameters[1].Descriptor.ShaderRegister = 0; + root_parameters[1].Descriptor.RegisterSpace = 0; root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Parameter 2 is the destination. - D3D12_DESCRIPTOR_RANGE root_source_range; - root_source_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - root_source_range.NumDescriptors = 1; - root_source_range.BaseShaderRegister = 0; - root_source_range.RegisterSpace = 0; - root_source_range.OffsetInDescriptorsFromTableStart = 0; - root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - root_parameters[2].DescriptorTable.NumDescriptorRanges = 1; - root_parameters[2].DescriptorTable.pDescriptorRanges = &root_source_range; + root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + root_parameters[2].Descriptor.ShaderRegister = 0; + root_parameters[2].Descriptor.RegisterSpace = 0; root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; D3D12_ROOT_SIGNATURE_DESC root_signature_desc; root_signature_desc.NumParameters = UINT(xe::countof(root_parameters)); @@ -1183,40 +1171,16 @@ void D3D12TextureCache::TransitionCurrentScaledResolveRange( buffer.resource(), buffer.SetResourceState(new_state), new_state); } -void D3D12TextureCache::CreateCurrentScaledResolveRangeUintPow2SRV( - D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2) { +D3D12_GPU_VIRTUAL_ADDRESS +D3D12TextureCache::GetCurrentScaledResolveRangeGPUAddress() const { assert_true(IsDrawResolutionScaled()); - size_t buffer_index = GetCurrentScaledResolveBufferIndex(); + const size_t buffer_index = GetCurrentScaledResolveBufferIndex(); const ScaledResolveVirtualBuffer* buffer = scaled_resolve_2gb_buffers_[buffer_index].get(); assert_not_null(buffer); - ui::d3d12::util::CreateBufferTypedSRV( - command_processor_.GetD3D12Provider().GetDevice(), handle, - buffer->resource(), - ui::d3d12::util::GetUintPow2DXGIFormat(element_size_bytes_pow2), - uint32_t(scaled_resolve_current_range_length_scaled_ >> - element_size_bytes_pow2), - (scaled_resolve_current_range_start_scaled_ - - (uint64_t(buffer_index) << 30)) >> - element_size_bytes_pow2); -} - -void D3D12TextureCache::CreateCurrentScaledResolveRangeUintPow2UAV( - D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2) { - assert_true(IsDrawResolutionScaled()); - size_t buffer_index = GetCurrentScaledResolveBufferIndex(); - const ScaledResolveVirtualBuffer* buffer = - scaled_resolve_2gb_buffers_[buffer_index].get(); - assert_not_null(buffer); - ui::d3d12::util::CreateBufferTypedUAV( - command_processor_.GetD3D12Provider().GetDevice(), handle, - buffer->resource(), - ui::d3d12::util::GetUintPow2DXGIFormat(element_size_bytes_pow2), - uint32_t(scaled_resolve_current_range_length_scaled_ >> - element_size_bytes_pow2), - (scaled_resolve_current_range_start_scaled_ - - (uint64_t(buffer_index) << 30)) >> - element_size_bytes_pow2); + return buffer->resource()->GetGPUVirtualAddress() + + (scaled_resolve_current_range_start_scaled_ - + (uint64_t(buffer_index) << 30)); } ID3D12Resource* D3D12TextureCache::RequestSwapTexture( @@ -1566,61 +1530,18 @@ bool D3D12TextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture, return false; } - // Begin loading. - // May use different buffers for scaled base and mips, and also addressability - // of more than 128 * 2^20 (2^D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP) - // texels is not mandatory - need two separate UAV descriptors for base and - // mips. - // Destination. - uint32_t descriptor_count = 1; - if (texture_resolution_scaled) { - // Source - base and mips, one or both. - descriptor_count += (level_first == 0 && level_last != 0) ? 2 : 1; - } else { - // Source - shared memory. - if (!bindless_resources_used_) { - ++descriptor_count; - } - } - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptors_allocated[3]; - if (!command_processor_.RequestOneUseSingleViewDescriptors( - descriptor_count, descriptors_allocated)) { - command_processor_.ReleaseScratchGPUBuffer(copy_buffer, copy_buffer_state); - return false; - } - uint32_t descriptor_write_index = 0; command_processor_.SetExternalPipeline(pipeline); command_list.D3DSetComputeRootSignature(load_root_signature_.Get()); - // Set up the destination descriptor. - assert_true(descriptor_write_index < descriptor_count); - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor_dest = - descriptors_allocated[descriptor_write_index++]; - ui::d3d12::util::CreateBufferTypedUAV( - device, descriptor_dest.first, copy_buffer, - ui::d3d12::util::GetUintPow2DXGIFormat(load_shader_info.dest_bpe_log2), - uint32_t(copy_buffer_size) >> load_shader_info.dest_bpe_log2); - command_list.D3DSetComputeRootDescriptorTable(2, descriptor_dest.second); - // Set up the unscaled source descriptor (scaled needs two descriptors that - // depend on the buffer being current, so they will be set later - for mips, - // after loading the base is done). + command_list.D3DSetComputeRootUnorderedAccessView( + 2, copy_buffer->GetGPUVirtualAddress()); + // Set up the unscaled source binding (scaled may have the base and the mips + // in different buffer resources). if (!texture_resolution_scaled) { D3D12SharedMemory& d3d12_shared_memory = static_cast(shared_memory()); d3d12_shared_memory.UseForReading(); - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor_unscaled_source; - if (bindless_resources_used_) { - descriptor_unscaled_source = - command_processor_.GetSharedMemoryUintPow2BindlessSRVHandlePair( - load_shader_info.source_bpe_log2); - } else { - assert_true(descriptor_write_index < descriptor_count); - descriptor_unscaled_source = - descriptors_allocated[descriptor_write_index++]; - d3d12_shared_memory.WriteUintPow2SRVDescriptor( - descriptor_unscaled_source.first, load_shader_info.source_bpe_log2); - } - command_list.D3DSetComputeRootDescriptorTable( - 1, descriptor_unscaled_source.second); + command_list.D3DSetComputeRootShaderResourceView( + 1, d3d12_shared_memory.GetGPUAddress()); } // Submit the copy buffer population commands. @@ -1656,20 +1577,15 @@ bool D3D12TextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture, uint32_t guest_size_unscaled = is_base ? d3d12_texture.GetGuestBaseSize() : d3d12_texture.GetGuestMipsSize(); if (!MakeScaledResolveRangeCurrent(guest_address, guest_size_unscaled, - load_shader_info.source_bpe_log2)) { + 4)) { command_processor_.ReleaseScratchGPUBuffer(copy_buffer, copy_buffer_state); return false; } TransitionCurrentScaledResolveRange( D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); - assert_true(descriptor_write_index < descriptor_count); - ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor_scaled_source = - descriptors_allocated[descriptor_write_index++]; - CreateCurrentScaledResolveRangeUintPow2SRV( - descriptor_scaled_source.first, load_shader_info.source_bpe_log2); - command_list.D3DSetComputeRootDescriptorTable( - 1, descriptor_scaled_source.second); + command_list.D3DSetComputeRootShaderResourceView( + 1, GetCurrentScaledResolveRangeGPUAddress()); if (!is_base) { scaled_mips_source_set_up = true; } diff --git a/src/xenia/gpu/d3d12/d3d12_texture_cache.h b/src/xenia/gpu/d3d12/d3d12_texture_cache.h index d03244774..703d09247 100644 --- a/src/xenia/gpu/d3d12/d3d12_texture_cache.h +++ b/src/xenia/gpu/d3d12/d3d12_texture_cache.h @@ -137,13 +137,9 @@ class D3D12TextureCache final : public TextureCache { bool MakeScaledResolveRangeCurrent(uint32_t start_unscaled, uint32_t length_unscaled, uint32_t length_scaled_alignment_log2 = 0); - // These functions create a view of the range specified in the last successful - // MakeScaledResolveRangeCurrent call because that function must be called - // before this. - void CreateCurrentScaledResolveRangeUintPow2SRV( - D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2); - void CreateCurrentScaledResolveRangeUintPow2UAV( - D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2); + // Returns the GPU address of the range specified in the last successful + // MakeScaledResolveRangeCurrent call. + D3D12_GPU_VIRTUAL_ADDRESS GetCurrentScaledResolveRangeGPUAddress() const; void TransitionCurrentScaledResolveRange(D3D12_RESOURCE_STATES new_state); void MarkCurrentScaledResolveRangeUAVWritesCommitNeeded() { assert_true(IsDrawResolutionScaled()); diff --git a/src/xenia/gpu/d3d12/deferred_command_list.cc b/src/xenia/gpu/d3d12/deferred_command_list.cc index b0f0f49f0..feb58e7b1 100644 --- a/src/xenia/gpu/d3d12/deferred_command_list.cc +++ b/src/xenia/gpu/d3d12/deferred_command_list.cc @@ -183,15 +183,13 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list, } break; case Command::kD3DSetComputeRootConstantBufferView: { auto& args = - *reinterpret_cast( - stream); + *reinterpret_cast(stream); command_list->SetComputeRootConstantBufferView( args.root_parameter_index, args.buffer_location); } break; case Command::kD3DSetGraphicsRootConstantBufferView: { auto& args = - *reinterpret_cast( - stream); + *reinterpret_cast(stream); command_list->SetGraphicsRootConstantBufferView( args.root_parameter_index, args.buffer_location); } break; @@ -207,6 +205,18 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list, command_list->SetGraphicsRootDescriptorTable(args.root_parameter_index, args.base_descriptor); } break; + case Command::kD3DSetComputeRootShaderResourceView: { + auto& args = + *reinterpret_cast(stream); + command_list->SetComputeRootShaderResourceView( + args.root_parameter_index, args.buffer_location); + } break; + case Command::kD3DSetGraphicsRootShaderResourceView: { + auto& args = + *reinterpret_cast(stream); + command_list->SetGraphicsRootShaderResourceView( + args.root_parameter_index, args.buffer_location); + } break; case Command::kD3DSetComputeRootSignature: { command_list->SetComputeRootSignature( *reinterpret_cast(stream)); @@ -215,6 +225,18 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list, command_list->SetGraphicsRootSignature( *reinterpret_cast(stream)); } break; + case Command::kD3DSetComputeRootUnorderedAccessView: { + auto& args = + *reinterpret_cast(stream); + command_list->SetComputeRootUnorderedAccessView( + args.root_parameter_index, args.buffer_location); + } break; + case Command::kD3DSetGraphicsRootUnorderedAccessView: { + auto& args = + *reinterpret_cast(stream); + command_list->SetGraphicsRootUnorderedAccessView( + args.root_parameter_index, args.buffer_location); + } break; case Command::kSetDescriptorHeaps: { auto& args = *reinterpret_cast(stream); diff --git a/src/xenia/gpu/d3d12/deferred_command_list.h b/src/xenia/gpu/d3d12/deferred_command_list.h index 16b70a1e8..4cf7f1b38 100644 --- a/src/xenia/gpu/d3d12/deferred_command_list.h +++ b/src/xenia/gpu/d3d12/deferred_command_list.h @@ -327,18 +327,18 @@ class DeferredCommandList { void D3DSetComputeRootConstantBufferView( UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS buffer_location) { - auto& args = *reinterpret_cast( + auto& args = *reinterpret_cast( WriteCommand(Command::kD3DSetComputeRootConstantBufferView, - sizeof(SetRootConstantBufferViewArguments))); + sizeof(SetRootDescriptorArguments))); args.root_parameter_index = root_parameter_index; args.buffer_location = buffer_location; } void D3DSetGraphicsRootConstantBufferView( UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS buffer_location) { - auto& args = *reinterpret_cast( + auto& args = *reinterpret_cast( WriteCommand(Command::kD3DSetGraphicsRootConstantBufferView, - sizeof(SetRootConstantBufferViewArguments))); + sizeof(SetRootDescriptorArguments))); args.root_parameter_index = root_parameter_index; args.buffer_location = buffer_location; } @@ -361,6 +361,24 @@ class DeferredCommandList { args.base_descriptor.ptr = base_descriptor.ptr; } + void D3DSetComputeRootShaderResourceView( + UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS buffer_location) { + auto& args = *reinterpret_cast( + WriteCommand(Command::kD3DSetComputeRootShaderResourceView, + sizeof(SetRootDescriptorArguments))); + args.root_parameter_index = root_parameter_index; + args.buffer_location = buffer_location; + } + + void D3DSetGraphicsRootShaderResourceView( + UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS buffer_location) { + auto& args = *reinterpret_cast( + WriteCommand(Command::kD3DSetGraphicsRootShaderResourceView, + sizeof(SetRootDescriptorArguments))); + args.root_parameter_index = root_parameter_index; + args.buffer_location = buffer_location; + } + void D3DSetComputeRootSignature(ID3D12RootSignature* root_signature) { auto& arg = *reinterpret_cast(WriteCommand( Command::kD3DSetComputeRootSignature, sizeof(ID3D12RootSignature*))); @@ -373,6 +391,24 @@ class DeferredCommandList { arg = root_signature; } + void D3DSetComputeRootUnorderedAccessView( + UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS buffer_location) { + auto& args = *reinterpret_cast( + WriteCommand(Command::kD3DSetComputeRootUnorderedAccessView, + sizeof(SetRootDescriptorArguments))); + args.root_parameter_index = root_parameter_index; + args.buffer_location = buffer_location; + } + + void D3DSetGraphicsRootUnorderedAccessView( + UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS buffer_location) { + auto& args = *reinterpret_cast( + WriteCommand(Command::kD3DSetGraphicsRootUnorderedAccessView, + sizeof(SetRootDescriptorArguments))); + args.root_parameter_index = root_parameter_index; + args.buffer_location = buffer_location; + } + void SetDescriptorHeaps(ID3D12DescriptorHeap* cbv_srv_uav_descriptor_heap, ID3D12DescriptorHeap* sampler_descriptor_heap) { auto& args = *reinterpret_cast(WriteCommand( @@ -432,8 +468,12 @@ class DeferredCommandList { kD3DSetGraphicsRootConstantBufferView, kD3DSetComputeRootDescriptorTable, kD3DSetGraphicsRootDescriptorTable, + kD3DSetComputeRootShaderResourceView, + kD3DSetGraphicsRootShaderResourceView, kD3DSetComputeRootSignature, kD3DSetGraphicsRootSignature, + kD3DSetComputeRootUnorderedAccessView, + kD3DSetGraphicsRootUnorderedAccessView, kSetDescriptorHeaps, kD3DSetPipelineState, kSetPipelineStateHandle, @@ -541,7 +581,7 @@ class DeferredCommandList { UINT dest_offset_in_32bit_values; }; - struct SetRootConstantBufferViewArguments { + struct SetRootDescriptorArguments { UINT root_parameter_index; D3D12_GPU_VIRTUAL_ADDRESS buffer_location; }; diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index 003575b4b..43d483991 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -94,7 +94,8 @@ PipelineCache::PipelineCache(D3D12CommandProcessor& command_processor, shader_translator_ = std::make_unique( provider.GetAdapterVendorID(), bindless_resources_used_, edram_rov_used, - render_target_cache_.gamma_render_target_as_srgb(), + !(edram_rov_used || + render_target_cache_.gamma_render_target_as_unorm16()), render_target_cache_.msaa_2x_supported(), render_target_cache_.draw_resolution_scale_x(), render_target_cache_.draw_resolution_scale_y(), @@ -387,7 +388,9 @@ void PipelineCache::InitializeShaderStorage( StringBuffer ucode_disasm_buffer; DxbcShaderTranslator translator( provider.GetAdapterVendorID(), bindless_resources_used_, - edram_rov_used, render_target_cache_.gamma_render_target_as_srgb(), + edram_rov_used, + !(edram_rov_used || + render_target_cache_.gamma_render_target_as_unorm16()), render_target_cache_.msaa_2x_supported(), render_target_cache_.draw_resolution_scale_x(), render_target_cache_.draw_resolution_scale_y(), diff --git a/src/xenia/gpu/draw_util.cc b/src/xenia/gpu/draw_util.cc index 54bf697b8..df5e110d9 100644 --- a/src/xenia/gpu/draw_util.cc +++ b/src/xenia/gpu/draw_util.cc @@ -912,15 +912,15 @@ void GetResolveEdramTileSpan(ResolveEdramInfo edram_info, constexpr ResolveCopyShaderInfo resolve_copy_shader_info[size_t(ResolveCopyShaderIndex::kCount)] = { - {"Resolve Copy Fast 32bpp 1x/2xMSAA", false, 4, 4, 6, 3}, - {"Resolve Copy Fast 32bpp 4xMSAA", false, 4, 4, 6, 3}, - {"Resolve Copy Fast 64bpp 1x/2xMSAA", false, 4, 4, 5, 3}, - {"Resolve Copy Fast 64bpp 4xMSAA", false, 3, 4, 5, 3}, - {"Resolve Copy Full 8bpp", true, 2, 3, 6, 3}, - {"Resolve Copy Full 16bpp", true, 2, 3, 5, 3}, - {"Resolve Copy Full 32bpp", true, 2, 4, 5, 3}, - {"Resolve Copy Full 64bpp", true, 2, 4, 5, 3}, - {"Resolve Copy Full 128bpp", true, 2, 4, 4, 3}, + {"Resolve Copy Fast 32bpp 1x/2xMSAA", 6, 3}, + {"Resolve Copy Fast 32bpp 4xMSAA", 6, 3}, + {"Resolve Copy Fast 64bpp 1x/2xMSAA", 5, 3}, + {"Resolve Copy Fast 64bpp 4xMSAA", 5, 3}, + {"Resolve Copy Full 8bpp", 6, 3}, + {"Resolve Copy Full 16bpp", 5, 3}, + {"Resolve Copy Full 32bpp", 5, 3}, + {"Resolve Copy Full 64bpp", 5, 3}, + {"Resolve Copy Full 128bpp", 4, 3}, }; XE_MSVC_OPTIMIZE_SMALL() bool GetResolveInfo(const RegisterFile& regs, const Memory& memory, diff --git a/src/xenia/gpu/draw_util.h b/src/xenia/gpu/draw_util.h index 81770ad8e..bd546592d 100644 --- a/src/xenia/gpu/draw_util.h +++ b/src/xenia/gpu/draw_util.h @@ -591,20 +591,6 @@ enum class ResolveCopyShaderIndex { struct ResolveCopyShaderInfo { // Debug name of the pipeline state object with this shader. const char* debug_name; - // Whether the EDRAM source needs be bound as a raw buffer (ByteAddressBuffer - // in Direct3D) since it can load different numbers of 32-bit values at once - // on some hardware. If the host API doesn't support raw buffers, a typed - // buffer with source_bpe_log2-byte elements needs to be used instead. - bool source_is_raw; - // Log2 of bytes per element of the type of the EDRAM buffer bound to the - // shader (at least 2). - uint32_t source_bpe_log2; - // Log2 of bytes per element of the type of the destination buffer bound to - // the shader (at least 2 because of the 128 megatexel minimum requirement on - // Direct3D 10+ - D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP - that - // prevents binding the entire shared memory buffer with smaller element - // sizes). - uint32_t dest_bpe_log2; // Log2 of number of pixels in a single thread group along X and Y. 64 threads // per group preferred (GCN lane count). uint32_t group_size_x_log2, group_size_y_log2; diff --git a/src/xenia/gpu/dxbc_shader_translator.cc b/src/xenia/gpu/dxbc_shader_translator.cc index 0faa3c5bb..7af15bc95 100644 --- a/src/xenia/gpu/dxbc_shader_translator.cc +++ b/src/xenia/gpu/dxbc_shader_translator.cc @@ -65,7 +65,7 @@ using namespace ucode; DxbcShaderTranslator::DxbcShaderTranslator( ui::GraphicsProvider::GpuVendorID vendor_id, bool bindless_resources_used, - bool edram_rov_used, bool gamma_render_target_as_srgb, + bool edram_rov_used, bool gamma_render_target_as_unorm8, bool msaa_2x_supported, uint32_t draw_resolution_scale_x, uint32_t draw_resolution_scale_y, bool force_emit_source_map) : a_(shader_code_, statistics_), @@ -73,7 +73,7 @@ DxbcShaderTranslator::DxbcShaderTranslator( vendor_id_(vendor_id), bindless_resources_used_(bindless_resources_used), edram_rov_used_(edram_rov_used), - gamma_render_target_as_srgb_(gamma_render_target_as_srgb), + gamma_render_target_as_unorm8_(gamma_render_target_as_unorm8), msaa_2x_supported_(msaa_2x_supported), draw_resolution_scale_x_(draw_resolution_scale_x), draw_resolution_scale_y_(draw_resolution_scale_y), @@ -222,9 +222,10 @@ void DxbcShaderTranslator::PopSystemTemp(uint32_t count) { } void DxbcShaderTranslator::PWLGammaToLinear( - uint32_t target_temp, uint32_t target_temp_component, uint32_t source_temp, - uint32_t source_temp_component, bool source_pre_saturated, uint32_t temp1, - uint32_t temp1_component, uint32_t temp2, uint32_t temp2_component) { + dxbc::Assembler& a, uint32_t target_temp, uint32_t target_temp_component, + uint32_t source_temp, uint32_t source_temp_component, + bool source_pre_saturated, uint32_t temp1, uint32_t temp1_component, + uint32_t temp2, uint32_t temp2_component) { // The source is needed only once to begin building the result, so it can be // the same as the destination. assert_true(temp1 != target_temp || temp1_component != target_temp_component); @@ -245,25 +246,25 @@ void DxbcShaderTranslator::PWLGammaToLinear( // Using `source >= threshold` comparisons because the input might have not // been saturated yet, and thus it may be NaN - since it will be saturated to // 0 later, the 0...64/255 case should be selected for it. - a_.OpGE(temp2_dest, source_src, dxbc::Src::LF(96.0f / 255.0f)); - a_.OpIf(true, temp2_src); + a.OpGE(temp2_dest, source_src, dxbc::Src::LF(96.0f / 255.0f)); + a.OpIf(true, temp2_src); // [96/255 ... 1 - a_.OpGE(temp2_dest, source_src, dxbc::Src::LF(192.0f / 255.0f)); - a_.OpMovC(temp1_dest, temp2_src, dxbc::Src::LF(8.0f / 1024.0f), - dxbc::Src::LF(4.0f / 1024.0f)); - a_.OpMovC(temp2_dest, temp2_src, dxbc::Src::LF(-1024.0f), - dxbc::Src::LF(-256.0f)); - a_.OpElse(); + a.OpGE(temp2_dest, source_src, dxbc::Src::LF(192.0f / 255.0f)); + a.OpMovC(temp1_dest, temp2_src, dxbc::Src::LF(8.0f / 1024.0f), + dxbc::Src::LF(4.0f / 1024.0f)); + a.OpMovC(temp2_dest, temp2_src, dxbc::Src::LF(-1024.0f), + dxbc::Src::LF(-256.0f)); + a.OpElse(); // 0 ... 96/255) - a_.OpGE(temp2_dest, source_src, dxbc::Src::LF(64.0f / 255.0f)); - a_.OpMovC(temp1_dest, temp2_src, dxbc::Src::LF(2.0f / 1024.0f), - dxbc::Src::LF(1.0f / 1024.0f)); - a_.OpMovC(temp2_dest, temp2_src, dxbc::Src::LF(-64.0f), dxbc::Src::LF(0.0f)); - a_.OpEndIf(); + a.OpGE(temp2_dest, source_src, dxbc::Src::LF(64.0f / 255.0f)); + a.OpMovC(temp1_dest, temp2_src, dxbc::Src::LF(2.0f / 1024.0f), + dxbc::Src::LF(1.0f / 1024.0f)); + a.OpMovC(temp2_dest, temp2_src, dxbc::Src::LF(-64.0f), dxbc::Src::LF(0.0f)); + a.OpEndIf(); if (!source_pre_saturated) { // Saturate the input, and flush NaN to 0. - a_.OpMov(target_dest, source_src, true); + a.OpMov(target_dest, source_src, true); } // linear = gamma * (255 * 1024) * scale + offset // As both 1024 and the scale are powers of 2, and 1024 * scale is not smaller @@ -272,22 +273,22 @@ void DxbcShaderTranslator::PWLGammaToLinear( // gamma * (255 * 1024 * scale) - or the option chosen here, as long as // 1024 is applied before the scale since the scale is < 1 (specifically at // least 1/1024), and it may make very small values denormal. - a_.OpMul(target_dest, source_pre_saturated ? source_src : target_src, - dxbc::Src::LF(255.0f * 1024.0f)); - a_.OpMAd(target_dest, target_src, temp1_src, temp2_src); + a.OpMul(target_dest, source_pre_saturated ? source_src : target_src, + dxbc::Src::LF(255.0f * 1024.0f)); + a.OpMAd(target_dest, target_src, temp1_src, temp2_src); // linear += trunc(linear * scale) - a_.OpMul(temp1_dest, target_src, temp1_src); - a_.OpRoundZ(temp1_dest, temp1_src); - a_.OpAdd(target_dest, target_src, temp1_src); + a.OpMul(temp1_dest, target_src, temp1_src); + a.OpRoundZ(temp1_dest, temp1_src); + a.OpAdd(target_dest, target_src, temp1_src); // linear *= 1/1023 - a_.OpMul(target_dest, target_src, dxbc::Src::LF(1.0f / 1023.0f)); + a.OpMul(target_dest, target_src, dxbc::Src::LF(1.0f / 1023.0f)); } void DxbcShaderTranslator::PreSaturatedLinearToPWLGamma( - uint32_t target_temp, uint32_t target_temp_component, uint32_t source_temp, - uint32_t source_temp_component, uint32_t temp_or_target, - uint32_t temp_or_target_component, uint32_t temp_non_target, - uint32_t temp_non_target_component) { + dxbc::Assembler& a, uint32_t target_temp, uint32_t target_temp_component, + uint32_t source_temp, uint32_t source_temp_component, + uint32_t temp_or_target, uint32_t temp_or_target_component, + uint32_t temp_non_target, uint32_t temp_non_target_component) { // The source may be the same as the target, but in this case it can't also be // used as a temporary variable. assert_true(target_temp != source_temp || @@ -317,28 +318,28 @@ void DxbcShaderTranslator::PreSaturatedLinearToPWLGamma( // Get the scale (into temp_or_target) and the offset (into temp_non_target) // for the piece. - a_.OpGE(temp_non_target_dest, source_src, dxbc::Src::LF(128.0f / 1023.0f)); - a_.OpIf(true, temp_non_target_src); + a.OpGE(temp_non_target_dest, source_src, dxbc::Src::LF(128.0f / 1023.0f)); + a.OpIf(true, temp_non_target_src); // [128/1023 ... 1 - a_.OpGE(temp_non_target_dest, source_src, dxbc::Src::LF(512.0f / 1023.0f)); - a_.OpMovC(temp_or_target_dest, temp_non_target_src, - dxbc::Src::LF(1023.0f / 8.0f), dxbc::Src::LF(1023.0f / 4.0f)); - a_.OpMovC(temp_non_target_dest, temp_non_target_src, - dxbc::Src::LF(128.0f / 255.0f), dxbc::Src::LF(64.0f / 255.0f)); - a_.OpElse(); + a.OpGE(temp_non_target_dest, source_src, dxbc::Src::LF(512.0f / 1023.0f)); + a.OpMovC(temp_or_target_dest, temp_non_target_src, + dxbc::Src::LF(1023.0f / 8.0f), dxbc::Src::LF(1023.0f / 4.0f)); + a.OpMovC(temp_non_target_dest, temp_non_target_src, + dxbc::Src::LF(128.0f / 255.0f), dxbc::Src::LF(64.0f / 255.0f)); + a.OpElse(); // 0 ... 128/1023) - a_.OpGE(temp_non_target_dest, source_src, dxbc::Src::LF(64.0f / 1023.0f)); - a_.OpMovC(temp_or_target_dest, temp_non_target_src, - dxbc::Src::LF(1023.0f / 2.0f), dxbc::Src::LF(1023.0f)); - a_.OpMovC(temp_non_target_dest, temp_non_target_src, - dxbc::Src::LF(32.0f / 255.0f), dxbc::Src::LF(0.0f)); - a_.OpEndIf(); + a.OpGE(temp_non_target_dest, source_src, dxbc::Src::LF(64.0f / 1023.0f)); + a.OpMovC(temp_or_target_dest, temp_non_target_src, + dxbc::Src::LF(1023.0f / 2.0f), dxbc::Src::LF(1023.0f)); + a.OpMovC(temp_non_target_dest, temp_non_target_src, + dxbc::Src::LF(32.0f / 255.0f), dxbc::Src::LF(0.0f)); + a.OpEndIf(); // gamma = trunc(linear * scale) * (1.0 / 255.0) + offset - a_.OpMul(target_dest, source_src, temp_or_target_src); - a_.OpRoundZ(target_dest, target_src); - a_.OpMAd(target_dest, target_src, dxbc::Src::LF(1.0f / 255.0f), - temp_non_target_src); + a.OpMul(target_dest, source_src, temp_or_target_src); + a.OpRoundZ(target_dest, target_src); + a.OpMAd(target_dest, target_src, dxbc::Src::LF(1.0f / 255.0f), + temp_non_target_src); } void DxbcShaderTranslator::RemapAndConvertVertexIndices( @@ -2135,7 +2136,8 @@ constexpr DxbcShaderTranslator::SystemConstantRdef {"xe_texture_swizzled_signs", ShaderRdefTypeIndex::kUint4Array2, sizeof(uint32_t) * 4 * 2}, - {"xe_textures_resolved", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, + {"xe_textures_resolution_scaled", ShaderRdefTypeIndex::kUint, + sizeof(uint32_t)}, {"xe_sample_count_log2", ShaderRdefTypeIndex::kUint2, sizeof(uint32_t) * 2}, {"xe_alpha_test_reference", ShaderRdefTypeIndex::kFloat, sizeof(float)}, diff --git a/src/xenia/gpu/dxbc_shader_translator.h b/src/xenia/gpu/dxbc_shader_translator.h index 6af1ce0b0..2b5e8599c 100644 --- a/src/xenia/gpu/dxbc_shader_translator.h +++ b/src/xenia/gpu/dxbc_shader_translator.h @@ -49,7 +49,7 @@ class DxbcShaderTranslator : public ShaderTranslator { public: DxbcShaderTranslator(ui::GraphicsProvider::GpuVendorID vendor_id, bool bindless_resources_used, bool edram_rov_used, - bool gamma_render_target_as_srgb = false, + bool gamma_render_target_as_unorm8 = false, bool msaa_2x_supported = true, uint32_t draw_resolution_scale_x = 1, uint32_t draw_resolution_scale_y = 1, @@ -316,9 +316,8 @@ class DxbcShaderTranslator : public ShaderTranslator { // components of each of the 32 used texture fetch constants. uint32_t texture_swizzled_signs[8]; - // Whether the contents of each texture in fetch constants comes from a - // resolve operation. - uint32_t textures_resolved; + // Whether each texture in fetch constants contains resolution-scaled data. + uint32_t textures_resolution_scaled; // Log2 of X and Y sample size. Used for alpha to mask, and for MSAA with // ROV, this is used for EDRAM address calculation. uint32_t sample_count_log2[2]; @@ -425,7 +424,7 @@ class DxbcShaderTranslator : public ShaderTranslator { kTextureSwizzledSigns, - kTexturesResolved, + kTexturesResolutionScaled, kSampleCountLog2, kAlphaTestReference, @@ -578,6 +577,26 @@ class DxbcShaderTranslator : public ShaderTranslator { uint32_t temp2_temp_component, bool remap_to_0_to_0_5); + // Converts one scalar from piecewise linear gamma to linear. The target may + // be the same as the source, the temporary variables must be different. If + // the source is not pre-saturated, saturation will be done internally. + static void PWLGammaToLinear(dxbc::Assembler& a, uint32_t target_temp, + uint32_t target_temp_component, + uint32_t source_temp, + uint32_t source_temp_component, + bool source_pre_saturated, uint32_t temp1, + uint32_t temp1_component, uint32_t temp2, + uint32_t temp2_component); + // Converts one scalar, which must be saturated before calling this function, + // from linear to piecewise linear gamma. The target may be the same as either + // the source or as temp_or_target, but not as both (and temp_or_target may + // not be the same as the source). temp_non_target must be different. + static void PreSaturatedLinearToPWLGamma( + dxbc::Assembler& a, uint32_t target_temp, uint32_t target_temp_component, + uint32_t source_temp, uint32_t source_temp_component, + uint32_t temp_or_target, uint32_t temp_or_target_component, + uint32_t temp_non_target, uint32_t temp_non_target_component); + protected: void Reset() override; @@ -689,24 +708,6 @@ class DxbcShaderTranslator : public ShaderTranslator { // inactive. void ExportToMemory(uint8_t export_eM); - // Converts one scalar from piecewise linear gamma to linear. The target may - // be the same as the source, the temporary variables must be different. If - // the source is not pre-saturated, saturation will be done internally. - void PWLGammaToLinear(uint32_t target_temp, uint32_t target_temp_component, - uint32_t source_temp, uint32_t source_temp_component, - bool source_pre_saturated, uint32_t temp1, - uint32_t temp1_component, uint32_t temp2, - uint32_t temp2_component); - // Converts one scalar, which must be saturated before calling this function, - // from linear to piecewise linear gamma. The target may be the same as either - // the source or as temp_or_target, but not as both (and temp_or_target may - // not be the same as the source). temp_non_target must be different. - void PreSaturatedLinearToPWLGamma( - uint32_t target_temp, uint32_t target_temp_component, - uint32_t source_temp, uint32_t source_temp_component, - uint32_t temp_or_target, uint32_t temp_or_target_component, - uint32_t temp_non_target, uint32_t temp_non_target_component); - bool IsSampleRate() const { assert_true(is_pixel_shader()); return DSV_IsWritingFloat24Depth() && !current_shader().writes_depth(); @@ -977,8 +978,9 @@ class DxbcShaderTranslator : public ShaderTranslator { bool edram_rov_used_; // Whether with RTV-based output-merger, k_8_8_8_8_GAMMA render targets are - // represented as host sRGB. - bool gamma_render_target_as_srgb_; + // represented as host 8-bit unsigned normalized, and require conversion in + // translated shaders. + bool gamma_render_target_as_unorm8_; // Whether 2x MSAA is emulated using real 2x MSAA rather than two samples of // 4x MSAA. diff --git a/src/xenia/gpu/dxbc_shader_translator_fetch.cc b/src/xenia/gpu/dxbc_shader_translator_fetch.cc index cde7812b0..b59c04283 100644 --- a/src/xenia/gpu/dxbc_shader_translator_fetch.cc +++ b/src/xenia/gpu/dxbc_shader_translator_fetch.cc @@ -1068,12 +1068,12 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( if (normalized_components_with_scaled_offsets) { // Using coord_and_sampler_temp.w as a temporary for the needed // resolution scale inverse - sampler not loaded yet. - a_.OpAnd( - dxbc::Dest::R(coord_and_sampler_temp, 0b1000), - LoadSystemConstant(SystemConstants::Index::kTexturesResolved, - offsetof(SystemConstants, textures_resolved), - dxbc::Src::kXXXX), - dxbc::Src::LU(uint32_t(1) << tfetch_index)); + a_.OpAnd(dxbc::Dest::R(coord_and_sampler_temp, 0b1000), + LoadSystemConstant( + SystemConstants::Index::kTexturesResolutionScaled, + offsetof(SystemConstants, textures_resolution_scaled), + dxbc::Src::kXXXX), + dxbc::Src::LU(uint32_t(1) << tfetch_index)); a_.OpIf(true, dxbc::Src::R(coord_and_sampler_temp, dxbc::Src::kWWWW)); a_.OpAdd( dxbc::Dest::R(coord_and_sampler_temp, @@ -1137,12 +1137,12 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( if (normalized_components_with_scaled_offsets) { // Using coord_and_sampler_temp.w as a temporary for the needed // resolution scale inverse - sampler not loaded yet. - a_.OpAnd( - dxbc::Dest::R(coord_and_sampler_temp, 0b1000), - LoadSystemConstant(SystemConstants::Index::kTexturesResolved, - offsetof(SystemConstants, textures_resolved), - dxbc::Src::kXXXX), - dxbc::Src::LU(uint32_t(1) << tfetch_index)); + a_.OpAnd(dxbc::Dest::R(coord_and_sampler_temp, 0b1000), + LoadSystemConstant( + SystemConstants::Index::kTexturesResolutionScaled, + offsetof(SystemConstants, textures_resolution_scaled), + dxbc::Src::kXXXX), + dxbc::Src::LU(uint32_t(1) << tfetch_index)); a_.OpIf(true, dxbc::Src::R(coord_and_sampler_temp, dxbc::Src::kWWWW)); a_.OpMAd(dxbc::Dest::R(coord_and_sampler_temp, normalized_components_with_scaled_offsets), @@ -2055,56 +2055,9 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( a_.OpBreak(); a_.OpCase(dxbc::Src::LU(uint32_t(xenos::TextureSign::kGamma))); uint32_t gamma_temp = PushSystemTemp(); - if (gamma_render_target_as_srgb_) { - // Check if the texture has sRGB rather that piecewise linear gamma. - // More likely that it's just a texture with PWL, put this case in the - // `if`, with `else` for sRGB resolved render targets. - a_.OpAnd( - dxbc::Dest::R(gamma_temp, 0b0001), - LoadSystemConstant(SystemConstants::Index::kTexturesResolved, - offsetof(SystemConstants, textures_resolved), - dxbc::Src::kXXXX), - dxbc::Src::LU(uint32_t(1) << tfetch_index)); - a_.OpIf(false, dxbc::Src::R(gamma_temp, dxbc::Src::kXXXX)); - } // Convert from piecewise linear. - PWLGammaToLinear(system_temp_result_, i, system_temp_result_, i, false, - gamma_temp, 0, gamma_temp, 1); - if (gamma_render_target_as_srgb_) { - a_.OpElse(); - // Convert from sRGB. - a_.OpMov(component_dest, component_src, true); - a_.OpGE(dxbc::Dest::R(gamma_temp, 0b0001), - dxbc::Src::LF(RenderTargetCache::kSrgbToLinearThreshold), - component_src); - a_.OpIf(true, dxbc::Src::R(gamma_temp, dxbc::Src::kXXXX)); - // sRGB <= kSrgbToLinearThreshold case - linear scale. - a_.OpMul(component_dest, component_src, - dxbc::Src::LF(1.0f / - RenderTargetCache::kSrgbToLinearDenominator1)); - a_.OpElse(); - // sRGB > kSrgbToLinearThreshold case. - // 0 and 1 must be exactly achievable - only convert when the - // saturated value is < 1. - a_.OpLT(dxbc::Dest::R(gamma_temp, 0b0001), component_src, - dxbc::Src::LF(1.0f)); - a_.OpIf(true, dxbc::Src::R(gamma_temp, dxbc::Src::kXXXX)); - a_.OpMAd(component_dest, component_src, - dxbc::Src::LF(1.0f / - RenderTargetCache::kSrgbToLinearDenominator2), - dxbc::Src::LF(RenderTargetCache::kSrgbToLinearOffset / - RenderTargetCache::kSrgbToLinearDenominator2)); - a_.OpLog(component_dest, component_src); - a_.OpMul(component_dest, component_src, - dxbc::Src::LF(RenderTargetCache::kSrgbToLinearExponent)); - a_.OpExp(component_dest, component_src); - // Close the < 1 check. - a_.OpEndIf(); - // Close the sRGB <= kSrgbToLinearThreshold check. - a_.OpEndIf(); - // Close the PWL or sRGB check. - a_.OpEndIf(); - } + PWLGammaToLinear(a_, system_temp_result_, i, system_temp_result_, i, + false, gamma_temp, 0, gamma_temp, 1); // Release gamma_temp. PopSystemTemp(); a_.OpBreak(); diff --git a/src/xenia/gpu/dxbc_shader_translator_om.cc b/src/xenia/gpu/dxbc_shader_translator_om.cc index 001be04b4..a181008ed 100644 --- a/src/xenia/gpu/dxbc_shader_translator_om.cc +++ b/src/xenia/gpu/dxbc_shader_translator_om.cc @@ -1197,7 +1197,7 @@ void DxbcShaderTranslator::ROV_UnpackColor( dxbc::Src::LF(1.0f / 255.0f)); if (i) { for (uint32_t j = 0; j < 3; ++j) { - PWLGammaToLinear(color_temp, j, color_temp, j, true, temp1, + PWLGammaToLinear(a_, color_temp, j, color_temp, j, true, temp1, temp1_component, temp2, temp2_component); } } @@ -1350,7 +1350,7 @@ void DxbcShaderTranslator::ROV_PackPreClampedColor( : xenos::ColorRenderTargetFormat::k_8_8_8_8))); for (uint32_t j = 0; j < 4; ++j) { if (i && j < 3) { - PreSaturatedLinearToPWLGamma(temp1, temp1_component, color_temp, j, + PreSaturatedLinearToPWLGamma(a_, temp1, temp1_component, color_temp, j, temp1, temp1_component, temp2, temp2_component); // Denormalize and add 0.5 for rounding. @@ -1685,7 +1685,7 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToRTVs() { SystemConstants::Index::kColorExpBias, offsetof(SystemConstants, color_exp_bias) + sizeof(float) * i, dxbc::Src::kXXXX)); - if (!gamma_render_target_as_srgb_) { + if (gamma_render_target_as_unorm8_) { // Convert to gamma space - this is incorrect, since it must be done after // blending on the Xbox 360, but this is just one of many blending issues // in the RTV path. @@ -1696,8 +1696,9 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToRTVs() { a_.OpMov(dxbc::Dest::R(system_temp_color, 0b0111), dxbc::Src::R(system_temp_color), true); for (uint32_t j = 0; j < 3; ++j) { - PreSaturatedLinearToPWLGamma(system_temp_color, j, system_temp_color, j, - gamma_temp, 0, gamma_temp, 1); + PreSaturatedLinearToPWLGamma(a_, system_temp_color, j, + system_temp_color, j, gamma_temp, 0, + gamma_temp, 1); } a_.OpEndIf(); } diff --git a/src/xenia/gpu/render_target_cache.cc b/src/xenia/gpu/render_target_cache.cc index e8887535e..b8574954e 100644 --- a/src/xenia/gpu/render_target_cache.cc +++ b/src/xenia/gpu/render_target_cache.cc @@ -144,16 +144,15 @@ DEFINE_bool( "into account for render-to-texture, for more correct shadow filtering, " "bloom, etc., in some cases.", "GPU"); -// Disabled by default because of full-screen effects that occur when game -// shaders assume piecewise linear (4541080F), much more severe than -// blending-related issues. DEFINE_bool( - gamma_render_target_as_srgb, false, - "When the host can't write piecewise linear gamma directly with correct " - "blending, use sRGB output on the host for conceptually correct blending " - "in linear color space while having slightly different precision " - "distribution in the render target and severely incorrect values if the " - "game accesses the resulting colors directly as raw data.", + gamma_render_target_as_unorm16, true, + "When the host can't write 8 bits per component pixels with piecewise " + "linear gamma encoding directly with correct blending, use the 16-bit " + "unsigned normalized format, if supported, for conceptually correct " + "8_8_8_8_GAMMA render target format blending in linear color space. " + "Greatly increases accuracy for this format, but may result in render " + "target copying costs if the game switches between 8_8_8_8_GAMMA and " + "8_8_8_8 views for the same EDRAM render target.", "GPU"); DEFINE_bool( mrt_edram_used_range_clamp_to_min, true, @@ -630,7 +629,6 @@ bool RenderTargetCache::Update(bool is_rasterization_done, uint32_t edram_bases[1 + xenos::kMaxColorRenderTargets]; uint32_t resource_formats[1 + xenos::kMaxColorRenderTargets]; uint32_t rts_are_64bpp = 0; - uint32_t color_rts_are_gamma = 0; if (is_rasterization_done) { if (normalized_depth_control.z_enable || normalized_depth_control.stencil_enable) { @@ -659,9 +657,6 @@ bool RenderTargetCache::Update(bool is_rasterization_done, if (is_64bpp) { rts_are_64bpp |= uint32_t(1) << rt_bit_index; } - if (color_format == xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { - color_rts_are_gamma |= uint32_t(1) << i; - } xenos::ColorRenderTargetFormat color_resource_format; if (interlock_barrier_only) { // Only changes in mapping between coordinates and addresses are @@ -747,7 +742,6 @@ bool RenderTargetCache::Update(bool is_rasterization_done, if (!are_accumulated_render_targets_valid_) { std::memset(last_update_accumulated_render_targets_, 0, sizeof(last_update_accumulated_render_targets_)); - last_update_accumulated_color_targets_are_gamma_ = 0; } return true; } @@ -958,26 +952,13 @@ bool RenderTargetCache::Update(bool is_rasterization_done, std::memcpy(last_update_accumulated_render_targets_, last_update_used_render_targets_, sizeof(last_update_accumulated_render_targets_)); - last_update_accumulated_color_targets_are_gamma_ = 0; are_accumulated_render_targets_valid_ = true; } - // Only update color space of render targets that actually matter here, don't - // disable gamma emulation (which may require ending the render pass) on the - // host, for example, if making a depth-only draw between color draws with a - // gamma target. - uint32_t color_rts_used_bits = depth_and_color_rts_used_bits >> 1; - // Ignore any render targets dropped before in this function for any reason. - color_rts_are_gamma &= color_rts_used_bits; - last_update_accumulated_color_targets_are_gamma_ = - (last_update_accumulated_color_targets_are_gamma_ & - ~color_rts_used_bits) | - color_rts_are_gamma; return true; } uint32_t RenderTargetCache::GetLastUpdateBoundRenderTargets( - bool distinguish_gamma_formats, uint32_t* depth_and_color_formats_out) const { if (GetPath() != Path::kHostRenderTargets) { if (depth_and_color_formats_out) { @@ -998,12 +979,7 @@ uint32_t RenderTargetCache::GetLastUpdateBoundRenderTargets( } rts_used |= uint32_t(1) << i; if (depth_and_color_formats_out) { - depth_and_color_formats_out[i] = - (distinguish_gamma_formats && i && - (last_update_accumulated_color_targets_are_gamma_ & - (uint32_t(1) << (i - 1)))) - ? uint32_t(xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) - : render_target->key().resource_format; + depth_and_color_formats_out[i] = render_target->key().resource_format; } } return rts_used; diff --git a/src/xenia/gpu/render_target_cache.h b/src/xenia/gpu/render_target_cache.h index ec592c562..c619541c8 100644 --- a/src/xenia/gpu/render_target_cache.h +++ b/src/xenia/gpu/render_target_cache.h @@ -32,7 +32,7 @@ DECLARE_bool(depth_transfer_not_equal_test); DECLARE_bool(depth_float24_round); DECLARE_bool(depth_float24_convert_in_pixel_shader); DECLARE_bool(draw_resolution_scaled_texture_offsets); -DECLARE_bool(gamma_render_target_as_srgb); +DECLARE_bool(gamma_render_target_as_unorm16); DECLARE_bool(native_2x_msaa); DECLARE_bool(native_stencil_value_output); DECLARE_bool(snorm16_render_target_full_range); @@ -72,12 +72,16 @@ class RenderTargetCache { // - 16_16_FLOAT, k_16_16_16_16_FLOAT - the Xenos float16 doesn't have // special values. // Significant differences: - // - 8_8_8_8_GAMMA - the piecewise linear gamma curve is very different than - // sRGB, one possible path is conversion in shaders (resulting in - // incorrect blending, especially visible on decals in 4D5307E6), another - // is using sRGB render targets and either conversion on resolve or - // reading the resolved data as a true sRGB texture (incorrect when the - // game accesses the data directly, like 4541080F). + // - 8_8_8_8_GAMMA - the piecewise linear gamma precision distribution + // encoding is very different from sRGB. Linear space blending can be + // obtained by promoting to R16G16B16A16_UNORM, but for compact storage, + // conversion in pixel shader output may be done, though it results in + // incorrect blending, especially visible on decals in 4D5307E6. Emulating + // by replacing the encoding with sRGB for render target writes and + // resolved texture reads could work for some games, but certain games, + // such as 4541080F, perform piecewise gamma encoding calculations in + // their code, and that produces noticeably incorrect results if the + // encoding is changed in guest texture memory. // - 2_10_10_10_FLOAT - ranges significantly different than in float16, much // smaller RGB range, and alpha is fixed-point and has only 2 bits. // - 16_16, 16_16_16_16 - has -32 to 32 range, not -1 to 1 - need either to @@ -91,28 +95,6 @@ class RenderTargetCache { kPixelShaderInterlock, }; - // Useful host-specific values. - // sRGB conversion from the Direct3D 11.3 functional specification. - static constexpr float kSrgbToLinearDenominator1 = 12.92f; - static constexpr float kSrgbToLinearDenominator2 = 1.055f; - static constexpr float kSrgbToLinearExponent = 2.4f; - static constexpr float kSrgbToLinearOffset = 0.055f; - static constexpr float kSrgbToLinearThreshold = 0.04045f; - static constexpr float SrgbToLinear(float srgb) { - // 0 and 1 must be exactly achievable, also convert NaN to 0. - if (!(srgb > 0.0f)) { - return 0.0f; - } - if (!(srgb < 1.0f)) { - return 1.0f; - } - if (srgb <= kSrgbToLinearThreshold) { - return srgb / kSrgbToLinearDenominator1; - } - return std::pow((srgb + kSrgbToLinearOffset) / kSrgbToLinearDenominator2, - kSrgbToLinearExponent); - } - // Pixel shader interlock implementation helpers. // Appended to the format in the format constant via bitwise OR. @@ -221,7 +203,6 @@ class RenderTargetCache { // formats (resource formats, but if needed, with gamma taken into account) of // each. uint32_t GetLastUpdateBoundRenderTargets( - bool distinguish_gamma_formats, uint32_t* depth_and_color_formats_out = nullptr) const; protected: @@ -238,6 +219,8 @@ class RenderTargetCache { const RegisterFile& register_file() const { return register_file_; } + virtual bool IsGammaFormatHostStorageSeparate() const = 0; + // Call last in implementation-specific initialization (when things like path // are initialized by the implementation). void InitializeCommon(); @@ -274,7 +257,7 @@ class RenderTargetCache { uint32_t pitch_tiles_at_32bpp : 8; // 19 xenos::MsaaSamples msaa_samples : xenos::kMsaaSamplesBits; // 21 uint32_t is_depth : 1; // 22 - // Ignoring the blending precision and sRGB. + // Ignoring the blending precision. uint32_t resource_format : xenos::kRenderTargetFormatBits; // 26 }; @@ -548,10 +531,6 @@ class RenderTargetCache { assert_true(GetPath() == Path::kHostRenderTargets); return last_update_accumulated_render_targets_; } - uint32_t last_update_accumulated_color_targets_are_gamma() const { - assert_true(GetPath() == Path::kHostRenderTargets); - return last_update_accumulated_color_targets_are_gamma_; - } const std::vector* last_update_transfers() const { assert_true(GetPath() == Path::kHostRenderTargets); @@ -697,11 +676,10 @@ class RenderTargetCache { } }; - static constexpr xenos::ColorRenderTargetFormat GetColorResourceFormat( - xenos::ColorRenderTargetFormat format) { - // sRGB, if used on the host, is a view property or global state - linear - // and sRGB host render targets can share data directly without transfers. - if (format == xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { + xenos::ColorRenderTargetFormat GetColorResourceFormat( + xenos::ColorRenderTargetFormat format) const { + if (format == xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA && + !IsGammaFormatHostStorageSeparate()) { return xenos::ColorRenderTargetFormat::k_8_8_8_8; } return xenos::GetStorageColorFormat(format); @@ -755,10 +733,6 @@ class RenderTargetCache { RenderTarget* last_update_accumulated_render_targets_[1 + xenos::kMaxColorRenderTargets]; - // Whether the color render targets (in bits 0...3) from the last successful - // update have k_8_8_8_8_GAMMA format, for sRGB emulation on the host if - // needed. - uint32_t last_update_accumulated_color_targets_are_gamma_; // If false, the next update must copy last_update_used_render_targets_ to // last_update_accumulated_render_targets_ - it's not beneficial or even // incorrect to keep the previously bound render targets. diff --git a/src/xenia/gpu/shaders/edram.xesli b/src/xenia/gpu/shaders/edram.xesli index 28029e6da..a306c45fa 100644 --- a/src/xenia/gpu/shaders/edram.xesli +++ b/src/xenia/gpu/shaders/edram.xesli @@ -20,10 +20,10 @@ // can't exceed 11 bits, and the modulo operator doesn't need to be performed to // access the data in the render targets that are located in both ends of the // EDRAM at the same time. -uint XeEdramOffsetInts(uint2_xe pixel_index, uint base_tiles, bool wrap, - uint pitch_tiles, uint msaa_samples, bool is_depth, - uint format_ints_log2, uint pixel_sample_index, - uint2_xe resolution_scale) { +uint XeEdramOffsetBytes(uint2_xe pixel_index, uint base_tiles, bool wrap, + uint pitch_tiles, uint msaa_samples, bool is_depth, + uint format_ints_log2, uint pixel_sample_index, + uint2_xe resolution_scale) { uint2_xe rt_sample_index = pixel_index << uint2_xe(greater_than_equal_xe( @@ -54,7 +54,7 @@ uint XeEdramOffsetInts(uint2_xe pixel_index, uint base_tiles, bool wrap, // EDRAM addressing is periodic (modulo the EDRAM size). address %= tile_size_at_32bpp.x * tile_size_at_32bpp.y * 2048u; } - return address; + return address << 2; } #endif // XENIA_GPU_SHADERS_EDRAM_XESLI_ diff --git a/src/xenia/gpu/shaders/host_depth_store_1xmsaa.cs.xesl b/src/xenia/gpu/shaders/host_depth_store_1xmsaa.cs.xesl index 4e389f1df..17c568960 100644 --- a/src/xenia/gpu/shaders/host_depth_store_1xmsaa.cs.xesl +++ b/src/xenia/gpu/shaders/host_depth_store_1xmsaa.cs.xesl @@ -10,15 +10,15 @@ #include "edram.xesli" #include "host_depth_store.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_host_depth_store_dest, set=0, binding=0, - u0, space0) +byte_buffer_align16_wo_declare_xe(xe_host_depth_store_dest, set=0, binding=0, + u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_HOST_DEPTH_STORE_PUSH_CONSTANTS_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_host_depth_store_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_host_depth_store_dest, buffer(1)) entry_binding_next_xe texture_xe(texture_2d_xe, xe_host_depth_store_source, set=1, binding=0, t0, space0, texture(0)) @@ -40,14 +40,12 @@ entry_inputs_end_code_begin_compute_xe int2_xe pixel_index = int2_xe( XeHostDepthStoreRectUnscaledOrigin(rect_constant) * resolution_scale + (in_global_thread_id_xe.xy << uint2_xe(3u, 0u))); - uint edram_address_int4s = - XeEdramOffsetInts(uint2_xe(pixel_index), 0u, false, - XeHostDepthStoreRTPitchTiles(rt_constant), - kXenosMsaaSamples_1X, false, 0u, 0u, - resolution_scale) - >> 2u; - array_buffer_store_xe( - xe_host_depth_store_dest, edram_address_int4s, + uint edram_address = XeEdramOffsetBytes( + uint2_xe(pixel_index), 0u, false, + XeHostDepthStoreRTPitchTiles(rt_constant), kXenosMsaaSamples_1X, false, + 0u, 0u, resolution_scale); + byte_buffer_align16_store16_xe( + xe_host_depth_store_dest, edram_address, float_bits_to_uint_xe(float4_xe( texel_fetch_2d_xe(xe_host_depth_store_source, pixel_index, 0).r, texel_fetch_2d_xe(xe_host_depth_store_source, @@ -56,8 +54,8 @@ entry_inputs_end_code_begin_compute_xe pixel_index + int2_xe(2, 0), 0).r, texel_fetch_2d_xe(xe_host_depth_store_source, pixel_index + int2_xe(3, 0), 0).r))); - array_buffer_store_xe( - xe_host_depth_store_dest, edram_address_int4s + 1u, + byte_buffer_align16_store16_xe( + xe_host_depth_store_dest, edram_address + 16u, float_bits_to_uint_xe(float4_xe( texel_fetch_2d_xe(xe_host_depth_store_source, pixel_index + int2_xe(4, 0), 0).r, diff --git a/src/xenia/gpu/shaders/host_depth_store_2xmsaa.cs.xesl b/src/xenia/gpu/shaders/host_depth_store_2xmsaa.cs.xesl index 4a974d156..ed11fa507 100644 --- a/src/xenia/gpu/shaders/host_depth_store_2xmsaa.cs.xesl +++ b/src/xenia/gpu/shaders/host_depth_store_2xmsaa.cs.xesl @@ -10,15 +10,15 @@ #include "edram.xesli" #include "host_depth_store.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_host_depth_store_dest, set=0, binding=0, - u0, space0) +byte_buffer_align16_wo_declare_xe(xe_host_depth_store_dest, set=0, binding=0, + u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_HOST_DEPTH_STORE_PUSH_CONSTANTS_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_host_depth_store_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_host_depth_store_dest, buffer(1)) entry_binding_next_xe texture_xe(texture_2d_ms_xe, xe_host_depth_store_source, set=1, binding=0, t0, space0, texture(0)) @@ -41,20 +41,18 @@ entry_inputs_end_code_begin_compute_xe XeHostDepthStoreRectUnscaledOrigin(rect_constant) * resolution_scale + uint2_xe(in_global_thread_id_xe.x << 3u, in_global_thread_id_xe.y >> 1u)); uint dest_sample_index = in_global_thread_id_xe.y & 1u; - uint edram_address_int4s = - XeEdramOffsetInts(uint2_xe(pixel_index), 0u, false, - XeHostDepthStoreRTPitchTiles(rt_constant), - kXenosMsaaSamples_2X, false, 0u, dest_sample_index, - resolution_scale) - >> 2u; + uint edram_address = XeEdramOffsetBytes( + uint2_xe(pixel_index), 0u, false, + XeHostDepthStoreRTPitchTiles(rt_constant), kXenosMsaaSamples_2X, false, + 0u, dest_sample_index, resolution_scale); // Top and bottom to Direct3D 10.1+ and Vulkan top 1 and bottom 0 (for 2x) or // top-left 0 and bottom-right 3 (for 4x). int source_sample_index = XeHostDepthStoreRTMsaa2xSupported(rt_constant) ? (bool(dest_sample_index) ? 0 : 1) : (bool(dest_sample_index) ? 3 : 0); - array_buffer_store_xe( - xe_host_depth_store_dest, edram_address_int4s, + byte_buffer_align16_store16_xe( + xe_host_depth_store_dest, edram_address, float_bits_to_uint_xe(float4_xe( texel_fetch_2d_ms_xe(xe_host_depth_store_source, pixel_index, source_sample_index).r, @@ -67,8 +65,8 @@ entry_inputs_end_code_begin_compute_xe texel_fetch_2d_ms_xe(xe_host_depth_store_source, pixel_index + int2_xe(3, 0), source_sample_index).r))); - array_buffer_store_xe( - xe_host_depth_store_dest, edram_address_int4s + 1u, + byte_buffer_align16_store16_xe( + xe_host_depth_store_dest, edram_address + 16u, float_bits_to_uint_xe(float4_xe( texel_fetch_2d_ms_xe(xe_host_depth_store_source, pixel_index + int2_xe(4, 0), diff --git a/src/xenia/gpu/shaders/host_depth_store_4xmsaa.cs.xesl b/src/xenia/gpu/shaders/host_depth_store_4xmsaa.cs.xesl index f708fe459..f7433488a 100644 --- a/src/xenia/gpu/shaders/host_depth_store_4xmsaa.cs.xesl +++ b/src/xenia/gpu/shaders/host_depth_store_4xmsaa.cs.xesl @@ -10,15 +10,15 @@ #include "edram.xesli" #include "host_depth_store.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_host_depth_store_dest, set=0, binding=0, - u0, space0) +byte_buffer_align16_wo_declare_xe(xe_host_depth_store_dest, set=0, binding=0, + u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_HOST_DEPTH_STORE_PUSH_CONSTANTS_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_host_depth_store_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_host_depth_store_dest, buffer(1)) entry_binding_next_xe texture_xe(texture_2d_ms_xe, xe_host_depth_store_source, set=1, binding=0, t0, space0, texture(0)) @@ -40,18 +40,17 @@ entry_inputs_end_code_begin_compute_xe int2_xe pixel_index = int2_xe( XeHostDepthStoreRectUnscaledOrigin(rect_constant) * resolution_scale + uint2_xe(in_global_thread_id_xe.x << 2u, in_global_thread_id_xe.y >> 1u)); - // For simplicity, passing samples directly, not pixels, to XeEdramOffsetInts. - uint edram_address_int4s = - XeEdramOffsetInts( - (uint2_xe(pixel_index) << 1u) | (in_global_thread_id_xe.xy & 1u), - 0u, false, XeHostDepthStoreRTPitchTiles(rt_constant), - kXenosMsaaSamples_1X, false, 0u, 0u, resolution_scale) - >> 2u; + // For simplicity, passing samples directly, not pixels, to + // XeEdramOffsetBytes. + uint edram_address = XeEdramOffsetBytes( + (uint2_xe(pixel_index) << 1u) | (in_global_thread_id_xe.xy & 1u), 0u, + false, XeHostDepthStoreRTPitchTiles(rt_constant), kXenosMsaaSamples_1X, + false, 0u, 0u, resolution_scale); // Render target horizontal sample in bit 0, vertical sample in bit 1. int source_sample_left = int((in_global_thread_id_xe.y & 1u) << 1u); int source_sample_right = source_sample_left + 1; - array_buffer_store_xe( - xe_host_depth_store_dest, edram_address_int4s, + byte_buffer_align16_store16_xe( + xe_host_depth_store_dest, edram_address, float_bits_to_uint_xe(float4_xe( texel_fetch_2d_ms_xe(xe_host_depth_store_source, pixel_index, source_sample_left).r, @@ -63,8 +62,8 @@ entry_inputs_end_code_begin_compute_xe texel_fetch_2d_ms_xe(xe_host_depth_store_source, pixel_index + int2_xe(1, 0), source_sample_right).r))); - array_buffer_store_xe( - xe_host_depth_store_dest, edram_address_int4s + 1u, + byte_buffer_align16_store16_xe( + xe_host_depth_store_dest, edram_address + 16u, float_bits_to_uint_xe(float4_xe( texel_fetch_2d_ms_xe(xe_host_depth_store_source, pixel_index + int2_xe(2, 0), diff --git a/src/xenia/gpu/shaders/resolve.xesli b/src/xenia/gpu/shaders/resolve.xesli index 397bb7281..f91cfa9cd 100644 --- a/src/xenia/gpu/shaders/resolve.xesli +++ b/src/xenia/gpu/shaders/resolve.xesli @@ -44,18 +44,22 @@ push_const_end_xe #define XE_RESOLVE_PUSH_CONST_BINDING push_const_binding_xe(buffer(0)) #ifndef XE_RESOLVE_CLEAR - #ifdef XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER - uint_vector_buffer_declare_xe(xe_resolve_edram, set=0, binding=0, t0, - space0) - #define XE_RESOLVE_COPY_EDRAM_BINDING \ - uint_vector_buffer_binding_xe(xe_resolve_edram, buffer(2)) - #else - array_buffer_declare_xe(XE_RESOLVE_SOURCE_TYPE, xe_resolve_edram, set=0, - binding=0, t0, space0) - #define XE_RESOLVE_COPY_EDRAM_BINDING \ - array_buffer_binding_xe(XE_RESOLVE_SOURCE_TYPE, xe_resolve_edram, \ - buffer(2)) + #if XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 4 + #define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO \ + byte_buffer_align4_declare_xe + #elif XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 8 + #define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO \ + byte_buffer_align8_declare_xe + #elif XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 16 + #define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO \ + byte_buffer_align16_declare_xe #endif + #ifdef XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO + XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO(xe_resolve_edram, set=0, + binding=0, t0, space0) + #endif + #define XE_RESOLVE_COPY_EDRAM_BINDING \ + byte_buffer_binding_xe(xe_resolve_edram, buffer(2)) #endif struct XeResolveInfo { @@ -153,8 +157,8 @@ XeResolveInfo XeResolveGetInfo(param_push_consts_xe) { return resolve_info; } -uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { - return 1u << (resolve_info.edram_format_ints_log2 + +uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) { + return 4u << (resolve_info.edram_format_ints_log2 + uint(resolve_info.edram_msaa_samples >= kXenosMsaaSamples_4X)); } @@ -231,9 +235,9 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { // Offset to the first sample to participate in averaging (or the sample to be // copied if not averaging). - uint XeResolveColorCopySourcePixelAddressIntsYHalfPixelOffsetFilling( + uint XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling( XeResolveInfo resolve_info, uint2_xe pixel_index) { - return XeEdramOffsetInts( + return XeEdramOffsetBytes( uint2_xe(pixel_index.x, max(pixel_index.y, resolve_info.half_pixel_offset_fill_source.y)) + @@ -457,116 +461,114 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { } } - #ifdef XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER + #if XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 4 void XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw( - param_uint_vector_buffer_xe(xe_resolve_edram) - param_next_after_uint_vector_buffer_xe - uint sample_address_ints, uint pixel_stride_ints, uint format_ints_log2, - uint format, out_param_xe(float4_xe, pixel_0), + param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe + uint sample_address_bytes, uint pixel_stride_bytes, + uint format_ints_log2, uint format, out_param_xe(float4_xe, pixel_0), out_param_xe(float4_xe, pixel_1)) { dont_flatten_xe if (format_ints_log2 != 0u) { uint4_xe packed; - dont_flatten_xe if (pixel_stride_ints == 2u) { - packed = uint_vector_buffer_load4_xe( - xe_resolve_edram, sample_address_ints); + dont_flatten_xe if (pixel_stride_bytes == 8u) { + packed = byte_buffer_align4_load16u_xe( + xe_resolve_edram, sample_address_bytes); } else { - packed.xy = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints); - packed.zw = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints + pixel_stride_ints); + packed.xy = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes); + packed.zw = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes + pixel_stride_bytes); } XeResolveUnpack64bpp2Samples(packed, format, pixel_0, pixel_1); } else { uint2_xe packed; - dont_flatten_xe if (pixel_stride_ints == 1u) { - packed = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints); + dont_flatten_xe if (pixel_stride_bytes == 4u) { + packed = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes); } else { - packed.x = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints); - packed.y = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + pixel_stride_ints); + packed.x = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes); + packed.y = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + pixel_stride_bytes); } XeResolveUnpack32bpp2Samples(packed, format, pixel_0, pixel_1); } } void XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw( - param_uint_vector_buffer_xe(xe_resolve_edram) - param_next_after_uint_vector_buffer_xe - uint sample_address_ints, uint pixel_stride_ints, uint format_ints_log2, - uint format, out_param_xe(float4_xe, pixel_0), + param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe + uint sample_address_bytes, uint pixel_stride_bytes, + uint format_ints_log2, uint format, out_param_xe(float4_xe, pixel_0), out_param_xe(float4_xe, pixel_1), out_param_xe(float4_xe, pixel_2), out_param_xe(float4_xe, pixel_3)) { dont_flatten_xe if (format_ints_log2 != 0u) { uint4_xe packed_01, packed_23; - dont_flatten_xe if (pixel_stride_ints == 2u) { - packed_01 = uint_vector_buffer_load4_xe( - xe_resolve_edram, sample_address_ints); - packed_23 = uint_vector_buffer_load4_xe( - xe_resolve_edram, sample_address_ints + 4u); + dont_flatten_xe if (pixel_stride_bytes == 8u) { + packed_01 = byte_buffer_align4_load16u_xe( + xe_resolve_edram, sample_address_bytes); + packed_23 = byte_buffer_align4_load16u_xe( + xe_resolve_edram, sample_address_bytes + 16u); } else { - packed_01.xy = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints); - packed_01.zw = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints + pixel_stride_ints); - packed_23.xy = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints + 2u * pixel_stride_ints); - packed_23.zw = uint_vector_buffer_load2_xe( - xe_resolve_edram, sample_address_ints + 3u * pixel_stride_ints); + packed_01.xy = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes); + packed_01.zw = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes + pixel_stride_bytes); + packed_23.xy = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes + 2u * pixel_stride_bytes); + packed_23.zw = byte_buffer_align4_load8u_xe( + xe_resolve_edram, sample_address_bytes + 3u * pixel_stride_bytes); } XeResolveUnpack64bpp4Samples(packed_01, packed_23, format, pixel_0, pixel_1, pixel_2, pixel_3); } else { uint4_xe packed; - dont_flatten_xe if (pixel_stride_ints == 1u) { - packed = uint_vector_buffer_load4_xe( - xe_resolve_edram, sample_address_ints); + dont_flatten_xe if (pixel_stride_bytes == 4u) { + packed = byte_buffer_align4_load16u_xe( + xe_resolve_edram, sample_address_bytes); } else { - packed.x = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints); - packed.y = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + pixel_stride_ints); - packed.z = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 2u * pixel_stride_ints); - packed.w = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 3u * pixel_stride_ints); + packed.x = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes); + packed.y = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + pixel_stride_bytes); + packed.z = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 2u * pixel_stride_bytes); + packed.w = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 3u * pixel_stride_bytes); } XeResolveUnpack32bpp4Samples(packed, format, pixel_0, pixel_1, pixel_2, pixel_3); } } - // For red/blue swapping for 64bpp, pre-add 1 to sample_address_ints. + // For red/blue swapping for 64bpp, pre-add 4 to sample_address_bytes. void XeResolveLoad8RedPixelSamplesFromRaw( - param_uint_vector_buffer_xe(xe_resolve_edram) - param_next_after_uint_vector_buffer_xe - uint sample_address_ints, uint pixel_stride_ints, uint format_ints_log2, - uint format, bool swap_32bpp, out_param_xe(float4_xe, pixels_0123), + param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe + uint sample_address_bytes, uint pixel_stride_bytes, + uint format_ints_log2, uint format, bool swap_32bpp, + out_param_xe(float4_xe, pixels_0123), out_param_xe(float4_xe, pixels_4567)) { uint4_xe packed_0123, packed_4567; - dont_flatten_xe if (pixel_stride_ints == 1u) { - packed_0123 = uint_vector_buffer_load4_xe( - xe_resolve_edram, sample_address_ints); - packed_4567 = uint_vector_buffer_load4_xe( - xe_resolve_edram, sample_address_ints + 4u); + dont_flatten_xe if (pixel_stride_bytes == 4u) { + packed_0123 = byte_buffer_align4_load16u_xe( + xe_resolve_edram, sample_address_bytes); + packed_4567 = byte_buffer_align4_load16u_xe( + xe_resolve_edram, sample_address_bytes + 16u); } else { - packed_0123.x = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints); - packed_0123.y = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + pixel_stride_ints); - packed_0123.z = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 2u * pixel_stride_ints); - packed_0123.w = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 3u * pixel_stride_ints); - packed_4567.x = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 4u * pixel_stride_ints); - packed_4567.y = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 5u * pixel_stride_ints); - packed_4567.z = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 6u * pixel_stride_ints); - packed_4567.w = uint_vector_buffer_load1_xe( - xe_resolve_edram, sample_address_ints + 7u * pixel_stride_ints); + packed_0123.x = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes); + packed_0123.y = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + pixel_stride_bytes); + packed_0123.z = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 2u * pixel_stride_bytes); + packed_0123.w = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 3u * pixel_stride_bytes); + packed_4567.x = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 4u * pixel_stride_bytes); + packed_4567.y = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 5u * pixel_stride_bytes); + packed_4567.z = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 6u * pixel_stride_bytes); + packed_4567.w = byte_buffer_align4_load4_xe( + xe_resolve_edram, sample_address_bytes + 7u * pixel_stride_bytes); } dont_flatten_xe if (format_ints_log2 != 0u) { XeResolveUnpack64bpp8RedUnswappedSamples(packed_0123, packed_4567, @@ -579,48 +581,46 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { } void XeResolveLoad2RGBAColors( - param_uint_vector_buffer_xe(xe_resolve_edram) - param_next_after_uint_vector_buffer_xe - XeResolveInfo resolve_info, uint address_ints, + param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe + XeResolveInfo resolve_info, uint address_bytes, out_param_xe(float4_xe, pixel_0), out_param_xe(float4_xe, pixel_1)) { - uint pixel_stride_ints = XeResolveEdramPixelStrideInts(resolve_info); + uint pixel_stride_bytes = XeResolveEdramPixelStrideBytes(resolve_info); XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints, pixel_stride_ints, resolve_info.edram_format_ints_log2, - resolve_info.edram_format, pixel_0, pixel_1); + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe + address_bytes, pixel_stride_bytes, + resolve_info.edram_format_ints_log2, resolve_info.edram_format, + pixel_0, pixel_1); float exp_bias = resolve_info.dest_exp_bias_factor; dont_flatten_xe if (resolve_info.sample_select >= kXenosCopySampleSelect_01) { - uint tile_row_stride_ints = 80u * resolve_info.resolution_scale.x; + uint tile_row_stride_bytes = 4u * 80u * resolve_info.resolution_scale.x; // TODO(Triang3l): Gamma-correct resolve for 8_8_8_8_GAMMA. exp_bias *= 0.5f; float4_xe msaa_resolve_pixel_0, msaa_resolve_pixel_1; XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + tile_row_stride_ints, pixel_stride_ints, + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe + address_bytes + tile_row_stride_bytes, pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, msaa_resolve_pixel_0, msaa_resolve_pixel_1); pixel_0 += msaa_resolve_pixel_0; pixel_1 += msaa_resolve_pixel_1; dont_flatten_xe if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) { - uint sample_stride_ints = 1u << resolve_info.edram_format_ints_log2; + uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2; exp_bias *= 0.5f; XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + sample_stride_ints, pixel_stride_ints, + pass_byte_buffer_xe(xe_resolve_edram) + pass_next_after_byte_buffer_xe + address_bytes + sample_stride_bytes, pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, msaa_resolve_pixel_0, msaa_resolve_pixel_1); pixel_0 += msaa_resolve_pixel_0; pixel_1 += msaa_resolve_pixel_1; XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + tile_row_stride_ints + sample_stride_ints, - pixel_stride_ints, resolve_info.edram_format_ints_log2, + pass_byte_buffer_xe(xe_resolve_edram) + pass_next_after_byte_buffer_xe + address_bytes + tile_row_stride_bytes + sample_stride_bytes, + pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, msaa_resolve_pixel_0, msaa_resolve_pixel_1); pixel_0 += msaa_resolve_pixel_0; @@ -636,21 +636,20 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { } void XeResolveLoad4RGBAColors( - param_uint_vector_buffer_xe(xe_resolve_edram) - param_next_after_uint_vector_buffer_xe - XeResolveInfo resolve_info, uint address_ints, + param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe + XeResolveInfo resolve_info, uint address_bytes, out_param_xe(float4_xe, pixel_0), out_param_xe(float4_xe, pixel_1), out_param_xe(float4_xe, pixel_2), out_param_xe(float4_xe, pixel_3)) { - uint pixel_stride_ints = XeResolveEdramPixelStrideInts(resolve_info); + uint pixel_stride_bytes = XeResolveEdramPixelStrideBytes(resolve_info); XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints, pixel_stride_ints, resolve_info.edram_format_ints_log2, - resolve_info.edram_format, pixel_0, pixel_1, pixel_2, pixel_3); + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe + address_bytes, pixel_stride_bytes, + resolve_info.edram_format_ints_log2, resolve_info.edram_format, + pixel_0, pixel_1, pixel_2, pixel_3); float exp_bias = resolve_info.dest_exp_bias_factor; dont_flatten_xe if (resolve_info.sample_select >= kXenosCopySampleSelect_01) { - uint tile_row_stride_ints = 80u * resolve_info.resolution_scale.x; + uint tile_row_stride_bytes = 4u * 80u * resolve_info.resolution_scale.x; // TODO(Triang3l): Gamma-correct resolve for 8_8_8_8_GAMMA. exp_bias *= 0.5f; float4_xe msaa_resolve_pixel_0; @@ -658,9 +657,8 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { float4_xe msaa_resolve_pixel_2; float4_xe msaa_resolve_pixel_3; XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + tile_row_stride_ints, pixel_stride_ints, + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe + address_bytes + tile_row_stride_bytes, pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, msaa_resolve_pixel_0, msaa_resolve_pixel_1, msaa_resolve_pixel_2, msaa_resolve_pixel_3); @@ -670,12 +668,12 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { pixel_3 += msaa_resolve_pixel_3; dont_flatten_xe if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) { - uint sample_stride_ints = 1u << resolve_info.edram_format_ints_log2; + uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2; exp_bias *= 0.5f; XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + sample_stride_ints, pixel_stride_ints, + pass_byte_buffer_xe(xe_resolve_edram) + pass_next_after_byte_buffer_xe + address_bytes + sample_stride_bytes, pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, msaa_resolve_pixel_0, msaa_resolve_pixel_1, msaa_resolve_pixel_2, msaa_resolve_pixel_3); @@ -684,10 +682,10 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { pixel_2 += msaa_resolve_pixel_2; pixel_3 += msaa_resolve_pixel_3; XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + tile_row_stride_ints + sample_stride_ints, - pixel_stride_ints, resolve_info.edram_format_ints_log2, + pass_byte_buffer_xe(xe_resolve_edram) + pass_next_after_byte_buffer_xe + address_bytes + tile_row_stride_bytes + sample_stride_bytes, + pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, msaa_resolve_pixel_0, msaa_resolve_pixel_1, msaa_resolve_pixel_2, msaa_resolve_pixel_3); pixel_0 += msaa_resolve_pixel_0; @@ -709,33 +707,30 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { } void XeResolveLoad8RedColors( - param_uint_vector_buffer_xe(xe_resolve_edram) - param_next_after_uint_vector_buffer_xe - XeResolveInfo resolve_info, uint address_ints, + param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe + XeResolveInfo resolve_info, uint address_bytes, out_param_xe(float4_xe, pixels_0123), out_param_xe(float4_xe, pixels_4567)) { - uint pixel_stride_ints = XeResolveEdramPixelStrideInts(resolve_info); - if (resolve_info.dest_swap) { + uint pixel_stride_bytes = XeResolveEdramPixelStrideBytes(resolve_info); + if (resolve_info.dest_swap && resolve_info.edram_format_ints_log2 != 0u) { // Likely want to load the blue part from the right half for 64bpp. - address_ints += resolve_info.edram_format_ints_log2; + address_bytes += 4u; } XeResolveLoad8RedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints, pixel_stride_ints, resolve_info.edram_format_ints_log2, - resolve_info.edram_format, resolve_info.dest_swap, pixels_0123, - pixels_4567); + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe + address_bytes, pixel_stride_bytes, + resolve_info.edram_format_ints_log2, resolve_info.edram_format, + resolve_info.dest_swap, pixels_0123, pixels_4567); float exp_bias = resolve_info.dest_exp_bias_factor; dont_flatten_xe if (resolve_info.sample_select >= kXenosCopySampleSelect_01) { - uint tile_row_stride_ints = 80u * resolve_info.resolution_scale.x; + uint tile_row_stride_bytes = 4u * 80u * resolve_info.resolution_scale.x; // TODO(Triang3l): Gamma-correct resolve for 8_8_8_8_GAMMA. exp_bias *= 0.5f; float4_xe msaa_resolve_pixels_0123, msaa_resolve_pixels_4567; XeResolveLoad8RedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + tile_row_stride_ints, pixel_stride_ints, + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe + address_bytes + tile_row_stride_bytes, pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, resolve_info.dest_swap, msaa_resolve_pixels_0123, msaa_resolve_pixels_4567); @@ -743,22 +738,22 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { pixels_4567 += msaa_resolve_pixels_4567; dont_flatten_xe if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) { - uint sample_stride_ints = 1u << resolve_info.edram_format_ints_log2; + uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2; exp_bias *= 0.5f; XeResolveLoad8RedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + sample_stride_ints, pixel_stride_ints, + pass_byte_buffer_xe(xe_resolve_edram) + pass_next_after_byte_buffer_xe + address_bytes + sample_stride_bytes, pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, resolve_info.dest_swap, msaa_resolve_pixels_0123, msaa_resolve_pixels_4567); pixels_0123 += msaa_resolve_pixels_0123; pixels_4567 += msaa_resolve_pixels_4567; XeResolveLoad8RedPixelSamplesFromRaw( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe - address_ints + tile_row_stride_ints + sample_stride_ints, - pixel_stride_ints, resolve_info.edram_format_ints_log2, + pass_byte_buffer_xe(xe_resolve_edram) + pass_next_after_byte_buffer_xe + address_bytes + tile_row_stride_bytes + sample_stride_bytes, + pixel_stride_bytes, resolve_info.edram_format_ints_log2, resolve_info.edram_format, resolve_info.dest_swap, msaa_resolve_pixels_0123, msaa_resolve_pixels_4567); pixels_0123 += msaa_resolve_pixels_0123; @@ -768,7 +763,7 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) { pixels_0123 *= exp_bias; pixels_4567 *= exp_bias; } - #endif // XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER + #endif // XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 4 uint4_xe XeResolveSwapRedBlue_8_8_8_8(uint4_xe pixels) { return (pixels & ~0xFF00FFu) | ((pixels & 0xFFu) << 16u) | diff --git a/src/xenia/gpu/shaders/resolve_clear_32bpp.xesli b/src/xenia/gpu/shaders/resolve_clear_32bpp.xesli index c57b5075b..8117436c1 100644 --- a/src/xenia/gpu/shaders/resolve_clear_32bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_clear_32bpp.xesli @@ -10,15 +10,15 @@ #define XE_RESOLVE_CLEAR #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_edram, set=0, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_edram, set=0, binding=0, u0, + space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_edram, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_edram, buffer(1)) entry_bindings_end_inputs_begin_compute_xe entry_in_global_thread_id_xe entry_inputs_end_code_begin_compute_xe @@ -34,17 +34,15 @@ entry_inputs_end_code_begin_compute_xe resolve_info.width_div_8_scaled << extent_scale.x) { return; } - uint address_int4s = - XeEdramOffsetInts( - (in_global_thread_id_xe.xy << uint2_xe(3u, 0u)) + - (resolve_info.edram_offset_scaled << extent_scale), - resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, - kXenosMsaaSamples_1X, resolve_info.edram_is_depth, 0u, 0u, - resolve_info.resolution_scale) - >> 2u; - array_buffer_store_xe(xe_resolve_edram, address_int4s, - resolve_info.clear_value.xxxx); - array_buffer_store_xe(xe_resolve_edram, address_int4s + 1u, - resolve_info.clear_value.xxxx); + uint address = XeEdramOffsetBytes( + (in_global_thread_id_xe.xy << uint2_xe(3u, 0u)) + + (resolve_info.edram_offset_scaled << extent_scale), + resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, + kXenosMsaaSamples_1X, resolve_info.edram_is_depth, 0u, 0u, + resolve_info.resolution_scale); + byte_buffer_align16_store16_xe(xe_resolve_edram, address, + resolve_info.clear_value.xxxx); + byte_buffer_align16_store16_xe(xe_resolve_edram, address + 16u, + resolve_info.clear_value.xxxx); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/resolve_clear_64bpp.xesli b/src/xenia/gpu/shaders/resolve_clear_64bpp.xesli index 46af18c41..cfb755fb6 100644 --- a/src/xenia/gpu/shaders/resolve_clear_64bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_clear_64bpp.xesli @@ -10,15 +10,15 @@ #define XE_RESOLVE_CLEAR #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_edram, set=0, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_edram, set=0, binding=0, u0, + space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_edram, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_edram, buffer(1)) entry_bindings_end_inputs_begin_compute_xe entry_in_global_thread_id_xe entry_inputs_end_code_begin_compute_xe @@ -34,17 +34,15 @@ entry_inputs_end_code_begin_compute_xe resolve_info.width_div_8_scaled << extent_scale.x) { return; } - uint address_int4s = - XeEdramOffsetInts( - (in_global_thread_id_xe.xy << uint2_xe(3u, 0u)) + - (resolve_info.edram_offset_scaled << extent_scale), - resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, - kXenosMsaaSamples_1X, false, 1u, 0u, resolve_info.resolution_scale) - >> 2u; + uint address = XeEdramOffsetBytes( + (in_global_thread_id_xe.xy << uint2_xe(3u, 0u)) + + (resolve_info.edram_offset_scaled << extent_scale), + resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, + kXenosMsaaSamples_1X, false, 1u, 0u, resolve_info.resolution_scale); uint i; unroll_xe for (i = 0u; i < 4u; ++i) { - array_buffer_store_xe(xe_resolve_edram, address_int4s + i, - resolve_info.clear_value.xyxy); + byte_buffer_align16_store16_xe(xe_resolve_edram, address + (i << 4), + resolve_info.clear_value.xyxy); } } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/resolve_fast_32bpp_1x2xmsaa.xesli b/src/xenia/gpu/shaders/resolve_fast_32bpp_1x2xmsaa.xesli index d0e85d73c..06a49a13e 100644 --- a/src/xenia/gpu/shaders/resolve_fast_32bpp_1x2xmsaa.xesli +++ b/src/xenia/gpu/shaders/resolve_fast_32bpp_1x2xmsaa.xesli @@ -8,18 +8,17 @@ */ #include "endian.xesli" -#define XE_RESOLVE_SOURCE_TYPE uint4_xe +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 16 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -34,21 +33,19 @@ entry_inputs_end_code_begin_compute_xe return; } uint2_xe pixel_index = in_global_thread_id_xe.xy << uint2_xe(3u, 0u); - uint source_address_int4s = - XeEdramOffsetInts( - uint2_xe(pixel_index.x, - max(pixel_index.y, - resolve_info.half_pixel_offset_fill_source.y)) + - resolve_info.edram_offset_scaled, - resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, - resolve_info.edram_msaa_samples, resolve_info.edram_is_depth, 0u, - XeResolveFirstSampleIndex(resolve_info.sample_select), - resolve_info.resolution_scale) - >> 2u; - uint4_xe pixels_0123 = - array_buffer_load_xe(xe_resolve_edram, source_address_int4s); - uint4_xe pixels_4567 = - array_buffer_load_xe(xe_resolve_edram, source_address_int4s + 1u); + uint source_address = XeEdramOffsetBytes( + uint2_xe(pixel_index.x, + max(pixel_index.y, + resolve_info.half_pixel_offset_fill_source.y)) + + resolve_info.edram_offset_scaled, + resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, + resolve_info.edram_msaa_samples, resolve_info.edram_is_depth, 0u, + XeResolveFirstSampleIndex(resolve_info.sample_select), + resolve_info.resolution_scale); + uint4_xe pixels_0123 = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address); + uint4_xe pixels_4567 = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 16u); dont_flatten_xe if (pixel_index.x == 0u && resolve_info.half_pixel_offset_fill_source.x != 0u) { @@ -61,13 +58,12 @@ entry_inputs_end_code_begin_compute_xe pixels_0123.x = pixels_0123.y; } XeResolveSwap8PixelsRedBlue32bpp(resolve_info, pixels_0123, pixels_4567); - uint dest_address = - XeResolveDestPixelAddress(resolve_info, pixel_index, 2u) >> 4u; - array_buffer_store_xe( + uint dest_address = XeResolveDestPixelAddress(resolve_info, pixel_index, 2u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap32(pixels_0123, resolve_info.dest_endian_128)); - dest_address += XeResolveLocalXAddressXor(4u, 2u) >> 4u; - array_buffer_store_xe( + dest_address += XeResolveLocalXAddressXor(4u, 2u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap32(pixels_4567, resolve_info.dest_endian_128)); } diff --git a/src/xenia/gpu/shaders/resolve_fast_32bpp_4xmsaa.xesli b/src/xenia/gpu/shaders/resolve_fast_32bpp_4xmsaa.xesli index a6b1b68c6..8f1453bd5 100644 --- a/src/xenia/gpu/shaders/resolve_fast_32bpp_4xmsaa.xesli +++ b/src/xenia/gpu/shaders/resolve_fast_32bpp_4xmsaa.xesli @@ -8,18 +8,17 @@ */ #include "endian.xesli" -#define XE_RESOLVE_SOURCE_TYPE uint4_xe +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 16 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -34,38 +33,36 @@ entry_inputs_end_code_begin_compute_xe return; } uint2_xe pixel_index = in_global_thread_id_xe.xy << uint2_xe(3u, 0u); - uint source_address_int4s = - XeEdramOffsetInts( - uint2_xe(pixel_index.x, - max(pixel_index.y, - resolve_info.half_pixel_offset_fill_source.y)) + - resolve_info.edram_offset_scaled, - resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, - kXenosMsaaSamples_4X, resolve_info.edram_is_depth, 0u, - XeResolveFirstSampleIndex(resolve_info.sample_select), - resolve_info.resolution_scale) - >> 2u; + uint source_address = XeEdramOffsetBytes( + uint2_xe(pixel_index.x, + max(pixel_index.y, + resolve_info.half_pixel_offset_fill_source.y)) + + resolve_info.edram_offset_scaled, + resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, + kXenosMsaaSamples_4X, resolve_info.edram_is_depth, 0u, + XeResolveFirstSampleIndex(resolve_info.sample_select), + resolve_info.resolution_scale); uint4_xe pixels_0123, pixels_4567; dont_flatten_xe if (resolve_info.sample_select != kXenosCopySampleSelect_2 && resolve_info.sample_select != kXenosCopySampleSelect_3) { - pixels_0123.xy = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s).xz; - pixels_0123.zw = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s + 1u).xz; - pixels_4567.xy = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s + 2u).xz; - pixels_4567.zw = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s + 3u).xz; + pixels_0123.xy = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address).xz; + pixels_0123.zw = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 0x10u).xz; + pixels_4567.xy = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 0x20u).xz; + pixels_4567.zw = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 0x30u).xz; } else { - pixels_0123.xy = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s).yw; - pixels_0123.zw = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s + 1u).yw; - pixels_4567.xy = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s + 2u).yw; - pixels_4567.zw = array_buffer_load_xe( - xe_resolve_edram, source_address_int4s + 3u).yw; + pixels_0123.xy = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address).yw; + pixels_0123.zw = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 0x10u).yw; + pixels_4567.xy = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 0x20u).yw; + pixels_4567.zw = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 0x30u).yw; } dont_flatten_xe if (pixel_index.x == 0u && @@ -79,13 +76,12 @@ entry_inputs_end_code_begin_compute_xe pixels_0123.x = pixels_0123.y; } XeResolveSwap8PixelsRedBlue32bpp(resolve_info, pixels_0123, pixels_4567); - uint dest_address = - XeResolveDestPixelAddress(resolve_info, pixel_index, 2u) >> 4u; - array_buffer_store_xe( + uint dest_address = XeResolveDestPixelAddress(resolve_info, pixel_index, 2u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap32(pixels_0123, resolve_info.dest_endian_128)); - dest_address += XeResolveLocalXAddressXor(4u, 2u) >> 4u; - array_buffer_store_xe( + dest_address += XeResolveLocalXAddressXor(4u, 2u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap32(pixels_4567, resolve_info.dest_endian_128)); } diff --git a/src/xenia/gpu/shaders/resolve_fast_64bpp_1x2xmsaa.xesli b/src/xenia/gpu/shaders/resolve_fast_64bpp_1x2xmsaa.xesli index 62449803e..a00280b32 100644 --- a/src/xenia/gpu/shaders/resolve_fast_64bpp_1x2xmsaa.xesli +++ b/src/xenia/gpu/shaders/resolve_fast_64bpp_1x2xmsaa.xesli @@ -8,18 +8,17 @@ */ #include "endian.xesli" -#define XE_RESOLVE_SOURCE_TYPE uint4_xe +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 16 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -34,21 +33,19 @@ entry_inputs_end_code_begin_compute_xe if (pixel_index.x >= resolve_info.width_div_8_scaled << 3u) { return; } - uint source_address_int4s = - XeEdramOffsetInts( - uint2_xe(pixel_index.x, - max(pixel_index.y, - resolve_info.half_pixel_offset_fill_source.y)) + - resolve_info.edram_offset_scaled, - resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, - resolve_info.edram_msaa_samples, false, 1u, - XeResolveFirstSampleIndex(resolve_info.sample_select), - resolve_info.resolution_scale) - >> 2u; - uint4_xe pixels_01 = - array_buffer_load_xe(xe_resolve_edram, source_address_int4s); - uint4_xe pixels_23 = - array_buffer_load_xe(xe_resolve_edram, source_address_int4s + 1u); + uint source_address = XeEdramOffsetBytes( + uint2_xe(pixel_index.x, + max(pixel_index.y, + resolve_info.half_pixel_offset_fill_source.y)) + + resolve_info.edram_offset_scaled, + resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, + resolve_info.edram_msaa_samples, false, 1u, + XeResolveFirstSampleIndex(resolve_info.sample_select), + resolve_info.resolution_scale); + uint4_xe pixels_01 = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address); + uint4_xe pixels_23 = byte_buffer_align16_load16_xe(xe_resolve_edram, + source_address + 16u); dont_flatten_xe if (pixel_index.x == 0u && resolve_info.half_pixel_offset_fill_source.x != 0u) { @@ -61,13 +58,12 @@ entry_inputs_end_code_begin_compute_xe pixels_01.xy = pixels_01.zw; } XeResolveSwap4PixelsRedBlue64bpp(resolve_info, pixels_01, pixels_23); - uint dest_address = - XeResolveDestPixelAddress(resolve_info, pixel_index, 3u) >> 4u; - array_buffer_store_xe( + uint dest_address = XeResolveDestPixelAddress(resolve_info, pixel_index, 3u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap64(pixels_01, resolve_info.dest_endian_128)); - dest_address += XeResolveLocalXAddressXor(2u, 3u) >> 4u; - array_buffer_store_xe( + dest_address += XeResolveLocalXAddressXor(2u, 3u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap64(pixels_23, resolve_info.dest_endian_128)); } diff --git a/src/xenia/gpu/shaders/resolve_fast_64bpp_4xmsaa.xesli b/src/xenia/gpu/shaders/resolve_fast_64bpp_4xmsaa.xesli index 020775f2f..4a7ef067e 100644 --- a/src/xenia/gpu/shaders/resolve_fast_64bpp_4xmsaa.xesli +++ b/src/xenia/gpu/shaders/resolve_fast_64bpp_4xmsaa.xesli @@ -8,18 +8,17 @@ */ #include "endian.xesli" -#define XE_RESOLVE_SOURCE_TYPE uint2_xe +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 8 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -34,25 +33,23 @@ entry_inputs_end_code_begin_compute_xe if (pixel_index.x >= resolve_info.width_div_8_scaled << 3u) { return; } - uint source_address_int2s = - XeEdramOffsetInts( - uint2_xe(pixel_index.x, - max(pixel_index.y, - resolve_info.half_pixel_offset_fill_source.y)) + - resolve_info.edram_offset_scaled, - resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, - kXenosMsaaSamples_4X, false, 1u, - XeResolveFirstSampleIndex(resolve_info.sample_select), - resolve_info.resolution_scale) - >> 1u; + uint source_address = XeEdramOffsetBytes( + uint2_xe(pixel_index.x, + max(pixel_index.y, + resolve_info.half_pixel_offset_fill_source.y)) + + resolve_info.edram_offset_scaled, + resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles, + kXenosMsaaSamples_4X, false, 1u, + XeResolveFirstSampleIndex(resolve_info.sample_select), + resolve_info.resolution_scale); uint4_xe pixels_01, pixels_23; - pixels_01.xy = array_buffer_load_xe(xe_resolve_edram, source_address_int2s); - pixels_01.zw = - array_buffer_load_xe(xe_resolve_edram, source_address_int2s + 2u); - pixels_23.xy = - array_buffer_load_xe(xe_resolve_edram, source_address_int2s + 4u); - pixels_23.zw = - array_buffer_load_xe(xe_resolve_edram, source_address_int2s + 6u); + pixels_01.xy = byte_buffer_align8_load8_xe(xe_resolve_edram, source_address); + pixels_01.zw = byte_buffer_align8_load8_xe(xe_resolve_edram, + source_address + 0x10u); + pixels_23.xy = byte_buffer_align8_load8_xe(xe_resolve_edram, + source_address + 0x20u); + pixels_23.zw = byte_buffer_align8_load8_xe(xe_resolve_edram, + source_address + 0x30u); dont_flatten_xe if (pixel_index.x == 0u && resolve_info.half_pixel_offset_fill_source.x != 0u) { @@ -65,13 +62,12 @@ entry_inputs_end_code_begin_compute_xe pixels_01.xy = pixels_01.zw; } XeResolveSwap4PixelsRedBlue64bpp(resolve_info, pixels_01, pixels_23); - uint dest_address = - XeResolveDestPixelAddress(resolve_info, pixel_index, 3u) >> 4u; - array_buffer_store_xe( + uint dest_address = XeResolveDestPixelAddress(resolve_info, pixel_index, 3u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap64(pixels_01, resolve_info.dest_endian_128)); - dest_address += XeResolveLocalXAddressXor(2u, 3u) >> 4u; - array_buffer_store_xe( + dest_address += XeResolveLocalXAddressXor(2u, 3u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap64(pixels_23, resolve_info.dest_endian_128)); } diff --git a/src/xenia/gpu/shaders/resolve_full_128bpp.xesli b/src/xenia/gpu/shaders/resolve_full_128bpp.xesli index 5935d2eee..398aa0801 100644 --- a/src/xenia/gpu/shaders/resolve_full_128bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_full_128bpp.xesli @@ -8,18 +8,17 @@ */ #include "endian.xesli" -#define XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 4 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -36,10 +35,9 @@ entry_inputs_end_code_begin_compute_xe } float4_xe pixel_0, pixel_1; XeResolveLoad2RGBAColors( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe resolve_info, - XeResolveColorCopySourcePixelAddressIntsYHalfPixelOffsetFilling( + XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling( resolve_info, uint2_xe(max(pixel_index.x, resolve_info.half_pixel_offset_fill_source.x), @@ -56,14 +54,13 @@ entry_inputs_end_code_begin_compute_xe pixel_1 = pixel_0; } // Only 32_32_32_32_FLOAT color format is 128bpp. - uint dest_address = - XeResolveDestPixelAddress(resolve_info, pixel_index, 4u) >> 4u; - array_buffer_store_xe( + uint dest_address = XeResolveDestPixelAddress(resolve_info, pixel_index, 4u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap128(float_bits_to_uint_xe(pixel_0), resolve_info.dest_endian_128)); - dest_address += XeResolveLocalXAddressXor(1u, 4u) >> 4u; - array_buffer_store_xe( + dest_address += XeResolveLocalXAddressXor(1u, 4u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap128(float_bits_to_uint_xe(pixel_1), resolve_info.dest_endian_128)); diff --git a/src/xenia/gpu/shaders/resolve_full_16bpp.xesli b/src/xenia/gpu/shaders/resolve_full_16bpp.xesli index 344d2d4f8..b5bc1af4f 100644 --- a/src/xenia/gpu/shaders/resolve_full_16bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_full_16bpp.xesli @@ -9,18 +9,17 @@ #include "endian.xesli" #include "pixel_formats.xesli" -#define XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 4 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint2_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align8_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint2_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -37,10 +36,9 @@ entry_inputs_end_code_begin_compute_xe } float4_xe pixel_0, pixel_1, pixel_2, pixel_3; XeResolveLoad4RGBAColors( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe resolve_info, - XeResolveColorCopySourcePixelAddressIntsYHalfPixelOffsetFilling( + XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling( resolve_info, pixel_index), pixel_0, pixel_1, pixel_2, pixel_3); uint2_xe packed = XePack16bpp4PixelsInUInt2( @@ -56,9 +54,8 @@ entry_inputs_end_code_begin_compute_xe } packed.x = (packed.x >> 16u) | (packed.x & 0xFFFF0000u); } - array_buffer_store_xe( - xe_resolve_dest, - XeResolveDestPixelAddress(resolve_info, pixel_index, 1u) >> 3u, + byte_buffer_align8_store8_xe( + xe_resolve_dest, XeResolveDestPixelAddress(resolve_info, pixel_index, 1u), XeEndianSwap16(packed, resolve_info.dest_endian_128)); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/resolve_full_32bpp.xesli b/src/xenia/gpu/shaders/resolve_full_32bpp.xesli index 92cdd75ec..ae3e18fc3 100644 --- a/src/xenia/gpu/shaders/resolve_full_32bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_full_32bpp.xesli @@ -9,18 +9,17 @@ #include "endian.xesli" #include "pixel_formats.xesli" -#define XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 4 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -39,10 +38,9 @@ entry_inputs_end_code_begin_compute_xe } float4_xe pixel_0, pixel_1, pixel_2, pixel_3; XeResolveLoad4RGBAColors( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe resolve_info, - XeResolveColorCopySourcePixelAddressIntsYHalfPixelOffsetFilling( + XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling( resolve_info, pixel_index), pixel_0, pixel_1, pixel_2, pixel_3); uint4_xe packed = XePack32bpp4Pixels(pixel_0, pixel_1, pixel_2, pixel_3, @@ -58,9 +56,8 @@ entry_inputs_end_code_begin_compute_xe } packed.x = packed.y; } - array_buffer_store_xe( - xe_resolve_dest, - XeResolveDestPixelAddress(resolve_info, pixel_index, 2u) >> 4u, + byte_buffer_align16_store16_xe( + xe_resolve_dest, XeResolveDestPixelAddress(resolve_info, pixel_index, 2u), XeEndianSwap32(packed, resolve_info.dest_endian_128)); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/resolve_full_64bpp.xesli b/src/xenia/gpu/shaders/resolve_full_64bpp.xesli index beb50c515..63a0fd4e3 100644 --- a/src/xenia/gpu/shaders/resolve_full_64bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_full_64bpp.xesli @@ -9,18 +9,17 @@ #include "endian.xesli" #include "pixel_formats.xesli" -#define XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 4 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align16_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -37,10 +36,9 @@ entry_inputs_end_code_begin_compute_xe } float4_xe pixel_0, pixel_1, pixel_2, pixel_3; XeResolveLoad4RGBAColors( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe resolve_info, - XeResolveColorCopySourcePixelAddressIntsYHalfPixelOffsetFilling( + XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling( resolve_info, pixel_index), pixel_0, pixel_1, pixel_2, pixel_3); uint4_xe packed_01, packed_23; @@ -57,13 +55,12 @@ entry_inputs_end_code_begin_compute_xe } packed_01.xy = packed_01.zw; } - uint dest_address = - XeResolveDestPixelAddress(resolve_info, pixel_index, 3u) >> 4u; - array_buffer_store_xe( + uint dest_address = XeResolveDestPixelAddress(resolve_info, pixel_index, 3u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap64(packed_01, resolve_info.dest_endian_128)); - dest_address += XeResolveLocalXAddressXor(2u, 3u) >> 4u; - array_buffer_store_xe( + dest_address += XeResolveLocalXAddressXor(2u, 3u); + byte_buffer_align16_store16_xe( xe_resolve_dest, dest_address, XeEndianSwap64(packed_23, resolve_info.dest_endian_128)); } diff --git a/src/xenia/gpu/shaders/resolve_full_8bpp.xesli b/src/xenia/gpu/shaders/resolve_full_8bpp.xesli index 0b9c7d677..29224d963 100644 --- a/src/xenia/gpu/shaders/resolve_full_8bpp.xesli +++ b/src/xenia/gpu/shaders/resolve_full_8bpp.xesli @@ -9,18 +9,17 @@ #include "endian.xesli" #include "pixel_formats.xesli" -#define XE_RESOLVE_COPY_EDRAM_IS_UINT_VECTOR_BUFFER +#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT 4 #include "resolve.xesli" -array_buffer_wo_declare_xe(uint2_xe, xe_resolve_dest, set=1, binding=0, u0, - space0) +byte_buffer_align8_wo_declare_xe(xe_resolve_dest, set=1, binding=0, u0, space0) #define LOCAL_SIZE_X_XE 8 #define LOCAL_SIZE_Y_XE 8 #define LOCAL_SIZE_Z_XE 1 entry_bindings_begin_compute_xe XE_RESOLVE_PUSH_CONST_BINDING entry_binding_next_xe - array_buffer_wo_binding_xe(uint2_xe, xe_resolve_dest, buffer(1)) + byte_buffer_wo_binding_xe(xe_resolve_dest, buffer(1)) entry_binding_next_xe XE_RESOLVE_COPY_EDRAM_BINDING entry_bindings_end_inputs_begin_compute_xe @@ -37,10 +36,9 @@ entry_inputs_end_code_begin_compute_xe uint2_xe pixel_index = in_global_thread_id_xe.xy << uint2_xe(3u, 0u); float4_xe pixels_0123, pixels_4567; XeResolveLoad8RedColors( - pass_uint_vector_buffer_xe(xe_resolve_edram) - pass_next_after_uint_vector_buffer_xe + pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe resolve_info, - XeResolveColorCopySourcePixelAddressIntsYHalfPixelOffsetFilling( + XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling( resolve_info, pixel_index), pixels_0123, pixels_4567); dont_flatten_xe @@ -56,9 +54,8 @@ entry_inputs_end_code_begin_compute_xe } // Convert to R8. // TODO(Triang3l): Investigate formats 8_A and 8_B. - array_buffer_store_xe( - xe_resolve_dest, - XeResolveDestPixelAddress(resolve_info, pixel_index, 0u) >> 3u, + byte_buffer_align8_store8_xe( + xe_resolve_dest, XeResolveDestPixelAddress(resolve_info, pixel_index, 0u), uint2_xe(XePackR8G8B8A8UNorm(pixels_0123), XePackR8G8B8A8UNorm(pixels_4567))); } diff --git a/src/xenia/gpu/shaders/texture_load.xesli b/src/xenia/gpu/shaders/texture_load.xesli index cc1b3664e..967f6169d 100644 --- a/src/xenia/gpu/shaders/texture_load.xesli +++ b/src/xenia/gpu/shaders/texture_load.xesli @@ -49,6 +49,21 @@ push_const_begin_xe(b0, space0) uint xe_texture_load_height_texels; push_const_end_xe +#define XE_TEXTURE_LOAD_ENTRY(source_byte_buffer_alignment) \ + byte_buffer_align16_wo_declare_xe(xe_texture_load_dest, set=0, binding=0, \ + u0, space0) \ + byte_buffer_align##source_byte_buffer_alignment##_declare_xe( \ + xe_texture_load_source, set=1, binding=0, t0, space0) \ + entry_bindings_begin_compute_xe \ + XE_TEXTURE_LOAD_PUSH_CONST_BINDING \ + entry_binding_next_xe \ + byte_buffer_wo_binding_xe(xe_texture_load_dest, buffer(1)) \ + entry_binding_next_xe \ + byte_buffer_binding_xe(xe_texture_load_source, buffer(2)) \ + entry_bindings_end_inputs_begin_compute_xe \ + entry_in_global_thread_id_xe \ + entry_inputs_end_code_begin_compute_xe + #define XE_TEXTURE_LOAD_PUSH_CONST_BINDING push_const_binding_xe(buffer(0)) struct XeTextureLoadInfo { diff --git a/src/xenia/gpu/shaders/texture_load_128bpb.xesli b/src/xenia/gpu/shaders/texture_load_128bpb.xesli index ccba3b6b8..ed451f228 100644 --- a/src/xenia/gpu/shaders/texture_load_128bpb.xesli +++ b/src/xenia/gpu/shaders/texture_load_128bpb.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 2 blocks. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -30,24 +18,24 @@ entry_inputs_end_code_begin_compute_xe if (any(greater_than_equal_xe(block_index.xy, load_info.size_blocks.xy))) { return; } - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, - load_info.size_blocks.y, 16u) + - load_info.host_offset) >> 4u); + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, + load_info.size_blocks.y, 16u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 4u) >> 4u; - array_buffer_store_xe( + XeTextureLoadSourceAddress(load_info, block_index, 4u); + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, - XeEndianSwap32(array_buffer_load_xe(xe_texture_load_source, - block_offset_guest), + XeEndianSwap32(byte_buffer_align16_load16_xe(xe_texture_load_source, + block_offset_guest), load_info.endian_32)); - ++block_offset_host; + block_offset_host += 16u; block_offset_guest += - XeTextureLoadLocalXAddressXor(1u, 4u, load_info.is_tiled) >> 4u; - array_buffer_store_xe( + XeTextureLoadLocalXAddressXor(1u, 4u, load_info.is_tiled); + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, - XeEndianSwap32(array_buffer_load_xe(xe_texture_load_source, - block_offset_guest), + XeEndianSwap32(byte_buffer_align16_load16_xe(xe_texture_load_source, + block_offset_guest), load_info.endian_32)); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/texture_load_16bpb.xesli b/src/xenia/gpu/shaders/texture_load_16bpb.xesli index 03cbb0d0b..37212163d 100644 --- a/src/xenia/gpu/shaders/texture_load_16bpb.xesli +++ b/src/xenia/gpu/shaders/texture_load_16bpb.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 16 blocks passed through an externally provided // uint4 transformation function (XE_TEXTURE_LOAD_16BPB_TRANSFORM). @@ -31,24 +19,24 @@ entry_inputs_end_code_begin_compute_xe if (any(greater_than_equal_xe(block_index.xy, load_info.size_blocks.xy))) { return; } - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, - load_info.size_blocks.y, 2u) + - load_info.host_offset) >> 4u); + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, + load_info.size_blocks.y, 2u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 1u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 1u); uint4_xe guest_blocks = XeEndianSwap16( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, - XE_TEXTURE_LOAD_16BPB_TRANSFORM(guest_blocks)); - ++block_offset_host; + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + XE_TEXTURE_LOAD_16BPB_TRANSFORM(guest_blocks)); + block_offset_host += 16u; block_offset_guest += - XeTextureLoadLocalXAddressXor(8u, 1u, load_info.is_tiled) >> 4u; + XeTextureLoadLocalXAddressXor(8u, 1u, load_info.is_tiled); guest_blocks = XeEndianSwap16( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, - XE_TEXTURE_LOAD_16BPB_TRANSFORM(guest_blocks)); + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + XE_TEXTURE_LOAD_16BPB_TRANSFORM(guest_blocks)); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/texture_load_32bpb.xesli b/src/xenia/gpu/shaders/texture_load_32bpb.xesli index f26680874..45fdc2932 100644 --- a/src/xenia/gpu/shaders/texture_load_32bpb.xesli +++ b/src/xenia/gpu/shaders/texture_load_32bpb.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 8 blocks passed through an externally provided // uint4 transformation function (XE_TEXTURE_LOAD_32BPB_TRANSFORM). @@ -31,24 +19,24 @@ entry_inputs_end_code_begin_compute_xe if (any(greater_than_equal_xe(block_index.xy, load_info.size_blocks.xy))) { return; } - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, - load_info.size_blocks.y, 4u) + - load_info.host_offset) >> 4u); + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, + load_info.size_blocks.y, 4u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 2u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 2u); uint4_xe guest_blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, - XE_TEXTURE_LOAD_32BPB_TRANSFORM(guest_blocks)); - ++block_offset_host; + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + XE_TEXTURE_LOAD_32BPB_TRANSFORM(guest_blocks)); + block_offset_host += 16u; block_offset_guest += - XeTextureLoadLocalXAddressXor(4u, 2u, load_info.is_tiled) >> 4u; + XeTextureLoadLocalXAddressXor(4u, 2u, load_info.is_tiled); guest_blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, - XE_TEXTURE_LOAD_32BPB_TRANSFORM(guest_blocks)); + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + XE_TEXTURE_LOAD_32BPB_TRANSFORM(guest_blocks)); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/texture_load_32bpb_64bpb.xesli b/src/xenia/gpu/shaders/texture_load_32bpb_64bpb.xesli index 60a5dba5b..04324939a 100644 --- a/src/xenia/gpu/shaders/texture_load_32bpb_64bpb.xesli +++ b/src/xenia/gpu/shaders/texture_load_32bpb_64bpb.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 8 packed 32-bit texels with the externally provided uint4 -> 2x // uint4 function (XE_TEXTURE_LOAD_32BPB_TO_64BPB) for converting to 64bpb - @@ -32,26 +20,30 @@ entry_inputs_end_code_begin_compute_xe if (any(greater_than_equal_xe(block_index.xy, load_info.size_blocks.xy))) { return; } - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, - load_info.size_blocks.y, 8u) + - load_info.host_offset) >> 4u); + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, + load_info.size_blocks.y, 8u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 2u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 2u); uint4_xe guest_blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); uint4_xe block_0, block_1; XE_TEXTURE_LOAD_32BPB_TO_64BPB(guest_blocks, block_0, block_1); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, block_0); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host + 1u, block_1); + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + block_0); + byte_buffer_align16_store16_xe(xe_texture_load_dest, + block_offset_host + 0x10u, block_1); block_offset_guest += - XeTextureLoadLocalXAddressXor(4u, 2u, load_info.is_tiled) >> 4u; + XeTextureLoadLocalXAddressXor(4u, 2u, load_info.is_tiled); guest_blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); XE_TEXTURE_LOAD_32BPB_TO_64BPB(guest_blocks, block_0, block_1); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host + 2u, block_0); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host + 3u, block_1); + byte_buffer_align16_store16_xe(xe_texture_load_dest, + block_offset_host + 0x20u, block_0); + byte_buffer_align16_store16_xe(xe_texture_load_dest, + block_offset_host + 0x30u, block_1); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/texture_load_64bpb.xesli b/src/xenia/gpu/shaders/texture_load_64bpb.xesli index ad8520ae8..df449ab2c 100644 --- a/src/xenia/gpu/shaders/texture_load_64bpb.xesli +++ b/src/xenia/gpu/shaders/texture_load_64bpb.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 4 blocks passed through an externally provided // uint4 transformation function (XE_TEXTURE_LOAD_64BPB_TRANSFORM). @@ -31,24 +19,24 @@ entry_inputs_end_code_begin_compute_xe if (any(greater_than_equal_xe(block_index.xy, load_info.size_blocks.xy))) { return; } - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, - load_info.size_blocks.y, 8u) + - load_info.host_offset) >> 4u); + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, + load_info.size_blocks.y, 8u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 3u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 3u); uint4_xe guest_blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, - XE_TEXTURE_LOAD_64BPB_TRANSFORM(guest_blocks)); - ++block_offset_host; + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + XE_TEXTURE_LOAD_64BPB_TRANSFORM(guest_blocks)); + block_offset_host += 16u; block_offset_guest += - XeTextureLoadLocalXAddressXor(2u, 3u, load_info.is_tiled) >> 4u; + XeTextureLoadLocalXAddressXor(2u, 3u, load_info.is_tiled); guest_blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe(xe_texture_load_dest, block_offset_host, - XE_TEXTURE_LOAD_64BPB_TRANSFORM(guest_blocks)); + byte_buffer_align16_store16_xe(xe_texture_load_dest, block_offset_host, + XE_TEXTURE_LOAD_64BPB_TRANSFORM(guest_blocks)); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/texture_load_8bpb.xesli b/src/xenia/gpu/shaders/texture_load_8bpb.xesli index 804a8e15e..92112d5a6 100644 --- a/src/xenia/gpu/shaders/texture_load_8bpb.xesli +++ b/src/xenia/gpu/shaders/texture_load_8bpb.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint2_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint2_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(8) { // 1 thread = 16 blocks. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -30,20 +18,20 @@ entry_inputs_end_code_begin_compute_xe if (any(greater_than_equal_xe(block_index.xy, load_info.size_blocks.xy))) { return; } - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, - load_info.size_blocks.y, 1u) + - load_info.host_offset) >> 4u); + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(block_index), load_info.host_pitch, + load_info.size_blocks.y, 1u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 0u) >> 3u; - array_buffer_store_xe( + XeTextureLoadSourceAddress(load_info, block_index, 0u); + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), - array_buffer_load_xe( + byte_buffer_align8_load8_xe(xe_texture_load_source, + block_offset_guest), + byte_buffer_align8_load8_xe( xe_texture_load_source, block_offset_guest + - (XeTextureLoadLocalXAddressXor(8u, 0u, load_info.is_tiled) - >> 3u)))); + XeTextureLoadLocalXAddressXor(8u, 0u, load_info.is_tiled)))); } entry_code_end_compute_xe diff --git a/src/xenia/gpu/shaders/texture_load_ctx1.cs.xesl b/src/xenia/gpu/shaders/texture_load_ctx1.cs.xesl index 6c093039b..6eb683269 100644 --- a/src/xenia/gpu/shaders/texture_load_ctx1.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_ctx1.cs.xesl @@ -24,19 +24,7 @@ // II JJ KK LL // MM NN OO PP -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 4 CTX1 blocks to 16x4 R8G8 texels. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -46,24 +34,24 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 2u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 2u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 3u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 3u); uint i; unroll_xe for (i = 0u; i < 2u; ++i) { if (i != 0u) { - ++block_offset_host; - // Odd 2 blocks = even 2 blocks + 32 bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_host += 16u; + block_offset_guest += XeTextureLoadLocalXAddressXor(2u, 3u, + load_info.is_tiled); } // Two blocks. uint4_xe blocks = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, + block_offset_guest), load_info.endian_32); // Unpack the endpoints as 0x00g000r0 0x00G000R0 0x00g100r1 0x00G100R1 so // they can be multiplied by their weights allowing overflow. @@ -71,22 +59,22 @@ entry_inputs_end_code_begin_compute_xe end_8in16.xz = ((blocks.xz >> 8u) & 0xFFu) | ((blocks.xz & 0xFFu) << 16u); end_8in16.yw = (blocks.xz >> 24u) | (blocks.xz & 0xFF0000u); uint2_xe weights_high = XeDXTHighColorWeights(blocks.yw); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeCTX1TwoBlocksRowToR8G8(end_8in16, weights_high)); dont_flatten_xe if (texel_index_host.y + 1u < load_info.height_texels) { - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + elements_pitch_host, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + load_info.host_pitch, XeCTX1TwoBlocksRowToR8G8(end_8in16, weights_high >> 8u)); dont_flatten_xe if (texel_index_host.y + 2u < load_info.height_texels) { - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 2u * elements_pitch_host, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 2u * load_info.host_pitch, XeCTX1TwoBlocksRowToR8G8(end_8in16, weights_high >> 16u)); dont_flatten_xe if (texel_index_host.y + 3u < load_info.height_texels) { - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, - block_offset_host + 3u * elements_pitch_host, + block_offset_host + 3u * load_info.host_pitch, XeCTX1TwoBlocksRowToR8G8(end_8in16, weights_high >> 24u)); } } diff --git a/src/xenia/gpu/shaders/texture_load_dxn_rg8.cs.xesl b/src/xenia/gpu/shaders/texture_load_dxn_rg8.cs.xesl index 80aa5a24d..432688633 100644 --- a/src/xenia/gpu/shaders/texture_load_dxn_rg8.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_dxn_rg8.cs.xesl @@ -10,19 +10,7 @@ #include "pixel_formats.xesli" #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 2 DXN blocks to 8x4 R8G8 texels. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -32,21 +20,20 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 2u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 2u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 4u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 4u); uint4_xe block_0 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - // Odd block = even block + 32 guest bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_guest += XeTextureLoadLocalXAddressXor(1u, 4u, + load_info.is_tiled); uint4_xe block_1 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); uint4_xe end_0 = (block_0.xxzz >> uint4_xe(0u, 8u, 0u, 8u)) & 0xFFu; uint4_xe end_1 = (block_1.xxzz >> uint4_xe(0u, 8u, 0u, 8u)) & 0xFFu; @@ -56,38 +43,38 @@ entry_inputs_end_code_begin_compute_xe XeDXT5HighAlphaWeights(end_0.zw, weights.y), XeDXT5HighAlphaWeights(end_1.xy, weights.z), XeDXT5HighAlphaWeights(end_1.zw, weights.w)); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8In16(end_0.xy, weights.x) | (XeDXT5RowToA8In16(end_0.zw, weights.y) << 8u), XeDXT5RowToA8In16(end_1.xy, weights.z) | (XeDXT5RowToA8In16(end_1.zw, weights.w) << 8u))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights >>= 12u; - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8In16(end_0.xy, weights.x) | (XeDXT5RowToA8In16(end_0.zw, weights.y) << 8u), XeDXT5RowToA8In16(end_1.xy, weights.z) | (XeDXT5RowToA8In16(end_1.zw, weights.w) << 8u))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights = uint4_xe(block_0.yw, block_1.yw) >> 8u; weights = uint4_xe(XeDXT5HighAlphaWeights(end_0.xy, weights.x), XeDXT5HighAlphaWeights(end_0.zw, weights.y), XeDXT5HighAlphaWeights(end_1.xy, weights.z), XeDXT5HighAlphaWeights(end_1.zw, weights.w)); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8In16(end_0.xy, weights.x) | (XeDXT5RowToA8In16(end_0.zw, weights.y) << 8u), XeDXT5RowToA8In16(end_1.xy, weights.z) | (XeDXT5RowToA8In16(end_1.zw, weights.w) << 8u))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights >>= 12u; - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8In16(end_0.xy, weights.x) | (XeDXT5RowToA8In16(end_0.zw, weights.y) << 8u), diff --git a/src/xenia/gpu/shaders/texture_load_dxt1_rgba8.cs.xesl b/src/xenia/gpu/shaders/texture_load_dxt1_rgba8.cs.xesl index 5aab74f27..439f56a70 100644 --- a/src/xenia/gpu/shaders/texture_load_dxt1_rgba8.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_dxt1_rgba8.cs.xesl @@ -10,19 +10,7 @@ #include "pixel_formats.xesli" #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 4 DXT1 blocks to 16x4 R8G8B8A8 texels. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -32,21 +20,20 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 4u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 4u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 3u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 3u); uint4_xe blocks_01 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - // Odd 2 blocks = even 2 blocks + 32 bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_guest += XeTextureLoadLocalXAddressXor(2u, 3u, + load_info.is_tiled); uint4_xe blocks_23 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); uint4_xe end_8in10_01 = uint4_xe(XeDXTColorEndpointsToBGR8In10(blocks_01.x), @@ -66,26 +53,26 @@ entry_inputs_end_code_begin_compute_xe if (texel_index_host.y + i >= load_info.height_texels) { break; } - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights >>= 8u; } - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, is_trans.x ? XeDXT1TransRowToRGBA8(end_8in10_01.xy, weights.x) : (XeDXTOpaqueRowToRGB8(end_8in10_01.xy, weights.x) | 0xFF000000u)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 1u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 0x10u, is_trans.y ? XeDXT1TransRowToRGBA8(end_8in10_01.zw, weights.y) : (XeDXTOpaqueRowToRGB8(end_8in10_01.zw, weights.y) | 0xFF000000u)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 2u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 0x20u, is_trans.z ? XeDXT1TransRowToRGBA8(end_8in10_23.xy, weights.z) : (XeDXTOpaqueRowToRGB8(end_8in10_23.xy, weights.z) | 0xFF000000u)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 3u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 0x30u, is_trans.w ? XeDXT1TransRowToRGBA8(end_8in10_23.zw, weights.w) : (XeDXTOpaqueRowToRGB8(end_8in10_23.zw, weights.w) | 0xFF000000u)); diff --git a/src/xenia/gpu/shaders/texture_load_dxt3_rgba8.cs.xesl b/src/xenia/gpu/shaders/texture_load_dxt3_rgba8.cs.xesl index 207030c32..077bd916a 100644 --- a/src/xenia/gpu/shaders/texture_load_dxt3_rgba8.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_dxt3_rgba8.cs.xesl @@ -10,19 +10,7 @@ #include "pixel_formats.xesli" #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 2 DXT3 blocks to 8x4 R8G8B8A8 texels. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -32,49 +20,49 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 4u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 4u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 4u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 4u); uint i; unroll_xe for (i = 0u; i < 2u; ++i) { if (i != 0u) { - ++block_offset_host; - // Odd block = even block + 32 guest bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_host += 16u; + block_offset_guest += XeTextureLoadLocalXAddressXor(1u, 4u, + load_info.is_tiled); } uint4_xe block = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, + block_offset_guest), load_info.endian_32); uint2_xe bgr_end_8in10 = XeDXTColorEndpointsToBGR8In10(block.z); // Sort the color indices so they can be used as weights for the second // endpoint. uint bgr_weights = XeDXTHighColorWeights(block.w); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights) + ((block.xxxx >> uint4_xe(0u, 4u, 8u, 12u)) & 0xFu) * 0x11000000u); dont_flatten_xe if (texel_index_host.y + 1u < load_info.height_texels) { - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + elements_pitch_host, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + load_info.host_pitch, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights >> 8u) + ((block.xxxx >> uint4_xe(16u, 20u, 24u, 28u)) & 0xFu) * 0x11000000u); dont_flatten_xe if (texel_index_host.y + 2u < load_info.height_texels) { - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 2u * elements_pitch_host, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 2u * load_info.host_pitch, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights >> 16u) + ((block.yyyy >> uint4_xe(0u, 4u, 8u, 12u)) & 0xFu) * 0x11000000u); dont_flatten_xe if (texel_index_host.y + 3u < load_info.height_texels) { - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, - block_offset_host + 3u * elements_pitch_host, + block_offset_host + 3u * load_info.host_pitch, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights >> 24u) + ((block.yyyy >> uint4_xe(16u, 20u, 24u, 28u)) & 0xFu) * 0x11000000u); diff --git a/src/xenia/gpu/shaders/texture_load_dxt3a.cs.xesl b/src/xenia/gpu/shaders/texture_load_dxt3a.cs.xesl index bfdb37601..c2015253f 100644 --- a/src/xenia/gpu/shaders/texture_load_dxt3a.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_dxt3a.cs.xesl @@ -10,19 +10,7 @@ #include "pixel_formats.xesli" #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 4 DXT3A blocks to 16x4 R8 texels (no need to convert to DXT3 // because the overhead is the same, 2x, but the size must be 4-aligned on @@ -34,38 +22,37 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 1u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 1u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 3u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 3u); uint4_xe blocks_01 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - // Odd 2 blocks = even 2 blocks + 32 bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_guest += XeTextureLoadLocalXAddressXor(2u, 3u, + load_info.is_tiled); uint4_xe blocks_23 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeDXT3FourBlocksRowToA8(uint4_xe(blocks_01.xz, blocks_23.xz))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; - array_buffer_store_xe( + block_offset_host += load_info.host_pitch; + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeDXT3FourBlocksRowToA8(uint4_xe(blocks_01.xz, blocks_23.xz) >> 16u)); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; - array_buffer_store_xe( + block_offset_host += load_info.host_pitch; + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeDXT3FourBlocksRowToA8(uint4_xe(blocks_01.yw, blocks_23.yw))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; - array_buffer_store_xe( + block_offset_host += load_info.host_pitch; + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeDXT3FourBlocksRowToA8( uint4_xe(blocks_01.yw, blocks_23.yw) >> 16u)); diff --git a/src/xenia/gpu/shaders/texture_load_dxt3aas1111.xesli b/src/xenia/gpu/shaders/texture_load_dxt3aas1111.xesli index 57d9e74e1..7ea57e610 100644 --- a/src/xenia/gpu/shaders/texture_load_dxt3aas1111.xesli +++ b/src/xenia/gpu/shaders/texture_load_dxt3aas1111.xesli @@ -9,19 +9,7 @@ #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 4 DXT3A-as-1111 blocks to 16x4 16bpp texels passed through an // externally provided @@ -34,53 +22,52 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 2u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 2u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 3u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 3u); uint4_xe blocks_01 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - // Odd 2 blocks = even 2 blocks + 32 bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_guest += XeTextureLoadLocalXAddressXor(2u, 3u, + load_info.is_tiled); uint4_xe blocks_23 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(blocks_01.xz)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 1u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 16u, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(blocks_23.xz)); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; uint4_xe high_halfblocks = uint4_xe(blocks_01.xz, blocks_23.xz) >> 16u; - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(high_halfblocks.xy)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 1u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 16u, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(high_halfblocks.zw)); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; - array_buffer_store_xe( + block_offset_host += load_info.host_pitch; + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(blocks_01.yw)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 1u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 16u, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(blocks_23.yw)); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; high_halfblocks = uint4_xe(blocks_01.yw, blocks_23.yw) >> 16u; - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(high_halfblocks.xy)); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 1u, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 16u, XE_TEXTURE_LOAD_DXT3A_AS_1_1_1_1_TO_16BPP(high_halfblocks.zw)); } } diff --git a/src/xenia/gpu/shaders/texture_load_dxt5_rgba8.cs.xesl b/src/xenia/gpu/shaders/texture_load_dxt5_rgba8.cs.xesl index 51dfcc080..5b935c740 100644 --- a/src/xenia/gpu/shaders/texture_load_dxt5_rgba8.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_dxt5_rgba8.cs.xesl @@ -10,19 +10,7 @@ #include "pixel_formats.xesli" #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 2 DXT5 blocks to 8x4 R8G8B8A8 texels. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -32,23 +20,23 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 4u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 4u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 4u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 4u); uint i; unroll_xe for (i = 0u; i < 2u; ++i) { if (i != 0u) { - ++block_offset_host; - // Odd block = even block + 32 guest bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_host += 16u; + block_offset_guest += XeTextureLoadLocalXAddressXor(1u, 4u, + load_info.is_tiled); } uint4_xe block = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, + block_offset_guest), load_info.endian_32); uint2_xe bgr_end_8in10 = XeDXTColorEndpointsToBGR8In10(block.z); // Sort the color indices so they can be used as weights for the second @@ -57,32 +45,32 @@ entry_inputs_end_code_begin_compute_xe uint2_xe alpha_end = (block.xx >> uint2_xe(0u, 8u)) & 0xFFu; uint alpha_weights = XeDXT5HighAlphaWeights( alpha_end, (block.x >> 16u) | ((block.y & 0xFFu) << 16u)); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights) | ((uint_x4_xe(XeDXT5RowToA8(alpha_end, alpha_weights)) << uint4_xe(24u, 16u, 8u, 0u)) & 0xFF000000u)); dont_flatten_xe if (texel_index_host.y + 1u < load_info.height_texels) { - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + elements_pitch_host, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + load_info.host_pitch, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights >> 8u) | ((uint_x4_xe(XeDXT5RowToA8(alpha_end, alpha_weights >> 12u)) << uint4_xe(24u, 16u, 8u, 0u)) & 0xFF000000u)); dont_flatten_xe if (texel_index_host.y + 2u < load_info.height_texels) { alpha_weights = XeDXT5HighAlphaWeights(alpha_end, block.y >> 8u); - array_buffer_store_xe( - xe_texture_load_dest, block_offset_host + 2u * elements_pitch_host, + byte_buffer_align16_store16_xe( + xe_texture_load_dest, block_offset_host + 2u * load_info.host_pitch, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights >> 16u) | ((uint_x4_xe(XeDXT5RowToA8(alpha_end, alpha_weights)) << uint4_xe(24u, 16u, 8u, 0u)) & 0xFF000000u)); dont_flatten_xe if (texel_index_host.y + 3u < load_info.height_texels) { - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, - block_offset_host + 3u * elements_pitch_host, + block_offset_host + 3u * load_info.host_pitch, XeDXTOpaqueRowToRGB8(bgr_end_8in10, bgr_weights >> 24u) | ((uint_x4_xe(XeDXT5RowToA8(alpha_end, alpha_weights >> 12u)) << uint4_xe(24u, 16u, 8u, 0u)) diff --git a/src/xenia/gpu/shaders/texture_load_dxt5a_r8.cs.xesl b/src/xenia/gpu/shaders/texture_load_dxt5a_r8.cs.xesl index d2fb00bf1..b601557bb 100644 --- a/src/xenia/gpu/shaders/texture_load_dxt5a_r8.cs.xesl +++ b/src/xenia/gpu/shaders/texture_load_dxt5a_r8.cs.xesl @@ -10,19 +10,7 @@ #include "pixel_formats.xesli" #include "texture_load.xesli" -array_buffer_wo_declare_xe(uint4_xe, xe_texture_load_dest, set=0, binding=0, u0, - space0) -array_buffer_declare_xe(uint4_xe, xe_texture_load_source, set=1, binding=0, t0, - space0) -entry_bindings_begin_compute_xe - XE_TEXTURE_LOAD_PUSH_CONST_BINDING - entry_binding_next_xe - array_buffer_wo_binding_xe(uint4_xe, xe_texture_load_dest, buffer(1)) - entry_binding_next_xe - array_buffer_binding_xe(uint4_xe, xe_texture_load_source, buffer(2)) -entry_bindings_end_inputs_begin_compute_xe - entry_in_global_thread_id_xe -entry_inputs_end_code_begin_compute_xe +XE_TEXTURE_LOAD_ENTRY(16) { // 1 thread = 4 DXT5A blocks to 16x4 R8 texels. XeTextureLoadInfo load_info = XeTextureLoadGetInfo(pass_push_consts_xe); @@ -32,21 +20,20 @@ entry_inputs_end_code_begin_compute_xe return; } uint3_xe texel_index_host = block_index << uint3_xe(2u, 2u, 0u); - uint block_offset_host = uint( - (XeTextureHostLinearOffset(int3_xe(texel_index_host), - load_info.host_pitch, load_info.height_texels, - 1u) + - load_info.host_offset) >> 4u); - uint elements_pitch_host = load_info.host_pitch >> 4u; + uint block_offset_host = + load_info.host_offset + + uint(XeTextureHostLinearOffset(int3_xe(texel_index_host), + load_info.host_pitch, + load_info.height_texels, 1u)); uint block_offset_guest = - XeTextureLoadSourceAddress(load_info, block_index, 3u) >> 4u; + XeTextureLoadSourceAddress(load_info, block_index, 3u); uint4_xe blocks_01 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); - // Odd 2 blocks = even 2 blocks + 32 bytes when tiled. - block_offset_guest += load_info.is_tiled ? 2u : 1u; + block_offset_guest += XeTextureLoadLocalXAddressXor(2u, 3u, + load_info.is_tiled); uint4_xe blocks_23 = XeEndianSwap32( - array_buffer_load_xe(xe_texture_load_source, block_offset_guest), + byte_buffer_align16_load16_xe(xe_texture_load_source, block_offset_guest), load_info.endian_32); uint4_xe end_01 = (blocks_01.xxzz >> uint4_xe(0u, 8u, 0u, 8u)) & 0xFFu; uint4_xe end_23 = (blocks_23.xxzz >> uint4_xe(0u, 8u, 0u, 8u)) & 0xFFu; @@ -57,38 +44,38 @@ entry_inputs_end_code_begin_compute_xe XeDXT5HighAlphaWeights(end_01.zw, weights.y), XeDXT5HighAlphaWeights(end_23.xy, weights.z), XeDXT5HighAlphaWeights(end_23.zw, weights.w)); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8(end_01.xy, weights.x), XeDXT5RowToA8(end_01.zw, weights.y), XeDXT5RowToA8(end_23.xy, weights.z), XeDXT5RowToA8(end_23.zw, weights.w))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights >>= 12u; - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8(end_01.xy, weights.x), XeDXT5RowToA8(end_01.zw, weights.y), XeDXT5RowToA8(end_23.xy, weights.z), XeDXT5RowToA8(end_23.zw, weights.w))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights = uint4_xe(blocks_01.yw, blocks_23.yw) >> 8u; weights = uint4_xe(XeDXT5HighAlphaWeights(end_01.xy, weights.x), XeDXT5HighAlphaWeights(end_01.zw, weights.y), XeDXT5HighAlphaWeights(end_23.xy, weights.z), XeDXT5HighAlphaWeights(end_23.zw, weights.w)); - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8(end_01.xy, weights.x), XeDXT5RowToA8(end_01.zw, weights.y), XeDXT5RowToA8(end_23.xy, weights.z), XeDXT5RowToA8(end_23.zw, weights.w))); dont_flatten_xe if (++texel_index_host.y < load_info.height_texels) { - block_offset_host += elements_pitch_host; + block_offset_host += load_info.host_pitch; weights >>= 12u; - array_buffer_store_xe( + byte_buffer_align16_store16_xe( xe_texture_load_dest, block_offset_host, uint4_xe(XeDXT5RowToA8(end_01.xy, weights.x), XeDXT5RowToA8(end_01.zw, weights.y), diff --git a/src/xenia/gpu/shaders/xenos_draw.hlsli b/src/xenia/gpu/shaders/xenos_draw.hlsli index 840662e27..a866ad460 100644 --- a/src/xenia/gpu/shaders/xenos_draw.hlsli +++ b/src/xenia/gpu/shaders/xenos_draw.hlsli @@ -23,7 +23,7 @@ cbuffer xe_system_cbuffer : register(b0) { uint4 xe_texture_swizzled_signs[2]; - uint xe_textures_resolved; + uint xe_textures_resolution_scaled; uint2 xe_sample_count_log2; float xe_alpha_test_reference; diff --git a/src/xenia/gpu/shared_memory.cc b/src/xenia/gpu/shared_memory.cc index e26ef4867..3f70a20c2 100644 --- a/src/xenia/gpu/shared_memory.cc +++ b/src/xenia/gpu/shared_memory.cc @@ -33,7 +33,7 @@ bool SharedMemory::InitializeCommon() { // them is probably beneficial, we do waste 16384 bytes with this alloc though uint64_t* system_page_flags_base = (uint64_t*)memory::AllocFixed( - nullptr, num_system_page_flags_ * 3 * sizeof(uint64_t), + nullptr, num_system_page_flags_ * 2 * sizeof(uint64_t), memory::AllocationType::kReserveCommit, memory::PageAccess::kReadWrite); if (!system_page_flags_base) { @@ -41,14 +41,10 @@ bool SharedMemory::InitializeCommon() { return false; } - system_page_flags_valid_ = system_page_flags_base, - system_page_flags_valid_and_gpu_resolved_ = - system_page_flags_base + (num_system_page_flags_), + system_page_flags_valid_ = system_page_flags_base; system_page_flags_valid_and_gpu_written_ = - system_page_flags_base + (num_system_page_flags_ * 2); + system_page_flags_base + num_system_page_flags_; memset(system_page_flags_valid_, 0, 8 * num_system_page_flags_entries); - memset(system_page_flags_valid_and_gpu_resolved_, 0, - 8 * num_system_page_flags_entries); memset(system_page_flags_valid_and_gpu_written_, 0, 8 * num_system_page_flags_entries); memory_invalidation_callback_handle_ = @@ -107,7 +103,6 @@ void SharedMemory::ShutdownCommon() { memory::DeallocFixed(system_page_flags_valid_, 0, memory::DeallocationType::kRelease); system_page_flags_valid_ = nullptr; - system_page_flags_valid_and_gpu_resolved_ = nullptr; system_page_flags_valid_and_gpu_written_ = nullptr; num_system_page_flags_ = 0; } @@ -286,8 +281,7 @@ void SharedMemory::FireWatches(uint32_t page_first, uint32_t page_last, } } -void SharedMemory::RangeWrittenByGpu(uint32_t start, uint32_t length, - bool is_resolve) { +void SharedMemory::RangeWrittenByGpu(uint32_t start, uint32_t length) { if (length == 0 || start >= kBufferSize) { return; } @@ -302,7 +296,7 @@ void SharedMemory::RangeWrittenByGpu(uint32_t start, uint32_t length, // Mark the range as valid (so pages are not reuploaded until modified by the // CPU) and watch it so the CPU can reuse it and this will be caught. - MakeRangeValid(start, length, true, is_resolve); + MakeRangeValid(start, length, true); } bool SharedMemory::AllocateSparseHostGpuMemoryRange( @@ -314,9 +308,7 @@ bool SharedMemory::AllocateSparseHostGpuMemoryRange( } void SharedMemory::MakeRangeValid(uint32_t start, uint32_t length, - bool written_by_gpu, - bool written_by_gpu_resolve) { - assert_false(written_by_gpu_resolve && !written_by_gpu); + bool written_by_gpu) { if (length == 0 || start >= kBufferSize) { return; } @@ -345,11 +337,6 @@ void SharedMemory::MakeRangeValid(uint32_t start, uint32_t length, } else { system_page_flags_valid_and_gpu_written_[i] &= ~valid_bits; } - if (written_by_gpu_resolve) { - system_page_flags_valid_and_gpu_resolved_[i] |= valid_bits; - } else { - system_page_flags_valid_and_gpu_resolved_[i] &= ~valid_bits; - } } } @@ -384,13 +371,9 @@ void SharedMemory::UnlinkWatchRange(WatchRange* range) { watch_range_first_free_ = range; } // todo: optimize, an enormous amount of cpu time (1.34%) is spent here. -bool SharedMemory::RequestRange(uint32_t start, uint32_t length, - bool* any_data_resolved_out) { +bool SharedMemory::RequestRange(uint32_t start, uint32_t length) { if (!length) { // Some texture or buffer is empty, for example - safe to draw in this case. - if (any_data_resolved_out) { - *any_data_resolved_out = false; - } return true; } if (start > kBufferSize || (kBufferSize - start) < length) { @@ -412,7 +395,6 @@ bool SharedMemory::RequestRange(uint32_t start, uint32_t length, std::pair* uploads = reinterpret_cast*>(upload_ranges_.data()); - bool any_data_resolved = false; uint32_t block_first = page_first >> 6; // swcache::PrefetchL1(&system_page_flags_[block_first]); uint32_t block_last = page_last >> 6; @@ -421,16 +403,12 @@ bool SharedMemory::RequestRange(uint32_t start, uint32_t length, { auto global_lock = global_critical_region_.Acquire(); TryFindUploadRange(block_first, block_last, page_first, page_last, - any_data_resolved, range_start, current_upload_range, - uploads); + range_start, current_upload_range, uploads); } if (range_start != UINT32_MAX) { uploads[current_upload_range++] = (std::make_pair(range_start, page_last + 1 - range_start)); } - if (any_data_resolved_out) { - *any_data_resolved_out = any_data_resolved; - } if (!current_upload_range) { return true; } @@ -451,34 +429,18 @@ void SharedMemory::TryFindUploadRange(const uint32_t& block_first, const uint32_t& block_last, const uint32_t& page_first, const uint32_t& page_last, - bool& any_data_resolved, uint32_t& range_start, unsigned int& current_upload_range, std::pair* uploads) { for (uint32_t i = block_first; i <= block_last; ++i) { - // const SystemPageFlagsBlock& block = system_page_flags_[i]; uint64_t block_valid = system_page_flags_valid_[i]; - uint64_t block_resolved = 0; - - if (any_data_resolved) { - block_resolved = 0; - } else { - block_resolved = system_page_flags_valid_and_gpu_resolved_[i]; - } if (i == block_first) { uint64_t block_before = mod_shift_left(uint64_t(1), page_first) - 1; block_valid |= block_before; - block_resolved &= ~block_before; } if (i == block_last && (page_last & 63) != 63) { uint64_t block_inside = mod_shift_left(uint64_t(1), page_last + 1) - 1; block_valid |= ~block_inside; - block_resolved &= block_inside; - } - // Consider pages in the block outside the requested range valid. - if (!block_resolved) { - } else { - any_data_resolved = true; } TryGetNextUploadRange(range_start, block_valid, i, current_upload_range, uploads); @@ -598,7 +560,6 @@ std::pair SharedMemory::MemoryInvalidationCallback( invalidate_bits &= (uint64_t(1) << ((page_last & 63) + 1)) - 1; } system_page_flags_valid_[i] &= ~invalidate_bits; - system_page_flags_valid_and_gpu_resolved_[i] &= ~invalidate_bits; system_page_flags_valid_and_gpu_written_[i] &= ~invalidate_bits; } diff --git a/src/xenia/gpu/shared_memory.h b/src/xenia/gpu/shared_memory.h index 3effe2771..23f92011d 100644 --- a/src/xenia/gpu/shared_memory.h +++ b/src/xenia/gpu/shared_memory.h @@ -71,13 +71,12 @@ class SharedMemory { // Checks if the range has been updated, uploads new data if needed and // ensures the host GPU memory backing the range are resident. Returns true if // the range has been fully updated and is usable. - bool RequestRange(uint32_t start, uint32_t length, - bool* any_data_resolved_out = nullptr); + bool RequestRange(uint32_t start, uint32_t length); void TryFindUploadRange(const uint32_t& block_first, const uint32_t& block_last, const uint32_t& page_first, const uint32_t& page_last, - bool& any_data_resolved, uint32_t& range_start, + uint32_t& range_start, unsigned int& current_upload_range, std::pair* uploads); @@ -100,7 +99,7 @@ class SharedMemory { // be called, to make sure, if the GPU writes don't overwrite *everything* in // the pages they touch, the CPU data is properly loaded to the unmodified // regions in those pages. - void RangeWrittenByGpu(uint32_t start, uint32_t length, bool is_resolve); + void RangeWrittenByGpu(uint32_t start, uint32_t length); protected: SharedMemory(Memory& memory); @@ -134,8 +133,7 @@ class SharedMemory { uint32_t length_allocations); // Mark the memory range as updated and protect it. - void MakeRangeValid(uint32_t start, uint32_t length, bool written_by_gpu, - bool written_by_gpu_resolve); + void MakeRangeValid(uint32_t start, uint32_t length, bool written_by_gpu); // Uploads a range of host pages - only called if host GPU sparse memory // allocation succeeded if needed. While uploading, MakeRangeValid must be @@ -204,9 +202,6 @@ class SharedMemory { // Subset of valid pages - whether each page in the GPU buffer contains data // that was written on the GPU, thus should not be invalidated spuriously. uint64_t valid_and_gpu_written; - // Subset of valid_and_gpu_written - whether each page in the GPU buffer - // contains data written specifically by resolving from EDRAM. - uint64_t valid_and_gpu_resolved; }; // chrispy: todo, systempageflagsblock should be 3 different arrays @@ -215,8 +210,7 @@ class SharedMemory { // std::vector system_page_flags_; uint64_t *system_page_flags_valid_ = nullptr, - *system_page_flags_valid_and_gpu_written_ = nullptr, - *system_page_flags_valid_and_gpu_resolved_ = nullptr; + *system_page_flags_valid_and_gpu_written_ = nullptr; unsigned num_system_page_flags_ = 0; static std::pair MemoryInvalidationCallbackThunk( void* context_ptr, uint32_t physical_address_start, uint32_t length, diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index 066b3b5ee..d5c7e5501 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -390,14 +390,12 @@ class SpirvShaderTranslator : public ShaderTranslator { bool native_2x_msaa_with_attachments, bool native_2x_msaa_no_attachments, bool edram_fragment_shader_interlock, - bool gamma_render_target_as_srgb = false, uint32_t draw_resolution_scale_x = 1, uint32_t draw_resolution_scale_y = 1) : features_(features), native_2x_msaa_with_attachments_(native_2x_msaa_with_attachments), native_2x_msaa_no_attachments_(native_2x_msaa_no_attachments), edram_fragment_shader_interlock_(edram_fragment_shader_interlock), - gamma_render_target_as_srgb_(gamma_render_target_as_srgb), draw_resolution_scale_x_(draw_resolution_scale_x), draw_resolution_scale_y_(draw_resolution_scale_y) {} @@ -779,9 +777,6 @@ class SpirvShaderTranslator : public ShaderTranslator { // (there's a single return from the shader). bool edram_fragment_shader_interlock_; // Whether with host render targets, k_8_8_8_8_GAMMA render targets are - // represented as host sRGB (gamma applied by the host after blending). - bool gamma_render_target_as_srgb_; - // Is currently writing the empty depth-only pixel shader, such as for depth // and stencil testing with fragment shader interlock. bool is_depth_only_fragment_shader_ = false; diff --git a/src/xenia/gpu/spirv_shader_translator_fetch.cc b/src/xenia/gpu/spirv_shader_translator_fetch.cc index 0cb910279..ee9f851a9 100644 --- a/src/xenia/gpu/spirv_shader_translator_fetch.cc +++ b/src/xenia/gpu/spirv_shader_translator_fetch.cc @@ -2272,7 +2272,6 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( builder_->createBranch(&block_sign_merge); // Gamma. builder_->setBuildPoint(&block_sign_gamma_start); - // TODO(Triang3l): Gamma resolve target as sRGB sampling. spv::Id sample_result_component_gamma = PWLGammaToLinear(sample_result_component_unsigned, false); // Get the current build point for the phi operation not to assume diff --git a/src/xenia/gpu/spirv_shader_translator_rb.cc b/src/xenia/gpu/spirv_shader_translator_rb.cc index cc600dc8a..6a6cb9aa9 100644 --- a/src/xenia/gpu/spirv_shader_translator_rb.cc +++ b/src/xenia/gpu/spirv_shader_translator_rb.cc @@ -1251,45 +1251,41 @@ void SpirvShaderTranslator::CompleteFragmentShaderInMain() { if_rt_write_mask_not_empty.makeEndIf(); if_fsi_color_written.makeEndIf(); } else { - if (!gamma_render_target_as_srgb_) { - // Convert to gamma space - this is incorrect, since it must be done - // after blending on the Xbox 360, but this is just one of many - // blending issues in the host render target path. When - // gamma_render_target_as_srgb_ is enabled, the host handles gamma - // conversion via sRGB render target format after blending. - uint_vector_temp_.clear(); - uint_vector_temp_.push_back(0); - uint_vector_temp_.push_back(1); - uint_vector_temp_.push_back(2); - spv::Id color_rgb = builder_->createRvalueSwizzle( - spv::NoPrecision, type_float3_, color, uint_vector_temp_); - spv::Id is_gamma = builder_->createBinOp( - spv::OpINotEqual, type_bool_, - builder_->createBinOp( - spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_, - builder_->makeUintConstant(kSysFlag_ConvertColor0ToGamma - << color_target_index)), - const_uint_0_); - SpirvBuilder::IfBuilder if_gamma( - is_gamma, spv::SelectionControlDontFlattenMask, *builder_); - spv::Id color_rgb_gamma = LinearToPWLGamma(color_rgb, false); - if_gamma.makeEndIf(); - color_rgb = if_gamma.createMergePhi(color_rgb_gamma, color_rgb); - { - std::unique_ptr color_rgba_shuffle_op = - std::make_unique(builder_->getUniqueId(), - type_float4_, - spv::OpVectorShuffle); - color_rgba_shuffle_op->addIdOperand(color_rgb); - color_rgba_shuffle_op->addIdOperand(color); - color_rgba_shuffle_op->addImmediateOperand(0); - color_rgba_shuffle_op->addImmediateOperand(1); - color_rgba_shuffle_op->addImmediateOperand(2); - color_rgba_shuffle_op->addImmediateOperand(3 + 3); - color = color_rgba_shuffle_op->getResultId(); - builder_->getBuildPoint()->addInstruction( - std::move(color_rgba_shuffle_op)); - } + // Convert to gamma space - this is incorrect, since it must be done + // after blending on the Xbox 360, but this is just one of many blending + // issues in the host render target path. + // TODO(Triang3l): Gamma as unorm8 check. + uint_vector_temp_.clear(); + uint_vector_temp_.push_back(0); + uint_vector_temp_.push_back(1); + uint_vector_temp_.push_back(2); + spv::Id color_rgb = builder_->createRvalueSwizzle( + spv::NoPrecision, type_float3_, color, uint_vector_temp_); + spv::Id is_gamma = builder_->createBinOp( + spv::OpINotEqual, type_bool_, + builder_->createBinOp( + spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_, + builder_->makeUintConstant(kSysFlag_ConvertColor0ToGamma + << color_target_index)), + const_uint_0_); + SpirvBuilder::IfBuilder if_gamma( + is_gamma, spv::SelectionControlDontFlattenMask, *builder_); + spv::Id color_rgb_gamma = LinearToPWLGamma(color_rgb, false); + if_gamma.makeEndIf(); + color_rgb = if_gamma.createMergePhi(color_rgb_gamma, color_rgb); + { + std::unique_ptr color_rgba_shuffle_op = + std::make_unique( + builder_->getUniqueId(), type_float4_, spv::OpVectorShuffle); + color_rgba_shuffle_op->addIdOperand(color_rgb); + color_rgba_shuffle_op->addIdOperand(color); + color_rgba_shuffle_op->addImmediateOperand(0); + color_rgba_shuffle_op->addImmediateOperand(1); + color_rgba_shuffle_op->addImmediateOperand(2); + color_rgba_shuffle_op->addImmediateOperand(3 + 3); + color = color_rgba_shuffle_op->getResultId(); + builder_->getBuildPoint()->addInstruction( + std::move(color_rgba_shuffle_op)); } builder_->createStore(color, color_variable); diff --git a/src/xenia/gpu/texture_cache.cc b/src/xenia/gpu/texture_cache.cc index e0e55aa09..8341764f1 100644 --- a/src/xenia/gpu/texture_cache.cc +++ b/src/xenia/gpu/texture_cache.cc @@ -71,76 +71,41 @@ namespace gpu { const TextureCache::LoadShaderInfo TextureCache::load_shader_info_[kLoadShaderCount] = { - // k8bpb - {3, 4, 1, 4}, - // k16bpb - {4, 4, 2, 4}, - // k32bpb - {4, 4, 4, 3}, - // k64bpb - {4, 4, 8, 2}, - // k128bpb - {4, 4, 16, 1}, - // kR5G5B5A1ToB5G5R5A1 - {4, 4, 2, 4}, - // kR5G6B5ToB5G6R5 - {4, 4, 2, 4}, - // kR5G5B6ToB5G6R5WithRBGASwizzle - {4, 4, 2, 4}, - // kRGBA4ToBGRA4 - {4, 4, 2, 4}, - // kRGBA4ToARGB4 - {4, 4, 2, 4}, - // kGBGR8ToGRGB8 - {4, 4, 4, 3}, - // kGBGR8ToRGB8 - {4, 4, 8, 3}, - // kBGRG8ToRGBG8 - {4, 4, 4, 3}, - // kBGRG8ToRGB8 - {4, 4, 8, 3}, - // kR10G11B11ToRGBA16 - {4, 4, 8, 3}, - // kR10G11B11ToRGBA16SNorm - {4, 4, 8, 3}, - // kR11G11B10ToRGBA16 - {4, 4, 8, 3}, - // kR11G11B10ToRGBA16SNorm - {4, 4, 8, 3}, - // kR16UNormToFloat - {4, 4, 2, 4}, - // kR16SNormToFloat - {4, 4, 2, 4}, - // kRG16UNormToFloat - {4, 4, 4, 3}, - // kRG16SNormToFloat - {4, 4, 4, 3}, - // kRGBA16UNormToFloat - {4, 4, 8, 2}, - // kRGBA16SNormToFloat - {4, 4, 8, 2}, - // kDXT1ToRGBA8 - {4, 4, 4, 2}, - // kDXT3ToRGBA8 - {4, 4, 4, 1}, - // kDXT5ToRGBA8 - {4, 4, 4, 1}, - // kDXNToRG8 - {4, 4, 2, 1}, - // kDXT3A - {4, 4, 1, 2}, - // kDXT3AAs1111ToBGRA4 - {4, 4, 2, 2}, - // kDXT3AAs1111ToARGB4 - {4, 4, 2, 2}, - // kDXT5AToR8 - {4, 4, 1, 2}, - // kCTX1 - {4, 4, 2, 2}, - // kDepthUnorm - {4, 4, 4, 3}, - // kDepthFloat - {4, 4, 4, 3}, + {1, 4}, // k8bpb + {2, 4}, // k16bpb + {4, 3}, // k32bpb + {8, 2}, // k64bpb + {16, 1}, // k128bpb + {2, 4}, // kR5G5B5A1ToB5G5R5A1 + {2, 4}, // kR5G6B5ToB5G6R5 + {2, 4}, // kR5G5B6ToB5G6R5WithRBGASwizzle + {2, 4}, // kRGBA4ToBGRA4 + {2, 4}, // kRGBA4ToARGB4 + {4, 3}, // kGBGR8ToGRGB8 + {8, 3}, // kGBGR8ToRGB8 + {4, 3}, // kBGRG8ToRGBG8 + {8, 3}, // kBGRG8ToRGB8 + {8, 3}, // kR10G11B11ToRGBA16 + {8, 3}, // kR10G11B11ToRGBA16SNorm + {8, 3}, // kR11G11B10ToRGBA16 + {8, 3}, // kR11G11B10ToRGBA16SNorm + {2, 4}, // kR16UNormToFloat + {2, 4}, // kR16SNormToFloat + {4, 3}, // kRG16UNormToFloat + {4, 3}, // kRG16SNormToFloat + {8, 2}, // kRGBA16UNormToFloat + {8, 2}, // kRGBA16SNormToFloat + {4, 2}, // kDXT1ToRGBA8 + {4, 1}, // kDXT3ToRGBA8 + {4, 1}, // kDXT5ToRGBA8 + {2, 1}, // kDXNToRG8 + {1, 2}, // kDXT3A + {2, 2}, // kDXT3AAs1111ToBGRA4 + {2, 2}, // kDXT3AAs1111ToARGB4 + {1, 2}, // kDXT5AToR8 + {2, 2}, // kCTX1 + {4, 3}, // kDepthUnorm + {4, 3}, // kDepthFloat }; TextureCache::TextureCache(const RegisterFile& register_file, @@ -329,7 +294,7 @@ void TextureCache::MarkRangeAsResolved(uint32_t start_unscaled, // Invalidate textures. Toggling individual textures between scaled and // unscaled also relies on invalidation through shared memory. - shared_memory().RangeWrittenByGpu(start_unscaled, length_unscaled, true); + shared_memory().RangeWrittenByGpu(start_unscaled, length_unscaled); } uint32_t TextureCache::GuestToHostSwizzle(uint32_t guest_swizzle, @@ -508,8 +473,6 @@ TextureCache::Texture::Texture(TextureCache& texture_cache, : texture_cache_(texture_cache), key_(key), guest_layout_(key.GetGuestLayout()), - base_resolved_(key.scaled_resolve), - mips_resolved_(key.scaled_resolve), last_usage_submission_index_(texture_cache.current_submission_index_), last_usage_time_(texture_cache.current_submission_time_), used_previous_(track_usage ? texture_cache.texture_used_last_ : nullptr), @@ -767,21 +730,17 @@ void TextureCache::LoadTexturesData(Texture** textures, uint32_t n_textures) { // portion of its pages is invalidated, in this case we'll need the texture // from the shared memory to load the unscaled parts. // TODO(Triang3l): Load unscaled parts. - bool base_resolved = texture.GetBaseResolved(); if (index_base_outdated & (1ULL << i)) { if (!shared_memory().RequestRange( texture_key.base_page << 12, - xe::align(texture.GetGuestBaseSize(), UINT32_C(16)), - texture_key.scaled_resolve ? nullptr : &base_resolved)) { + xe::align(texture.GetGuestBaseSize(), UINT32_C(16)))) { continue; } } - bool mips_resolved = texture.GetMipsResolved(); if (index_mips_outdated & (1ULL << i)) { if (!shared_memory().RequestRange( texture_key.mip_page << 12, - xe::align(texture.GetGuestMipsSize(), UINT32_C(16)), - texture_key.scaled_resolve ? nullptr : &mips_resolved)) { + xe::align(texture.GetGuestMipsSize(), UINT32_C(16)))) { continue; } } @@ -807,13 +766,6 @@ void TextureCache::LoadTexturesData(Texture** textures, uint32_t n_textures) { continue; } - // Update the source of the texture (resolve vs. CPU or memexport) for - // purposes of handling piecewise gamma emulation via sRGB and for - // resolution scale in sampling offsets. - if (!texture_key.scaled_resolve) { - texture.SetBaseResolved(base_resolved); - texture.SetMipsResolved(mips_resolved); - } // reque for makeuptodatandwatch textures[i] = &texture; } @@ -870,21 +822,17 @@ bool TextureCache::LoadTextureData(Texture& texture) { // its pages is invalidated, in this case we'll need the texture from the // shared memory to load the unscaled parts. // TODO(Triang3l): Load unscaled parts. - bool base_resolved = texture.GetBaseResolved(); if (base_outdated) { if (!shared_memory().RequestRange( texture_key.base_page << 12, - xe::align(texture.GetGuestBaseSize(), UINT32_C(16)), - texture_key.scaled_resolve ? nullptr : &base_resolved)) { + xe::align(texture.GetGuestBaseSize(), UINT32_C(16)))) { return false; } } - bool mips_resolved = texture.GetMipsResolved(); if (mips_outdated) { if (!shared_memory().RequestRange( texture_key.mip_page << 12, - xe::align(texture.GetGuestMipsSize(), UINT32_C(16)), - texture_key.scaled_resolve ? nullptr : &mips_resolved)) { + xe::align(texture.GetGuestMipsSize(), UINT32_C(16)))) { return false; } } @@ -909,14 +857,6 @@ bool TextureCache::LoadTextureData(Texture& texture) { return false; } - // Update the source of the texture (resolve vs. CPU or memexport) for - // purposes of handling piecewise gamma emulation via sRGB and for resolution - // scale in sampling offsets. - if (!texture_key.scaled_resolve) { - texture.SetBaseResolved(base_resolved); - texture.SetMipsResolved(mips_resolved); - } - // Mark the ranges as uploaded and watch them. This is needed for scaled // resolves as well to detect when the CPU wants to reuse the memory for a // regular texture or a vertex buffer, and thus the scaled resolve version is diff --git a/src/xenia/gpu/texture_cache.h b/src/xenia/gpu/texture_cache.h index f14d14a3d..aa2f946e8 100644 --- a/src/xenia/gpu/texture_cache.h +++ b/src/xenia/gpu/texture_cache.h @@ -137,7 +137,7 @@ class TextureCache { GetValidTextureBinding(fetch_constant_index); return binding ? binding->swizzled_signs : kSwizzledSignsUnsigned; } - bool IsActiveTextureResolved(uint32_t fetch_constant_index) const { + bool IsActiveTextureResolutionScaled(uint32_t fetch_constant_index) const { const TextureBinding* binding = GetValidTextureBinding(fetch_constant_index); if (!binding) { @@ -263,18 +263,6 @@ class TextureCache { } uint64_t last_usage_time() const { return last_usage_time_; } - bool GetBaseResolved() const { return base_resolved_; } - void SetBaseResolved(bool base_resolved) { - assert_false(!base_resolved && key().scaled_resolve); - base_resolved_ = base_resolved; - } - bool GetMipsResolved() const { return mips_resolved_; } - void SetMipsResolved(bool mips_resolved) { - assert_false(!mips_resolved && key().scaled_resolve); - mips_resolved_ = mips_resolved; - } - bool IsResolved() const { return base_resolved_ || mips_resolved_; } - bool base_outdated(const global_unique_lock_type& global_lock) const { return base_outdated_; } @@ -332,13 +320,6 @@ class TextureCache { // texture is 2D. bool force_load_3d_tiling_ = false; - // Whether the most up-to-date base / mips contain pages with data from a - // resolve operation (rather than from the CPU or memexport), primarily for - // choosing between piecewise linear gamma and sRGB when the former is - // emulated with the latter. - bool base_resolved_; - bool mips_resolved_; - // These are to be accessed within the global critical region to synchronize // with shared memory. // Whether the recent base level data needs reloading from the memory. @@ -501,11 +482,6 @@ class TextureCache { }; struct LoadShaderInfo { - // Log2 of the sizes, in bytes, of the elements in the source (guest) and - // the destination (host) buffer bindings accessed by the copying shader, - // since the shader may copy multiple blocks per one invocation. - uint32_t source_bpe_log2; - uint32_t dest_bpe_log2; // Number of bytes in a host resolution-scaled block (corresponding to a // guest block if not decompressing, or a host texel if decompressing) // written by the shader. diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 417bc8824..e81536c68 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -2748,7 +2748,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type, // Invalidate textures in memexported memory and watch for changes. for (const draw_util::MemExportRange& memexport_range : memexport_ranges_) { shared_memory_->RangeWrittenByGpu(memexport_range.base_address_dwords << 2, - memexport_range.size_bytes, false); + memexport_range.size_bytes); } // CPU readback for memexport data (if enabled). @@ -4031,11 +4031,13 @@ void VulkanCommandProcessor::UpdateSystemConstantValues( flags |= uint32_t(alpha_test_function) << SpirvShaderTranslator::kSysFlag_AlphaPassIfLess_Shift; // Gamma writing. - // TODO(Triang3l): Gamma as sRGB check. - for (uint32_t i = 0; i < xenos::kMaxColorRenderTargets; ++i) { - if (color_infos[i].color_format == - xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { - flags |= SpirvShaderTranslator::kSysFlag_ConvertColor0ToGamma << i; + // TODO(Triang3l): Gamma as unorm8 check. + if (!edram_fragment_shader_interlock) { + for (uint32_t i = 0; i < xenos::kMaxColorRenderTargets; ++i) { + if (color_infos[i].color_format == + xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA) { + flags |= SpirvShaderTranslator::kSysFlag_ConvertColor0ToGamma << i; + } } } if (edram_fragment_shader_interlock && depth_stencil_enabled) { @@ -4216,7 +4218,8 @@ void VulkanCommandProcessor::UpdateSystemConstantValues( while (xe::bit_scan_forward(textures_remaining, &texture_index)) { textures_remaining &= ~(UINT32_C(1) << texture_index); textures_resolved |= - uint32_t(texture_cache_->IsActiveTextureResolved(texture_index)) + uint32_t( + texture_cache_->IsActiveTextureResolutionScaled(texture_index)) << texture_index; } dirty |= system_constants_.textures_resolved != textures_resolved; diff --git a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc index 5ffaded3c..e47d82637 100644 --- a/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc +++ b/src/xenia/gpu/vulkan/vulkan_pipeline_cache.cc @@ -74,7 +74,6 @@ bool VulkanPipelineCache::Initialize() { render_target_cache_.msaa_2x_attachments_supported(), render_target_cache_.msaa_2x_no_attachments_supported(), edram_fragment_shader_interlock, - render_target_cache_.gamma_render_target_as_srgb(), render_target_cache_.draw_resolution_scale_x(), render_target_cache_.draw_resolution_scale_y()); diff --git a/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc b/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc index 9783d3973..ab2cde38c 100644 --- a/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc +++ b/src/xenia/gpu/vulkan/vulkan_render_target_cache.cc @@ -519,8 +519,13 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) { if (path_ == Path::kHostRenderTargets) { // Host render targets. + // TODO(Triang3l): When color space conversion is implemented in the + // ownership transfer and resolve dump shaders, allow + // `gamma_render_target_as_unorm16` if VK_FORMAT_R16G16B16A16_UNORM supports + // the SAMPLED_IMAGE | COLOR_ATTACHMENT | COLOR_ATTACHMENT_BLEND features. + gamma_render_target_as_unorm16_ = false; + depth_float24_round_ = cvars::depth_float24_round; - gamma_render_target_as_srgb_ = cvars::gamma_render_target_as_srgb; // Host depth storing pipeline layout. VkDescriptorSetLayout host_depth_store_descriptor_set_layouts[] = { @@ -721,8 +726,8 @@ bool VulkanRenderTargetCache::Initialize(uint32_t shared_memory_binding_count) { } else if (path_ == Path::kPixelShaderInterlock) { // Pixel (fragment) shader interlock. - // Blending is done in linear space directly in shaders. - gamma_render_target_as_srgb_ = false; + // Piecewise linear gamma is 8-bit with programmable blending. + gamma_render_target_as_unorm16_ = false; // Always true float24 depth rounded to the nearest even. depth_float24_round_ = true; @@ -1407,11 +1412,6 @@ bool VulkanRenderTargetCache::Update( depth_and_color_render_targets, last_update_transfers()); - uint32_t render_targets_are_srgb = - gamma_render_target_as_srgb_ - ? last_update_accumulated_color_targets_are_gamma() - : 0; - if (depth_and_color_render_targets[0]) { render_pass_key.depth_and_color_used |= 1 << 0; render_pass_key.depth_format = @@ -1420,30 +1420,22 @@ bool VulkanRenderTargetCache::Update( if (depth_and_color_render_targets[1]) { render_pass_key.depth_and_color_used |= 1 << 1; render_pass_key.color_0_view_format = - (render_targets_are_srgb & (1 << 0)) - ? xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA - : depth_and_color_render_targets[1]->key().GetColorFormat(); + depth_and_color_render_targets[1]->key().GetColorFormat(); } if (depth_and_color_render_targets[2]) { render_pass_key.depth_and_color_used |= 1 << 2; render_pass_key.color_1_view_format = - (render_targets_are_srgb & (1 << 1)) - ? xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA - : depth_and_color_render_targets[2]->key().GetColorFormat(); + depth_and_color_render_targets[2]->key().GetColorFormat(); } if (depth_and_color_render_targets[3]) { render_pass_key.depth_and_color_used |= 1 << 3; render_pass_key.color_2_view_format = - (render_targets_are_srgb & (1 << 2)) - ? xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA - : depth_and_color_render_targets[3]->key().GetColorFormat(); + depth_and_color_render_targets[3]->key().GetColorFormat(); } if (depth_and_color_render_targets[4]) { render_pass_key.depth_and_color_used |= 1 << 4; render_pass_key.color_3_view_format = - (render_targets_are_srgb & (1 << 3)) - ? xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA - : depth_and_color_render_targets[4]->key().GetColorFormat(); + depth_and_color_render_targets[4]->key().GetColorFormat(); } const Framebuffer* framebuffer = last_update_framebuffer_; @@ -1703,8 +1695,8 @@ VkFormat VulkanRenderTargetCache::GetColorVulkanFormat( case xenos::ColorRenderTargetFormat::k_8_8_8_8: return VK_FORMAT_R8G8B8A8_UNORM; case xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA: - return gamma_render_target_as_srgb_ ? VK_FORMAT_R8G8B8A8_SRGB - : VK_FORMAT_R8G8B8A8_UNORM; + return gamma_render_target_as_unorm16_ ? VK_FORMAT_R16G16B16A16_UNORM + : VK_FORMAT_R8G8B8A8_UNORM; case xenos::ColorRenderTargetFormat::k_2_10_10_10: case xenos::ColorRenderTargetFormat::k_2_10_10_10_AS_10_10_10_10: return VK_FORMAT_A2B10G10R10_UNORM_PACK32; @@ -1775,9 +1767,6 @@ VulkanRenderTargetCache::VulkanRenderTarget::~VulkanRenderTarget() { if (view_color_transfer_separate_ != VK_NULL_HANDLE) { dfn.vkDestroyImageView(device, view_color_transfer_separate_, nullptr); } - if (view_srgb_ != VK_NULL_HANDLE) { - dfn.vkDestroyImageView(device, view_srgb_, nullptr); - } if (view_stencil_ != VK_NULL_HANDLE) { dfn.vkDestroyImageView(device, view_stencil_, nullptr); } @@ -1789,6 +1778,10 @@ VulkanRenderTargetCache::VulkanRenderTarget::~VulkanRenderTarget() { dfn.vkFreeMemory(device, memory_, nullptr); } +bool VulkanRenderTargetCache::IsGammaFormatHostStorageSeparate() const { + return gamma_render_target_as_unorm16_; +} + uint32_t VulkanRenderTargetCache::GetMaxRenderTargetWidth() const { const ui::vulkan::VulkanDevice::Properties& device_properties = command_processor_.GetVulkanDevice()->properties(); @@ -1838,7 +1831,6 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( image_create_info.pQueueFamilyIndices = nullptr; image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkFormat transfer_format; - bool is_srgb_view_needed = false; if (key.is_depth) { image_create_info.format = GetDepthVulkanFormat(key.GetDepthFormat()); transfer_format = image_create_info.format; @@ -1847,11 +1839,7 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( xenos::ColorRenderTargetFormat color_format = key.GetColorFormat(); image_create_info.format = GetColorVulkanFormat(color_format); transfer_format = GetColorOwnershipTransferVulkanFormat(color_format); - is_srgb_view_needed = - gamma_render_target_as_srgb_ && - (color_format == xenos::ColorRenderTargetFormat::k_8_8_8_8 || - color_format == xenos::ColorRenderTargetFormat::k_8_8_8_8_GAMMA); - if (image_create_info.format != transfer_format || is_srgb_view_needed) { + if (image_create_info.format != transfer_format) { image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; } image_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; @@ -1905,7 +1893,6 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( } VkImageView view_depth_stencil = VK_NULL_HANDLE; VkImageView view_stencil = VK_NULL_HANDLE; - VkImageView view_srgb = VK_NULL_HANDLE; VkImageView view_color_transfer_separate = VK_NULL_HANDLE; if (key.is_depth) { view_create_info.subresourceRange.aspectMask = @@ -1939,22 +1926,6 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( return nullptr; } } else { - if (is_srgb_view_needed) { - view_create_info.format = VK_FORMAT_R8G8B8A8_SRGB; - if (dfn.vkCreateImageView(device, &view_create_info, nullptr, - &view_srgb) != VK_SUCCESS) { - XELOGE( - "VulkanRenderTarget: Failed to create an sRGB view for a {}x{} " - "{}xMSAA render target", - image_create_info.extent.width, image_create_info.extent.height, - uint32_t(1) << uint32_t(key.msaa_samples), - xenos::GetColorRenderTargetFormatName(key.GetColorFormat())); - dfn.vkDestroyImageView(device, view_depth_color, nullptr); - dfn.vkDestroyImage(device, image, nullptr); - dfn.vkFreeMemory(device, memory, nullptr); - return nullptr; - } - } if (transfer_format != image_create_info.format) { view_create_info.format = transfer_format; if (dfn.vkCreateImageView(device, &view_create_info, nullptr, @@ -1964,9 +1935,6 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( "{}xMSAA {} render target", image_create_info.extent.width, image_create_info.extent.height, uint32_t(1) << uint32_t(key.msaa_samples), key.GetFormatName()); - if (view_srgb != VK_NULL_HANDLE) { - dfn.vkDestroyImageView(device, view_srgb, nullptr); - } dfn.vkDestroyImageView(device, view_depth_color, nullptr); dfn.vkDestroyImage(device, image, nullptr); dfn.vkFreeMemory(device, memory, nullptr); @@ -1987,9 +1955,6 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( if (view_color_transfer_separate != VK_NULL_HANDLE) { dfn.vkDestroyImageView(device, view_color_transfer_separate, nullptr); } - if (view_srgb != VK_NULL_HANDLE) { - dfn.vkDestroyImageView(device, view_srgb, nullptr); - } dfn.vkDestroyImageView(device, view_depth_color, nullptr); dfn.vkDestroyImage(device, image, nullptr); dfn.vkFreeMemory(device, memory, nullptr); @@ -2037,7 +2002,7 @@ RenderTargetCache::RenderTarget* VulkanRenderTargetCache::CreateRenderTarget( 0, nullptr); return new VulkanRenderTarget(key, *this, image, memory, view_depth_color, - view_depth_stencil, view_stencil, view_srgb, + view_depth_stencil, view_stencil, view_color_transfer_separate, descriptor_set_index_transfer_source); } diff --git a/src/xenia/gpu/vulkan/vulkan_render_target_cache.h b/src/xenia/gpu/vulkan/vulkan_render_target_cache.h index f1f1136b5..f23a3abc4 100644 --- a/src/xenia/gpu/vulkan/vulkan_render_target_cache.h +++ b/src/xenia/gpu/vulkan/vulkan_render_target_cache.h @@ -58,7 +58,6 @@ class VulkanRenderTargetCache final : public RenderTargetCache { // even for kD24S8. xenos::DepthRenderTargetFormat depth_format : xenos::kDepthRenderTargetFormatBits; // 8 - // Linear or sRGB included if host sRGB is used. xenos::ColorRenderTargetFormat color_0_view_format : xenos::kColorRenderTargetFormatBits; // 12 xenos::ColorRenderTargetFormat color_1_view_format @@ -155,9 +154,6 @@ class VulkanRenderTargetCache final : public RenderTargetCache { return depth_unorm24_vulkan_format_supported_; } bool depth_float24_round() const { return depth_float24_round_; } - bool gamma_render_target_as_srgb() const { - return gamma_render_target_as_srgb_; - } bool msaa_2x_attachments_supported() const { return msaa_2x_attachments_supported_; @@ -186,6 +182,8 @@ class VulkanRenderTargetCache final : public RenderTargetCache { bool* is_integer_out = nullptr) const; protected: + bool IsGammaFormatHostStorageSeparate() const override; + uint32_t GetMaxRenderTargetWidth() const override; uint32_t GetMaxRenderTargetHeight() const override; @@ -336,7 +334,6 @@ class VulkanRenderTargetCache final : public RenderTargetCache { VkImage image, VkDeviceMemory memory, VkImageView view_depth_color, VkImageView view_depth_stencil, VkImageView view_stencil, - VkImageView view_srgb, VkImageView view_color_transfer_separate, size_t descriptor_set_index_transfer_source) : RenderTarget(key), @@ -346,7 +343,6 @@ class VulkanRenderTargetCache final : public RenderTargetCache { view_depth_color_(view_depth_color), view_depth_stencil_(view_depth_stencil), view_stencil_(view_stencil), - view_srgb_(view_srgb), view_color_transfer_separate_(view_color_transfer_separate), descriptor_set_index_transfer_source_( descriptor_set_index_transfer_source) {} @@ -421,7 +417,6 @@ class VulkanRenderTargetCache final : public RenderTargetCache { // Optional views. VkImageView view_depth_stencil_; VkImageView view_stencil_; - VkImageView view_srgb_; VkImageView view_color_transfer_separate_; // 2 sampled images for depth / stencil, 1 sampled image for color. @@ -866,7 +861,7 @@ class VulkanRenderTargetCache final : public RenderTargetCache { void DumpRenderTargets(uint32_t dump_base, uint32_t dump_row_length_used, uint32_t dump_rows, uint32_t dump_pitch); - bool gamma_render_target_as_srgb_ = false; + bool gamma_render_target_as_unorm16_ = false; bool depth_unorm24_vulkan_format_supported_ = false; bool depth_float24_round_ = false; diff --git a/src/xenia/gpu/vulkan/vulkan_shared_memory.cc b/src/xenia/gpu/vulkan/vulkan_shared_memory.cc index 0c1d03aaa..fe8dc6487 100644 --- a/src/xenia/gpu/vulkan/vulkan_shared_memory.cc +++ b/src/xenia/gpu/vulkan/vulkan_shared_memory.cc @@ -446,7 +446,7 @@ bool VulkanSharedMemory::UploadRanges( break; } MakeRangeValid(upload_range_start << page_size_log2(), - uint32_t(upload_buffer_size), false, false); + uint32_t(upload_buffer_size), false); if (upload_buffer_size < (1ULL << 32) && upload_buffer_size > 8192) { memory::vastcpy( diff --git a/src/xenia/gpu/vulkan/vulkan_texture_cache.cc b/src/xenia/gpu/vulkan/vulkan_texture_cache.cc index 155358546..b7224ed9a 100644 --- a/src/xenia/gpu/vulkan/vulkan_texture_cache.cc +++ b/src/xenia/gpu/vulkan/vulkan_texture_cache.cc @@ -1335,11 +1335,6 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture, write_descriptor_set_dest.pTexelBufferView = nullptr; } // TODO(Triang3l): Use a single 512 MB shared memory binding if possible. - // Aligning because if the data for a vector in a storage buffer is provided - // partially, the value read may still be (0, 0, 0, 0), and small (especially - // linear) textures won't be loaded correctly. - uint32_t source_length_alignment = UINT32_C(1) - << load_shader_info.source_bpe_log2; VkDescriptorSet descriptor_set_source_base = VK_NULL_HANDLE; VkDescriptorSet descriptor_set_source_mips = VK_NULL_HANDLE; VkDescriptorBufferInfo write_descriptor_set_source_base_buffer_info; @@ -1374,10 +1369,10 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture, write_descriptor_set_source_base_buffer_info.buffer = scaled_buffer; write_descriptor_set_source_base_buffer_info.offset = buffer_relative_offset; - write_descriptor_set_source_base_buffer_info.range = - xe::align(guest_size * draw_resolution_scale_area, - source_length_alignment); - + // Align because shaders use up to 16-byte loads for multiple + // blocks at once. + write_descriptor_set_source_base_buffer_info.range = xe::align( + guest_size * draw_resolution_scale_area, uint32_t(16)); } else { XELOGE( "Scaled resolve texture load: Failed to get current scaled " @@ -1405,8 +1400,10 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture, vulkan_shared_memory.buffer(); write_descriptor_set_source_base_buffer_info.offset = texture_key.base_page << 12; + // Align (primarily the last row of linear textures) because shaders use + // up to 16-byte loads for multiple blocks at once. write_descriptor_set_source_base_buffer_info.range = - xe::align(vulkan_texture.GetGuestBaseSize(), source_length_alignment); + xe::align(vulkan_texture.GetGuestBaseSize(), uint32_t(16)); } VkWriteDescriptorSet& write_descriptor_set_source_base = write_descriptor_sets[write_descriptor_set_count++]; @@ -1440,8 +1437,10 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture, vulkan_shared_memory.buffer(); write_descriptor_set_source_mips_buffer_info.offset = texture_key.mip_page << 12; + // Align (primarily the last row of a linear packed mip tail) because + // shaders use up to 16-byte loads for multiple blocks at once. write_descriptor_set_source_mips_buffer_info.range = - xe::align(vulkan_texture.GetGuestMipsSize(), source_length_alignment); + xe::align(vulkan_texture.GetGuestMipsSize(), uint32_t(16)); VkWriteDescriptorSet& write_descriptor_set_source_mips = write_descriptor_sets[write_descriptor_set_count++]; write_descriptor_set_source_mips.sType = diff --git a/src/xenia/ui/shaders/xesl.xesli b/src/xenia/ui/shaders/xesl.xesli index fbe30d097..deec8f07c 100644 --- a/src/xenia/ui/shaders/xesl.xesli +++ b/src/xenia/ui/shaders/xesl.xesli @@ -281,70 +281,70 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } #endif // SHADING_LANGUAGE_*_XE #ifndef entry_outputs_begin_xe #define entry_outputs_begin_xe -#endif // !entry_outputs_begin_xe +#endif #ifndef entry_out_position_xe #define entry_out_position_xe -#endif // !entry_out_position_xe +#endif #ifndef entry_outputs_end_stage_inputs_begin_xe #define entry_outputs_end_stage_inputs_begin_xe -#endif // !entry_outputs_end_stage_inputs_begin_xe +#endif #ifndef entry_in_stage_vertex_xe #define entry_in_stage_vertex_xe(type, name, index, semantic) \ entry_in_stage_xe(type, name, index, semantic) -#endif // !entry_in_stage_vertex_xe +#endif #ifndef entry_stage_inputs_end_bindings_begin_vertex_xe #define entry_stage_inputs_end_bindings_begin_vertex_xe -#endif // !entry_stage_inputs_end_bindings_begin_vertex_xe +#endif #ifndef entry_stage_inputs_end_bindings_begin_pixel_xe #define entry_stage_inputs_end_bindings_begin_pixel_xe -#endif // !entry_stage_inputs_end_bindings_begin_pixel_xe +#endif #ifndef entry_bindings_begin_compute_xe #define entry_bindings_begin_compute_xe -#endif // !entry_bindings_begin_compute_xe +#endif #ifndef entry_binding_next_xe #define entry_binding_next_xe -#endif // !entry_binding_next_xe +#endif #ifndef entry_bindings_end_inputs_begin_xe #define entry_bindings_end_inputs_begin_xe -#endif // !entry_bindings_end_inputs_begin_xe +#endif #ifndef entry_bindings_empty_end_inputs_begin_xe #define entry_bindings_empty_end_inputs_begin_xe -#endif // !entry_bindings_empty_end_inputs_begin_xe +#endif #ifndef entry_bindings_end_inputs_begin_compute_xe #define entry_bindings_end_inputs_begin_compute_xe -#endif // !entry_bindings_end_inputs_begin_compute_xe +#endif #ifndef entry_input_next_xe #define entry_input_next_xe -#endif // !entry_input_next_xe +#endif #ifndef entry_in_stage_inputs_xe #define entry_in_stage_inputs_xe -#endif // !entry_in_stage_inputs_xe +#endif #ifndef entry_in_vertex_id_xe #define entry_in_vertex_id_xe -#endif // !entry_in_vertex_id_xe +#endif #ifndef entry_in_pixel_coord_xe #define entry_in_pixel_coord_xe -#endif // !entry_in_pixel_coord_xe +#endif #ifndef entry_in_group_id_xe #define entry_in_group_id_xe -#endif // !entry_in_group_id_xe +#endif #ifndef entry_in_local_thread_id_xe #define entry_in_local_thread_id_xe -#endif // !entry_in_local_thread_id_xe +#endif #ifndef entry_in_global_thread_id_xe #define entry_in_global_thread_id_xe -#endif // !entry_in_global_thread_id_xe +#endif #ifndef entry_in_local_thread_index_xe #define entry_in_local_thread_index_xe -#endif // !entry_in_local_thread_index_xe +#endif #ifndef entry_code_end_xe #define entry_code_end_xe \ entry_return_xe \ } -#endif // !entry_code_end_xe +#endif #ifndef entry_code_end_compute_xe #define entry_code_end_compute_xe } -#endif // !entry_code_end_compute_xe +#endif // NDC_DIRECTION_Y_XE, assuming a positive viewport height, is: // * 1.0 if +out_position_xe.y is towards +in_pixel_coord_xe.y, @@ -353,7 +353,7 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } #define NDC_DIRECTION_Y_XE 1.0f #else #define NDC_DIRECTION_Y_XE -1.0f -#endif // SHADING_LANGUAGE_GLSL_XE +#endif #if SHADING_LANGUAGE_GLSL_XE // GLSL requires just const for declaring a constant in the global scope. @@ -461,140 +461,214 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } #endif // SHADING_LANGUAGE_*_XE #ifndef const_buffer_binding_xe #define const_buffer_binding_xe(name, msl_buffer) -#endif // !const_buffer_binding_xe +#endif #ifndef push_const_binding_xe #define push_const_binding_xe(msl_buffer) -#endif // !push_const_binding_xe +#endif -// Declarations of typed storage buffers and dword buffers (_declare) must be -// outside the entry point, but their bindings (_binding) must also be specified -// in the entry point binding declarations. +// Byte buffers represent raw data accessible as `uint` vectors, addressed with +// a byte offset with some alignment requirement, and implemented as storage +// buffers on GLSL, byte address buffers on HLSL, and buffer pointers on MSL. // -// An array buffer is a buffer limited to 1/2/4-component vectors of 32-bit -// integers and floats, a typed buffer on Direct3D, but a storage buffer (as -// opposed to a texel buffer, which has a very small minimum requirement for the -// maximum size) on Vulkan. +// These underlying binding types were chosen primarily because of the high +// range limits they offer, as well as the ability for the compiler and the GPU +// to take more optimal access paths as it's known that no type conversion would +// be necessary. // -// A UInt vector buffer is a buffer containing 32-bit values, but loading or -// storing may be done for 2, 3 or 4 consecutive values that are still -// 32-bit-aligned, and depending on the language and hardware support, access -// of multiple elements may or may not be compiled into a single hardware -// instruction instead of separate accesses of individual elements. Each index -// value corresponds to a 32-bit element. Implementations for languages without -// native support must use functions, not macros, for adding the component -// offset to the index to avoid evaluating the address multiple times. +// In Vulkan, the minimum required `maxStorageBufferRange` is 128 MB, while only +// 65536 is required for `maxTexelBufferElements`. +// +// In Direct3D 11 and 12, the range limit for typed buffers is 2^27 elements +// (`REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP`), and according to "Summary of +// Changes in this Chapter from D3D10 to D3D11.3" in the chapter 21 "System +// Limits on Various Resources" in the Direct3D 11.3 Functional Specification, +// this limit also applies to structured buffers. However, the entire resource +// (up to 2 GB - `REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM` - in most +// cases) must be accessible via a byte address buffer. +// +// Also, byte address buffers were chosen over structured buffers because 8-byte +// and 16-byte accesses are common, and the same buffer may need to be accessed +// with different granularities, however, in Direct3D 11, one buffer can't be +// accessed with different structure byte strides. +// +// Bounds checking is not guaranteed for byte buffers (may be bound via root +// descriptors on Direct3D 12, and on MSL they're bound as pointers). +// +// For 4-aligned byte buffers, loads larger than the alignment of the buffer are +// supported, with the `u` load expecting the address to be aligned to the +// buffer alignment, and the `a` load expecting it to be aligned to the size of +// the loaded data. +// +// Declarations of byte buffers (`_declare`) must be outside the entry point, +// but their bindings (`_binding`) must also be specified in the entry point +// function signature. This is necessary so byte buffers can be declared and +// used in header files and in functions declared in them, as they're +// implemented as buffer blocks in GLSL. +// +// The `_impl` definitions are for internal use in this file. + #if SHADING_LANGUAGE_GLSL_XE - // Binding declarations. - #define array_buffer_declare_xe(value_type, name, glsl_set, glsl_binding, \ - hlsl_t, hlsl_t_space) \ - layout(std430, glsl_set, glsl_binding) \ - readonly buffer name##_xe_block { \ - value_type data[]; \ + #define byte_buffer_declare_xe_impl(value_type, name, glsl_set, \ + glsl_binding, hlsl_t, hlsl_t_space) \ + layout(std430, glsl_set, glsl_binding) \ + readonly buffer name##_xe_block { \ + value_type data[]; \ } name; - #define array_buffer_wo_declare_xe(value_type, name, glsl_set, glsl_binding, \ - hlsl_u, hlsl_u_space) \ - layout(std430, glsl_set, glsl_binding) \ - writeonly buffer name##_xe_block { \ - value_type data[]; \ + #define byte_buffer_wo_declare_xe_impl(value_type, name, glsl_set, \ + glsl_binding, hlsl_t, hlsl_t_space) \ + layout(std430, glsl_set, glsl_binding) \ + writeonly buffer name##_xe_block { \ + value_type data[]; \ } name; - #define uint_vector_buffer_declare_xe(name, glsl_set, glsl_binding, hlsl_t, \ - hlsl_t_space) \ - layout(std430, glsl_set, glsl_binding) \ - readonly buffer name##_xe_block { \ - uint data[]; \ - } name; \ - uint2_xe name##_xe_load2(uint position) { \ - return uint2_xe(name.data[position], name.data[position + 1u]); \ - } \ - uint3_xe name##_xe_load3(uint position) { \ - return uint3_xe(name.data[position], name.data[position + 1u], \ - name.data[position + 2u]); \ - } \ - uint4_xe name##_xe_load4(uint position) { \ - return uint4_xe(name.data[position], name.data[position + 1u], \ - name.data[position + 2u], name.data[position + 3u]); \ - } - // Loading and storing. - #define array_buffer_load_xe(name, position) ((name).data[uint(position)]) - #define array_buffer_store_xe(name, position, value) \ - ((name).data[uint(position)] = (value)) - #define uint_vector_buffer_load1_xe(name, position) \ - ((name).data[uint(position)]) - #define uint_vector_buffer_load2_xe(name, position) \ - name##_xe_load2(uint(position)) - #define uint_vector_buffer_load3_xe(name, position) \ - name##_xe_load3(uint(position)) - #define uint_vector_buffer_load4_xe(name, position) \ - name##_xe_load4(uint(position)) + + #define byte_buffer_align4_load4_xe(name, byte_address) \ + ((name).data[uint(byte_address) >> 2]) + #define byte_buffer_align4_load8u_xe(name, byte_address) \ + uint2_xe((name).data[uint(byte_address) >> 2], \ + (name).data[(uint(byte_address) >> 2) + 1u]) + #define byte_buffer_align4_load16u_xe(name, byte_address) \ + uint4_xe((name).data[uint(byte_address) >> 2], \ + (name).data[(uint(byte_address) >> 2) + 1u], \ + (name).data[(uint(byte_address) >> 2) + 2u], \ + (name).data[(uint(byte_address) >> 2) + 3u]) + + #define byte_buffer_align8_load8_xe(name, byte_address) \ + ((name).data[uint(byte_address) >> 3]) + + #define byte_buffer_align16_load16_xe(name, byte_address) \ + ((name).data[uint(byte_address) >> 4]) + + #define byte_buffer_align4_store4_xe(name, byte_address, value) \ + ((name).data[uint(byte_address) >> 2] = (value)) + #define byte_buffer_align8_store8_xe(name, byte_address, value) \ + ((name).data[uint(byte_address) >> 3] = (value)) + #define byte_buffer_align16_store16_xe(name, byte_address, value) \ + ((name).data[uint(byte_address) >> 4] = (value)) + #elif SHADING_LANGUAGE_HLSL_XE - // Binding declarations. - #define array_buffer_declare_xe(value_type, name, glsl_set, glsl_binding, \ - hlsl_t, hlsl_t_space) \ - Buffer name : register(hlsl_t, hlsl_t_space); - #define array_buffer_wo_declare_xe(value_type, name, glsl_set, glsl_binding, \ - hlsl_u, hlsl_u_space) \ - RWBuffer name : register(hlsl_u, hlsl_u_space); - #define uint_vector_buffer_declare_xe(name, glsl_set, glsl_binding, hlsl_t, \ - hlsl_t_space) \ + #define byte_buffer_declare_xe_impl(value_type, name, glsl_set, \ + glsl_binding, hlsl_t, hlsl_t_space) \ ByteAddressBuffer name : register(hlsl_t, hlsl_t_space); - // Loading and storing. - #define array_buffer_load_xe(name, position) ((name)[uint(position)]) - #define array_buffer_store_xe(name, position, value) \ - ((name)[uint(position)] = (value)) - #define uint_vector_buffer_load1_xe(name, position) \ - ((name).Load(int(position) << 2)) - #define uint_vector_buffer_load2_xe(name, position) \ - ((name).Load2(int(position) << 2)) - #define uint_vector_buffer_load3_xe(name, position) \ - ((name).Load3(int(position) << 2)) - #define uint_vector_buffer_load4_xe(name, position) \ - ((name).Load4(int(position) << 2)) + #define byte_buffer_wo_declare_xe_impl(value_type, name, glsl_set, \ + glsl_binding, hlsl_t, hlsl_t_space) \ + RWByteAddressBuffer name : register(hlsl_t, hlsl_t_space); + + #define byte_buffer_align4_load4_xe(name, byte_address) \ + ((name).Load(uint(byte_address))) + #define byte_buffer_align4_load8u_xe(name, byte_address) \ + ((name).Load2(uint(byte_address))) + #define byte_buffer_align4_load16u_xe(name, byte_address) \ + ((name).Load4(uint(byte_address))) + + #define byte_buffer_align8_load8_xe(name, byte_address) \ + ((name).Load2(uint(byte_address))) + + #define byte_buffer_align16_load16_xe(name, byte_address) \ + ((name).Load4(uint(byte_address))) + + #define byte_buffer_align4_store4_xe(name, byte_address, value) \ + ((name).Store(uint(byte_address), value)) + #define byte_buffer_align8_store8_xe(name, byte_address, value) \ + ((name).Store2(uint(byte_address), value)) + #define byte_buffer_align16_store16_xe(name, byte_address, value) \ + ((name).Store4(uint(byte_address), value)) + #elif SHADING_LANGUAGE_MSL_XE - // Binding declarations. - #define array_buffer_binding_xe(value_type, name, msl_buffer) \ - const device value_type* name [[msl_buffer]] - #define array_buffer_wo_binding_xe(value_type, name, msl_buffer) \ - device value_type* name [[msl_buffer]] - #define uint_vector_buffer_binding_xe(name, msl_buffer) \ - const device uint* name [[msl_buffer]] - // Loading and storing. - #define array_buffer_load_xe(name, position) ((name)[size_t(position)]) - #define array_buffer_store_xe(name, position, value) \ - ((name)[size_t(position)] = (value)) - #define uint_vector_buffer_load1_xe(name, position) ((name)[size_t(position)]) - #define uint_vector_buffer_load2_xe(name, position) \ + #define byte_buffer_binding_xe(name, msl_buffer) \ + const device char* name [[msl_buffer]] + #define byte_buffer_wo_binding_xe(name, msl_buffer) \ + device char* name [[msl_buffer]] + + #define byte_buffer_align4_load4_xe(name, byte_address) \ + (*reinterpret_cast(&(name)[(byte_address)])) + #define byte_buffer_align4_load8u_xe(name, byte_address) \ uint2_xe(*reinterpret_cast( \ - &((name)[size_t(position)]))) - #define uint_vector_buffer_load3_xe(name, position) \ - uint3_xe(*reinterpret_cast( \ - &((name)[size_t(position)]))) - #define uint_vector_buffer_load4_xe(name, position) \ + &(name)[(byte_address)])) + #define byte_buffer_align4_load8a_xe(name, byte_address) \ + (*reinterpret_cast(&(name)[(byte_address)])) + #define byte_buffer_align4_load16u_xe(name, byte_address) \ uint4_xe(*reinterpret_cast( \ - &((name)[size_t(position)]))) + &(name)[(byte_address)])) + #define byte_buffer_align4_load16a_xe(name, byte_address) \ + (*reinterpret_cast(&(name)[(byte_address)])) + + #define byte_buffer_align8_load8_xe(name, byte_address) \ + (*reinterpret_cast(&(name)[(byte_address)])) + + #define byte_buffer_align16_load16_xe(name, byte_address) \ + (*reinterpret_cast(&(name)[(byte_address)])) + + #define byte_buffer_align4_store4_xe(name, byte_address, value) \ + (*reinterpret_cast(&(name)[(byte_address)]) = (value)) + #define byte_buffer_align8_store8_xe(name, byte_address, value) \ + (*reinterpret_cast(&(name)[(byte_address)]) = (value)) + #define byte_buffer_align16_store16_xe(name, byte_address, value) \ + (*reinterpret_cast(&(name)[(byte_address)]) = (value)) + #else - #error Storage buffers not defined for the target language. + #error Byte buffers not defined for the target language. #endif // SHADING_LANGUAGE_*_XE -#ifndef array_buffer_declare_xe - #define array_buffer_declare_xe(value_type, name, glsl_set, glsl_binding, \ + +#ifndef byte_buffer_declare_xe_impl + #define byte_buffer_declare_xe_impl(value_type, name, glsl_set, \ + glsl_binding, hlsl_t, hlsl_t_space) +#endif +#ifndef byte_buffer_binding_xe + #define byte_buffer_binding_xe(name, msl_buffer) +#endif +#ifndef byte_buffer_wo_declare_xe_impl + #define byte_buffer_wo_declare_xe_impl(value_type, name, glsl_set, \ + glsl_binding, hlsl_t, hlsl_t_space) +#endif +#ifndef byte_buffer_wo_binding_xe + #define byte_buffer_wo_binding_xe(name, msl_buffer) +#endif + +#ifndef byte_buffer_align4_declare_xe + #define byte_buffer_align4_declare_xe(name, glsl_set, glsl_binding, hlsl_t, \ + hlsl_t_space) \ + byte_buffer_declare_xe_impl(uint, name, glsl_set, glsl_binding, hlsl_t, \ + hlsl_t_space) +#endif +#ifndef byte_buffer_align4_wo_declare_xe + #define byte_buffer_align4_wo_declare_xe(name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) \ + byte_buffer_wo_declare_xe_impl(uint, name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) +#endif + +#ifndef byte_buffer_align8_declare_xe + #define byte_buffer_align8_declare_xe(name, glsl_set, glsl_binding, hlsl_t, \ + hlsl_t_space) \ + byte_buffer_declare_xe_impl(uint2_xe, name, glsl_set, glsl_binding, \ hlsl_t, hlsl_t_space) -#endif // !array_buffer_declare_xe -#ifndef array_buffer_wo_declare_xe - #define array_buffer_wo_declare_xe(value_type, name, glsl_set, glsl_binding, \ - hlsl_u, hlsl_u_space) -#endif // !array_buffer_wo_declare_xe -#ifndef array_buffer_binding_xe - #define array_buffer_binding_xe(value_type, name, msl_buffer) -#endif // !array_buffer_binding_xe -#ifndef array_buffer_wo_binding_xe - #define array_buffer_wo_binding_xe(value_type, name, msl_buffer) -#endif // !array_buffer_wo_binding_xe -#ifndef uint_vector_buffer_declare_xe - #define uint_vector_buffer_declare_xe(name, glsl_set, glsl_binding, hlsl_t, \ - hlsl_t_space) -#endif // !uint_vector_buffer_declare_xe -#ifndef uint_vector_buffer_binding_xe - #define uint_vector_buffer_binding_xe(name, msl_buffer) -#endif // !uint_vector_buffer_binding_xe +#endif +#ifndef byte_buffer_align8_wo_declare_xe + #define byte_buffer_align8_wo_declare_xe(name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) \ + byte_buffer_wo_declare_xe_impl(uint2_xe, name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) +#endif + +#ifndef byte_buffer_align16_declare_xe + #define byte_buffer_align16_declare_xe(name, glsl_set, glsl_binding, hlsl_t, \ + hlsl_t_space) \ + byte_buffer_declare_xe_impl(uint4_xe, name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) +#endif +#ifndef byte_buffer_align16_wo_declare_xe + #define byte_buffer_align16_wo_declare_xe(name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) \ + byte_buffer_wo_declare_xe_impl(uint4_xe, name, glsl_set, glsl_binding, \ + hlsl_t, hlsl_t_space) +#endif + +#ifndef byte_buffer_align4_load8a_xe + #define byte_buffer_align4_load8a_xe byte_buffer_align4_load8u_xe +#endif +#ifndef byte_buffer_align4_load16a_xe + #define byte_buffer_align4_load16a_xe byte_buffer_align4_load16u_xe +#endif // Buffer, texture, sampler and image bindings must be in the entry point // bindings declaration. @@ -741,7 +815,7 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } #if !COMBINED_TEXTURE_SAMPLER_XE #ifndef sampler_2d_xe #define sampler_2d_xe texture_2d_xe - #endif // !sampler_2d_xe + #endif #ifndef sampler_xe #define sampler_xe(sampler_type, name, glsl_set, glsl_binding, hlsl_t, \ hlsl_t_space, hlsl_s, hlsl_s_space, msl_texture, \ @@ -751,32 +825,32 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } entry_binding_next_xe \ sampler_state_xe(name##_xe_sampler, glsl_set, glsl_binding, hlsl_s, \ hlsl_s_space, msl_sampler) - #endif // !sampler_xe + #endif #ifndef sample_comb_lod_2d_xe #define sample_comb_lod_2d_xe(texture_sampler_name, position, lod) \ sample_sep_lod_2d_xe(texture_sampler_name, \ texture_sampler_name##_xe_sampler, position, lod) - #endif // !sample_comb_lod_2d_xe + #endif #ifndef gather_comb_2d_r_xe #define gather_comb_2d_r_xe(texture_sampler_name, position) \ gather_sep_2d_r_xe(texture_sampler_name, \ texture_sampler_name##_xe_sampler, position) - #endif // !gather_comb_2d_r_xe + #endif #ifndef gather_comb_2d_g_xe #define gather_comb_2d_g_xe(texture_sampler_name, position) \ gather_sep_2d_g_xe(texture_sampler_name, \ texture_sampler_name##_xe_sampler, position) - #endif // !gather_comb_2d_g_xe + #endif #ifndef gather_comb_2d_b_xe #define gather_comb_2d_b_xe(texture_sampler_name, position) \ gather_sep_2d_b_xe(texture_sampler_name, \ texture_sampler_name##_xe_sampler, position) - #endif // !gather_comb_2d_b_xe + #endif #ifndef gather_comb_2d_a_xe #define gather_comb_2d_a_xe(texture_sampler_name, position) \ gather_sep_2d_a_xe(texture_sampler_name, \ texture_sampler_name##_xe_sampler, position) - #endif // !gather_comb_2d_a_xe + #endif #endif // !COMBINED_TEXTURE_SAMPLER_XE // Passing bindings to functions, and also output and input / output parameters. @@ -795,55 +869,59 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } #define param_next_after_const_buffer_xe , #define param_push_consts_xe constant push_const_struct_xe& push_consts_xe #define param_next_after_push_consts_xe , - #define param_uint_vector_buffer_xe(name) const device uint* name - #define param_next_after_uint_vector_buffer_xe , + #define param_byte_buffer_xe(name) const device char* name + #define param_byte_buffer_wo_xe(name) device char* name + #define param_next_after_byte_buffer_xe , // Call arguments. #define pass_const_buffer_xe(name) (name) #define pass_next_after_const_buffer_xe , #define pass_push_consts_xe push_consts_xe #define pass_next_after_push_consts_xe , - #define pass_uint_vector_buffer_xe(name) (name) - #define pass_next_after_uint_vector_buffer_xe , + #define pass_byte_buffer_xe(name) (name) + #define pass_next_after_byte_buffer_xe , #endif // SHADING_LANGUAGE_*_XE // Prototype parameters. #ifndef param_const_buffer_xe #define param_const_buffer_xe(name) -#endif // !param_const_buffer_xe +#endif #ifndef param_next_after_const_buffer_xe #define param_next_after_const_buffer_xe -#endif // !param_next_after_const_buffer_xe +#endif #ifndef param_push_consts_xe #define param_push_consts_xe -#endif // !param_push_consts_xe +#endif #ifndef param_next_after_push_consts_xe #define param_next_after_push_consts_xe -#endif // !param_next_after_push_consts_xe -#ifndef param_uint_vector_buffer_xe - #define param_uint_vector_buffer_xe(name) -#endif // !param_uint_vector_buffer_xe -#ifndef param_next_after_uint_vector_buffer_xe - #define param_next_after_uint_vector_buffer_xe -#endif // !param_next_after_uint_vector_buffer_xe +#endif +#ifndef param_byte_buffer_xe + #define param_byte_buffer_xe(name) +#endif +#ifndef param_byte_buffer_wo_xe + #define param_byte_buffer_wo_xe(name) +#endif +#ifndef param_next_after_byte_buffer_xe + #define param_next_after_byte_buffer_xe +#endif // Call arguments. #ifndef pass_const_buffer_xe #define pass_const_buffer_xe(name) -#endif // !pass_const_buffer_xe +#endif #ifndef pass_next_after_const_buffer_xe #define pass_next_after_const_buffer_xe -#endif // !pass_next_after_const_buffer_xe +#endif #ifndef pass_push_consts_xe #define pass_push_consts_xe -#endif // !pass_push_consts_xe +#endif #ifndef pass_next_after_push_consts_xe #define pass_next_after_push_consts_xe -#endif // !pass_next_after_push_consts_xe -#ifndef pass_uint_vector_buffer_xe - #define pass_uint_vector_buffer_xe(name) -#endif // !pass_uint_vector_buffer_xe -#ifndef pass_next_after_uint_vector_buffer_xe - #define pass_next_after_uint_vector_buffer_xe -#endif // !pass_next_after_uint_vector_buffer_xe +#endif +#ifndef pass_byte_buffer_xe + #define pass_byte_buffer_xe(name) +#endif +#ifndef pass_next_after_byte_buffer_xe + #define pass_next_after_byte_buffer_xe +#endif // Attributes. @@ -860,16 +938,16 @@ float4_xe float_x4_xe(float x) { return float4_xe(x, x, x, x); } #endif // SHADING_LANGUAGE_*_XE #ifndef unroll_xe #define unroll_xe -#endif // !unroll_xe +#endif #ifndef dont_unroll #define dont_unroll -#endif // !dont_unroll +#endif #ifndef flatten_xe #define flatten_xe -#endif // !flatten_xe +#endif #ifndef dont_flatten_xe #define dont_flatten_xe -#endif // !dont_flatten_xe +#endif // Function aliases.