Browse Source
GPU: Partially implemented the Maxwell DMA engine.
GPU: Partially implemented the Maxwell DMA engine.
Only tiled->linear and linear->tiled copies that aren't offsetted are supported for now. Queries are not supported. Swizzled copies are not supported.nce_cpp
7 changed files with 237 additions and 1 deletions
-
2src/video_core/CMakeLists.txt
-
6src/video_core/command_processor.cpp
-
1src/video_core/engines/fermi_2d.cpp
-
69src/video_core/engines/maxwell_dma.cpp
-
155src/video_core/engines/maxwell_dma.h
-
2src/video_core/gpu.cpp
-
3src/video_core/gpu.h
@ -0,0 +1,69 @@ |
|||
// Copyright 2018 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "core/memory.h"
|
|||
#include "video_core/engines/maxwell_dma.h"
|
|||
#include "video_core/textures/decoders.h"
|
|||
|
|||
namespace Tegra { |
|||
namespace Engines { |
|||
|
|||
MaxwellDMA::MaxwellDMA(MemoryManager& memory_manager) : memory_manager(memory_manager) {} |
|||
|
|||
void MaxwellDMA::WriteReg(u32 method, u32 value) { |
|||
ASSERT_MSG(method < Regs::NUM_REGS, |
|||
"Invalid MaxwellDMA register, increase the size of the Regs structure"); |
|||
|
|||
regs.reg_array[method] = value; |
|||
|
|||
#define MAXWELLDMA_REG_INDEX(field_name) \
|
|||
(offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) |
|||
|
|||
switch (method) { |
|||
case MAXWELLDMA_REG_INDEX(exec): { |
|||
HandleCopy(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
#undef MAXWELLDMA_REG_INDEX
|
|||
} |
|||
|
|||
void MaxwellDMA::HandleCopy() { |
|||
NGLOG_WARNING(HW_GPU, "Requested a DMA copy"); |
|||
|
|||
const GPUVAddr source = regs.src_address.Address(); |
|||
const GPUVAddr dest = regs.dst_address.Address(); |
|||
|
|||
const VAddr source_cpu = *memory_manager.GpuToCpuAddress(source); |
|||
const VAddr dest_cpu = *memory_manager.GpuToCpuAddress(dest); |
|||
|
|||
// TODO(Subv): Perform more research and implement all features of this engine.
|
|||
ASSERT(regs.exec.enable_swizzle == 0); |
|||
ASSERT(regs.exec.enable_2d == 1); |
|||
ASSERT(regs.exec.query_mode == Regs::QueryMode::None); |
|||
ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); |
|||
ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); |
|||
ASSERT(regs.src_params.pos_x == 0); |
|||
ASSERT(regs.src_params.pos_y == 0); |
|||
ASSERT(regs.dst_params.pos_x == 0); |
|||
ASSERT(regs.dst_params.pos_y == 0); |
|||
ASSERT(regs.exec.is_dst_linear != regs.exec.is_src_linear); |
|||
|
|||
u8* src_buffer = Memory::GetPointer(source_cpu); |
|||
u8* dst_buffer = Memory::GetPointer(dest_cpu); |
|||
|
|||
if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { |
|||
// If the input is tiled and the output is linear, deswizzle the input and copy it over.
|
|||
Texture::CopySwizzledData(regs.src_params.size_x, regs.src_params.size_y, 1, 1, src_buffer, |
|||
dst_buffer, true, regs.src_params.BlockHeight()); |
|||
} else { |
|||
// If the input is linear and the output is tiled, swizzle the input and copy it over.
|
|||
Texture::CopySwizzledData(regs.dst_params.size_x, regs.dst_params.size_y, 1, 1, dst_buffer, |
|||
src_buffer, false, regs.dst_params.BlockHeight()); |
|||
} |
|||
} |
|||
|
|||
} // namespace Engines
|
|||
} // namespace Tegra
|
|||
@ -0,0 +1,155 @@ |
|||
// Copyright 2018 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include "common/assert.h" |
|||
#include "common/bit_field.h" |
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
#include "video_core/gpu.h" |
|||
#include "video_core/memory_manager.h" |
|||
|
|||
namespace Tegra { |
|||
namespace Engines { |
|||
|
|||
class MaxwellDMA final { |
|||
public: |
|||
explicit MaxwellDMA(MemoryManager& memory_manager); |
|||
~MaxwellDMA() = default; |
|||
|
|||
/// Write the value to the register identified by method. |
|||
void WriteReg(u32 method, u32 value); |
|||
|
|||
struct Regs { |
|||
static constexpr size_t NUM_REGS = 0x1D6; |
|||
|
|||
struct Parameters { |
|||
union { |
|||
BitField<0, 4, u32> block_depth; |
|||
BitField<4, 4, u32> block_height; |
|||
BitField<8, 4, u32> block_width; |
|||
}; |
|||
u32 size_x; |
|||
u32 size_y; |
|||
u32 size_z; |
|||
u32 pos_z; |
|||
union { |
|||
BitField<0, 16, u32> pos_x; |
|||
BitField<16, 16, u32> pos_y; |
|||
}; |
|||
|
|||
u32 BlockHeight() const { |
|||
return 1 << block_height; |
|||
} |
|||
}; |
|||
|
|||
static_assert(sizeof(Parameters) == 24, "Parameters has wrong size"); |
|||
|
|||
enum class CopyMode : u32 { |
|||
None = 0, |
|||
Unk1 = 1, |
|||
Unk2 = 2, |
|||
}; |
|||
|
|||
enum class QueryMode : u32 { |
|||
None = 0, |
|||
Short = 1, |
|||
Long = 2, |
|||
}; |
|||
|
|||
enum class QueryIntr : u32 { |
|||
None = 0, |
|||
Block = 1, |
|||
NonBlock = 2, |
|||
}; |
|||
|
|||
union { |
|||
struct { |
|||
INSERT_PADDING_WORDS(0xC0); |
|||
|
|||
struct { |
|||
union { |
|||
BitField<0, 2, CopyMode> copy_mode; |
|||
BitField<2, 1, u32> flush; |
|||
|
|||
BitField<3, 2, QueryMode> query_mode; |
|||
BitField<5, 2, QueryIntr> query_intr; |
|||
|
|||
BitField<7, 1, u32> is_src_linear; |
|||
BitField<8, 1, u32> is_dst_linear; |
|||
|
|||
BitField<9, 1, u32> enable_2d; |
|||
BitField<10, 1, u32> enable_swizzle; |
|||
}; |
|||
} exec; |
|||
|
|||
INSERT_PADDING_WORDS(0x3F); |
|||
|
|||
struct { |
|||
u32 address_high; |
|||
u32 address_low; |
|||
|
|||
GPUVAddr Address() const { |
|||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | |
|||
address_low); |
|||
} |
|||
} src_address; |
|||
|
|||
struct { |
|||
u32 address_high; |
|||
u32 address_low; |
|||
|
|||
GPUVAddr Address() const { |
|||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | |
|||
address_low); |
|||
} |
|||
} dst_address; |
|||
|
|||
u32 src_pitch; |
|||
u32 dst_pitch; |
|||
u32 x_count; |
|||
u32 y_count; |
|||
|
|||
INSERT_PADDING_WORDS(0xBB); |
|||
|
|||
Parameters dst_params; |
|||
|
|||
INSERT_PADDING_WORDS(1); |
|||
|
|||
Parameters src_params; |
|||
|
|||
INSERT_PADDING_WORDS(0x13); |
|||
}; |
|||
std::array<u32, NUM_REGS> reg_array; |
|||
}; |
|||
} regs{}; |
|||
|
|||
MemoryManager& memory_manager; |
|||
|
|||
private: |
|||
/// Performs the copy from the source buffer to the destination buffer as configured in the |
|||
/// registers. |
|||
void HandleCopy(); |
|||
}; |
|||
|
|||
#define ASSERT_REG_POSITION(field_name, position) \ |
|||
static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \ |
|||
"Field " #field_name " has invalid position") |
|||
|
|||
ASSERT_REG_POSITION(exec, 0xC0); |
|||
ASSERT_REG_POSITION(src_address, 0x100); |
|||
ASSERT_REG_POSITION(dst_address, 0x102); |
|||
ASSERT_REG_POSITION(src_pitch, 0x104); |
|||
ASSERT_REG_POSITION(dst_pitch, 0x105); |
|||
ASSERT_REG_POSITION(x_count, 0x106); |
|||
ASSERT_REG_POSITION(y_count, 0x107); |
|||
ASSERT_REG_POSITION(dst_params, 0x1C3); |
|||
ASSERT_REG_POSITION(src_params, 0x1CA); |
|||
|
|||
#undef ASSERT_REG_POSITION |
|||
|
|||
} // namespace Engines |
|||
} // namespace Tegra |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue