mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-20 22:05:12 +00:00
- Also fix visual corruption when using disjoint indexed draws - Refactor draw call emit again (vk) - Improve execution barrier resolve - Allow vertex/index rebase inside begin/end pair - Add ALPHA_TEST to list of excluded methods [TODO: defer raster state] - gl bringup - Simplify - using the simple_array gets back a few more fps :)
246 lines
No EOL
5.4 KiB
C++
246 lines
No EOL
5.4 KiB
C++
#pragma once
|
|
|
|
#include <Utilities/types.h>
|
|
#include <Utilities/Atomic.h>
|
|
#include <Utilities/mutex.h>
|
|
#include <Utilities/thread.h>
|
|
|
|
#include "rsx_utils.h"
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
|
|
#ifndef __unused
|
|
#define __unused(expression) do { (void)(expression); } while(0)
|
|
#endif
|
|
|
|
struct RsxDmaControl;
|
|
|
|
namespace rsx
|
|
{
|
|
class thread;
|
|
|
|
namespace FIFO
|
|
{
|
|
enum internal_commands : u32
|
|
{
|
|
NOP = 0,
|
|
FIFO_EMPTY = 0xDEADF1F0,
|
|
FIFO_BUSY = 0xBABEF1F0,
|
|
FIFO_PACKET_BEGIN = 0xF1F0,
|
|
FIFO_DISABLED_COMMAND = 0xF1F4,
|
|
FIFO_DRAW_BARRIER = 0xF1F8,
|
|
};
|
|
|
|
struct register_pair
|
|
{
|
|
u32 reg;
|
|
u32 value;
|
|
u32 loc;
|
|
u32 reserved;
|
|
};
|
|
|
|
struct fifo_buffer_info_t
|
|
{
|
|
u32 start_loc;
|
|
u32 length;
|
|
u32 num_draw_calls;
|
|
u32 draw_call_distance_weight;
|
|
};
|
|
|
|
struct branch_target_info_t
|
|
{
|
|
u32 branch_target;
|
|
u32 branch_origin;
|
|
s64 weight;
|
|
u64 checksum_16;
|
|
u64 reserved;
|
|
};
|
|
|
|
struct optimization_pass
|
|
{
|
|
virtual void optimize(const fifo_buffer_info_t& info, simple_array<register_pair>& commands, const u32* registers) = 0;
|
|
};
|
|
|
|
struct flattening_pass : public optimization_pass
|
|
{
|
|
private:
|
|
std::array<bool, 0x10000 / 4> m_skippable_registers;
|
|
|
|
public:
|
|
flattening_pass();
|
|
void optimize(const fifo_buffer_info_t& info, simple_array<register_pair>& commands, const u32* registers) override;
|
|
};
|
|
|
|
struct reordering_pass : public optimization_pass
|
|
{
|
|
private:
|
|
|
|
struct instruction_buffer_t
|
|
{
|
|
std::unordered_map<u32, u32> m_storage;
|
|
simple_array<u32> m_insertion_order;
|
|
|
|
instruction_buffer_t()
|
|
{
|
|
m_insertion_order.reserve(64);
|
|
}
|
|
|
|
void add_cmd(u32 reg, u32 value)
|
|
{
|
|
const auto is_new = std::get<1>(m_storage.insert_or_assign(reg, value));
|
|
if (!is_new)
|
|
{
|
|
for (auto &loc : m_insertion_order)
|
|
{
|
|
if (loc == reg)
|
|
{
|
|
loc |= 0x80000000;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_insertion_order.push_back(reg);
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
m_storage.clear();
|
|
m_insertion_order.clear();
|
|
}
|
|
|
|
void swap(instruction_buffer_t& other)
|
|
{
|
|
m_storage.swap(other.m_storage);
|
|
m_insertion_order.swap(other.m_insertion_order);
|
|
}
|
|
|
|
auto size() const
|
|
{
|
|
return m_storage.size();
|
|
}
|
|
|
|
inline std::pair<u32, u32> get(int index) const
|
|
{
|
|
const auto key = m_insertion_order[index];
|
|
if (key & 0x80000000)
|
|
{
|
|
// Disabled by a later write to the same register
|
|
// TODO: Track command type registers and avoid this
|
|
return { FIFO_DISABLED_COMMAND, 0 };
|
|
}
|
|
|
|
const auto value = m_storage.at(key);
|
|
return { key, value };
|
|
}
|
|
|
|
bool operator == (const instruction_buffer_t& other) const
|
|
{
|
|
if (size() == other.size())
|
|
{
|
|
for (const auto &e : other.m_storage)
|
|
{
|
|
const auto found = m_storage.find(e.first);
|
|
if (found == m_storage.end())
|
|
return false;
|
|
|
|
if (found->second != e.second)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
struct draw_call
|
|
{
|
|
instruction_buffer_t prologue;
|
|
std::vector<register_pair> draws;
|
|
bool write_prologue;
|
|
u32 primitive_type;
|
|
const register_pair* start_pos;
|
|
|
|
bool matches(const instruction_buffer_t setup, u32 prim) const
|
|
{
|
|
if (prim != primitive_type)
|
|
return false;
|
|
|
|
return prologue == setup;
|
|
}
|
|
};
|
|
|
|
instruction_buffer_t registers_changed;
|
|
std::vector<draw_call> bins;
|
|
|
|
std::unordered_multimap<u32, fifo_buffer_info_t> m_results_prediction_table;
|
|
|
|
public:
|
|
void optimize(const fifo_buffer_info_t& info, simple_array<register_pair>& commands, const u32* registers) override;
|
|
};
|
|
|
|
class FIFO_control
|
|
{
|
|
RsxDmaControl* m_ctrl = nullptr;
|
|
u32 m_internal_get = 0;
|
|
|
|
std::shared_ptr<thread_base> m_prefetcher_thread;
|
|
u32 m_prefetch_get = 0;
|
|
atomic_t<bool> m_prefetcher_busy{ false };
|
|
atomic_t<bool> m_fifo_busy{ false };
|
|
fifo_buffer_info_t m_prefetcher_info;
|
|
bool m_prefetcher_speculating;
|
|
|
|
std::vector<std::unique_ptr<optimization_pass>> m_optimization_passes;
|
|
|
|
simple_array<register_pair> m_queue;
|
|
simple_array<register_pair> m_prefetched_queue;
|
|
atomic_t<u32> m_command_index{ 0 };
|
|
|
|
shared_mutex m_prefetch_mutex; // Guards prefetch queue
|
|
shared_mutex m_queue_mutex; // Guards primary queue
|
|
atomic_t<u64> m_ctrl_tag{ 0 }; // 'Guards' control registers
|
|
|
|
register_pair empty_cmd { FIFO_EMPTY };
|
|
register_pair busy_cmd { FIFO_BUSY };
|
|
|
|
u32 m_memwatch_addr = 0;
|
|
u32 m_memwatch_cmp = 0;
|
|
|
|
fifo_buffer_info_t m_fifo_info;
|
|
std::unordered_multimap<u32, branch_target_info_t> m_branch_prediction_table;
|
|
|
|
void read_ahead(fifo_buffer_info_t& info, simple_array<register_pair>& commands, u32& get_pointer);
|
|
void optimize(const fifo_buffer_info_t& info, simple_array<register_pair>& commands);
|
|
void clear_buffer();
|
|
|
|
u32 get_likely_target(u32 source);
|
|
void report_branch_miss(u32 source, u32 target, u32 actual);
|
|
void report_branch_hit(u32 source, u32 target);
|
|
bool test_prefetcher_correctness(u32 actual_target);
|
|
|
|
public:
|
|
FIFO_control(rsx::thread* pctrl);
|
|
~FIFO_control() {}
|
|
|
|
void set_get(u32 get, bool spinning = false);
|
|
void set_put(u32 put);
|
|
|
|
const register_pair& read();
|
|
inline const register_pair& read_unsafe();
|
|
|
|
void register_optimization_pass(optimization_pass* pass);
|
|
|
|
void finalize();
|
|
|
|
public:
|
|
static bool is_blocking_cmd(u32 cmd);
|
|
static bool is_sync_cmd(u32 cmd);
|
|
};
|
|
}
|
|
} |