Merge branch 'master' of https://github.com/xenia-project/xenia into canary_experimental
This commit is contained in:
commit
26415cb8b1
|
@ -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():
|
||||
|
|
|
@ -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 ::
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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_);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) +
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a14f5c03834a79fc401626a4dad7a58a2da0c445
|
||||
Subproject commit a437fe6d8efef17c8ad33d39f5815032e7adf5d7
|
|
@ -1 +1 @@
|
|||
Subproject commit b424665e0899769b200231ba943353a5fee1b6b6
|
||||
Subproject commit 55b03c7493a7abed33cf803d1380a40fa8af903f
|
|
@ -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",
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f087dc8fcdcd6aabba68e671ae17ff3e975134f4
|
||||
Subproject commit b2b8cf2f50a449720874f43445e23d75b77dcc43
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
|
@ -1 +1 @@
|
|||
Subproject commit ca30ef4269150e71a950106c6cfa8f94898581da
|
||||
Subproject commit 81160fee56027226bc80b48e196d0332f5541a8c
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
|
@ -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 "
|
||||
|
|
Loading…
Reference in New Issue