early-access version 1358

This commit is contained in:
pineappleEA
2021-01-23 07:41:16 +01:00
parent 2e0deb5e50
commit 8231512517
13 changed files with 199 additions and 293 deletions

View File

@@ -1243,9 +1243,15 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
if (!cpu_addr || size == 0) {
return NULL_BINDING;
}
// HACK(Rodrigo): This is the number of bytes bound in host beyond the guest API's range.
// It exists due to some games like Astral Chain operate out of bounds.
// Binding the whole map range would be technically correct, but games have large maps that make
// this approach unaffordable for now.
static constexpr u32 arbitrary_extra_bytes = 0xc000;
const u32 bytes_to_map_end = static_cast<u32>(gpu_memory.BytesToMapEnd(gpu_addr));
const Binding binding{
.cpu_addr = *cpu_addr,
.size = size,
.size = std::min(size + arbitrary_extra_bytes, bytes_to_map_end),
.buffer_id = BufferId{},
};
return binding;

View File

@@ -4,6 +4,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/process.h"
@@ -38,6 +39,12 @@ GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std
}
GPUVAddr MemoryManager::Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size) {
const auto it = std::ranges::lower_bound(map_ranges, gpu_addr, {}, &MapRange::first);
if (it != map_ranges.end() && it->first == gpu_addr) {
it->second = size;
} else {
map_ranges.insert(it, MapRange{gpu_addr, size});
}
return UpdateRange(gpu_addr, cpu_addr, size);
}
@@ -52,10 +59,16 @@ GPUVAddr MemoryManager::MapAllocate32(VAddr cpu_addr, std::size_t size) {
}
void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
if (!size) {
if (size == 0) {
return;
}
const auto it = std::ranges::lower_bound(map_ranges, gpu_addr, {}, &MapRange::first);
if (it != map_ranges.end()) {
ASSERT(it->first == gpu_addr);
map_ranges.erase(it);
} else {
UNREACHABLE_MSG("Unmapping non-existent GPU address=0x{:x}", gpu_addr);
}
// Flush and invalidate through the GPU interface, to be asynchronous if possible.
const std::optional<VAddr> cpu_addr = GpuToCpuAddress(gpu_addr);
ASSERT(cpu_addr);
@@ -237,6 +250,12 @@ const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const {
return system.Memory().GetPointer(*address);
}
size_t MemoryManager::BytesToMapEnd(GPUVAddr gpu_addr) const noexcept {
auto it = std::ranges::upper_bound(map_ranges, gpu_addr, {}, &MapRange::first);
--it;
return it->second - (gpu_addr - it->first);
}
void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const {
std::size_t remaining_size{size};
std::size_t page_index{gpu_src_addr >> page_bits};

View File

@@ -85,6 +85,9 @@ public:
[[nodiscard]] u8* GetPointer(GPUVAddr addr);
[[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
/// Returns the number of bytes until the end of the memory map containing the given GPU address
[[nodiscard]] size_t BytesToMapEnd(GPUVAddr gpu_addr) const noexcept;
/**
* ReadBlock and WriteBlock are full read and write operations over virtual
* GPU Memory. It's important to use these when GPU memory may not be continuous
@@ -160,6 +163,9 @@ private:
std::vector<PageEntry> page_table;
std::vector<std::pair<VAddr, std::size_t>> cache_invalidate_queue;
using MapRange = std::pair<GPUVAddr, size_t>;
std::vector<MapRange> map_ranges;
};
} // namespace Tegra

View File

@@ -465,6 +465,14 @@ public:
return operands.size();
}
NodeBlock& GetOperands() {
return operands;
}
const NodeBlock& GetOperands() const {
return operands;
}
[[nodiscard]] const Node& operator[](std::size_t operand_index) const {
return operands.at(operand_index);
}

View File

@@ -388,9 +388,54 @@ void ShaderIR::SetInternalFlagsFromInteger(NodeBlock& bb, Node value, bool sets_
if (!sets_cc) {
return;
}
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value), Immediate(0));
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
switch (value->index()) {
case 0: // Operation Node
SearchOperands(bb, value);
break;
case 2: // Genral Purpose Node
if (const auto* gpr = std::get_if<GprNode>(value.get())) {
LOG_DEBUG(HW_GPU, "GprNode: index={}", gpr->GetIndex());
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value),
Immediate(gpr->GetIndex()));
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
}
break;
default:
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value), Immediate(0));
SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
LOG_WARNING(HW_GPU, "Node Type: {}", value->index());
break;
}
}
void ShaderIR::SearchOperands(NodeBlock& nb, Node var) {
const auto* op = std::get_if<OperationNode>(var.get());
if (op == nullptr) {
return;
}
if (op->GetOperandsCount() == 0) {
return;
}
for (auto& operand : op->GetOperands()) {
switch (operand->index()) {
case 0: // Operation Node
return SearchOperands(nb, operand);
case 2: // General Purpose Node
if (const auto* gpr = std::get_if<GprNode>(operand.get())) {
LOG_DEBUG(HW_GPU, "Child GprNode: index={}", gpr->GetIndex());
Node zerop = Operation(OperationCode::LogicalIEqual, std::move(operand),
Immediate(gpr->GetIndex()));
SetInternalFlag(nb, InternalFlag::Zero, std::move(zerop));
}
break;
default:
LOG_WARNING(HW_GPU, "Child Node Type: {}", operand->index());
break;
}
}
}
Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {

View File

@@ -350,6 +350,9 @@ private:
/// Access a bindless image sampler.
ImageEntry& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
/// Recursive Iteration over the OperationNode operands, searching for GprNodes.
void SearchOperands(NodeBlock& nb, Node var);
/// Extracts a sequence of bits from a node
Node BitfieldExtract(Node value, u32 offset, u32 bits);