From bb5eb4f20ac74e06317ed5b0c98282cde1f9e119 Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 8 Sep 2018 15:58:20 -0500 Subject: GPU: Basic implementation of the Kepler Inline Memory engine (p2mf). This engine writes data from a FIFO register into the configured address. --- src/video_core/CMakeLists.txt | 2 + src/video_core/command_processor.cpp | 4 ++ src/video_core/engines/kepler_memory.cpp | 45 ++++++++++++++++ src/video_core/engines/kepler_memory.h | 90 ++++++++++++++++++++++++++++++++ src/video_core/gpu.cpp | 2 + src/video_core/gpu.h | 3 ++ 6 files changed, 146 insertions(+) create mode 100644 src/video_core/engines/kepler_memory.cpp create mode 100644 src/video_core/engines/kepler_memory.h (limited to 'src/video_core') diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 65b5f57c3..4a79ce39c 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(video_core STATIC debug_utils/debug_utils.h engines/fermi_2d.cpp engines/fermi_2d.h + engines/kepler_memory.cpp + engines/kepler_memory.h engines/maxwell_3d.cpp engines/maxwell_3d.h engines/maxwell_compute.cpp diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 2625ddfdc..f1aa6091b 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -14,6 +14,7 @@ #include "core/tracer/recorder.h" #include "video_core/command_processor.h" #include "video_core/engines/fermi_2d.h" +#include "video_core/engines/kepler_memory.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_compute.h" #include "video_core/engines/maxwell_dma.h" @@ -69,6 +70,9 @@ void GPU::ProcessCommandLists(const std::vector& commands) { case EngineID::MAXWELL_DMA_COPY_A: maxwell_dma->WriteReg(method, value); break; + case EngineID::KEPLER_INLINE_TO_MEMORY_B: + kepler_memory->WriteReg(method, value); + break; default: UNIMPLEMENTED_MSG("Unimplemented engine"); } diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp new file mode 100644 index 000000000..66ae6332d --- /dev/null +++ b/src/video_core/engines/kepler_memory.cpp @@ -0,0 +1,45 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/memory.h" +#include "video_core/engines/kepler_memory.h" + +namespace Tegra::Engines { + +KeplerMemory::KeplerMemory(MemoryManager& memory_manager) : memory_manager(memory_manager) {} +KeplerMemory::~KeplerMemory() = default; + +void KeplerMemory::WriteReg(u32 method, u32 value) { + ASSERT_MSG(method < Regs::NUM_REGS, + "Invalid KeplerMemory register, increase the size of the Regs structure"); + + regs.reg_array[method] = value; + + switch (method) { + case KEPLERMEMORY_REG_INDEX(exec): { + state.write_offset = 0; + break; + } + case KEPLERMEMORY_REG_INDEX(data): { + ProcessData(value); + break; + } + } +} + +void KeplerMemory::ProcessData(u32 data) { + ASSERT_MSG(regs.exec.linear, "Non-linear uploads are not supported"); + ASSERT(regs.dest.x == 0 && regs.dest.y == 0 && regs.dest.z == 0); + + GPUVAddr address = regs.dest.Address(); + VAddr dest_address = + *memory_manager.GpuToCpuAddress(address + state.write_offset * sizeof(u32)); + + Memory::Write32(dest_address, data); + + state.write_offset++; +} + +} // namespace Tegra::Engines diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h new file mode 100644 index 000000000..b0d0078cf --- /dev/null +++ b/src/video_core/engines/kepler_memory.h @@ -0,0 +1,90 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/assert.h" +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "video_core/memory_manager.h" + +namespace Tegra::Engines { + +#define KEPLERMEMORY_REG_INDEX(field_name) \ + (offsetof(Tegra::Engines::KeplerMemory::Regs, field_name) / sizeof(u32)) + +class KeplerMemory final { +public: + KeplerMemory(MemoryManager& memory_manager); + ~KeplerMemory(); + + /// Write the value to the register identified by method. + void WriteReg(u32 method, u32 value); + + struct Regs { + static constexpr size_t NUM_REGS = 0x7F; + + union { + struct { + INSERT_PADDING_WORDS(0x60); + + u32 line_length_in; + u32 line_count; + + struct { + u32 address_high; + u32 address_low; + u32 pitch; + u32 block_dimensions; + u32 width; + u32 height; + u32 depth; + u32 z; + u32 x; + u32 y; + + GPUVAddr Address() const { + return static_cast((static_cast(address_high) << 32) | + address_low); + } + } dest; + + struct { + union { + BitField<0, 1, u32> linear; + }; + } exec; + + u32 data; + + INSERT_PADDING_WORDS(0x11); + }; + std::array reg_array; + }; + } regs{}; + + struct { + u32 write_offset = 0; + } state{}; + +private: + MemoryManager& memory_manager; + + void ProcessData(u32 data); +}; + +#define ASSERT_REG_POSITION(field_name, position) \ + static_assert(offsetof(KeplerMemory::Regs, field_name) == position * 4, \ + "Field " #field_name " has invalid position") + +ASSERT_REG_POSITION(line_length_in, 0x60); +ASSERT_REG_POSITION(line_count, 0x61); +ASSERT_REG_POSITION(dest, 0x62); +ASSERT_REG_POSITION(exec, 0x6C); +ASSERT_REG_POSITION(data, 0x6D); +#undef ASSERT_REG_POSITION + +} // namespace Tegra::Engines diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 86a809f86..baa8b63b7 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -4,6 +4,7 @@ #include "common/assert.h" #include "video_core/engines/fermi_2d.h" +#include "video_core/engines/kepler_memory.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_compute.h" #include "video_core/engines/maxwell_dma.h" @@ -27,6 +28,7 @@ GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { fermi_2d = std::make_unique(*memory_manager); maxwell_compute = std::make_unique(); maxwell_dma = std::make_unique(*memory_manager); + kepler_memory = std::make_unique(*memory_manager); } GPU::~GPU() = default; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 589a59b4f..7329ca766 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -102,6 +102,7 @@ class Fermi2D; class Maxwell3D; class MaxwellCompute; class MaxwellDMA; +class KeplerMemory; } // namespace Engines enum class EngineID { @@ -146,6 +147,8 @@ private: std::unique_ptr maxwell_compute; /// DMA engine std::unique_ptr maxwell_dma; + /// Inline memory engine + std::unique_ptr kepler_memory; }; } // namespace Tegra -- cgit v1.2.3