Revert "[engine, dma] Adjustment of the execution mask handling"
This commit is contained in:
parent
8bbbd28f48
commit
6b7e54e115
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
|
@ -7,11 +7,7 @@
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "video_core/dma_pusher.h"
|
#include "video_core/dma_pusher.h"
|
||||||
#include "video_core/engines/fermi_2d.h"
|
|
||||||
#include "video_core/engines/kepler_compute.h"
|
|
||||||
#include "video_core/engines/kepler_memory.h"
|
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/engines/maxwell_dma.h"
|
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/guest_memory.h"
|
#include "video_core/guest_memory.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
|
@ -87,41 +83,12 @@ bool DmaPusher::Step() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.size > 0) {
|
if (header.size > 0) {
|
||||||
const bool use_safe_read = Settings::IsDMALevelDefault()
|
if (Settings::IsDMALevelDefault() ? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh()) : Settings::IsDMALevelSafe()) {
|
||||||
? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh())
|
Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::SafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers);
|
||||||
: Settings::IsDMALevelSafe();
|
ProcessCommands(headers);
|
||||||
constexpr u32 bulk_count = 32;
|
|
||||||
const size_t total_size = static_cast<size_t>(header.size);
|
|
||||||
const size_t total_bytes = total_size * sizeof(CommandHeader);
|
|
||||||
if (use_safe_read) {
|
|
||||||
memory_manager.FlushRegion(dma_state.dma_get, total_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
const u8* direct_span = memory_manager.GetSpan(dma_state.dma_get, total_bytes);
|
|
||||||
if (direct_span) {
|
|
||||||
const auto* headers = reinterpret_cast<const CommandHeader*>(direct_span);
|
|
||||||
for (u32 offset = 0; offset < header.size; offset += bulk_count) {
|
|
||||||
const u32 count = (std::min)(bulk_count, header.size - offset);
|
|
||||||
ProcessCommands(std::span<const CommandHeader>(headers + offset, count),
|
|
||||||
static_cast<u64>(offset) * sizeof(CommandHeader));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (u32 offset = 0; offset < header.size; offset += bulk_count) {
|
Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::UnsafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers);
|
||||||
const u32 count = (std::min)(bulk_count, header.size - offset);
|
ProcessCommands(headers);
|
||||||
command_headers.resize_destructive(count);
|
|
||||||
const GPUVAddr gpu_addr =
|
|
||||||
dma_state.dma_get + static_cast<GPUVAddr>(offset) * sizeof(CommandHeader);
|
|
||||||
if (use_safe_read) {
|
|
||||||
memory_manager.ReadBlock(gpu_addr, command_headers.data(),
|
|
||||||
count * sizeof(CommandHeader));
|
|
||||||
} else {
|
|
||||||
memory_manager.ReadBlockUnsafe(gpu_addr, command_headers.data(),
|
|
||||||
count * sizeof(CommandHeader));
|
|
||||||
}
|
|
||||||
ProcessCommands(
|
|
||||||
std::span<const CommandHeader>(command_headers.data(), count),
|
|
||||||
static_cast<u64>(offset) * sizeof(CommandHeader));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,78 +110,51 @@ bool DmaPusher::Step() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands, u64 base_word_offset) {
|
void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands) {
|
||||||
u32 method = dma_state.method;
|
|
||||||
u32 method_count = dma_state.method_count;
|
|
||||||
u32 subchannel = dma_state.subchannel;
|
|
||||||
u64 dma_word_offset = dma_state.dma_word_offset;
|
|
||||||
bool non_incrementing = dma_state.non_incrementing;
|
|
||||||
bool is_last_call = dma_state.is_last_call;
|
|
||||||
const u64 dma_get = dma_state.dma_get;
|
|
||||||
|
|
||||||
const auto sync_state = [&]() {
|
|
||||||
dma_state.method = method;
|
|
||||||
dma_state.method_count = method_count;
|
|
||||||
dma_state.subchannel = subchannel;
|
|
||||||
dma_state.dma_word_offset = dma_word_offset;
|
|
||||||
dma_state.non_incrementing = non_incrementing;
|
|
||||||
dma_state.is_last_call = is_last_call;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (size_t index = 0; index < commands.size();) {
|
for (size_t index = 0; index < commands.size();) {
|
||||||
// Data word of methods command
|
// Data word of methods command
|
||||||
if (method_count && non_incrementing) {
|
if (dma_state.method_count && dma_state.non_incrementing) {
|
||||||
auto const& command_header = commands[index]; //must ref (MUltiMethod re)
|
auto const& command_header = commands[index]; //must ref (MUltiMethod re)
|
||||||
dma_word_offset = base_word_offset + u32(index * sizeof(u32));
|
dma_state.dma_word_offset = u32(index * sizeof(u32));
|
||||||
const u32 max_write =
|
const u32 max_write = u32(std::min<std::size_t>(index + dma_state.method_count, commands.size()) - index);
|
||||||
u32(std::min<std::size_t>(index + method_count, commands.size()) - index);
|
|
||||||
sync_state();
|
|
||||||
CallMultiMethod(&command_header.argument, max_write);
|
CallMultiMethod(&command_header.argument, max_write);
|
||||||
method_count -= max_write;
|
dma_state.method_count -= max_write;
|
||||||
is_last_call = true;
|
dma_state.is_last_call = true;
|
||||||
index += max_write;
|
index += max_write;
|
||||||
} else if (method_count) {
|
} else if (dma_state.method_count) {
|
||||||
auto const command_header = commands[index]; //can copy
|
auto const command_header = commands[index]; //can copy
|
||||||
dma_word_offset = base_word_offset + u32(index * sizeof(u32));
|
dma_state.dma_word_offset = u32(index * sizeof(u32));
|
||||||
is_last_call = method_count <= 1;
|
dma_state.is_last_call = dma_state.method_count <= 1;
|
||||||
sync_state();
|
|
||||||
CallMethod(command_header.argument);
|
CallMethod(command_header.argument);
|
||||||
method += !non_incrementing ? 1 : 0;
|
dma_state.method += !dma_state.non_incrementing ? 1 : 0;
|
||||||
non_incrementing |= dma_increment_once;
|
dma_state.non_incrementing |= dma_increment_once;
|
||||||
method_count--;
|
dma_state.method_count--;
|
||||||
index++;
|
index++;
|
||||||
} else {
|
} else {
|
||||||
auto const command_header = commands[index]; //can copy
|
auto const command_header = commands[index]; //can copy
|
||||||
// No command active - this is the first word of a new one
|
// No command active - this is the first word of a new one
|
||||||
switch (command_header.mode) {
|
switch (command_header.mode) {
|
||||||
case SubmissionMode::Increasing:
|
case SubmissionMode::Increasing:
|
||||||
method = command_header.method;
|
SetState(command_header);
|
||||||
subchannel = command_header.subchannel;
|
dma_state.non_incrementing = false;
|
||||||
method_count = command_header.method_count;
|
|
||||||
non_incrementing = false;
|
|
||||||
dma_increment_once = false;
|
dma_increment_once = false;
|
||||||
break;
|
break;
|
||||||
case SubmissionMode::NonIncreasing:
|
case SubmissionMode::NonIncreasing:
|
||||||
method = command_header.method;
|
SetState(command_header);
|
||||||
subchannel = command_header.subchannel;
|
dma_state.non_incrementing = true;
|
||||||
method_count = command_header.method_count;
|
|
||||||
non_incrementing = true;
|
|
||||||
dma_increment_once = false;
|
dma_increment_once = false;
|
||||||
break;
|
break;
|
||||||
case SubmissionMode::Inline:
|
case SubmissionMode::Inline:
|
||||||
method = command_header.method;
|
dma_state.method = command_header.method;
|
||||||
subchannel = command_header.subchannel;
|
dma_state.subchannel = command_header.subchannel;
|
||||||
dma_word_offset = u64(-s64(dma_get)); // negate to set address as 0
|
dma_state.dma_word_offset = u64(-s64(dma_state.dma_get)); // negate to set address as 0
|
||||||
sync_state();
|
|
||||||
CallMethod(command_header.arg_count);
|
CallMethod(command_header.arg_count);
|
||||||
non_incrementing = true;
|
dma_state.non_incrementing = true;
|
||||||
dma_increment_once = false;
|
dma_increment_once = false;
|
||||||
break;
|
break;
|
||||||
case SubmissionMode::IncreaseOnce:
|
case SubmissionMode::IncreaseOnce:
|
||||||
method = command_header.method;
|
SetState(command_header);
|
||||||
subchannel = command_header.subchannel;
|
dma_state.non_incrementing = false;
|
||||||
method_count = command_header.method_count;
|
|
||||||
non_incrementing = false;
|
|
||||||
dma_increment_once = true;
|
dma_increment_once = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -223,8 +163,6 @@ void DmaPusher::ProcessCommands(std::span<const CommandHeader> commands, u64 bas
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_state();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmaPusher::SetState(const CommandHeader& command_header) {
|
void DmaPusher::SetState(const CommandHeader& command_header) {
|
||||||
|
|
@ -243,45 +181,12 @@ void DmaPusher::CallMethod(u32 argument) const {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
auto subchannel = subchannels[dma_state.subchannel];
|
auto subchannel = subchannels[dma_state.subchannel];
|
||||||
if (!subchannel) {
|
if (!subchannel->execution_mask[dma_state.method]) {
|
||||||
return;
|
subchannel->method_sink.emplace_back(dma_state.method, argument);
|
||||||
}
|
|
||||||
const u32 method = dma_state.method;
|
|
||||||
const u32 word_index = method >> 6;
|
|
||||||
const u64 bit_mask = 1ULL << (method & 63);
|
|
||||||
const bool is_executable =
|
|
||||||
word_index < subchannel->execution_mask_words.size() &&
|
|
||||||
(subchannel->execution_mask_words[word_index] & bit_mask) != 0;
|
|
||||||
if (!is_executable) {
|
|
||||||
subchannel->method_sink.emplace_back(method, argument);
|
|
||||||
} else {
|
} else {
|
||||||
subchannel->ConsumeSink();
|
subchannel->ConsumeSink();
|
||||||
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
|
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
|
||||||
switch (subchannel_type[dma_state.subchannel]) {
|
subchannel->CallMethod(dma_state.method, argument, dma_state.is_last_call);
|
||||||
case Engines::EngineTypes::Maxwell3D:
|
|
||||||
static_cast<Engines::Maxwell3D*>(subchannel)->CallMethod(method, argument,
|
|
||||||
dma_state.is_last_call);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::KeplerCompute:
|
|
||||||
static_cast<Engines::KeplerCompute*>(subchannel)->CallMethod(
|
|
||||||
method, argument, dma_state.is_last_call);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::Fermi2D:
|
|
||||||
static_cast<Engines::Fermi2D*>(subchannel)->CallMethod(method, argument,
|
|
||||||
dma_state.is_last_call);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::MaxwellDMA:
|
|
||||||
static_cast<Engines::MaxwellDMA*>(subchannel)->CallMethod(method, argument,
|
|
||||||
dma_state.is_last_call);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::KeplerMemory:
|
|
||||||
static_cast<Engines::KeplerMemory*>(subchannel)->CallMethod(
|
|
||||||
method, argument, dma_state.is_last_call);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
subchannel->CallMethod(method, argument, dma_state.is_last_call);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -291,37 +196,9 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const {
|
||||||
puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
|
puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, dma_state.method_count);
|
||||||
} else {
|
} else {
|
||||||
auto subchannel = subchannels[dma_state.subchannel];
|
auto subchannel = subchannels[dma_state.subchannel];
|
||||||
if (!subchannel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
subchannel->ConsumeSink();
|
subchannel->ConsumeSink();
|
||||||
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
|
subchannel->current_dma_segment = dma_state.dma_get + dma_state.dma_word_offset;
|
||||||
switch (subchannel_type[dma_state.subchannel]) {
|
subchannel->CallMultiMethod(dma_state.method, base_start, num_methods, dma_state.method_count);
|
||||||
case Engines::EngineTypes::Maxwell3D:
|
|
||||||
static_cast<Engines::Maxwell3D*>(subchannel)->CallMultiMethod(
|
|
||||||
dma_state.method, base_start, num_methods, dma_state.method_count);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::KeplerCompute:
|
|
||||||
static_cast<Engines::KeplerCompute*>(subchannel)->CallMultiMethod(
|
|
||||||
dma_state.method, base_start, num_methods, dma_state.method_count);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::Fermi2D:
|
|
||||||
static_cast<Engines::Fermi2D*>(subchannel)->CallMultiMethod(
|
|
||||||
dma_state.method, base_start, num_methods, dma_state.method_count);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::MaxwellDMA:
|
|
||||||
static_cast<Engines::MaxwellDMA*>(subchannel)->CallMultiMethod(
|
|
||||||
dma_state.method, base_start, num_methods, dma_state.method_count);
|
|
||||||
break;
|
|
||||||
case Engines::EngineTypes::KeplerMemory:
|
|
||||||
static_cast<Engines::KeplerMemory*>(subchannel)->CallMultiMethod(
|
|
||||||
dma_state.method, base_start, num_methods, dma_state.method_count);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
subchannel->CallMultiMethod(dma_state.method, base_start, num_methods,
|
|
||||||
dma_state.method_count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
|
@ -148,7 +148,7 @@ private:
|
||||||
static constexpr u32 non_puller_methods = 0x40;
|
static constexpr u32 non_puller_methods = 0x40;
|
||||||
static constexpr u32 max_subchannels = 8;
|
static constexpr u32 max_subchannels = 8;
|
||||||
bool Step();
|
bool Step();
|
||||||
void ProcessCommands(std::span<const CommandHeader> commands, u64 base_word_offset = 0);
|
void ProcessCommands(std::span<const CommandHeader> commands);
|
||||||
|
|
||||||
void SetState(const CommandHeader& command_header);
|
void SetState(const CommandHeader& command_header);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -8,16 +5,8 @@
|
||||||
#include "video_core/dirty_flags.h"
|
#include "video_core/dirty_flags.h"
|
||||||
#include "video_core/engines/draw_manager.h"
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.h"
|
||||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
|
||||||
|
|
||||||
namespace Tegra::Engines {
|
namespace Tegra::Engines {
|
||||||
namespace {
|
|
||||||
template <typename RasterizerT>
|
|
||||||
inline void DrawFast(RasterizerT* rasterizer, bool draw_indexed, u32 instance_count) {
|
|
||||||
rasterizer->Draw(draw_indexed, instance_count);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
|
DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
|
||||||
|
|
||||||
void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
|
void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
|
||||||
|
|
@ -278,13 +267,9 @@ void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
|
||||||
UpdateTopology();
|
UpdateTopology();
|
||||||
|
|
||||||
if (maxwell3d->ShouldExecute()) {
|
if (maxwell3d->ShouldExecute()) {
|
||||||
if (auto* rasterizer_vulkan = maxwell3d->RasterizerVulkan()) {
|
|
||||||
DrawFast(rasterizer_vulkan, draw_indexed, instance_count);
|
|
||||||
} else {
|
|
||||||
maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
|
maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void DrawManager::ProcessDrawIndirect() {
|
void DrawManager::ProcessDrawIndirect() {
|
||||||
LOG_TRACE(
|
LOG_TRACE(
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <bitset>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -26,11 +26,6 @@ class EngineInterface {
|
||||||
public:
|
public:
|
||||||
virtual ~EngineInterface() = default;
|
virtual ~EngineInterface() = default;
|
||||||
|
|
||||||
static constexpr size_t ExecutionMaskBits = (std::numeric_limits<u16>::max)();
|
|
||||||
static constexpr size_t ExecutionMaskWordBits = 64;
|
|
||||||
static constexpr size_t ExecutionMaskWords =
|
|
||||||
(ExecutionMaskBits + ExecutionMaskWordBits - 1) / ExecutionMaskWordBits;
|
|
||||||
|
|
||||||
/// Write the value to the register identified by method.
|
/// Write the value to the register identified by method.
|
||||||
virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0;
|
virtual void CallMethod(u32 method, u32 method_argument, bool is_last_call) = 0;
|
||||||
|
|
||||||
|
|
@ -45,33 +40,7 @@ public:
|
||||||
ConsumeSinkImpl();
|
ConsumeSinkImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearExecutionMask() {
|
std::bitset<(std::numeric_limits<u16>::max)()> execution_mask{};
|
||||||
execution_mask_words.fill(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetExecutionMaskBit(u32 method, bool value = true) {
|
|
||||||
if (method >= ExecutionMaskBits) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const size_t word_index = method >> 6;
|
|
||||||
const u64 bit_mask = 1ULL << (method & 63);
|
|
||||||
if (value) {
|
|
||||||
execution_mask_words[word_index] |= bit_mask;
|
|
||||||
} else {
|
|
||||||
execution_mask_words[word_index] &= ~bit_mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsExecutionMaskSet(u32 method) const {
|
|
||||||
if (method >= ExecutionMaskBits) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const size_t word_index = method >> 6;
|
|
||||||
const u64 bit_mask = 1ULL << (method & 63);
|
|
||||||
return (execution_mask_words[word_index] & bit_mask) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<u64, ExecutionMaskWords> execution_mask_words{};
|
|
||||||
std::vector<std::pair<u32, u32>> method_sink{};
|
std::vector<std::pair<u32, u32>> method_sink{};
|
||||||
bool current_dirty{};
|
bool current_dirty{};
|
||||||
GPUVAddr current_dma_segment;
|
GPUVAddr current_dma_segment;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
|
@ -26,8 +26,8 @@ Fermi2D::Fermi2D(MemoryManager& memory_manager_) : memory_manager{memory_manager
|
||||||
regs.src.depth = 1;
|
regs.src.depth = 1;
|
||||||
regs.dst.depth = 1;
|
regs.dst.depth = 1;
|
||||||
|
|
||||||
ClearExecutionMask();
|
execution_mask.reset();
|
||||||
SetExecutionMaskBit(FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1);
|
execution_mask[FERMI2D_REG_INDEX(pixels_from_memory.src_y0) + 1] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fermi2D::~Fermi2D() = default;
|
Fermi2D::~Fermi2D() = default;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
|
@ -17,10 +15,10 @@ namespace Tegra::Engines {
|
||||||
|
|
||||||
KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
|
KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
|
||||||
: system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {
|
: system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {
|
||||||
ClearExecutionMask();
|
execution_mask.reset();
|
||||||
SetExecutionMaskBit(KEPLER_COMPUTE_REG_INDEX(exec_upload));
|
execution_mask[KEPLER_COMPUTE_REG_INDEX(exec_upload)] = true;
|
||||||
SetExecutionMaskBit(KEPLER_COMPUTE_REG_INDEX(data_upload));
|
execution_mask[KEPLER_COMPUTE_REG_INDEX(data_upload)] = true;
|
||||||
SetExecutionMaskBit(KEPLER_COMPUTE_REG_INDEX(launch));
|
execution_mask[KEPLER_COMPUTE_REG_INDEX(launch)] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeplerCompute::~KeplerCompute() = default;
|
KeplerCompute::~KeplerCompute() = default;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
@ -22,9 +19,9 @@ KeplerMemory::~KeplerMemory() = default;
|
||||||
void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
|
void KeplerMemory::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
|
||||||
upload_state.BindRasterizer(rasterizer_);
|
upload_state.BindRasterizer(rasterizer_);
|
||||||
|
|
||||||
ClearExecutionMask();
|
execution_mask.reset();
|
||||||
SetExecutionMaskBit(KEPLERMEMORY_REG_INDEX(exec));
|
execution_mask[KEPLERMEMORY_REG_INDEX(exec)] = true;
|
||||||
SetExecutionMaskBit(KEPLERMEMORY_REG_INDEX(data));
|
execution_mask[KEPLERMEMORY_REG_INDEX(data)] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeplerMemory::ConsumeSinkImpl() {
|
void KeplerMemory::ConsumeSinkImpl() {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.h"
|
||||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
|
||||||
#include "video_core/textures/texture.h"
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
namespace Tegra::Engines {
|
namespace Tegra::Engines {
|
||||||
|
|
@ -31,23 +30,15 @@ Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
|
||||||
memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} {
|
memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} {
|
||||||
dirty.flags.flip();
|
dirty.flags.flip();
|
||||||
InitializeRegisterDefaults();
|
InitializeRegisterDefaults();
|
||||||
ClearExecutionMask();
|
execution_mask.reset();
|
||||||
for (size_t i = 0; i < ExecutionMaskBits; ++i) {
|
for (size_t i = 0; i < execution_mask.size(); i++)
|
||||||
if (IsMethodExecutable(u32(i))) {
|
execution_mask[i] = IsMethodExecutable(u32(i));
|
||||||
SetExecutionMaskBit(u32(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Maxwell3D::~Maxwell3D() = default;
|
Maxwell3D::~Maxwell3D() = default;
|
||||||
|
|
||||||
void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
|
void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
|
||||||
rasterizer = rasterizer_;
|
rasterizer = rasterizer_;
|
||||||
if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan) {
|
|
||||||
rasterizer_vulkan = static_cast<Vulkan::RasterizerVulkan*>(rasterizer_);
|
|
||||||
} else {
|
|
||||||
rasterizer_vulkan = nullptr;
|
|
||||||
}
|
|
||||||
upload_state.BindRasterizer(rasterizer_);
|
upload_state.BindRasterizer(rasterizer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,37 +292,31 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
|
||||||
|
|
||||||
void Maxwell3D::ConsumeSinkImpl() {
|
void Maxwell3D::ConsumeSinkImpl() {
|
||||||
const auto control = shadow_state.shadow_ram_control;
|
const auto control = shadow_state.shadow_ram_control;
|
||||||
DirtyState::Flags pending_flags{};
|
|
||||||
if (control == Regs::ShadowRamControl::Track || control == Regs::ShadowRamControl::TrackWithFilter) {
|
if (control == Regs::ShadowRamControl::Track || control == Regs::ShadowRamControl::TrackWithFilter) {
|
||||||
for (auto [method, value] : method_sink) {
|
for (auto [method, value] : method_sink) {
|
||||||
shadow_state.reg_array[method] = value;
|
shadow_state.reg_array[method] = value;
|
||||||
ProcessDirtyRegisters(method, value, &pending_flags);
|
ProcessDirtyRegisters(method, value);
|
||||||
}
|
}
|
||||||
} else if (control == Regs::ShadowRamControl::Replay) {
|
} else if (control == Regs::ShadowRamControl::Replay) {
|
||||||
for (auto [method, value] : method_sink) {
|
for (auto [method, value] : method_sink)
|
||||||
ProcessDirtyRegisters(method, shadow_state.reg_array[method], &pending_flags);
|
ProcessDirtyRegisters(method, shadow_state.reg_array[method]);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (auto [method, value] : method_sink) {
|
for (auto [method, value] : method_sink)
|
||||||
ProcessDirtyRegisters(method, value, &pending_flags);
|
ProcessDirtyRegisters(method, value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dirty.flags |= pending_flags;
|
|
||||||
method_sink.clear();
|
method_sink.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument, DirtyState::Flags* pending_flags) {
|
void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) {
|
||||||
if (regs.reg_array[method] != argument) {
|
if (regs.reg_array[method] != argument) {
|
||||||
regs.reg_array[method] = argument;
|
regs.reg_array[method] = argument;
|
||||||
auto const& table0 = dirty.tables[0];
|
auto const& table0 = dirty.tables[0];
|
||||||
auto const& table1 = dirty.tables[1];
|
auto const& table1 = dirty.tables[1];
|
||||||
u8 const flag0 = table0[method];
|
u8 const flag0 = table0[method];
|
||||||
u8 const flag1 = table1[method];
|
u8 const flag1 = table1[method];
|
||||||
auto& target_flags = pending_flags ? *pending_flags : dirty.flags;
|
dirty.flags[flag0] = true;
|
||||||
target_flags.set(flag0);
|
if (flag1 != flag0)
|
||||||
if (flag1 != flag0) {
|
dirty.flags[flag1] = true;
|
||||||
target_flags.set(flag1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,6 @@ namespace VideoCore {
|
||||||
class RasterizerInterface;
|
class RasterizerInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Vulkan {
|
|
||||||
class RasterizerVulkan;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Tegra::Engines {
|
namespace Tegra::Engines {
|
||||||
|
|
||||||
class DrawManager;
|
class DrawManager;
|
||||||
|
|
@ -3097,10 +3093,6 @@ public:
|
||||||
return *rasterizer;
|
return *rasterizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vulkan::RasterizerVulkan* RasterizerVulkan() const {
|
|
||||||
return rasterizer_vulkan;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DirtyState {
|
struct DirtyState {
|
||||||
using Flags = std::bitset<(std::numeric_limits<u8>::max)()>;
|
using Flags = std::bitset<(std::numeric_limits<u8>::max)()>;
|
||||||
using Table = std::array<u8, Regs::NUM_REGS>;
|
using Table = std::array<u8, Regs::NUM_REGS>;
|
||||||
|
|
@ -3149,7 +3141,7 @@ private:
|
||||||
|
|
||||||
u32 ProcessShadowRam(u32 method, u32 argument);
|
u32 ProcessShadowRam(u32 method, u32 argument);
|
||||||
|
|
||||||
void ProcessDirtyRegisters(u32 method, u32 argument, DirtyState::Flags* pending_flags = nullptr);
|
void ProcessDirtyRegisters(u32 method, u32 argument);
|
||||||
|
|
||||||
void ConsumeSinkImpl() override;
|
void ConsumeSinkImpl() override;
|
||||||
|
|
||||||
|
|
@ -3201,7 +3193,6 @@ private:
|
||||||
MemoryManager& memory_manager;
|
MemoryManager& memory_manager;
|
||||||
|
|
||||||
VideoCore::RasterizerInterface* rasterizer = nullptr;
|
VideoCore::RasterizerInterface* rasterizer = nullptr;
|
||||||
Vulkan::RasterizerVulkan* rasterizer_vulkan = nullptr;
|
|
||||||
|
|
||||||
/// Start offsets of each macro in macro_memory
|
/// Start offsets of each macro in macro_memory
|
||||||
std::array<u32, 0x80> macro_positions{};
|
std::array<u32, 0x80> macro_positions{};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
|
@ -23,8 +23,8 @@ using namespace Texture;
|
||||||
|
|
||||||
MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
|
MaxwellDMA::MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_)
|
||||||
: system{system_}, memory_manager{memory_manager_} {
|
: system{system_}, memory_manager{memory_manager_} {
|
||||||
ClearExecutionMask();
|
execution_mask.reset();
|
||||||
SetExecutionMaskBit(offsetof(Regs, launch_dma) / sizeof(u32));
|
execution_mask[offsetof(Regs, launch_dma) / sizeof(u32)] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaxwellDMA::~MaxwellDMA() = default;
|
MaxwellDMA::~MaxwellDMA() = default;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue