Merge branch 'master' of https://github.com/xenia-project/xenia into canary_experimental

This commit is contained in:
Gliniak 2022-12-31 10:53:25 +01:00
commit 26415cb8b1
38 changed files with 632 additions and 6570 deletions

View File

@ -25,7 +25,7 @@ def command_ndk_build(platform, configuration, target):
def xenia_base_tests_filters():
# https://github.com/xenia-project/xenia/issues/2036
return 'exclude:"Wait on Timer" exclude:"Wait on Multiple Timers"'
return 'exclude:"Wait on Timer" exclude:"Wait on Multiple Timers" exclude:"HighResolutionTimer"'
# Run lint in a separate pipeline so that it will try building even if lint fails
def pipeline_lint():

View File

@ -403,12 +403,17 @@ void EmulatorWindow::DisplayConfigDialog::OnDraw(ImGuiIO& io) {
new_presenter_config.GetFsrSharpnessReduction();
ImGui::TextUnformatted(
"FSR sharpness reduction when upscaling (lower is sharper):");
// Power 2.0 as the reduction is in stops, used in exp2.
const auto label =
fmt::format("{:.3f} stops", fsr_sharpness_reduction);
// Power 2.0 scaling as the reduction is in stops, used in exp2.
fsr_sharpness_reduction = sqrt(2.f * fsr_sharpness_reduction);
ImGui::SliderFloat(
"##FSRSharpnessReduction", &fsr_sharpness_reduction,
ui::Presenter::GuestOutputPaintConfig::kFsrSharpnessReductionMin,
ui::Presenter::GuestOutputPaintConfig::kFsrSharpnessReductionMax,
"%.3f stops", 2.0f);
label.c_str(), ImGuiSliderFlags_NoInput);
fsr_sharpness_reduction =
.5f * fsr_sharpness_reduction * fsr_sharpness_reduction;
ImGui::SameLine();
if (ImGui::Button("Reset##ResetFSRSharpnessReduction")) {
fsr_sharpness_reduction = ui::Presenter::GuestOutputPaintConfig ::

View File

@ -28,6 +28,7 @@ DEFINE_int64(x64_extension_mask, -1LL,
" 512 = AVX512VL\n"
" 1024 = AVX512BW\n"
" 2048 = AVX512DQ\n"
" 4096 = AVX512VBMI\n"
" -1 = Detect and utilize all possible processor features\n",
"x64");
namespace xe {

View File

@ -28,13 +28,14 @@ enum X64FeatureFlags : uint64_t {
kX64EmitAVX512BW = 1 << 10,
kX64EmitAVX512DQ = 1 << 11,
kX64EmitAVX512VBMI = 1 << 12,
kX64EmitAVX512Ortho = kX64EmitAVX512F | kX64EmitAVX512VL,
kX64EmitAVX512Ortho64 = kX64EmitAVX512Ortho | kX64EmitAVX512DQ,
kX64FastJrcx = 1 << 12, // jrcxz is as fast as any other jump ( >= Zen1)
kX64FastJrcx = 1 << 13, // jrcxz is as fast as any other jump ( >= Zen1)
kX64FastLoop =
1 << 13, // loop/loope/loopne is as fast as any other jump ( >= Zen2)
kX64EmitAVX512VBMI = 1 << 14,
1 << 14, // loop/loope/loopne is as fast as any other jump ( >= Zen2)
kX64FlagsIndependentVars =
1 << 15, // if true, instructions that only modify some flags (like
// inc/dec) do not introduce false dependencies on EFLAGS
@ -54,7 +55,7 @@ uint64_t GetFeatureFlags();
XE_COLD
void InitFeatureFlags();
}
} // namespace amd64
} // namespace xe
#endif // XENIA_BASE_PLATFORM_AMD64_H_

View File

@ -755,6 +755,19 @@ struct VECTOR_SUB
// src1/src2.
e.vpsubd(e.xmm1, src1, src2);
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho)) {
// If the result is less or equal to the first operand then
// we did not underflow
Opmask not_underflow = e.k1;
// _mm_cmple_epu32_mask
e.vpcmpud(not_underflow, e.xmm1, src1, 0x2);
// Copy over values that did not underflow, write zero
// everywhere else
e.vmovdqa32(dest | not_underflow | e.T_z, e.xmm1);
return;
}
// If result is greater than either of the inputs, we've
// underflowed (only need to check one input)
// if (res > src1) then underflowed
@ -766,6 +779,21 @@ struct VECTOR_SUB
} else {
e.vpsubd(e.xmm1, src1, src2);
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho |
kX64EmitAVX512DQ)) {
e.vmovdqa32(e.xmm3, src1);
e.vpternlogd(e.xmm3, e.xmm1, src2, 0b00011000);
const Opmask saturate = e.k1;
e.vpmovd2m(saturate, e.xmm3);
e.vpsrad(e.xmm2, e.xmm1, 31);
e.vpxord(e.xmm2, e.xmm2, e.GetXmmConstPtr(XMMSignMaskI32));
e.vpblendmd(dest | saturate, e.xmm1, e.xmm2);
return;
}
// We can only overflow if the signs of the operands are
// opposite. If signs are opposite and result sign isn't the
// same as src1's sign, we've overflowed. if ((s32b)((src1 ^
@ -2296,7 +2324,23 @@ struct PERMUTE_V128
} else {
e.vxorps(e.xmm0, i.src1, e.GetXmmConstPtr(XMMSwapWordMask));
}
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho | kX64EmitAVX512VBMI)) {
Xmm table_lo = e.xmm1;
if (i.src2.is_constant) {
e.LoadConstantXmm(table_lo, i.src2.constant());
} else {
table_lo = i.src2;
}
Opmask zeroes = e.k1;
// _mm_cmple_epu8_mask
e.vpcmpub(zeroes, e.xmm0, e.GetXmmConstPtr(XMMPermuteControl15), 2);
e.vpermb(i.dest.reg() | zeroes | e.T_z, e.xmm0, table_lo);
return;
}
e.vpand(e.xmm0, e.GetXmmConstPtr(XMMPermuteByteMask));
if (i.src2.is_constant) {
e.LoadConstantXmm(i.dest, i.src2.constant());
e.vpshufb(i.dest, i.dest, e.xmm0);
@ -2312,6 +2356,39 @@ struct PERMUTE_V128
// General permute.
// Control mask needs to be shuffled.
// TODO(benvanik): do constants here instead of in generated code.
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho | kX64EmitAVX512BW |
kX64EmitAVX512VBMI)) {
Xmm table_idx = e.xmm0;
if (i.src1.is_constant) {
e.LoadConstantXmm(table_idx, i.src1.constant());
e.vxorps(table_idx, table_idx, e.GetXmmConstPtr(XMMSwapWordMask));
} else {
e.vxorps(table_idx, i.src1, e.GetXmmConstPtr(XMMSwapWordMask));
}
Xmm table_lo = e.xmm1;
if (i.src2.value->IsConstantZero()) {
e.vpxor(table_lo, table_lo);
} else if (i.src2.is_constant) {
e.LoadConstantXmm(table_lo, i.src2.constant());
} else {
table_lo = i.src2;
}
Xmm table_hi = e.xmm2;
if (i.src3.value->IsConstantZero()) {
e.vpxor(table_hi, table_hi);
} else if (i.src3.is_constant) {
e.LoadConstantXmm(table_hi, i.src3.constant());
} else {
table_hi = i.src3;
}
e.vpermi2b(table_idx, table_lo, table_hi);
e.vmovdqu8(i.dest, table_idx);
return;
}
if (i.src1.is_constant) {
e.LoadConstantXmm(e.xmm2, i.src1.constant());
e.vxorps(e.xmm2, e.xmm2, e.GetXmmConstPtr(XMMSwapWordMask));
@ -2319,6 +2396,7 @@ struct PERMUTE_V128
e.vxorps(e.xmm2, i.src1, e.GetXmmConstPtr(XMMSwapWordMask));
}
e.vpand(e.xmm2, e.GetXmmConstPtr(XMMPermuteByteMask));
Xmm src2_shuf = e.xmm0;
if (i.src2.value->IsConstantZero()) {
e.vpxor(src2_shuf, src2_shuf);
@ -2346,8 +2424,39 @@ struct PERMUTE_V128
static void EmitByInt16(X64Emitter& e, const EmitArgType& i) {
// src1 is an array of indices corresponding to positions within src2 and
// src3.
// src3
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho | kX64EmitAVX512BW)) {
e.LoadConstantXmm(e.xmm1, vec128s(0x1));
Xmm table_idx = e.xmm0;
if (i.src1.is_constant) {
e.LoadConstantXmm(table_idx, i.src1.constant());
e.vpxord(table_idx, table_idx, e.xmm1);
} else {
e.vpxord(table_idx, i.src1, e.xmm1);
}
Xmm table_lo = e.xmm1;
if (i.src2.is_constant) {
e.LoadConstantXmm(table_lo, i.src2.constant());
} else {
table_lo = i.src2;
}
Xmm table_hi = e.xmm2;
if (i.src3.is_constant) {
e.LoadConstantXmm(table_hi, i.src3.constant());
} else {
table_hi = i.src3;
}
e.vpermi2w(table_idx, table_lo, table_hi);
e.vmovdqu8(i.dest, table_idx);
return;
}
assert_true(i.src1.is_constant);
vec128_t perm = (i.src1.constant() & vec128s(0xF)) ^ vec128s(0x1);
vec128_t perm_ctrl = vec128b(0);
for (int i = 0; i < 8; i++) {

View File

@ -37,6 +37,7 @@
#include "xenia/cpu/backend/x64/x64_tracers.h"
// needed for stmxcsr
#include "xenia/cpu/backend/x64/x64_stack_layout.h"
#include "xenia/cpu/backend/x64/x64_util.h"
#include "xenia/cpu/hir/hir_builder.h"
#include "xenia/cpu/processor.h"
@ -700,6 +701,26 @@ struct SELECT_F64
static void Emit(X64Emitter& e, const EmitArgType& i) {
e.ChangeMxcsrMode(MXCSRMode::Fpu);
// dest = src1 != 0 ? src2 : src3
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho)) {
e.movzx(e.rax, i.src1);
e.vmovq(e.xmm0, e.rax);
e.vptestmq(e.k1, e.xmm0, e.xmm0);
const Xmm src2 = i.src2.is_constant ? e.xmm1 : i.src2;
if (i.src2.is_constant) {
e.LoadConstantXmm(src2, i.src2.constant());
}
const Xmm src3 = i.src3.is_constant ? e.xmm2 : i.src3;
if (i.src3.is_constant) {
e.LoadConstantXmm(src3, i.src3.constant());
}
e.vpblendmq(i.dest.reg() | e.k1, src3, src2);
return;
}
e.movzx(e.eax, i.src1);
e.vmovd(e.xmm1, e.eax);
e.vpxor(e.xmm0, e.xmm0);
@ -762,7 +783,7 @@ struct SELECT_V128_V128
: Sequence<SELECT_V128_V128,
I<OPCODE_SELECT, V128Op, V128Op, V128Op, V128Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
Xmm src1 = i.src1.is_constant ? e.xmm0 : i.src1;
const Xmm src1 = i.src1.is_constant ? e.xmm0 : i.src1;
PermittedBlend mayblend = GetPermittedBlendForSelectV128(i.src1.value);
// todo: detect whether src1 is only 0 or FFFF and use blends if so.
// currently we only detect cmps
@ -770,16 +791,25 @@ struct SELECT_V128_V128
e.LoadConstantXmm(src1, i.src1.constant());
}
Xmm src2 = i.src2.is_constant ? e.xmm1 : i.src2;
const Xmm src2 = i.src2.is_constant ? e.xmm1 : i.src2;
if (i.src2.is_constant) {
e.LoadConstantXmm(src2, i.src2.constant());
}
Xmm src3 = i.src3.is_constant ? e.xmm2 : i.src3;
const Xmm src3 = i.src3.is_constant ? e.xmm2 : i.src3;
if (i.src3.is_constant) {
e.LoadConstantXmm(src3, i.src3.constant());
}
if (e.IsFeatureEnabled(kX64EmitAVX512Ortho)) {
e.vmovdqa(e.xmm3, src1);
e.vpternlogd(e.xmm3, src2, src3,
(~TernaryOperand::a & TernaryOperand::b) |
(TernaryOperand::c & TernaryOperand::a));
e.vmovdqa(i.dest, e.xmm3);
return;
}
if (mayblend == PermittedBlend::Int8) {
e.vpblendvb(i.dest, src2, src3, src1);
} else if (mayblend == PermittedBlend::Ps) {

View File

@ -0,0 +1,46 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_BACKEND_X64_X64_UTIL_H_
#define XENIA_CPU_BACKEND_X64_X64_UTIL_H_
#include "xenia/base/vec128.h"
#include "xenia/cpu/backend/x64/x64_backend.h"
#include "xenia/cpu/backend/x64/x64_emitter.h"
namespace xe {
namespace cpu {
namespace backend {
namespace x64 {
// Used to generate ternary logic truth-tables for vpternlog
// Use these to directly refer to terms and perform binary operations upon them
// and the resulting value will be the ternary lookup table
// ex:
// (TernaryOperand::a | ~TernaryOperand::b) & TernaryOperand::c
// = 0b10100010
// = 0xa2
// vpternlog a, b, c, 0xa2
//
// ~(TernaryOperand::a ^ TernaryOperand::b) & TernaryOperand::c
// = 0b10000010
// = 0x82
// vpternlog a, b, c, 0x82
namespace TernaryOperand {
constexpr uint8_t a = 0b11110000;
constexpr uint8_t b = 0b11001100;
constexpr uint8_t c = 0b10101010;
} // namespace TernaryOperand
} // namespace x64
} // namespace backend
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_BACKEND_X64_X64_UTIL_H_

View File

@ -39,9 +39,6 @@ bool FinalizationPass::Run(HIRBuilder* builder) {
auto block = builder->first_block();
while (block) {
block->ordinal = block_ordinal++;
// Ensure all labels have names.
// Remove unneeded jumps.
auto tail = block->instr_tail;
if (tail && tail->opcode == &OPCODE_BRANCH_info) {

View File

@ -367,7 +367,7 @@ void DebugWindow::DrawSourcePane() {
ImGui::PushButtonRepeat(true);
bool can_step = !cache_.is_running && state_.thread_info;
if (ImGui::ButtonEx("Step PPC", ImVec2(0, 0),
can_step ? 0 : ImGuiButtonFlags_Disabled)) {
can_step ? 0 : ImGuiItemFlags_Disabled)) {
// By enabling the button when stepping we allow repeat behavior.
if (processor_->execution_state() != cpu::ExecutionState::kStepping) {
processor_->StepGuestInstruction(state_.thread_info->thread_id);
@ -385,7 +385,7 @@ void DebugWindow::DrawSourcePane() {
ImGui::SameLine();
ImGui::PushButtonRepeat(true);
if (ImGui::ButtonEx("Step x64", ImVec2(0, 0),
can_step ? 0 : ImGuiButtonFlags_Disabled)) {
can_step ? 0 : ImGuiItemFlags_Disabled)) {
// By enabling the button when stepping we allow repeat behavior.
if (processor_->execution_state() != cpu::ExecutionState::kStepping) {
processor_->StepHostInstruction(state_.thread_info->thread_id);

View File

@ -876,15 +876,17 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
// Show achievments data
XELOGI("-------------------- ACHIEVEMENTS --------------------");
auto ach = db.GetAchievements();
for (const auto& entry : ach) {
const std::vector<kernel::util::XdbfAchievementTableEntry>
achievement_list = db.GetAchievements();
for (const kernel::util::XdbfAchievementTableEntry& entry :
achievement_list) {
std::string label = db.GetStringTableEntry(language, entry.label_id);
std::string desc =
db.GetStringTableEntry(language, entry.description_id);
XELOGI("{} - {} - {} - {}", entry.id, label, desc, entry.gamerscore);
}
XELOGI("----------------- END OF ACHIEVEMENTS --------------------");
XELOGI("----------------- END OF ACHIEVEMENTS ----------------");
auto icon_block = db.icon();
if (icon_block) {

View File

@ -1038,6 +1038,36 @@ bool D3D12CommandProcessor::SetupContext() {
parameter.Descriptor.RegisterSpace = 0;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
}
// Shared memory SRV and UAV.
D3D12_DESCRIPTOR_RANGE root_shared_memory_view_ranges[2];
{
auto& parameter =
root_parameters_bindless[kRootParameter_Bindless_SharedMemory];
parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
parameter.DescriptorTable.NumDescriptorRanges =
uint32_t(xe::countof(root_shared_memory_view_ranges));
parameter.DescriptorTable.pDescriptorRanges =
root_shared_memory_view_ranges;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
{
auto& range = root_shared_memory_view_ranges[0];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
range.NumDescriptors = 1;
range.BaseShaderRegister =
UINT(DxbcShaderTranslator::SRVMainRegister::kSharedMemory);
range.RegisterSpace = UINT(DxbcShaderTranslator::SRVSpace::kMain);
range.OffsetInDescriptorsFromTableStart = 0;
}
{
auto& range = root_shared_memory_view_ranges[1];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
range.NumDescriptors = 1;
range.BaseShaderRegister =
UINT(DxbcShaderTranslator::UAVRegister::kSharedMemory);
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = 1;
}
}
// Sampler heap.
D3D12_DESCRIPTOR_RANGE root_bindless_sampler_range;
{
@ -1057,7 +1087,7 @@ bool D3D12CommandProcessor::SetupContext() {
root_bindless_sampler_range.OffsetInDescriptorsFromTableStart = 0;
}
// View heap.
D3D12_DESCRIPTOR_RANGE root_bindless_view_ranges[6];
D3D12_DESCRIPTOR_RANGE root_bindless_view_ranges[4];
{
auto& parameter =
root_parameters_bindless[kRootParameter_Bindless_ViewHeap];
@ -1066,34 +1096,6 @@ bool D3D12CommandProcessor::SetupContext() {
parameter.DescriptorTable.NumDescriptorRanges = 0;
parameter.DescriptorTable.pDescriptorRanges = root_bindless_view_ranges;
parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
// Shared memory SRV.
{
assert_true(parameter.DescriptorTable.NumDescriptorRanges <
xe::countof(root_bindless_view_ranges));
auto& range = root_bindless_view_ranges[parameter.DescriptorTable
.NumDescriptorRanges++];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
range.NumDescriptors = 1;
range.BaseShaderRegister =
UINT(DxbcShaderTranslator::SRVMainRegister::kSharedMemory);
range.RegisterSpace = UINT(DxbcShaderTranslator::SRVSpace::kMain);
range.OffsetInDescriptorsFromTableStart =
UINT(SystemBindlessView::kSharedMemoryRawSRV);
}
// Shared memory UAV.
{
assert_true(parameter.DescriptorTable.NumDescriptorRanges <
xe::countof(root_bindless_view_ranges));
auto& range = root_bindless_view_ranges[parameter.DescriptorTable
.NumDescriptorRanges++];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
range.NumDescriptors = 1;
range.BaseShaderRegister =
UINT(DxbcShaderTranslator::UAVRegister::kSharedMemory);
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart =
UINT(SystemBindlessView::kSharedMemoryRawUAV);
}
// EDRAM.
if (render_target_cache_->GetPath() ==
RenderTargetCache::Path::kPixelShaderInterlock) {
@ -1458,6 +1460,20 @@ bool D3D12CommandProcessor::SetupContext() {
if (bindless_resources_used_) {
// Create the system bindless descriptors once all resources are
// initialized.
// kNullRawSRV.
ui::d3d12::util::CreateBufferRawSRV(
device,
provider.OffsetViewDescriptor(
view_bindless_heap_cpu_start_,
uint32_t(SystemBindlessView::kNullRawSRV)),
nullptr, 0);
// kNullRawUAV.
ui::d3d12::util::CreateBufferRawUAV(
device,
provider.OffsetViewDescriptor(
view_bindless_heap_cpu_start_,
uint32_t(SystemBindlessView::kNullRawUAV)),
nullptr, 0);
// kNullTexture2DArray.
D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc;
null_srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
@ -2731,7 +2747,8 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
used_texture_mask, normalized_depth_control, normalized_color_mask);
// Update constant buffers, descriptors and root parameters.
if (!UpdateBindings(vertex_shader, pixel_shader, root_signature)) {
if (!UpdateBindings(vertex_shader, pixel_shader, root_signature,
memexport_used)) {
return false;
}
// Must not call anything that can change the descriptor heap from now on!
@ -3413,6 +3430,7 @@ bool D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
cbuffer_binding_float_pixel_.up_to_date = false;
cbuffer_binding_bool_loop_.up_to_date = false;
cbuffer_binding_fetch_.up_to_date = false;
current_shared_memory_binding_is_uav_.reset();
if (bindless_resources_used_) {
cbuffer_binding_descriptor_indices_vertex_.up_to_date = false;
cbuffer_binding_descriptor_indices_pixel_.up_to_date = false;
@ -4299,9 +4317,10 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(
}
}
bool D3D12CommandProcessor::UpdateBindings(
const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader,
ID3D12RootSignature* root_signature) {
bool D3D12CommandProcessor::UpdateBindings(const D3D12Shader* vertex_shader,
const D3D12Shader* pixel_shader,
ID3D12RootSignature* root_signature,
bool shared_memory_is_uav) {
const ui::d3d12::D3D12Provider& provider = GetD3D12Provider();
ID3D12Device* device = provider.GetDevice();
const RegisterFile& regs = *register_file_;
@ -4338,6 +4357,9 @@ bool D3D12CommandProcessor::UpdateBindings(
uint32_t root_parameter_bool_loop_constants =
bindless_resources_used_ ? kRootParameter_Bindless_BoolLoopConstants
: kRootParameter_Bindful_BoolLoopConstants;
uint32_t root_parameter_shared_memory_and_bindful_edram =
bindless_resources_used_ ? kRootParameter_Bindless_SharedMemory
: kRootParameter_Bindful_SharedMemoryAndEdram;
//
// Update root constant buffers that are common for bindful and bindless.
@ -4505,6 +4527,13 @@ bool D3D12CommandProcessor::UpdateBindings(
// Update descriptors.
//
if (!current_shared_memory_binding_is_uav_.has_value() ||
current_shared_memory_binding_is_uav_.value() != shared_memory_is_uav) {
current_shared_memory_binding_is_uav_ = shared_memory_is_uav;
current_graphics_root_up_to_date_ &=
~(1u << root_parameter_shared_memory_and_bindful_edram);
}
// Get textures and samplers used by the vertex shader, check if the last used
// samplers are compatible and update them.
size_t texture_layout_uid_vertex =
@ -4815,7 +4844,9 @@ bool D3D12CommandProcessor::UpdateBindings(
bool retval = UpdateBindings_BindfulPath(
texture_layout_uid_vertex, textures_vertex, texture_layout_uid_pixel,
textures_pixel, sampler_count_vertex, sampler_count_pixel, retflag);
if (retflag) return retval;
if (retflag) {
return retval;
}
}
// Update the root parameters.
@ -4854,6 +4885,31 @@ bool D3D12CommandProcessor::UpdateBindings(
current_graphics_root_up_to_date_ |= 1u
<< root_parameter_bool_loop_constants;
}
if (!(current_graphics_root_up_to_date_ &
(1u << root_parameter_shared_memory_and_bindful_edram))) {
assert_true(current_shared_memory_binding_is_uav_.has_value());
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_and_bindful_edram;
if (bindless_resources_used_) {
gpu_handle_shared_memory_and_bindful_edram =
provider.OffsetViewDescriptor(
view_bindless_heap_gpu_start_,
uint32_t(current_shared_memory_binding_is_uav_.value()
? SystemBindlessView ::
kNullRawSRVAndSharedMemoryRawUAVStart
: SystemBindlessView ::
kSharedMemoryRawSRVAndNullRawUAVStart));
} else {
gpu_handle_shared_memory_and_bindful_edram =
current_shared_memory_binding_is_uav_.value()
? gpu_handle_shared_memory_uav_and_edram_
: gpu_handle_shared_memory_srv_and_edram_;
}
deferred_command_list_.D3DSetGraphicsRootDescriptorTable(
root_parameter_shared_memory_and_bindful_edram,
gpu_handle_shared_memory_and_bindful_edram);
current_graphics_root_up_to_date_ |=
1u << root_parameter_shared_memory_and_bindful_edram;
}
if (bindless_resources_used_) {
if (!(current_graphics_root_up_to_date_ &
(1u << kRootParameter_Bindless_DescriptorIndicesPixel))) {
@ -4895,14 +4951,6 @@ bool D3D12CommandProcessor::UpdateBindings(
XE_COLD
XE_NOINLINE
void D3D12CommandProcessor::UpdateBindings_UpdateRootBindful() {
if (!(current_graphics_root_up_to_date_ &
(1u << kRootParameter_Bindful_SharedMemoryAndEdram))) {
deferred_command_list_.D3DSetGraphicsRootDescriptorTable(
kRootParameter_Bindful_SharedMemoryAndEdram,
gpu_handle_shared_memory_and_edram_);
current_graphics_root_up_to_date_ |=
1u << kRootParameter_Bindful_SharedMemoryAndEdram;
}
uint32_t extra_index;
extra_index = current_graphics_root_bindful_extras_.textures_pixel;
if (extra_index != RootBindfulExtraParameterIndices::kUnavailable &&
@ -5031,7 +5079,7 @@ bool D3D12CommandProcessor::UpdateBindings_BindfulPath(
bindful_textures_written_pixel_ = false;
// If updating fully, write the shared memory SRV and UAV descriptors and,
// if needed, the EDRAM descriptor.
gpu_handle_shared_memory_and_edram_ = view_gpu_handle;
gpu_handle_shared_memory_srv_and_edram_ = view_gpu_handle;
shared_memory_->WriteRawSRVDescriptor(view_cpu_handle);
view_cpu_handle.ptr += descriptor_size_view;
view_gpu_handle.ptr += descriptor_size_view;
@ -5043,6 +5091,19 @@ bool D3D12CommandProcessor::UpdateBindings_BindfulPath(
view_cpu_handle.ptr += descriptor_size_view;
view_gpu_handle.ptr += descriptor_size_view;
}
// Null SRV + UAV + EDRAM.
gpu_handle_shared_memory_uav_and_edram_ = view_gpu_handle;
ui::d3d12::util::CreateBufferRawSRV(provider.GetDevice(), view_cpu_handle, nullptr, 0);
view_cpu_handle.ptr += descriptor_size_view;
view_gpu_handle.ptr += descriptor_size_view;
shared_memory_->WriteRawUAVDescriptor(view_cpu_handle);
view_cpu_handle.ptr += descriptor_size_view;
view_gpu_handle.ptr += descriptor_size_view;
if (edram_rov_used) {
render_target_cache_->WriteEdramUintPow2UAVDescriptor(view_cpu_handle, 2);
view_cpu_handle.ptr += descriptor_size_view;
view_gpu_handle.ptr += descriptor_size_view;
}
current_graphics_root_up_to_date_ &=
~(1u << kRootParameter_Bindful_SharedMemoryAndEdram);
}

View File

@ -14,6 +14,7 @@
#include <atomic>
#include <deque>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>
@ -136,11 +137,19 @@ class D3D12CommandProcessor final : public CommandProcessor {
uint32_t count, ui::d3d12::util::DescriptorCpuGpuHandlePair* handles_out);
// These are needed often, so they are always allocated.
enum class SystemBindlessView : uint32_t {
kSharedMemoryRawSRV,
// Both may be bound as one root parameter.
kSharedMemoryRawSRVAndNullRawUAVStart,
kSharedMemoryRawSRV = kSharedMemoryRawSRVAndNullRawUAVStart,
kNullRawUAV,
// Both may be bound as one root parameter.
kNullRawSRVAndSharedMemoryRawUAVStart,
kNullRawSRV = kNullRawSRVAndSharedMemoryRawUAVStart,
kSharedMemoryRawUAV,
kSharedMemoryR32UintSRV,
kSharedMemoryR32G32UintSRV,
kSharedMemoryR32G32B32A32UintSRV,
kSharedMemoryRawUAV,
kSharedMemoryR32UintUAV,
kSharedMemoryR32G32UintUAV,
kSharedMemoryR32G32B32A32UintUAV,
@ -348,10 +357,10 @@ class D3D12CommandProcessor final : public CommandProcessor {
kRootParameter_Bindful_SystemConstants, // +2 = 6 in all.
// Pretty rarely used and rarely changed - flow control constants.
kRootParameter_Bindful_BoolLoopConstants, // +2 = 8 in all.
// Never changed except for when starting a new descriptor heap - shared
// memory byte address buffer, and, if ROV is used for EDRAM, EDRAM R32_UINT
// UAV.
// SRV/UAV descriptor table.
// Changed only when starting a new descriptor heap or when switching
// between shared memory as SRV and UAV - shared memory byte address buffer
// (as SRV and as UAV, either may be null if not used), and, if ROV is used
// for EDRAM, EDRAM R32_UINT UAV.
kRootParameter_Bindful_SharedMemoryAndEdram, // +1 = 9 in all.
kRootParameter_Bindful_Count_Base,
@ -375,10 +384,14 @@ class D3D12CommandProcessor final : public CommandProcessor {
kRootParameter_Bindless_DescriptorIndicesVertex, // +2 = 6 in VS.
kRootParameter_Bindless_SystemConstants, // +2 = 8 in all.
kRootParameter_Bindless_BoolLoopConstants, // +2 = 10 in all.
// Changed only when switching between shared memory as SRV and UAV - shared
// memory byte address buffer (as SRV and as UAV, either may be null if not
// used).
kRootParameter_Bindless_SharedMemory, // +1 = 11 in all.
// Unbounded sampler descriptor table - changed in case of overflow.
kRootParameter_Bindless_SamplerHeap, // +1 = 11 in all.
kRootParameter_Bindless_SamplerHeap, // +1 = 12 in all.
// Unbounded SRV/UAV descriptor table - never changed.
kRootParameter_Bindless_ViewHeap, // +1 = 12 in all.
kRootParameter_Bindless_ViewHeap, // +1 = 13 in all.
kRootParameter_Bindless_Count,
};
@ -467,7 +480,8 @@ class D3D12CommandProcessor final : public CommandProcessor {
uint32_t normalized_color_mask);
bool UpdateBindings(const D3D12Shader* vertex_shader,
const D3D12Shader* pixel_shader,
ID3D12RootSignature* root_signature);
ID3D12RootSignature* root_signature,
bool shared_memory_is_uav);
XE_COLD
XE_NOINLINE
void UpdateBindings_UpdateRootBindful();
@ -739,6 +753,13 @@ class D3D12CommandProcessor final : public CommandProcessor {
ConstantBufferBinding cbuffer_binding_descriptor_indices_vertex_;
ConstantBufferBinding cbuffer_binding_descriptor_indices_pixel_;
// Whether the latest shared memory and EDRAM buffer binding contains the
// shared memory UAV rather than the SRV.
// Separate descriptor tables for the SRV and the UAV, even though only one is
// accessed dynamically in the shaders, are used to prevent a validation
// message about missing resource states in PIX.
std::optional<bool> current_shared_memory_binding_is_uav_;
// Pages with the descriptors currently used for handling Xenos draw calls.
uint64_t draw_view_bindful_heap_index_;
uint64_t draw_sampler_bindful_heap_index_;
@ -771,7 +792,8 @@ class D3D12CommandProcessor final : public CommandProcessor {
std::vector<uint32_t> current_sampler_bindless_indices_pixel_;
// Latest bindful descriptor handles used for handling Xenos draw calls.
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_and_edram_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_srv_and_edram_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_uav_and_edram_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_textures_vertex_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_textures_pixel_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_samplers_vertex_;

View File

@ -1226,15 +1226,13 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex");
builder_->addMemberName(type_struct_per_vertex,
kOutputPerVertexMemberPosition, "gl_Position");
builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberPosition,
spv::DecorationInvariant);
builder_->addMemberDecoration(type_struct_per_vertex,
kOutputPerVertexMemberPosition,
spv::DecorationBuiltIn, spv::BuiltInPosition);
builder_->addDecoration(type_struct_per_vertex, spv::DecorationBlock);
output_per_vertex_ = builder_->createVariable(
spv::NoPrecision, spv::StorageClassOutput, type_struct_per_vertex, "");
builder_->addDecoration(output_per_vertex_, spv::DecorationInvariant);
main_interface_.push_back(output_per_vertex_);
}

View File

@ -265,10 +265,9 @@ TextureGuestLayout GetGuestTextureLayout(
}
layout.mips_total_extent_bytes = 0;
const FormatInfo* const format_info = FormatInfo::Get(format);
const uint32_t bytes_per_block = format_info->bytes_per_block();
const unsigned char block_width_sh = FormatInfo::GetWidthShift(format);
const unsigned char block_height_sh = FormatInfo::GetHeightShift(format);
const FormatInfo* format_info = FormatInfo::Get(format);
uint32_t bytes_per_block = format_info->bytes_per_block();
// The loop counter can mean two things depending on whether the packed mip
// tail is stored as mip 0, because in this case, it would be ambiguous since
// both the base and the mips would be on "level 0", but stored separately and
@ -313,12 +312,9 @@ TextureGuestLayout GetGuestTextureLayout(
z_slice_stride_texel_rows_unaligned =
std::max(xe::next_pow2(height_texels) >> level, uint32_t(1));
}
// maybe do 1 << block_width_sh instead of format_info->block_width, since
// we'll have cl loaded with the shift anyway
uint32_t row_pitch_blocks_tile_aligned =
xe::align(xe::align<uint32_t>(row_pitch_texels_unaligned,
format_info->block_width) >>
block_width_sh,
uint32_t row_pitch_blocks_tile_aligned = xe::align(
xe::align(row_pitch_texels_unaligned, format_info->block_width) /
format_info->block_width,
xenos::kTextureTileWidthHeight);
level_layout.row_pitch_bytes =
row_pitch_blocks_tile_aligned * bytes_per_block;
@ -331,10 +327,9 @@ TextureGuestLayout GetGuestTextureLayout(
}
level_layout.z_slice_stride_block_rows =
dimension != xenos::DataDimension::k1D
? xe::align<uint32_t>(
xe::align<uint32_t>(z_slice_stride_texel_rows_unaligned,
format_info->block_height) >>
block_height_sh,
? xe::align(xe::align(z_slice_stride_texel_rows_unaligned,
format_info->block_height) /
format_info->block_height,
xenos::kTextureTileWidthHeight)
: 1;
level_layout.array_slice_stride_bytes =
@ -352,54 +347,19 @@ TextureGuestLayout GetGuestTextureLayout(
// be smaller (especially in the 1280x720 linear k_8_8_8_8 case in 4E4D083E,
// for which memory exactly for 1280x720 is allocated, and aligning the
// height to 32 would cause access of an unallocated page) or bigger than
// the stride. For tiled textures, this is the dimensions aligned to 32x32x4
// blocks (or x1 for the missing dimensions).
uint32_t level_width_blocks =
xe::align<uint32_t>(std::max(width_texels >> level, uint32_t(1)),
format_info->block_width) >>
block_width_sh;
uint32_t level_height_blocks =
xe::align<uint32_t>(std::max(height_texels >> level, uint32_t(1)),
format_info->block_height) >>
block_height_sh;
uint32_t level_depth = std::max(depth >> level, uint32_t(1));
if (is_tiled) {
level_layout.x_extent_blocks =
xe::align(level_width_blocks, xenos::kTextureTileWidthHeight);
level_layout.y_extent_blocks =
xe::align(level_height_blocks, xenos::kTextureTileWidthHeight);
uint32_t bytes_per_block_log2 = xe::log2_floor(bytes_per_block);
if (dimension == xenos::DataDimension::k3D) {
level_layout.z_extent =
xe::align(level_depth, xenos::kTextureTileDepth);
// 32-block-row x 4 slice portions laid out sequentially (4-slice-major,
// 32-block-row-minor), address extent within a 32x32x4 tile depends on
// the pitch. Origins of 32x32x4 tiles grow monotonically, first along
// Z, then along Y, then along X.
level_layout.array_slice_data_extent_bytes =
GetTiledAddressUpperBound3D(
level_layout.x_extent_blocks, level_layout.y_extent_blocks,
level_layout.z_extent, row_pitch_blocks_tile_aligned,
level_layout.y_extent_blocks, bytes_per_block_log2);
} else {
level_layout.z_extent = 1;
// Origins of 32x32 tiles grow monotonically, first along Y, then along
// X.
level_layout.array_slice_data_extent_bytes =
GetTiledAddressUpperBound2D(
level_layout.x_extent_blocks, level_layout.y_extent_blocks,
row_pitch_blocks_tile_aligned, bytes_per_block_log2);
}
} else {
// the stride.
if (level == layout.packed_level) {
// Calculate the portion of the mip tail actually used by the needed
// mips. The actually used region may be significantly smaller than the
// full 32x32-texel-aligned tail. A 2x2 texture (for example, in
// 494707D4, there's a 2x2 k_8_8_8_8 linear texture with packed mips),
// Calculate the portion of the mip tail actually used by the needed mips.
// The actually used region may be significantly smaller than the full
// 32x32-texel-aligned (and, for mips, calculated from the base dimensions
// rounded to powers of two - 58410A7A has an 80x260 tiled texture with
// packed mips at level 3 containing a mip ending at Y = 36, while
// 260 >> 3 == 32, but 512 >> 3 == 64) tail. A 2x2 texture (for example,
// in 494707D4, there's a 2x2 k_8_8_8_8 linear texture with packed mips),
// for instance, would have its 2x2 base at (16, 0) and its 1x1 mip at
// (8, 0) - and we need 2 or 1 rows in these cases, not 32 - the 32 rows
// would span two 4 KB pages rather than one, taking the 256-byte pitch
// alignment in linear textures into account.
// in a linear texture (with 256-byte pitch alignment) would span two 4 KB
// pages rather than one.
level_layout.x_extent_blocks = 0;
level_layout.y_extent_blocks = 0;
level_layout.z_extent = 0;
@ -412,30 +372,51 @@ TextureGuestLayout GetGuestTextureLayout(
GetPackedMipOffset(width_texels, height_texels, depth, format,
packed_sublevel, packed_sublevel_x_blocks,
packed_sublevel_y_blocks, packed_sublevel_z);
level_layout.x_extent_blocks = std::max<uint32_t>(
level_layout.x_extent_blocks = std::max(
level_layout.x_extent_blocks,
packed_sublevel_x_blocks +
(xe::align<uint32_t>(
xe::align(
std::max(width_texels >> packed_sublevel, uint32_t(1)),
format_info->block_width) >>
block_width_sh));
level_layout.y_extent_blocks = std::max<uint32_t>(
format_info->block_width) /
format_info->block_width);
level_layout.y_extent_blocks = std::max(
level_layout.y_extent_blocks,
packed_sublevel_y_blocks +
(xe::align<uint32_t>(
xe::align(
std::max(height_texels >> packed_sublevel, uint32_t(1)),
format_info->block_height) >>
block_height_sh));
format_info->block_height) /
format_info->block_height);
level_layout.z_extent =
std::max(level_layout.z_extent,
packed_sublevel_z +
std::max(depth >> packed_sublevel, uint32_t(1)));
}
} else {
level_layout.x_extent_blocks = level_width_blocks;
level_layout.y_extent_blocks = level_height_blocks;
level_layout.z_extent = level_depth;
level_layout.x_extent_blocks =
xe::align(std::max(width_texels >> level, uint32_t(1)),
format_info->block_width) /
format_info->block_width;
level_layout.y_extent_blocks =
xe::align(std::max(height_texels >> level, uint32_t(1)),
format_info->block_height) /
format_info->block_height;
level_layout.z_extent = std::max(depth >> level, uint32_t(1));
}
if (is_tiled) {
uint32_t bytes_per_block_log2 = xe::log2_floor(bytes_per_block);
if (dimension == xenos::DataDimension::k3D) {
level_layout.array_slice_data_extent_bytes =
GetTiledAddressUpperBound3D(
level_layout.x_extent_blocks, level_layout.y_extent_blocks,
level_layout.z_extent, row_pitch_blocks_tile_aligned,
level_layout.y_extent_blocks, bytes_per_block_log2);
} else {
level_layout.array_slice_data_extent_bytes =
GetTiledAddressUpperBound2D(
level_layout.x_extent_blocks, level_layout.y_extent_blocks,
row_pitch_blocks_tile_aligned, bytes_per_block_log2);
}
} else {
level_layout.array_slice_data_extent_bytes =
z_stride_bytes * (level_layout.z_extent - 1) +
level_layout.row_pitch_bytes * (level_layout.y_extent_blocks - 1) +

View File

@ -144,24 +144,27 @@ struct TextureGuestLayout {
// multiplied by the array slice count.
uint32_t array_slice_stride_bytes;
// Estimated amount of memory this level occupies, and variables involved in
// its calculation. Not aligned to kTextureSubresourceAlignmentBytes. For
// tiled textures, this will be rounded to 32x32x4 blocks (or 32x32x1
// depending on the dimension), but for the linear subresources, this may be
// significantly (including less 4 KB pages) smaller than the aligned size
// (like for 4E4D083E where aligning the height of a 1280x720 linear texture
// results in access violations). For the linear mip tail, this includes all
// the mip levels stored in it. If the width is bigger than the pitch, this
// will also be taken into account for the last row so all memory actually
// used by the texture will be loaded, and may be bigger than the distance
// between array slices or levels. The purpose of this parameter is to make
// the memory amount that needs to be resident as close to the real amount
// as possible, to make sure all the needed data will be read, but also, if
// possible, unneeded memory pages won't be accessed (since that may trigger
// an access violation on the CPU).
// The exclusive upper bound of blocks needed at this level (this level for
// non-packed levels, or all the packed levels for the packed mip tail).
uint32_t x_extent_blocks;
uint32_t y_extent_blocks;
uint32_t z_extent;
// Estimated amount of memory this level occupies. Not aligned to
// kTextureSubresourceAlignmentBytes. For tiled textures, this will be
// calculated for the extent rounded to 32x32x4 blocks (or 32x32x1 depending
// on the dimensionality), but for linear textures, as well as for mips of
// non-power-of-two tiled textures, this may be significantly (including
// less 4 KB pages) smaller than the aligned size (like for 4E4D083E where
// aligning the height of a 1280x720 linear texture results in access
// violations). For the linear mip tail, this includes all the mip levels
// stored in it. If the width is bigger than the pitch, this will also be
// taken into account for the last row so all memory actually used by the
// texture will be loaded, and may be bigger than the distance between array
// slices or levels. The purpose of this parameter is to make the memory
// amount that needs to be resident as close to the real amount as possible,
// to make sure all the needed data will be read, but also, if possible,
// unneeded memory pages won't be accessed (since that may trigger an access
// violation on the CPU).
uint32_t array_slice_data_extent_bytes;
// Including all array slices.
uint32_t level_data_extent_bytes;

View File

@ -258,7 +258,7 @@ void TraceViewer::DrawControllerUI() {
}
ImGui::SameLine();
ImGui::SliderInt("", &target_frame, 0, player_->frame_count() - 1);
ImGui::SliderInt("##", &target_frame, 0, player_->frame_count() - 1);
if (target_frame != player_->current_frame_index() &&
!player_->is_playing_trace()) {
player_->SeekFrame(target_frame);
@ -554,7 +554,7 @@ void TraceViewer::DrawCommandListUI() {
}
ImGui::PushItemWidth(float(column_width - 15));
ImGui::SliderInt("", &target_command, -1, command_count - 1);
ImGui::SliderInt("##", &target_command, -1, command_count - 1);
ImGui::PopItemWidth();
if (target_command != player_->current_command_index() &&
@ -733,8 +733,8 @@ void TraceViewer::DrawTextureInfo(
ImGui::Columns(2);
if (texture) {
ImVec2 button_size(256, 256);
if (ImGui::ImageButton(ImTextureID(texture), button_size, ImVec2(0, 0),
ImVec2(1, 1))) {
if (ImGui::ImageButton("#texture_info_image", ImTextureID(texture),
button_size, ImVec2(0, 0), ImVec2(1, 1))) {
// show viewer
}
} else {
@ -818,8 +818,7 @@ void TraceViewer::DrawVertexFetcher(Shader* shader,
int display_start, display_end;
ImGui::CalcListClipping(vertex_count, ImGui::GetTextLineHeight(),
&display_start, &display_end);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
(display_start)*ImGui::GetTextLineHeight());
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
ImGui::Columns(column_count);
if (display_start <= 1) {
for (size_t el_index = 0; el_index < vertex_binding.attributes.size();
@ -1005,8 +1004,8 @@ void TraceViewer::DrawVertexFetcher(Shader* shader,
}
}
ImGui::Columns(1);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (vertex_count - display_end) *
ImGui::GetTextLineHeight());
ImGui::Dummy(
ImVec2(0, (vertex_count - display_end) * ImGui::GetTextLineHeight()));
ImGui::PopStyleVar();
ImGui::EndChild();
}
@ -1463,19 +1462,21 @@ void TraceViewer::DrawStateUI() {
ImVec2 button_pos = ImGui::GetCursorScreenPos();
ImVec2 button_size(256, 256);
ImTextureID tex = 0;
ImGui::PushID(i);
if (write_mask) {
auto color_target = GetColorRenderTarget(surface_pitch, surface_msaa,
color_base, color_format);
tex = ImTextureID(color_target);
if (ImGui::ImageButton(tex, button_size, ImVec2(0, 0),
if (ImGui::ImageButton("#color_image", tex, button_size, ImVec2(0, 0),
ImVec2(1, 1))) {
// show viewer
}
} else {
ImGui::ImageButton(ImTextureID(0), button_size, ImVec2(0, 0),
ImVec2(1, 1), -1, ImVec4(0, 0, 0, 0),
ImGui::ImageButton("#color_image", ImTextureID(0), button_size,
ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0),
ImVec4(0, 0, 0, 0));
}
ImGui::PopID();
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Text("Color Target %d (%s), base %.4X, pitch %d, format %s", i,
@ -1586,8 +1587,8 @@ void TraceViewer::DrawStateUI() {
auto button_pos = ImGui::GetCursorScreenPos();
ImVec2 button_size(256, 256);
ImGui::ImageButton(ImTextureID(depth_target), button_size, ImVec2(0, 0),
ImVec2(1, 1));
ImGui::ImageButton("#depth_stencil_image", ImTextureID(depth_target),
button_size, ImVec2(0, 0), ImVec2(1, 1));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
@ -1640,8 +1641,7 @@ void TraceViewer::DrawStateUI() {
ImGui::CalcListClipping(int(vertices.size() / 4),
ImGui::GetTextLineHeight(), &display_start,
&display_end);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
(display_start)*ImGui::GetTextLineHeight());
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
ImGui::Columns(int(el_size), "#vsvertices", true);
for (size_t i = display_start; i < display_end; i++) {
@ -1662,9 +1662,8 @@ void TraceViewer::DrawStateUI() {
}
ImGui::Columns(1);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
((vertices.size() / 4) - display_end) *
ImGui::GetTextLineHeight());
ImGui::Dummy(ImVec2(0, ((vertices.size() / 4) - display_end) *
ImGui::GetTextLineHeight()));
ImGui::EndChild();
} else {
ImGui::Text("No vertex shader output");
@ -1708,8 +1707,7 @@ void TraceViewer::DrawStateUI() {
ImGui::CalcListClipping(1 + draw_info.index_count,
ImGui::GetTextLineHeight(), &display_start,
&display_end);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
(display_start)*ImGui::GetTextLineHeight());
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
ImGui::Columns(2, "#indices", true);
ImGui::SetColumnOffset(1, 60);
if (display_start <= 1) {
@ -1744,9 +1742,8 @@ void TraceViewer::DrawStateUI() {
ImGui::NextColumn();
}
ImGui::Columns(1);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
(draw_info.index_count - display_end) *
ImGui::GetTextLineHeight());
ImGui::Dummy(ImVec2(0, (draw_info.index_count - display_end) *
ImGui::GetTextLineHeight()));
ImGui::PopStyleVar();
ImGui::EndChild();
}

View File

@ -2546,8 +2546,6 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// After all commands that may dispatch, copy or insert barriers, submit the
// barriers (may end the render pass), and (re)enter the render pass before
// drawing.
// TODO(Triang3l): Handle disabled variableMultisampleRate by restarting the
// render pass with no attachments if the sample count becomes different.
SubmitBarriersAndEnterRenderTargetCacheRenderPass(
render_target_cache_->last_update_render_pass(),
render_target_cache_->last_update_framebuffer());

View File

@ -581,6 +581,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
primitive_processing_result.host_primitive_reset_enabled;
description_out.depth_clamp_enable =
device_features.depthClamp &&
regs.Get<reg::PA_CL_CLIP_CNTL>().clip_disable;
// TODO(Triang3l): Tessellation.
@ -825,6 +826,10 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet(
return false;
}
if (!device_features.depthClamp && description.depth_clamp_enable) {
return false;
}
if (!device_features.fillModeNonSolid &&
description.polygon_mode != PipelinePolygonMode::kFill) {
return false;
@ -1173,9 +1178,6 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
builder.makeStructType(id_vector_temp, "gl_PerVertex");
builder.addMemberName(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position, "gl_Position");
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position,
spv::DecorationInvariant);
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position,
spv::DecorationBuiltIn, spv::BuiltInPosition);
@ -1183,9 +1185,6 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
builder.addMemberName(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_clip_distance,
"gl_ClipDistance");
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_clip_distance,
spv::DecorationInvariant);
builder.addMemberDecoration(
type_struct_out_gl_per_vertex, member_out_gl_per_vertex_clip_distance,
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
@ -1194,6 +1193,7 @@ VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
spv::Id out_gl_per_vertex =
builder.createVariable(spv::NoPrecision, spv::StorageClassOutput,
type_struct_out_gl_per_vertex, "");
builder.addDecoration(out_gl_per_vertex, spv::DecorationInvariant);
main_interface.push_back(out_gl_per_vertex);
// Begin the main function.

View File

@ -44,9 +44,13 @@ class VulkanRenderTargetCache final : public RenderTargetCache {
// targets are different for 2x and 4x guest MSAA, pipelines because the
// sample mask will have 2 samples excluded for 2x-as-4x).
// This has effect only on the attachments, but even in cases when there
// are no attachments, it can be used to the sample count between
// are no attachments, it can be used to pass the sample count between
// subsystems, for instance, to specify the desired number of samples to
// use when there are no attachments in pipelines.
// Also, without attachments, using separate render passes for different
// sample counts ensures that if the variableMultisampleRate feature is
// not supported, no draws with different rasterization sample counts end
// up in one render pass.
xenos::MsaaSamples msaa_samples : xenos::kMsaaSamplesBits; // 2
// << 0 is depth, << 1...4 is color.
uint32_t depth_and_color_used : 1 + xenos::kMaxColorRenderTargets; // 7

View File

@ -32,6 +32,10 @@ bool SDLHelper::Prepare() {
is_prepared_ &= SetHints();
is_prepared_ &= RedirectLog();
SDL_version ver = {};
SDL_GetVersion(&ver);
XELOGI("SDL Version {}.{}.{} initialized.", ver.major, ver.minor, ver.patch);
return is_prepared_;
}

View File

@ -69,12 +69,12 @@ std::string XdbfWrapper::GetStringTableEntry(XLanguage language,
}
auto xstr_head =
reinterpret_cast<const XdbfXstrHeader*>(language_block.buffer);
reinterpret_cast<const XdbfSectionHeader*>(language_block.buffer);
assert_true(xstr_head->magic == kXdbfSignatureXstr);
assert_true(xstr_head->version == 1);
const uint8_t* ptr = language_block.buffer + sizeof(XdbfXstrHeader);
for (uint16_t i = 0; i < xstr_head->string_count; ++i) {
const uint8_t* ptr = language_block.buffer + sizeof(XdbfSectionHeader);
for (uint16_t i = 0; i < xstr_head->count; ++i) {
auto entry = reinterpret_cast<const XdbfStringTableEntry*>(ptr);
ptr += sizeof(XdbfStringTableEntry);
if (entry->id == string_id) {
@ -94,19 +94,18 @@ std::vector<XdbfAchievementTableEntry> XdbfWrapper::GetAchievements() const {
return achievements;
}
auto xstr_head =
reinterpret_cast<const XdbfXstrHeader*>(achievement_table.buffer);
assert_true(xstr_head->magic == kXdbfSignatureXach);
assert_true(xstr_head->version == 1);
auto xach_head =
reinterpret_cast<const XdbfSectionHeader*>(achievement_table.buffer);
assert_true(xach_head->magic == kXdbfSignatureXach);
assert_true(xach_head->version == 1);
const uint8_t* ptr = achievement_table.buffer + sizeof(XdbfXstrHeader);
for (uint16_t i = 0; i < xstr_head->string_count; ++i) {
const uint8_t* ptr = achievement_table.buffer + sizeof(XdbfSectionHeader);
for (uint16_t i = 0; i < xach_head->count; ++i) {
auto entry = reinterpret_cast<const XdbfAchievementTableEntry*>(ptr);
ptr += sizeof(XdbfAchievementTableEntry);
achievements.push_back(*entry);
}
return achievements;
}
XLanguage XdbfGameData::GetExistingLanguage(XLanguage language_to_check) const {

View File

@ -62,13 +62,13 @@ struct XdbfXstc {
};
static_assert_size(XdbfXstc, 16);
struct XdbfXstrHeader {
struct XdbfSectionHeader {
xe::be<uint32_t> magic;
xe::be<uint32_t> version;
xe::be<uint32_t> size;
xe::be<uint16_t> string_count;
xe::be<uint16_t> count;
};
static_assert_size(XdbfXstrHeader, 14);
static_assert_size(XdbfSectionHeader, 14);
struct XdbfStringTableEntry {
xe::be<uint16_t> id;

View File

@ -719,14 +719,15 @@ dword_result_t XamUserCreateAchievementEnumerator_entry(
return result;
}
const kernel::util::XdbfGameData db = kernel_state()->title_xdbf();
const util::XdbfGameData db = kernel_state()->title_xdbf();
if (db.is_valid()) {
XLanguage language = db.GetExistingLanguage(static_cast<XLanguage>(cvars::user_language));
std::vector<kernel::util::XdbfAchievementTableEntry> achievement_list =
const XLanguage language =
db.GetExistingLanguage(static_cast<XLanguage>(cvars::user_language));
const std::vector<util::XdbfAchievementTableEntry> achievement_list =
db.GetAchievements();
for (const auto& entry : achievement_list) {
for (const util::XdbfAchievementTableEntry& entry : achievement_list) {
auto item = XStaticAchievementEnumerator::AchievementDetails{
entry.id,
xe::to_utf16(db.GetStringTableEntry(language, entry.label_id)),

View File

@ -148,14 +148,16 @@ bool Win32FilePicker::Show(Window* parent_window) {
if (type() == Type::kFile) {
// Set the file types to display only. Notice that this is a 1-based array.
std::vector<std::pair<std::u16string, std::u16string>> file_pairs;
using u16sPair = std::pair<std::u16string, std::u16string>;
std::vector<std::unique_ptr<u16sPair>> file_pairs;
std::vector<COMDLG_FILTERSPEC> file_types;
for (const auto& extension : this->extensions()) {
const auto& file_pair =
file_pairs.emplace_back(std::move(xe::to_utf16(extension.first)),
std::move(xe::to_utf16(extension.second)));
file_types.push_back({(LPCWSTR)file_pair.first.c_str(),
(LPCWSTR)file_pair.second.c_str()});
file_pairs.emplace_back(std::make_unique<u16sPair>(
xe::to_utf16(extension.first), xe::to_utf16(extension.second)));
file_types.push_back(
{reinterpret_cast<LPCWSTR>(file_pair->first.c_str()),
reinterpret_cast<LPCWSTR>(file_pair->second.c_str())});
}
hr = file_dialog->SetFileTypes(static_cast<UINT>(file_types.size()),
file_types.data());

View File

@ -62,11 +62,11 @@ void ImGuiDrawer::AddDialog(ImGuiDialog* dialog) {
dialogs_.cend()) {
return;
}
if (dialog_loop_next_index_ == SIZE_MAX && dialogs_.empty()) {
// First dialog added. dialog_loop_next_index_ == SIZE_MAX is also checked
// because in a situation of removing the only dialog, then adding a dialog,
// from within a dialog's Draw function, the removal would not cause the
// listener and the drawer to be removed (it's deferred in this case).
if (dialogs_.empty() && !IsDrawingDialogs()) {
// First dialog added. !IsDrawingDialogs() is also checked because in a
// situation of removing the only dialog, then adding a dialog, from within
// a dialog's Draw function, re-registering the ImGuiDrawer may result in
// ImGui being drawn multiple times in the current frame.
window_->AddInputListener(this, z_order_);
if (presenter_) {
presenter_->AddUIDrawerFromUIThread(this, z_order_);
@ -81,7 +81,7 @@ void ImGuiDrawer::RemoveDialog(ImGuiDialog* dialog) {
if (it == dialogs_.cend()) {
return;
}
if (dialog_loop_next_index_ != SIZE_MAX) {
if (IsDrawingDialogs()) {
// Actualize the next dialog index after the erasure from the vector.
size_t existing_index = size_t(std::distance(dialogs_.cbegin(), it));
if (dialog_loop_next_index_ > existing_index) {
@ -89,17 +89,7 @@ void ImGuiDrawer::RemoveDialog(ImGuiDialog* dialog) {
}
}
dialogs_.erase(it);
if (dialog_loop_next_index_ == SIZE_MAX && dialogs_.empty()) {
if (presenter_) {
presenter_->RemoveUIDrawerFromUIThread(this);
}
window_->RemoveInputListener(this);
// Clear all input since no input will be received anymore, and when the
// drawer becomes active again, it'd have an outdated input state otherwise
// which will be persistent until new events actualize individual input
// properties.
ClearInput();
}
DetachIfLastDialogRemoved();
}
void ImGuiDrawer::Initialize() {
@ -194,24 +184,6 @@ void ImGuiDrawer::Initialize() {
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.21f);
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
io.KeyMap[ImGuiKey_Tab] = int(ui::VirtualKey::kTab);
io.KeyMap[ImGuiKey_LeftArrow] = int(ui::VirtualKey::kLeft);
io.KeyMap[ImGuiKey_RightArrow] = int(ui::VirtualKey::kRight);
io.KeyMap[ImGuiKey_UpArrow] = int(ui::VirtualKey::kUp);
io.KeyMap[ImGuiKey_DownArrow] = int(ui::VirtualKey::kDown);
io.KeyMap[ImGuiKey_Home] = int(ui::VirtualKey::kHome);
io.KeyMap[ImGuiKey_End] = int(ui::VirtualKey::kEnd);
io.KeyMap[ImGuiKey_Delete] = int(ui::VirtualKey::kDelete);
io.KeyMap[ImGuiKey_Backspace] = int(ui::VirtualKey::kBack);
io.KeyMap[ImGuiKey_Enter] = int(ui::VirtualKey::kReturn);
io.KeyMap[ImGuiKey_Escape] = int(ui::VirtualKey::kEscape);
io.KeyMap[ImGuiKey_A] = int(ui::VirtualKey::kA);
io.KeyMap[ImGuiKey_C] = int(ui::VirtualKey::kC);
io.KeyMap[ImGuiKey_V] = int(ui::VirtualKey::kV);
io.KeyMap[ImGuiKey_X] = int(ui::VirtualKey::kX);
io.KeyMap[ImGuiKey_Y] = int(ui::VirtualKey::kY);
io.KeyMap[ImGuiKey_Z] = int(ui::VirtualKey::kZ);
frame_time_tick_frequency_ = double(Clock::QueryHostTickFrequency());
last_frame_time_ticks_ = Clock::QueryHostTickCount();
@ -219,6 +191,33 @@ void ImGuiDrawer::Initialize() {
reset_mouse_position_after_next_frame_ = false;
}
std::optional<ImGuiKey> ImGuiDrawer::VirtualKeyToImGuiKey(VirtualKey vkey) {
static const std::map<VirtualKey, ImGuiKey> map = {
{ui::VirtualKey::kTab, ImGuiKey_Tab},
{ui::VirtualKey::kLeft, ImGuiKey_LeftArrow},
{ui::VirtualKey::kRight, ImGuiKey_RightArrow},
{ui::VirtualKey::kUp, ImGuiKey_UpArrow},
{ui::VirtualKey::kDown, ImGuiKey_DownArrow},
{ui::VirtualKey::kHome, ImGuiKey_Home},
{ui::VirtualKey::kEnd, ImGuiKey_End},
{ui::VirtualKey::kDelete, ImGuiKey_Delete},
{ui::VirtualKey::kBack, ImGuiKey_Backspace},
{ui::VirtualKey::kReturn, ImGuiKey_Enter},
{ui::VirtualKey::kEscape, ImGuiKey_Escape},
{ui::VirtualKey::kA, ImGuiKey_A},
{ui::VirtualKey::kC, ImGuiKey_C},
{ui::VirtualKey::kV, ImGuiKey_V},
{ui::VirtualKey::kX, ImGuiKey_X},
{ui::VirtualKey::kY, ImGuiKey_Y},
{ui::VirtualKey::kZ, ImGuiKey_Z},
};
if (auto search = map.find(vkey); search != map.end()) {
return search->second;
} else {
return std::nullopt;
}
}
void ImGuiDrawer::SetupFontTexture() {
if (font_texture_ || !immediate_drawer_) {
return;
@ -301,7 +300,7 @@ void ImGuiDrawer::Draw(UIDrawContext& ui_draw_context) {
ImGui::NewFrame();
assert_true(dialog_loop_next_index_ == SIZE_MAX);
assert_true(!IsDrawingDialogs());
dialog_loop_next_index_ = 0;
while (dialog_loop_next_index_ < dialogs_.size()) {
dialogs_[dialog_loop_next_index_++]->Draw();
@ -319,11 +318,11 @@ void ImGuiDrawer::Draw(UIDrawContext& ui_draw_context) {
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
}
if (dialogs_.empty()) {
// All dialogs have removed themselves during the draw, detach.
presenter_->RemoveUIDrawerFromUIThread(this);
window_->RemoveInputListener(this);
} else {
// Detaching is deferred if the last dialog is removed during drawing, perform
// it now if needed.
DetachIfLastDialogRemoved();
if (!dialogs_.empty()) {
// Repaint (and handle input) continuously if still active.
presenter_->RequestUIPaintFromUIThread();
}
@ -346,14 +345,13 @@ void ImGuiDrawer::RenderDrawLists(ImDrawData* data,
batch.index_count = cmd_list->IdxBuffer.size();
immediate_drawer_->BeginDrawBatch(batch);
int index_offset = 0;
for (int j = 0; j < cmd_list->CmdBuffer.size(); ++j) {
const auto& cmd = cmd_list->CmdBuffer[j];
ImmediateDraw draw;
draw.primitive_type = ImmediatePrimitiveType::kTriangles;
draw.count = cmd.ElemCount;
draw.index_offset = index_offset;
draw.index_offset = cmd.IdxOffset;
draw.texture = reinterpret_cast<ImmediateTexture*>(cmd.TextureId);
draw.scissor = true;
draw.scissor_left = cmd.ClipRect.x;
@ -361,8 +359,6 @@ void ImGuiDrawer::RenderDrawLists(ImDrawData* data,
draw.scissor_right = cmd.ClipRect.z;
draw.scissor_bottom = cmd.ClipRect.w;
immediate_drawer_->Draw(draw);
index_offset += cmd.ElemCount;
}
immediate_drawer_->EndDrawBatch();
@ -497,13 +493,7 @@ void ImGuiDrawer::ClearInput() {
}
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
std::memset(io.MouseDown, 0, sizeof(io.MouseDown));
io.MouseWheel = 0.0f;
io.MouseWheelH = 0.0f;
io.KeyCtrl = false;
io.KeyShift = false;
io.KeyAlt = false;
io.KeySuper = false;
std::memset(io.KeysDown, 0, sizeof(io.KeysDown));
io.ClearInputKeys();
io.ClearInputCharacters();
touch_pointer_id_ = TouchEvent::kPointerIDNone;
reset_mouse_position_after_next_frame_ = false;
@ -511,9 +501,9 @@ void ImGuiDrawer::ClearInput() {
void ImGuiDrawer::OnKey(KeyEvent& e, bool is_down) {
auto& io = GetIO();
VirtualKey virtual_key = e.virtual_key();
if (size_t(virtual_key) < xe::countof(io.KeysDown)) {
io.KeysDown[size_t(virtual_key)] = is_down;
const VirtualKey virtual_key = e.virtual_key();
if (auto imGuiKey = VirtualKeyToImGuiKey(virtual_key); imGuiKey) {
io.AddKeyEvent(*imGuiKey, is_down);
}
switch (virtual_key) {
case VirtualKey::kShift:
@ -557,5 +547,24 @@ void ImGuiDrawer::SwitchToPhysicalMouseAndUpdateMousePosition(
UpdateMousePosition(float(e.x()), float(e.y()));
}
void ImGuiDrawer::DetachIfLastDialogRemoved() {
// IsDrawingDialogs() is also checked because in a situation of removing the
// only dialog, then adding a dialog, from within a dialog's Draw function,
// re-registering the ImGuiDrawer may result in ImGui being drawn multiple
// times in the current frame.
if (!dialogs_.empty() || IsDrawingDialogs()) {
return;
}
if (presenter_) {
presenter_->RemoveUIDrawerFromUIThread(this);
}
window_->RemoveInputListener(this);
// Clear all input since no input will be received anymore, and when the
// drawer becomes active again, it'd have an outdated input state otherwise
// which will be persistent until new events actualize individual input
// properties.
ClearInput();
}
} // namespace ui
} // namespace xe

View File

@ -23,6 +23,7 @@
struct ImDrawData;
struct ImGuiContext;
struct ImGuiIO;
enum ImGuiKey : int;
namespace xe {
namespace ui {
@ -74,6 +75,11 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {
void UpdateMousePosition(float x, float y);
void SwitchToPhysicalMouseAndUpdateMousePosition(const MouseEvent& e);
bool IsDrawingDialogs() const { return dialog_loop_next_index_ != SIZE_MAX; }
void DetachIfLastDialogRemoved();
std::optional<ImGuiKey> VirtualKeyToImGuiKey(VirtualKey vkey);
Window* window_;
size_t z_order_;

2
third_party/FFmpeg vendored

@ -1 +1 @@
Subproject commit a14f5c03834a79fc401626a4dad7a58a2da0c445
Subproject commit a437fe6d8efef17c8ad33d39f5815032e7adf5d7

2
third_party/SDL2 vendored

@ -1 +1 @@
Subproject commit b424665e0899769b200231ba943353a5fee1b6b6
Subproject commit 55b03c7493a7abed33cf803d1380a40fa8af903f

View File

@ -42,6 +42,7 @@ project("SDL2")
"SDL2/include/SDL_filesystem.h",
"SDL2/include/SDL_gamecontroller.h",
"SDL2/include/SDL_gesture.h",
"SDL2/include/SDL_guid.h",
"SDL2/include/SDL_haptic.h",
"SDL2/include/SDL_hints.h",
"SDL2/include/SDL_hidapi.h",
@ -112,6 +113,7 @@ project("SDL2")
"SDL2/src/audio/winmm/SDL_winmm.h",
"SDL2/src/core/windows/SDL_directx.h",
"SDL2/src/core/windows/SDL_hid.h",
"SDL2/src/core/windows/SDL_immdevice.h",
"SDL2/src/core/windows/SDL_windows.h",
"SDL2/src/core/windows/SDL_xinput.h",
"SDL2/src/dynapi/SDL_dynapi.h",
@ -127,7 +129,6 @@ project("SDL2")
"SDL2/src/events/SDL_gesture_c.h",
"SDL2/src/events/SDL_keyboard_c.h",
"SDL2/src/events/SDL_mouse_c.h",
"SDL2/src/events/SDL_sysevents.h",
"SDL2/src/events/SDL_touch_c.h",
"SDL2/src/events/SDL_windowevents_c.h",
"SDL2/src/haptic/SDL_haptic_c.h",
@ -155,6 +156,7 @@ project("SDL2")
"SDL2/src/misc/SDL_sysurl.h",
"SDL2/src/power/SDL_syspower.h",
"SDL2/src/render/direct3d11/SDL_shaders_d3d11.h",
"SDL2/src/render/direct3d12/SDL_shaders_d3d12.h",
"SDL2/src/render/direct3d/SDL_shaders_d3d.h",
"SDL2/src/render/opengles2/SDL_gles2funcs.h",
"SDL2/src/render/opengles2/SDL_shaders_gles2.h",
@ -175,8 +177,11 @@ project("SDL2")
"SDL2/src/SDL_assert_c.h",
"SDL2/src/SDL_dataqueue.h",
"SDL2/src/SDL_error_c.h",
"SDL2/src/SDL_guid.c",
"SDL2/src/SDL_hints_c.h",
"SDL2/src/SDL_internal.h",
"SDL2/src/SDL_list.h",
"SDL2/src/SDL_log_c.h",
"SDL2/src/sensor/dummy/SDL_dummysensor.h",
"SDL2/src/sensor/SDL_sensor_c.h",
"SDL2/src/sensor/SDL_syssensor.h",
@ -259,6 +264,7 @@ project("SDL2")
"SDL2/src/audio/wasapi/SDL_wasapi.c",
"SDL2/src/audio/wasapi/SDL_wasapi_win32.c",
"SDL2/src/core/windows/SDL_hid.c",
"SDL2/src/core/windows/SDL_immdevice.c",
"SDL2/src/core/windows/SDL_windows.c",
"SDL2/src/core/windows/SDL_xinput.c",
"SDL2/src/cpuinfo/SDL_cpuinfo.c",
@ -281,13 +287,16 @@ project("SDL2")
"SDL2/src/haptic/windows/SDL_windowshaptic.c",
"SDL2/src/haptic/windows/SDL_xinputhaptic.c",
"SDL2/src/hidapi/SDL_hidapi.c",
"SDL2/src/joystick/controller_type.c",
"SDL2/src/joystick/dummy/SDL_sysjoystick.c",
"SDL2/src/joystick/hidapi/SDL_hidapijoystick.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_combined.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_gamecube.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_luna.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_ps4.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_ps5.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_rumble.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_shield.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_stadia.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_switch.c",
"SDL2/src/joystick/hidapi/SDL_hidapi_xbox360.c",
@ -329,6 +338,8 @@ project("SDL2")
"SDL2/src/power/SDL_power.c",
"SDL2/src/power/windows/SDL_syspower.c",
"SDL2/src/render/direct3d11/SDL_shaders_d3d11.c",
"SDL2/src/render/direct3d12/SDL_render_d3d12.c",
"SDL2/src/render/direct3d12/SDL_shaders_d3d12.c",
"SDL2/src/render/direct3d/SDL_render_d3d.c",
"SDL2/src/render/direct3d11/SDL_render_d3d11.c",
"SDL2/src/render/direct3d/SDL_shaders_d3d.c",
@ -350,16 +361,20 @@ project("SDL2")
"SDL2/src/SDL.c",
"SDL2/src/SDL_assert.c",
"SDL2/src/SDL_dataqueue.c",
"SDL2/src/SDL_list.c",
"SDL2/src/SDL_error.c",
"SDL2/src/SDL_hints.c",
"SDL2/src/SDL_log.c",
"SDL2/src/SDL_utils.c",
"SDL2/src/sensor/dummy/SDL_dummysensor.c",
"SDL2/src/sensor/SDL_sensor.c",
"SDL2/src/sensor/windows/SDL_windowssensor.c",
"SDL2/src/stdlib/SDL_crc16.c",
"SDL2/src/stdlib/SDL_crc32.c",
"SDL2/src/stdlib/SDL_getenv.c",
"SDL2/src/stdlib/SDL_iconv.c",
"SDL2/src/stdlib/SDL_malloc.c",
"SDL2/src/stdlib/SDL_mslibc.c",
"SDL2/src/stdlib/SDL_qsort.c",
"SDL2/src/stdlib/SDL_stdlib.c",
"SDL2/src/stdlib/SDL_string.c",

2
third_party/cxxopts vendored

@ -1 +1 @@
Subproject commit f087dc8fcdcd6aabba68e671ae17ff3e975134f4
Subproject commit b2b8cf2f50a449720874f43445e23d75b77dcc43

File diff suppressed because it is too large Load Diff

30
third_party/fxaa/LICENSE vendored Normal file
View File

@ -0,0 +1,30 @@
BSD 3-Clause License
Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of NVIDIA CORPORATION nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

2
third_party/imgui vendored

@ -1 +1 @@
Subproject commit ca30ef4269150e71a950106c6cfa8f94898581da
Subproject commit 81160fee56027226bc80b48e196d0332f5541a8c

View File

@ -24,6 +24,7 @@ project("imgui")
"imgui/imgui_draw.cpp",
"imgui/imgui_demo.cpp",
"imgui/imgui_internal.h",
"imgui/imgui_tables.cpp",
"imgui/imgui_widgets.cpp",
"imgui/imstb_rectpack.h",
"imgui/imstb_textedit.h",

View File

@ -213,7 +213,7 @@ def import_vs_environment():
install_path = None
env_tool_args = None
vswhere = subprocess.check_output('third_party/vswhere/vswhere.exe -version "[15,)" -latest -format json -utf8', shell=False, universal_newlines=True, encoding="utf-8")
vswhere = subprocess.check_output('tools/vswhere/vswhere.exe -version "[15,)" -latest -format json -utf8', shell=False, universal_newlines=True, encoding="utf-8")
if vswhere:
vswhere = json.loads(vswhere)
if vswhere and len(vswhere) > 0:

20
tools/vswhere/LICENSE.txt Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (C) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -76,7 +76,7 @@ def import_vs_environment():
env_tool_args = None
vswhere = subprocess.check_output(
'third_party/vswhere/vswhere.exe -version "[15,)" -latest -prerelease -format json -utf8 -products '
'tools/vswhere/vswhere.exe -version "[15,)" -latest -prerelease -format json -utf8 -products '
"Microsoft.VisualStudio.Product.Enterprise "
"Microsoft.VisualStudio.Product.Professional "
"Microsoft.VisualStudio.Product.Community "