// 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/gpu.h" #include "video_core/memory_manager.h" namespace Tegra::Engines { #define FERMI2D_REG_INDEX(field_name) \ (offsetof(Tegra::Engines::Fermi2D::Regs, field_name) / sizeof(u32)) class Fermi2D final { public: explicit Fermi2D(MemoryManager& memory_manager); ~Fermi2D() = default; /// Write the value to the register identified by method. void WriteReg(u32 method, u32 value); struct Regs { static constexpr size_t NUM_REGS = 0x258; struct Surface { RenderTargetFormat format; BitField<0, 1, u32> linear; union { BitField<0, 4, u32> block_depth; BitField<4, 4, u32> block_height; BitField<8, 4, u32> block_width; }; u32 depth; u32 layer; u32 pitch; u32 width; u32 height; u32 address_high; u32 address_low; GPUVAddr Address() const { return static_cast((static_cast(address_high) << 32) | address_low); } u32 BlockHeight() const { // The block height is stored in log2 format. return 1 << block_height; } }; static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size"); enum class Operation : u32 { SrcCopyAnd = 0, ROPAnd = 1, Blend = 2, SrcCopy = 3, ROP = 4, SrcCopyPremult = 5, BlendPremult = 6, }; union { struct { INSERT_PADDING_WORDS(0x80); Surface dst; INSERT_PADDING_WORDS(2); Surface src; INSERT_PADDING_WORDS(0x15); Operation operation; INSERT_PADDING_WORDS(0x9); // TODO(Subv): This is only a guess. u32 trigger; INSERT_PADDING_WORDS(0x1A3); }; std::array reg_array; }; } regs{}; MemoryManager& memory_manager; private: /// Performs the copy from the source surface to the destination surface as configured in the /// registers. void HandleSurfaceCopy(); }; #define ASSERT_REG_POSITION(field_name, position) \ static_assert(offsetof(Fermi2D::Regs, field_name) == position * 4, \ "Field " #field_name " has invalid position") ASSERT_REG_POSITION(dst, 0x80); ASSERT_REG_POSITION(src, 0x8C); ASSERT_REG_POSITION(operation, 0xAB); ASSERT_REG_POSITION(trigger, 0xB5); #undef ASSERT_REG_POSITION } // namespace Tegra::Engines