2022-04-23 08:59:50 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2018-06-10 22:02:33 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <array>
|
2019-03-06 01:25:01 +00:00
|
|
|
#include <cstddef>
|
2019-04-23 16:41:55 +00:00
|
|
|
#include <vector>
|
2018-06-10 22:02:33 +00:00
|
|
|
#include "common/bit_field.h"
|
|
|
|
#include "common/common_types.h"
|
2020-04-28 01:47:58 +00:00
|
|
|
#include "video_core/engines/engine_interface.h"
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2019-02-16 03:05:17 +00:00
|
|
|
namespace Core {
|
|
|
|
class System;
|
|
|
|
}
|
|
|
|
|
2019-04-05 22:21:15 +00:00
|
|
|
namespace Tegra {
|
|
|
|
class MemoryManager;
|
|
|
|
}
|
|
|
|
|
2021-07-10 16:19:10 +00:00
|
|
|
namespace VideoCore {
|
|
|
|
class RasterizerInterface;
|
|
|
|
}
|
|
|
|
|
2018-07-20 22:14:17 +00:00
|
|
|
namespace Tegra::Engines {
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2021-07-10 16:19:10 +00:00
|
|
|
class AccelerateDMAInterface {
|
|
|
|
public:
|
|
|
|
/// Write the value to the register identified by method.
|
|
|
|
virtual bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) = 0;
|
2021-07-13 01:33:08 +00:00
|
|
|
|
|
|
|
virtual bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) = 0;
|
2021-07-10 16:19:10 +00:00
|
|
|
};
|
|
|
|
|
2019-04-23 12:44:52 +00:00
|
|
|
/**
|
2020-07-04 01:00:30 +00:00
|
|
|
* This engine is known as gk104_copy. Documentation can be found in:
|
|
|
|
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h
|
2019-04-23 12:44:52 +00:00
|
|
|
* https://github.com/envytools/envytools/blob/master/rnndb/fifo/gk104_copy.xml
|
|
|
|
*/
|
|
|
|
|
2020-04-28 01:47:58 +00:00
|
|
|
class MaxwellDMA final : public EngineInterface {
|
2018-06-10 22:02:33 +00:00
|
|
|
public:
|
2020-07-04 01:00:30 +00:00
|
|
|
struct PackedGPUVAddr {
|
|
|
|
u32 upper;
|
|
|
|
u32 lower;
|
|
|
|
|
|
|
|
constexpr operator GPUVAddr() const noexcept {
|
|
|
|
return (static_cast<GPUVAddr>(upper & 0xff) << 32) | lower;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
union BlockSize {
|
|
|
|
BitField<0, 4, u32> width;
|
|
|
|
BitField<4, 4, u32> height;
|
|
|
|
BitField<8, 4, u32> depth;
|
|
|
|
BitField<12, 4, u32> gob_height;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(BlockSize) == 4);
|
|
|
|
|
|
|
|
union Origin {
|
|
|
|
BitField<0, 16, u32> x;
|
|
|
|
BitField<16, 16, u32> y;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(Origin) == 4);
|
|
|
|
|
|
|
|
struct Parameters {
|
|
|
|
BlockSize block_size;
|
|
|
|
u32 width;
|
|
|
|
u32 height;
|
|
|
|
u32 depth;
|
|
|
|
u32 layer;
|
|
|
|
Origin origin;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(Parameters) == 24);
|
|
|
|
|
|
|
|
struct Semaphore {
|
|
|
|
PackedGPUVAddr address;
|
|
|
|
u32 payload;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(Semaphore) == 12);
|
|
|
|
|
|
|
|
struct RenderEnable {
|
|
|
|
enum class Mode : u32 {
|
2020-08-31 14:22:03 +00:00
|
|
|
// Note: This uses Pascal case in order to avoid the identifiers
|
|
|
|
// FALSE and TRUE, which are reserved on Darwin.
|
|
|
|
False = 0,
|
|
|
|
True = 1,
|
|
|
|
Conditional = 2,
|
|
|
|
RenderIfEqual = 3,
|
|
|
|
RenderIfNotEqual = 4,
|
2020-07-04 01:00:30 +00:00
|
|
|
};
|
2020-04-20 06:16:56 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
PackedGPUVAddr address;
|
|
|
|
BitField<0, 3, Mode> mode;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(RenderEnable) == 12);
|
|
|
|
|
|
|
|
enum class PhysModeTarget : u32 {
|
|
|
|
LOCAL_FB = 0,
|
|
|
|
COHERENT_SYSMEM = 1,
|
|
|
|
NONCOHERENT_SYSMEM = 2,
|
|
|
|
};
|
|
|
|
using PhysMode = BitField<0, 2, PhysModeTarget>;
|
|
|
|
|
|
|
|
union LaunchDMA {
|
|
|
|
enum class DataTransferType : u32 {
|
|
|
|
NONE = 0,
|
|
|
|
PIPELINED = 1,
|
|
|
|
NON_PIPELINED = 2,
|
|
|
|
};
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class SemaphoreType : u32 {
|
|
|
|
NONE = 0,
|
|
|
|
RELEASE_ONE_WORD_SEMAPHORE = 1,
|
|
|
|
RELEASE_FOUR_WORD_SEMAPHORE = 2,
|
|
|
|
};
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class InterruptType : u32 {
|
|
|
|
NONE = 0,
|
|
|
|
BLOCKING = 1,
|
|
|
|
NON_BLOCKING = 2,
|
|
|
|
};
|
2018-10-11 23:11:47 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class MemoryLayout : u32 {
|
|
|
|
BLOCKLINEAR = 0,
|
|
|
|
PITCH = 1,
|
2018-06-10 22:02:33 +00:00
|
|
|
};
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class Type : u32 {
|
|
|
|
VIRTUAL = 0,
|
|
|
|
PHYSICAL = 1,
|
|
|
|
};
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class SemaphoreReduction : u32 {
|
|
|
|
IMIN = 0,
|
|
|
|
IMAX = 1,
|
|
|
|
IXOR = 2,
|
|
|
|
IAND = 3,
|
|
|
|
IOR = 4,
|
|
|
|
IADD = 5,
|
|
|
|
INC = 6,
|
|
|
|
DEC = 7,
|
|
|
|
FADD = 0xA,
|
2019-04-23 15:21:00 +00:00
|
|
|
};
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class SemaphoreReductionSign : u32 {
|
|
|
|
SIGNED = 0,
|
|
|
|
UNSIGNED = 1,
|
2018-06-10 22:02:33 +00:00
|
|
|
};
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
enum class BypassL2 : u32 {
|
|
|
|
USE_PTE_SETTING = 0,
|
|
|
|
FORCE_VOLATILE = 1,
|
2018-06-10 22:02:33 +00:00
|
|
|
};
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
BitField<0, 2, DataTransferType> data_transfer_type;
|
|
|
|
BitField<2, 1, u32> flush_enable;
|
|
|
|
BitField<3, 2, SemaphoreType> semaphore_type;
|
|
|
|
BitField<5, 2, InterruptType> interrupt_type;
|
|
|
|
BitField<7, 1, MemoryLayout> src_memory_layout;
|
|
|
|
BitField<8, 1, MemoryLayout> dst_memory_layout;
|
|
|
|
BitField<9, 1, u32> multi_line_enable;
|
|
|
|
BitField<10, 1, u32> remap_enable;
|
|
|
|
BitField<11, 1, u32> rmwdisable;
|
|
|
|
BitField<12, 1, Type> src_type;
|
|
|
|
BitField<13, 1, Type> dst_type;
|
|
|
|
BitField<14, 4, SemaphoreReduction> semaphore_reduction;
|
|
|
|
BitField<18, 1, SemaphoreReductionSign> semaphore_reduction_sign;
|
|
|
|
BitField<19, 1, u32> reduction_enable;
|
|
|
|
BitField<20, 1, BypassL2> bypass_l2;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(LaunchDMA) == 4);
|
|
|
|
|
|
|
|
struct RemapConst {
|
2021-09-20 00:36:41 +00:00
|
|
|
enum class Swizzle : u32 {
|
2020-07-04 01:00:30 +00:00
|
|
|
SRC_X = 0,
|
|
|
|
SRC_Y = 1,
|
|
|
|
SRC_Z = 2,
|
|
|
|
SRC_W = 3,
|
|
|
|
CONST_A = 4,
|
|
|
|
CONST_B = 5,
|
|
|
|
NO_WRITE = 6,
|
2018-06-10 22:02:33 +00:00
|
|
|
};
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
PackedGPUVAddr address;
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
union {
|
|
|
|
BitField<0, 3, Swizzle> dst_x;
|
|
|
|
BitField<4, 3, Swizzle> dst_y;
|
|
|
|
BitField<8, 3, Swizzle> dst_z;
|
|
|
|
BitField<12, 3, Swizzle> dst_w;
|
2022-08-14 09:36:36 +00:00
|
|
|
BitField<0, 12, u32> dst_components_raw;
|
2020-07-04 01:00:30 +00:00
|
|
|
BitField<16, 2, u32> component_size_minus_one;
|
|
|
|
BitField<20, 2, u32> num_src_components_minus_one;
|
|
|
|
BitField<24, 2, u32> num_dst_components_minus_one;
|
|
|
|
};
|
2022-08-14 09:36:36 +00:00
|
|
|
|
2022-09-01 03:45:22 +00:00
|
|
|
Swizzle GetComponent(size_t i) const {
|
2022-08-14 09:36:36 +00:00
|
|
|
const u32 raw = dst_components_raw;
|
|
|
|
return static_cast<Swizzle>((raw >> (i * 3)) & 0x7);
|
|
|
|
}
|
2020-07-04 01:00:30 +00:00
|
|
|
};
|
|
|
|
static_assert(sizeof(RemapConst) == 12);
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2021-07-10 16:19:10 +00:00
|
|
|
void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
|
|
|
|
|
2020-12-04 19:39:12 +00:00
|
|
|
explicit MaxwellDMA(Core::System& system_, MemoryManager& memory_manager_);
|
2021-04-12 13:49:04 +00:00
|
|
|
~MaxwellDMA() override;
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
/// Write the value to the register identified by method.
|
|
|
|
void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
/// Write multiple values to the register identified by method.
|
|
|
|
void CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
|
|
|
u32 methods_pending) override;
|
2018-06-10 22:02:33 +00:00
|
|
|
|
|
|
|
private:
|
2020-07-04 01:00:30 +00:00
|
|
|
/// Performs the copy from the source buffer to the destination buffer as configured in the
|
|
|
|
/// registers.
|
|
|
|
void Launch();
|
|
|
|
|
|
|
|
void CopyBlockLinearToPitch();
|
|
|
|
|
|
|
|
void CopyPitchToBlockLinear();
|
|
|
|
|
2022-11-06 11:50:54 +00:00
|
|
|
void CopyBlockLinearToBlockLinear();
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
void FastCopyBlockLinearToPitch();
|
|
|
|
|
2022-02-21 05:11:33 +00:00
|
|
|
void ReleaseSemaphore();
|
|
|
|
|
2019-02-16 03:05:17 +00:00
|
|
|
Core::System& system;
|
|
|
|
|
2019-04-05 22:25:20 +00:00
|
|
|
MemoryManager& memory_manager;
|
2021-07-27 11:30:54 +00:00
|
|
|
VideoCore::RasterizerInterface* rasterizer = nullptr;
|
2019-04-05 22:25:20 +00:00
|
|
|
|
2019-04-23 16:41:55 +00:00
|
|
|
std::vector<u8> read_buffer;
|
|
|
|
std::vector<u8> write_buffer;
|
2022-11-06 11:50:54 +00:00
|
|
|
std::vector<u8> intermediate_buffer;
|
2019-04-23 16:41:55 +00:00
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
static constexpr std::size_t NUM_REGS = 0x800;
|
|
|
|
struct Regs {
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
u32 reserved[0x40];
|
|
|
|
u32 nop;
|
|
|
|
u32 reserved01[0xf];
|
|
|
|
u32 pm_trigger;
|
|
|
|
u32 reserved02[0x3f];
|
|
|
|
Semaphore semaphore;
|
|
|
|
u32 reserved03[0x2];
|
|
|
|
RenderEnable render_enable;
|
|
|
|
PhysMode src_phys_mode;
|
|
|
|
PhysMode dst_phys_mode;
|
|
|
|
u32 reserved04[0x26];
|
|
|
|
LaunchDMA launch_dma;
|
|
|
|
u32 reserved05[0x3f];
|
|
|
|
PackedGPUVAddr offset_in;
|
|
|
|
PackedGPUVAddr offset_out;
|
|
|
|
u32 pitch_in;
|
|
|
|
u32 pitch_out;
|
|
|
|
u32 line_length_in;
|
|
|
|
u32 line_count;
|
2021-07-10 16:19:10 +00:00
|
|
|
u32 reserved06[0xb6];
|
|
|
|
u32 remap_consta_value;
|
|
|
|
u32 remap_constb_value;
|
2020-07-04 01:00:30 +00:00
|
|
|
RemapConst remap_const;
|
|
|
|
Parameters dst_params;
|
|
|
|
u32 reserved07[0x1];
|
|
|
|
Parameters src_params;
|
|
|
|
u32 reserved08[0x275];
|
|
|
|
u32 pm_trigger_end;
|
|
|
|
u32 reserved09[0x3ba];
|
|
|
|
};
|
|
|
|
std::array<u32, NUM_REGS> reg_array;
|
|
|
|
};
|
|
|
|
} regs{};
|
2018-06-10 22:02:33 +00:00
|
|
|
|
|
|
|
#define ASSERT_REG_POSITION(field_name, position) \
|
|
|
|
static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \
|
|
|
|
"Field " #field_name " has invalid position")
|
|
|
|
|
2020-07-04 01:00:30 +00:00
|
|
|
ASSERT_REG_POSITION(launch_dma, 0xC0);
|
|
|
|
ASSERT_REG_POSITION(offset_in, 0x100);
|
|
|
|
ASSERT_REG_POSITION(offset_out, 0x102);
|
|
|
|
ASSERT_REG_POSITION(pitch_in, 0x104);
|
|
|
|
ASSERT_REG_POSITION(pitch_out, 0x105);
|
|
|
|
ASSERT_REG_POSITION(line_length_in, 0x106);
|
|
|
|
ASSERT_REG_POSITION(line_count, 0x107);
|
|
|
|
ASSERT_REG_POSITION(remap_const, 0x1C0);
|
|
|
|
ASSERT_REG_POSITION(dst_params, 0x1C3);
|
|
|
|
ASSERT_REG_POSITION(src_params, 0x1CA);
|
2018-06-10 22:02:33 +00:00
|
|
|
|
|
|
|
#undef ASSERT_REG_POSITION
|
2020-07-04 01:00:30 +00:00
|
|
|
};
|
2018-06-10 22:02:33 +00:00
|
|
|
|
2018-07-20 22:14:17 +00:00
|
|
|
} // namespace Tegra::Engines
|