mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #4046 from ogniK5377/macro-hle-prod
Add support for HLEing Macros
This commit is contained in:
		
						commit
						32343d820d
					
				@ -27,6 +27,8 @@ add_library(video_core STATIC
 | 
			
		||||
    engines/shader_type.h
 | 
			
		||||
    macro/macro.cpp
 | 
			
		||||
    macro/macro.h
 | 
			
		||||
    macro/macro_hle.cpp
 | 
			
		||||
    macro/macro_hle.h
 | 
			
		||||
    macro/macro_interpreter.cpp
 | 
			
		||||
    macro/macro_interpreter.h
 | 
			
		||||
    macro/macro_jit_x64.cpp
 | 
			
		||||
 | 
			
		||||
@ -128,7 +128,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
 | 
			
		||||
        ((method - MacroRegistersStart) >> 1) % static_cast<u32>(macro_positions.size());
 | 
			
		||||
 | 
			
		||||
    // Execute the current macro.
 | 
			
		||||
    macro_engine->Execute(macro_positions[entry], parameters);
 | 
			
		||||
    macro_engine->Execute(*this, macro_positions[entry], parameters);
 | 
			
		||||
    if (mme_draw.current_mode != MMEDrawMode::Undefined) {
 | 
			
		||||
        FlushMMEInlineDraw();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1418,6 +1418,14 @@ public:
 | 
			
		||||
        return execute_on;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface& GetRasterizer() {
 | 
			
		||||
        return rasterizer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const VideoCore::RasterizerInterface& GetRasterizer() const {
 | 
			
		||||
        return rasterizer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Notify a memory write has happened.
 | 
			
		||||
    void OnMemoryWrite() {
 | 
			
		||||
        dirty.flags |= dirty.on_write_stores;
 | 
			
		||||
 | 
			
		||||
@ -2,23 +2,37 @@
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <boost/container_hash/hash.hpp>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "video_core/engines/maxwell_3d.h"
 | 
			
		||||
#include "video_core/macro/macro.h"
 | 
			
		||||
#include "video_core/macro/macro_hle.h"
 | 
			
		||||
#include "video_core/macro/macro_interpreter.h"
 | 
			
		||||
#include "video_core/macro/macro_jit_x64.h"
 | 
			
		||||
 | 
			
		||||
namespace Tegra {
 | 
			
		||||
 | 
			
		||||
MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d)
 | 
			
		||||
    : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {}
 | 
			
		||||
 | 
			
		||||
MacroEngine::~MacroEngine() = default;
 | 
			
		||||
 | 
			
		||||
void MacroEngine::AddCode(u32 method, u32 data) {
 | 
			
		||||
    uploaded_macro_code[method].push_back(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
 | 
			
		||||
void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method,
 | 
			
		||||
                          const std::vector<u32>& parameters) {
 | 
			
		||||
    auto compiled_macro = macro_cache.find(method);
 | 
			
		||||
    if (compiled_macro != macro_cache.end()) {
 | 
			
		||||
        compiled_macro->second->Execute(parameters, method);
 | 
			
		||||
        const auto& cache_info = compiled_macro->second;
 | 
			
		||||
        if (cache_info.has_hle_program) {
 | 
			
		||||
            cache_info.hle_program->Execute(parameters, method);
 | 
			
		||||
        } else {
 | 
			
		||||
            cache_info.lle_program->Execute(parameters, method);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Macro not compiled, check if it's uploaded and if so, compile it
 | 
			
		||||
        auto macro_code = uploaded_macro_code.find(method);
 | 
			
		||||
@ -26,8 +40,21 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
 | 
			
		||||
            UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        macro_cache[method] = Compile(macro_code->second);
 | 
			
		||||
        macro_cache[method]->Execute(parameters, method);
 | 
			
		||||
        auto& cache_info = macro_cache[method];
 | 
			
		||||
        cache_info.hash = boost::hash_value(macro_code->second);
 | 
			
		||||
        cache_info.lle_program = Compile(macro_code->second);
 | 
			
		||||
 | 
			
		||||
        auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
 | 
			
		||||
        if (hle_program.has_value()) {
 | 
			
		||||
            cache_info.has_hle_program = true;
 | 
			
		||||
            cache_info.hle_program = std::move(hle_program.value());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cache_info.has_hle_program) {
 | 
			
		||||
            cache_info.hle_program->Execute(parameters, method);
 | 
			
		||||
        } else {
 | 
			
		||||
            cache_info.lle_program->Execute(parameters, method);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,11 @@
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Tegra {
 | 
			
		||||
 | 
			
		||||
namespace Engines {
 | 
			
		||||
class Maxwell3D;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Macro {
 | 
			
		||||
constexpr std::size_t NUM_MACRO_REGISTERS = 8;
 | 
			
		||||
enum class Operation : u32 {
 | 
			
		||||
@ -94,6 +96,8 @@ union MethodAddress {
 | 
			
		||||
 | 
			
		||||
} // namespace Macro
 | 
			
		||||
 | 
			
		||||
class HLEMacro;
 | 
			
		||||
 | 
			
		||||
class CachedMacro {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~CachedMacro() = default;
 | 
			
		||||
@ -107,20 +111,29 @@ public:
 | 
			
		||||
 | 
			
		||||
class MacroEngine {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~MacroEngine() = default;
 | 
			
		||||
    explicit MacroEngine(Engines::Maxwell3D& maxwell3d);
 | 
			
		||||
    virtual ~MacroEngine();
 | 
			
		||||
 | 
			
		||||
    // Store the uploaded macro code to compile them when they're called.
 | 
			
		||||
    void AddCode(u32 method, u32 data);
 | 
			
		||||
 | 
			
		||||
    // Compiles the macro if its not in the cache, and executes the compiled macro
 | 
			
		||||
    void Execute(u32 method, const std::vector<u32>& parameters);
 | 
			
		||||
    void Execute(Engines::Maxwell3D& maxwell3d, u32 method, const std::vector<u32>& parameters);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    virtual std::unique_ptr<CachedMacro> Compile(const std::vector<u32>& code) = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unordered_map<u32, std::unique_ptr<CachedMacro>> macro_cache;
 | 
			
		||||
    struct CacheInfo {
 | 
			
		||||
        std::unique_ptr<CachedMacro> lle_program{};
 | 
			
		||||
        std::unique_ptr<CachedMacro> hle_program{};
 | 
			
		||||
        u64 hash{};
 | 
			
		||||
        bool has_hle_program{};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<u32, CacheInfo> macro_cache;
 | 
			
		||||
    std::unordered_map<u32, std::vector<u32>> uploaded_macro_code;
 | 
			
		||||
    std::unique_ptr<HLEMacro> hle_macros;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										113
									
								
								src/video_core/macro/macro_hle.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/video_core/macro/macro_hle.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "video_core/engines/maxwell_3d.h"
 | 
			
		||||
#include "video_core/macro/macro_hle.h"
 | 
			
		||||
#include "video_core/rasterizer_interface.h"
 | 
			
		||||
 | 
			
		||||
namespace Tegra {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
// HLE'd functions
 | 
			
		||||
static void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d,
 | 
			
		||||
                                 const std::vector<u32>& parameters) {
 | 
			
		||||
    const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
 | 
			
		||||
 | 
			
		||||
    maxwell3d.regs.draw.topology.Assign(
 | 
			
		||||
        static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] &
 | 
			
		||||
                                                                        ~(0x3ffffff << 26)));
 | 
			
		||||
    maxwell3d.regs.vb_base_instance = parameters[5];
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = instance_count;
 | 
			
		||||
    maxwell3d.regs.vb_element_base = parameters[3];
 | 
			
		||||
    maxwell3d.regs.index_array.count = parameters[1];
 | 
			
		||||
    maxwell3d.regs.index_array.first = parameters[4];
 | 
			
		||||
 | 
			
		||||
    if (maxwell3d.ShouldExecute()) {
 | 
			
		||||
        maxwell3d.GetRasterizer().Draw(true, true);
 | 
			
		||||
    }
 | 
			
		||||
    maxwell3d.regs.index_array.count = 0;
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = 0;
 | 
			
		||||
    maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d,
 | 
			
		||||
                                 const std::vector<u32>& parameters) {
 | 
			
		||||
    const u32 count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
 | 
			
		||||
 | 
			
		||||
    maxwell3d.regs.vertex_buffer.first = parameters[3];
 | 
			
		||||
    maxwell3d.regs.vertex_buffer.count = parameters[1];
 | 
			
		||||
    maxwell3d.regs.vb_base_instance = parameters[4];
 | 
			
		||||
    maxwell3d.regs.draw.topology.Assign(
 | 
			
		||||
        static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = count;
 | 
			
		||||
 | 
			
		||||
    if (maxwell3d.ShouldExecute()) {
 | 
			
		||||
        maxwell3d.GetRasterizer().Draw(false, true);
 | 
			
		||||
    }
 | 
			
		||||
    maxwell3d.regs.vertex_buffer.count = 0;
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = 0;
 | 
			
		||||
    maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d,
 | 
			
		||||
                                 const std::vector<u32>& parameters) {
 | 
			
		||||
    const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
 | 
			
		||||
    const u32 element_base = parameters[4];
 | 
			
		||||
    const u32 base_instance = parameters[5];
 | 
			
		||||
    maxwell3d.regs.index_array.first = parameters[3];
 | 
			
		||||
    maxwell3d.regs.reg_array[0x446] = element_base; // vertex id base?
 | 
			
		||||
    maxwell3d.regs.index_array.count = parameters[1];
 | 
			
		||||
    maxwell3d.regs.vb_element_base = element_base;
 | 
			
		||||
    maxwell3d.regs.vb_base_instance = base_instance;
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = instance_count;
 | 
			
		||||
    maxwell3d.CallMethodFromMME(0x8e3, 0x640);
 | 
			
		||||
    maxwell3d.CallMethodFromMME(0x8e4, element_base);
 | 
			
		||||
    maxwell3d.CallMethodFromMME(0x8e5, base_instance);
 | 
			
		||||
    maxwell3d.regs.draw.topology.Assign(
 | 
			
		||||
        static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
 | 
			
		||||
    if (maxwell3d.ShouldExecute()) {
 | 
			
		||||
        maxwell3d.GetRasterizer().Draw(true, true);
 | 
			
		||||
    }
 | 
			
		||||
    maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base?
 | 
			
		||||
    maxwell3d.regs.index_array.count = 0;
 | 
			
		||||
    maxwell3d.regs.vb_element_base = 0x0;
 | 
			
		||||
    maxwell3d.regs.vb_base_instance = 0x0;
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = 0;
 | 
			
		||||
    maxwell3d.CallMethodFromMME(0x8e3, 0x640);
 | 
			
		||||
    maxwell3d.CallMethodFromMME(0x8e4, 0x0);
 | 
			
		||||
    maxwell3d.CallMethodFromMME(0x8e5, 0x0);
 | 
			
		||||
    maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
constexpr std::array<std::pair<u64, HLEFunction>, 3> hle_funcs{{
 | 
			
		||||
    std::make_pair<u64, HLEFunction>(0x771BB18C62444DA0, &HLE_771BB18C62444DA0),
 | 
			
		||||
    std::make_pair<u64, HLEFunction>(0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD),
 | 
			
		||||
    std::make_pair<u64, HLEFunction>(0x0217920100488FF7, &HLE_0217920100488FF7),
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
 | 
			
		||||
HLEMacro::~HLEMacro() = default;
 | 
			
		||||
 | 
			
		||||
std::optional<std::unique_ptr<CachedMacro>> HLEMacro::GetHLEProgram(u64 hash) const {
 | 
			
		||||
    const auto it = std::find_if(hle_funcs.cbegin(), hle_funcs.cend(),
 | 
			
		||||
                                 [hash](const auto& pair) { return pair.first == hash; });
 | 
			
		||||
    if (it == hle_funcs.end()) {
 | 
			
		||||
        return std::nullopt;
 | 
			
		||||
    }
 | 
			
		||||
    return std::make_unique<HLEMacroImpl>(maxwell3d, it->second);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HLEMacroImpl::~HLEMacroImpl() = default;
 | 
			
		||||
 | 
			
		||||
HLEMacroImpl::HLEMacroImpl(Engines::Maxwell3D& maxwell3d, HLEFunction func)
 | 
			
		||||
    : maxwell3d(maxwell3d), func(func) {}
 | 
			
		||||
 | 
			
		||||
void HLEMacroImpl::Execute(const std::vector<u32>& parameters, u32 method) {
 | 
			
		||||
    func(maxwell3d, parameters);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Tegra
 | 
			
		||||
							
								
								
									
										44
									
								
								src/video_core/macro/macro_hle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/video_core/macro/macro_hle.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/macro/macro.h"
 | 
			
		||||
 | 
			
		||||
namespace Tegra {
 | 
			
		||||
 | 
			
		||||
namespace Engines {
 | 
			
		||||
class Maxwell3D;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters);
 | 
			
		||||
 | 
			
		||||
class HLEMacro {
 | 
			
		||||
public:
 | 
			
		||||
    explicit HLEMacro(Engines::Maxwell3D& maxwell3d);
 | 
			
		||||
    ~HLEMacro();
 | 
			
		||||
 | 
			
		||||
    std::optional<std::unique_ptr<CachedMacro>> GetHLEProgram(u64 hash) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Engines::Maxwell3D& maxwell3d;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HLEMacroImpl : public CachedMacro {
 | 
			
		||||
public:
 | 
			
		||||
    explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d, HLEFunction func);
 | 
			
		||||
    ~HLEMacroImpl();
 | 
			
		||||
 | 
			
		||||
    void Execute(const std::vector<u32>& parameters, u32 method) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Engines::Maxwell3D& maxwell3d;
 | 
			
		||||
    HLEFunction func;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Tegra
 | 
			
		||||
@ -11,7 +11,8 @@
 | 
			
		||||
MICROPROFILE_DEFINE(MacroInterp, "GPU", "Execute macro interpreter", MP_RGB(128, 128, 192));
 | 
			
		||||
 | 
			
		||||
namespace Tegra {
 | 
			
		||||
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
 | 
			
		||||
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d)
 | 
			
		||||
    : MacroEngine::MacroEngine(maxwell3d), maxwell3d(maxwell3d) {}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<CachedMacro> MacroInterpreter::Compile(const std::vector<u32>& code) {
 | 
			
		||||
    return std::make_unique<MacroInterpreterImpl>(maxwell3d, code);
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,8 @@ static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({
 | 
			
		||||
    BRANCH_HOLDER,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
MacroJITx64::MacroJITx64(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
 | 
			
		||||
MacroJITx64::MacroJITx64(Engines::Maxwell3D& maxwell3d)
 | 
			
		||||
    : MacroEngine::MacroEngine(maxwell3d), maxwell3d(maxwell3d) {}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<CachedMacro> MacroJITx64::Compile(const std::vector<u32>& code) {
 | 
			
		||||
    return std::make_unique<MacroJITx64Impl>(maxwell3d, code);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user