mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
Compare commits
4 Commits
e5f0ee7fc2
...
0cad4672e9
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cad4672e9 | |||
| cd4eab9d65 | |||
| fde0b98e69 | |||
| d4465faa79 |
@@ -740,6 +740,12 @@ void RenderExecutor::FindBuffers(std::span<PreparedBindings* const> stages) {
|
||||
const auto descriptor = DecodeNativeDescriptor<ShaderBufferResource>(snapshot.buffers[resource]);
|
||||
const auto address = descriptor.Base48();
|
||||
auto size = descriptor.GetSize();
|
||||
if (size != 0 && descriptor.Stride() == 0 && descriptor.OutOfBounds() == 2 &&
|
||||
!metadata.scalar) {
|
||||
// OOB_SELECT=2 only tests NumRecords != 0; a zero-stride fetch
|
||||
// still needs its full payload when NumRecords is smaller than it.
|
||||
size = std::max(size, uint64_t {metadata.max_byte_extent});
|
||||
}
|
||||
if (address == 0 || size == 0) {
|
||||
source = {};
|
||||
continue;
|
||||
@@ -757,12 +763,13 @@ void RenderExecutor::FindBuffers(std::span<PreparedBindings* const> stages) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto& graphics = m_context.GetGraphics();
|
||||
const auto limit = uint64_t {graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange} -
|
||||
(graphics.StorageMinAlignment() - 1);
|
||||
size = std::min({size, uint64_t {256} * 1024 * 1024, limit});
|
||||
}
|
||||
// PPSA15246
|
||||
const auto& graphics = m_context.GetGraphics();
|
||||
const auto limit =
|
||||
uint64_t {graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange} -
|
||||
(graphics.StorageMinAlignment() - 1);
|
||||
size = std::min({size, uint64_t {256} * 1024 * 1024, limit});
|
||||
}
|
||||
// Finite GPU descriptors can span sparse PRT holes; clamp only oversized/sentinel ranges.
|
||||
if (size >= (uint64_t {1} << 30u) || descriptor.NumRecords() == UINT32_MAX) {
|
||||
|
||||
@@ -636,6 +636,9 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
||||
EXIT_NOT_IMPLEMENTED(pipeline.pipeline_layout == nullptr);
|
||||
|
||||
vk::ComputePipelineCreateInfo info {};
|
||||
if (input_info.stage.program->info.uses_gds) {
|
||||
info.flags = vk::PipelineCreateFlagBits::eDispatchBase;
|
||||
}
|
||||
info.stage = comp_shader_stage_info;
|
||||
info.layout = pipeline.pipeline_layout;
|
||||
info.basePipelineIndex = -1;
|
||||
|
||||
@@ -447,7 +447,27 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
||||
}
|
||||
|
||||
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.pipeline);
|
||||
vk_buffer.dispatch(thread_group_x, thread_group_y, thread_group_z);
|
||||
constexpr uint32_t DISPATCH_INITIATOR_ORDERED_APPEND_ENABLE = 1u << 3u;
|
||||
const uint64_t group_threads = uint64_t {std::max(input_info.threads_num[0], 1u)} *
|
||||
std::max(input_info.threads_num[1], 1u) *
|
||||
std::max(input_info.threads_num[2], 1u);
|
||||
if ((mode & DISPATCH_INITIATOR_ORDERED_APPEND_ENABLE) != 0 && program.info.uses_gds &&
|
||||
group_threads <= input_info.wave_size && !input_info.lds_storage) {
|
||||
// A single guest wave per group can run in launch order without a device-wide
|
||||
// spinlock. Keep the guest workgroup IDs when splitting the dispatch.
|
||||
for (uint32_t z = 0; z < thread_group_z; ++z) {
|
||||
for (uint32_t y = 0; y < thread_group_y; ++y) {
|
||||
for (uint32_t x = 0; x < thread_group_x; ++x) {
|
||||
if ((x | y | z) != 0u) {
|
||||
ShaderAccessBarrier(vk_buffer, vk::PipelineStageFlagBits::eComputeShader);
|
||||
}
|
||||
vk_buffer.dispatchBase(x, y, z, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vk_buffer.dispatch(thread_group_x, thread_group_y, thread_group_z);
|
||||
}
|
||||
Common::DebugCounters::Add(Common::DebugCounters::Counter::Dispatches);
|
||||
|
||||
// The removed host fence also ordered read-only dispatches before later writers.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
find_package(Qt6 COMPONENTS Concurrent Network Widgets REQUIRED)
|
||||
find_package(Qt6 6.8 COMPONENTS Concurrent Network Widgets REQUIRED)
|
||||
add_subdirectory("${KYTY_SOURCE_DIR}/updater" "${CMAKE_CURRENT_BINARY_DIR}/updater")
|
||||
|
||||
set(CMAKE_AUTOUIC_SEARCH_PATHS forms)
|
||||
|
||||
@@ -112,6 +112,49 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="themeLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_theme">
|
||||
<property name="text">
|
||||
<string>Theme:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="theme_combo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>System</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Dark</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Light</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="themeSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
@@ -26,6 +27,7 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QSettings>
|
||||
#include <QStringList>
|
||||
#include <QStyleHints>
|
||||
#include <QTextStream>
|
||||
#include <QVariant>
|
||||
#include <QtCore>
|
||||
@@ -61,7 +63,8 @@ constexpr DWORD CMD_Y_CHARS = 1000;
|
||||
#endif
|
||||
constexpr char SETTINGS_MAIN_DIALOG[] = "MainDialog";
|
||||
constexpr char SETTINGS_MAIN_LAST_GEOMETRY[] = "geometry";
|
||||
constexpr char SETTINGS_CHECK_UPDATES[] = "check_updates_on_startup";
|
||||
constexpr char SETTINGS_CHECK_UPDATES[] = "check_updates_on_startup";
|
||||
constexpr char SETTINGS_THEME[] = "theme";
|
||||
|
||||
class MainDialogPrivate: public QObject {
|
||||
Q_OBJECT
|
||||
@@ -86,6 +89,17 @@ public:
|
||||
private:
|
||||
static QByteArray g_last_geometry;
|
||||
static bool g_check_updates_on_startup;
|
||||
static int g_theme;
|
||||
|
||||
static void ApplyTheme(int theme) {
|
||||
auto scheme = Qt::ColorScheme::Unknown;
|
||||
switch (theme) {
|
||||
case 1: scheme = Qt::ColorScheme::Dark; break;
|
||||
case 2: scheme = Qt::ColorScheme::Light; break;
|
||||
default: break;
|
||||
}
|
||||
QApplication::styleHints()->setColorScheme(scheme);
|
||||
}
|
||||
|
||||
Ui::MainDialog* m_ui = {nullptr};
|
||||
MainDialog* m_main_dialog = nullptr;
|
||||
@@ -101,6 +115,7 @@ private:
|
||||
|
||||
QByteArray MainDialogPrivate::g_last_geometry;
|
||||
bool MainDialogPrivate::g_check_updates_on_startup = true;
|
||||
int MainDialogPrivate::g_theme = 0;
|
||||
|
||||
MainDialog::MainDialog(QWidget* parent): QDialog(parent), m_p(new MainDialogPrivate(this)) {
|
||||
m_p->Setup(this);
|
||||
@@ -119,6 +134,8 @@ void MainDialogPrivate::Setup(MainDialog* main_dialog) {
|
||||
m_main_dialog = main_dialog;
|
||||
m_update_checker = new UpdateChecker(main_dialog);
|
||||
m_ui->check_updates_on_startup->setChecked(g_check_updates_on_startup);
|
||||
m_ui->theme_combo->setCurrentIndex(g_theme);
|
||||
ApplyTheme(g_theme);
|
||||
m_ui->check_updates_link->setVisible(UpdateChecker::IsSupported());
|
||||
m_ui->check_updates_on_startup->setVisible(UpdateChecker::IsSupported());
|
||||
|
||||
@@ -149,6 +166,11 @@ void MainDialogPrivate::Setup(MainDialog* main_dialog) {
|
||||
g_check_updates_on_startup = checked;
|
||||
m_ui->widget->WriteSettings();
|
||||
});
|
||||
connect(m_ui->theme_combo, &QComboBox::currentIndexChanged, this, [this](int index) {
|
||||
g_theme = index;
|
||||
ApplyTheme(index);
|
||||
m_ui->widget->WriteSettings();
|
||||
});
|
||||
connect(main_dialog, &MainDialog::Resize, [this]() {
|
||||
g_last_geometry = m_main_dialog->saveGeometry();
|
||||
m_ui->widget->WriteSettings();
|
||||
@@ -516,6 +538,7 @@ void MainDialogPrivate::WriteSettings(QSettings& s) {
|
||||
s.setValue(SETTINGS_MAIN_LAST_GEOMETRY, g_last_geometry);
|
||||
}
|
||||
s.setValue(SETTINGS_CHECK_UPDATES, g_check_updates_on_startup);
|
||||
s.setValue(SETTINGS_THEME, g_theme);
|
||||
|
||||
s.endGroup();
|
||||
}
|
||||
@@ -525,6 +548,10 @@ void MainDialogPrivate::ReadSettings(QSettings& s) {
|
||||
|
||||
g_last_geometry = s.value(SETTINGS_MAIN_LAST_GEOMETRY, g_last_geometry).toByteArray();
|
||||
g_check_updates_on_startup = s.value(SETTINGS_CHECK_UPDATES, true).toBool();
|
||||
g_theme = s.value(SETTINGS_THEME, 0).toInt();
|
||||
if (g_theme < 0 || g_theme > 2) {
|
||||
g_theme = 0;
|
||||
}
|
||||
|
||||
s.endGroup();
|
||||
}
|
||||
|
||||
@@ -10855,6 +10855,227 @@ public:
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckZeroStrideBufferBinding() {
|
||||
constexpr const char *name = "ZeroStrideBufferBinding";
|
||||
constexpr uintptr_t base = 0x0000000204c00000ull;
|
||||
constexpr uint64_t size = 0x10000;
|
||||
constexpr auto output = base + 0x2000;
|
||||
constexpr u32 value = 0x80000578u;
|
||||
std::array<std::vector<u32>, 2> codes;
|
||||
for (u32 scalar = 0; scalar < codes.size(); ++scalar) {
|
||||
auto &code = codes[scalar];
|
||||
if (scalar) {
|
||||
code = {EncodeSmem0(0x08, 16), EncodeSmem1(0, 125),
|
||||
EncodeSopp(0x0c, 0), EncodeVop1(0x01, 1, 16)};
|
||||
} else {
|
||||
code = {EncodeMubuf0(0x00, 0, false, false),
|
||||
EncodeMubuf1(1, 0, 0), EncodeSopp(0x0c, 0)};
|
||||
}
|
||||
code.insert(code.end(), {EncodeVop2(0x1a, 2, InlineU32(2), 0),
|
||||
EncodeMubuf0(0x1c), EncodeMubuf1(1, 1, 2)});
|
||||
AppendEnd(&code);
|
||||
ShaderMapUserData(reinterpret_cast<uint64_t>(code.data()),
|
||||
{.type = Prospero::ShaderBinaryType::kCs,
|
||||
.code_size_bytes = static_cast<u32>(code.size() * sizeof(u32))});
|
||||
}
|
||||
EnsureRuntimeContext();
|
||||
int64_t physical = -1;
|
||||
Require(name, "allocate", LibKernel::Memory::KernelAllocateDirectMemory(
|
||||
0, LibKernel::Memory::KernelGetDirectMemorySize(), size, size, 0, &physical) == 0,
|
||||
"buffer binding allocation failed");
|
||||
void *mapped = reinterpret_cast<void *>(base);
|
||||
Require(name, "map", LibKernel::Memory::KernelMapDirectMemory(
|
||||
&mapped, size, 0x3, 0x10, physical, size) == 0 &&
|
||||
mapped == reinterpret_cast<void *>(base), "buffer binding mapping failed");
|
||||
for (const auto prefix : {0u, 8u})
|
||||
Require(name, "input backing", LibKernel::Memory::TryWriteBacking(
|
||||
base + 0x1000 + prefix, &value, sizeof(value)), "input DWORD could not be written");
|
||||
RenderContext context(m_runtime_context);
|
||||
context.InitializeGpu(nullptr);
|
||||
LibKernel::Memory::InstallGpuResources(&context);
|
||||
context.GetGpu().SendCommandSync([&] {
|
||||
CommandProcessor processor(context, 0);
|
||||
processor.BufferInit();
|
||||
context.MapMemory(base, size);
|
||||
auto &cache = context.GetBufferCache();
|
||||
auto &shaders = processor.GetShCtx();
|
||||
struct Case { u32 mode, records; bool scalar; u32 expected; };
|
||||
constexpr Case cases[]{{2, 1, false, value}, {2, 0, false, 0},
|
||||
{3, 1, false, 0}, {3, 4, false, value},
|
||||
{2, 1, true, 0}, {2, 4, true, value}};
|
||||
for (const auto wave : {32u, 64u}) {
|
||||
for (const auto prefix : {0u, 8u}) {
|
||||
const auto address = base + 0x1000 + prefix;
|
||||
for (const auto test : cases) {
|
||||
cache.FillBuffer(output, wave * sizeof(u32), 0xa5a5a5a5u, false);
|
||||
shaders.SetCsShader({
|
||||
.data_addr = reinterpret_cast<uint64_t>(codes[test.scalar].data()),
|
||||
.num_thread_x = wave, .num_thread_y = 1, .num_thread_z = 1,
|
||||
.wave_size = static_cast<uint8_t>(wave), .user_sgpr = 8});
|
||||
ShaderBufferResource input{}, out{};
|
||||
input.UpdateAddress48(address);
|
||||
input.fields[2] = test.records;
|
||||
input.fields[3] = DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u) |
|
||||
(test.mode << 28u);
|
||||
out.UpdateAddress48(output);
|
||||
out.fields[2] = wave * sizeof(u32);
|
||||
out.fields[3] = DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u) | (3u << 28u);
|
||||
for (u32 i = 0; i < 4; ++i) {
|
||||
shaders.SetCsUserSgpr(i, input.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i + 4, out.fields[i], HW::UserSgprType::Unknown);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, wave == 32 ? 0x8041u : 0x41u);
|
||||
cache.ReadMemory(output, wave * sizeof(u32));
|
||||
std::array<u32, 64> actual{};
|
||||
Require(name, "readback", LibKernel::Memory::TryReadBacking(
|
||||
output, actual.data(), wave * sizeof(u32)), "buffer output was unreadable");
|
||||
Require(name, "vector and scalar range rules",
|
||||
std::all_of(actual.begin(), actual.begin() + wave,
|
||||
[&](u32 word) { return word == test.expected; }),
|
||||
"wave=" + std::to_string(wave) + " prefix=" + std::to_string(prefix) +
|
||||
" mode=" + std::to_string(test.mode) +
|
||||
" records=" + std::to_string(test.records) +
|
||||
" scalar=" + std::to_string(test.scalar));
|
||||
}
|
||||
}
|
||||
}
|
||||
context.UnmapMemory(base, size);
|
||||
context.GetCommandScheduler().Finish();
|
||||
});
|
||||
LibKernel::Memory::InstallGpuResources(nullptr);
|
||||
context.ShutdownGpu();
|
||||
Require(name, "release", LibKernel::Memory::KernelCheckedReleaseDirectMemory(
|
||||
physical, size) == 0, "buffer binding release failed");
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckOrderedDispatch() {
|
||||
constexpr const char *name = "OrderedDispatch";
|
||||
constexpr uintptr_t base = 0x0000000204a00000ull;
|
||||
constexpr uint64_t size = 0x10000;
|
||||
constexpr u32 sentinel = 0xa5a5a5a5u;
|
||||
constexpr u32 terminator = 0xc00c3f00u;
|
||||
// Each wave appends one packet, except the empty second wave. The final
|
||||
// wave's terminator must follow every packet, as in GPU-generated PM4.
|
||||
std::vector<u32> code{EncodeSop2(0x26, 12, 9, 5),
|
||||
EncodeSop2(0x00, 12, 12, 8),
|
||||
EncodeSop2(0x26, 12, 12, 4),
|
||||
EncodeSop2(0x00, 12, 12, 7),
|
||||
EncodeSopc(0x06, 12, InlineU32(1)),
|
||||
EncodeSop2(0x0a, 13, InlineU32(0), InlineU32(1)),
|
||||
EncodeSMovB32(124, InlineU32(0)),
|
||||
EncodeSop1(0x04, 126, InlineU32(1)),
|
||||
EncodeVop1(0x01, 2, 13),
|
||||
EncodeDs0(0x3f, 0x300, true),
|
||||
EncodeDs1(3, 0, 2),
|
||||
EncodeSopp(0x0c, 0),
|
||||
EncodeSop2(0x1e, 14, 12, InlineU32(2)),
|
||||
EncodeVop1(0x01, 1, 14),
|
||||
EncodeMubuf0(0x1c),
|
||||
EncodeMubuf1(3, 0, 1),
|
||||
EncodeSop2(0x01, 14, 6, InlineU32(1)),
|
||||
EncodeSop2(0x00, 15, 12, InlineU32(1))};
|
||||
AppendSMovLiteral(&code, 16, terminator);
|
||||
code.insert(code.end(),
|
||||
{EncodeSopc(0x06, 12, 14), EncodeSop2(0x0a, 15, 16, 15),
|
||||
EncodeVop1(0x01, 2, 15), EncodeVop2(0x1a, 1, InlineU32(2), 3),
|
||||
EncodeSopc(0x06, 13, InlineU32(0)),
|
||||
EncodeSop2(0x0b, 126, InlineU32(0), InlineU32(1)),
|
||||
EncodeMubuf0(0x1c, 16 * sizeof(u32)), EncodeMubuf1(2, 0, 1)});
|
||||
AppendEnd(&code);
|
||||
ShaderMapUserData(
|
||||
reinterpret_cast<uint64_t>(code.data()),
|
||||
{.type = Prospero::ShaderBinaryType::kCs,
|
||||
.code_size_bytes = static_cast<u32>(code.size() * sizeof(u32))});
|
||||
EnsureRuntimeContext();
|
||||
int64_t physical = -1;
|
||||
Require(name, "allocate",
|
||||
LibKernel::Memory::KernelAllocateDirectMemory(
|
||||
0, LibKernel::Memory::KernelGetDirectMemorySize(), size, size,
|
||||
0, &physical) == 0,
|
||||
"ordered dispatch allocation failed");
|
||||
void *mapped = reinterpret_cast<void *>(base);
|
||||
Require(name, "map",
|
||||
LibKernel::Memory::KernelMapDirectMemory(&mapped, size, 0x3, 0x10,
|
||||
physical, size) == 0 &&
|
||||
mapped == reinterpret_cast<void *>(base),
|
||||
"ordered dispatch mapping failed");
|
||||
RenderContext context(m_runtime_context);
|
||||
context.InitializeGpu(nullptr);
|
||||
LibKernel::Memory::InstallGpuResources(&context);
|
||||
context.GetGpu().SendCommandSync([&] {
|
||||
CommandProcessor processor(context, 0);
|
||||
processor.BufferInit();
|
||||
context.MapMemory(base, size);
|
||||
auto &cache = context.GetBufferCache();
|
||||
auto &shaders = processor.GetShCtx();
|
||||
for (u32 wave_size : {32u, 64u}) {
|
||||
for (const auto groups :
|
||||
{std::array{3u, 1u, 1u}, std::array{2u, 2u, 2u}}) {
|
||||
const u32 count = groups[0] * groups[1] * groups[2];
|
||||
cache.FillBuffer(base, 64 * sizeof(u32), sentinel, false);
|
||||
cache.FillBuffer(0, sizeof(u32), 0, true);
|
||||
shaders.SetCsShader(
|
||||
{.data_addr = reinterpret_cast<uint64_t>(code.data()),
|
||||
.num_thread_x = wave_size,
|
||||
.num_thread_y = 1,
|
||||
.num_thread_z = 1,
|
||||
.wave_size = static_cast<uint8_t>(wave_size),
|
||||
.user_sgpr = 7,
|
||||
.tgid_x_en = true,
|
||||
.tgid_y_en = true,
|
||||
.tgid_z_en = true});
|
||||
ShaderBufferResource output{};
|
||||
output.UpdateAddress48(base);
|
||||
output.fields[2] = 64 * sizeof(u32);
|
||||
output.fields[3] =
|
||||
DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u);
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
shaders.SetCsUserSgpr(i, output.fields[i],
|
||||
HW::UserSgprType::Unknown);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
shaders.SetCsUserSgpr(4 + i, i == 2 ? count : groups[i],
|
||||
HW::UserSgprType::Unknown);
|
||||
processor.DispatchDirect(groups[0], groups[1], groups[2],
|
||||
wave_size == 32 ? 0x8049u : 0x49u);
|
||||
cache.CopyBuffer(base + 63 * sizeof(u32), 0, sizeof(u32), false,
|
||||
true);
|
||||
cache.ReadMemory(base, 64 * sizeof(u32));
|
||||
std::array<u32, 64> actual{}, expected;
|
||||
expected.fill(sentinel);
|
||||
u32 prefix = 0;
|
||||
for (u32 group = 0; group < count; ++group) {
|
||||
expected[group] = prefix;
|
||||
if (group != 1)
|
||||
expected[16 + prefix++] =
|
||||
group + 1 == count ? terminator : group + 1;
|
||||
}
|
||||
expected[63] = prefix;
|
||||
Require(name, "readback",
|
||||
LibKernel::Memory::TryReadBacking(base, actual.data(),
|
||||
sizeof(actual)),
|
||||
"ordered dispatch output could not be read back");
|
||||
Require(name, "stable packet append", actual == expected,
|
||||
"ordered append changed packet order, workgroup IDs, "
|
||||
"empty-wave prefix or GDS count");
|
||||
}
|
||||
}
|
||||
context.UnmapMemory(base, size);
|
||||
context.GetCommandScheduler().Finish();
|
||||
});
|
||||
LibKernel::Memory::InstallGpuResources(nullptr);
|
||||
context.ShutdownGpu();
|
||||
Require(name, "unmap", LibKernel::Memory::KernelMunmap(base, size) == 0,
|
||||
"ordered dispatch unmap failed");
|
||||
Require(name, "release",
|
||||
LibKernel::Memory::KernelReleaseDirectMemory(physical, size) == 0,
|
||||
"ordered dispatch release failed");
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckNativeIndirectDispatch() {
|
||||
constexpr const char *name = "NativeIndirectDispatch";
|
||||
constexpr uintptr_t base = 0x0000000204600000ull;
|
||||
@@ -49416,6 +49637,16 @@ int main(int argc, char **argv) {
|
||||
vulkan.CheckNativeIndirectDispatch();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--ordered-dispatch-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckOrderedDispatch();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--zero-stride-binding-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckZeroStrideBufferBinding();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--layered-image-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckUnifiedImageViewCache();
|
||||
@@ -49668,6 +49899,8 @@ int main(int argc, char **argv) {
|
||||
vulkan.CheckGpuTilerCpuParity();
|
||||
vulkan.CheckNativeIndirectDispatch();
|
||||
CheckComputeLdsLimit(vulkan);
|
||||
vulkan.CheckOrderedDispatch();
|
||||
vulkan.CheckZeroStrideBufferBinding();
|
||||
vulkan.CheckNullTextureDescriptors();
|
||||
vulkan.CheckBdaPageTableUploads();
|
||||
vulkan.CheckBdaSyncUploads();
|
||||
|
||||
Reference in New Issue
Block a user