mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 20:22:30 +01:00
Get reworked RSX to compile
This commit is contained in:
parent
10fe14e783
commit
c1aaa1bcf6
@ -509,7 +509,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
|
||||
|
||||
auto& draw_call = rsx::method_registers.current_draw_clause;
|
||||
const rsx::flags32_t vertex_state_mask = rsx::vertex_base_changed | rsx::vertex_arrays_changed;
|
||||
const rsx::flags32_t vertex_state = (sub_index == 0) ? rsx::vertex_arrays_changed : draw_call.execute_pipeline_dependencies() & vertex_state_mask;
|
||||
const rsx::flags32_t vertex_state = (sub_index == 0) ? rsx::vertex_arrays_changed : draw_call.execute_pipeline_dependencies(m_ctx) & vertex_state_mask;
|
||||
|
||||
if (vertex_state & rsx::vertex_arrays_changed)
|
||||
{
|
||||
@ -540,7 +540,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
|
||||
// Execute remainining pipeline barriers with NOP draw
|
||||
do
|
||||
{
|
||||
draw_call.execute_pipeline_dependencies();
|
||||
draw_call.execute_pipeline_dependencies(m_ctx);
|
||||
} while (draw_call.next());
|
||||
|
||||
draw_call.end();
|
||||
|
310
rpcs3/Emu/RSX/NV47/FW/draw_call.hpp
Normal file
310
rpcs3/Emu/RSX/NV47/FW/draw_call.hpp
Normal file
@ -0,0 +1,310 @@
|
||||
#pragma once
|
||||
|
||||
#include "draw_call.inc.h"
|
||||
|
||||
#include "Emu/RSX/Common/simple_array.hpp"
|
||||
#include "Emu/RSX/gcm_enums.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
class draw_clause
|
||||
{
|
||||
// Stores the first and count argument from draw/draw indexed parameters between begin/end clauses.
|
||||
simple_array<draw_range_t> draw_command_ranges{};
|
||||
|
||||
// Stores rasterization barriers for primitive types sensitive to adjacency
|
||||
simple_array<barrier_t> draw_command_barriers{};
|
||||
|
||||
// Counter used to parse the commands in order
|
||||
u32 current_range_index{};
|
||||
|
||||
// Location of last execution barrier
|
||||
u32 last_execution_barrier_index{};
|
||||
|
||||
// Helper functions
|
||||
// Add a new draw command
|
||||
void append_draw_command(const draw_range_t& range)
|
||||
{
|
||||
current_range_index = draw_command_ranges.size();
|
||||
draw_command_ranges.push_back(range);
|
||||
}
|
||||
|
||||
// Insert a new draw command within the others
|
||||
void insert_draw_command(u32 index, const draw_range_t& range)
|
||||
{
|
||||
auto range_It = draw_command_ranges.begin();
|
||||
std::advance(range_It, index);
|
||||
|
||||
current_range_index = index;
|
||||
draw_command_ranges.insert(range_It, range);
|
||||
|
||||
// Update all barrier draw ids after this one
|
||||
for (auto& barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id >= index)
|
||||
{
|
||||
barrier.draw_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
primitive_type primitive{};
|
||||
draw_command command{};
|
||||
|
||||
bool is_immediate_draw{}; // Set if part of the draw is submitted via push registers
|
||||
bool is_disjoint_primitive{}; // Set if primitive type does not rely on adjacency information
|
||||
bool primitive_barrier_enable{}; // Set once to signal that a primitive restart barrier can be inserted
|
||||
|
||||
simple_array<u32> inline_vertex_array{};
|
||||
|
||||
void operator()(utils::serial& ar);
|
||||
|
||||
void insert_command_barrier(command_barrier_type type, u32 arg, u32 register_index = 0);
|
||||
|
||||
/**
|
||||
* Optimize commands for rendering
|
||||
*/
|
||||
void compile()
|
||||
{
|
||||
// End draw call append mode
|
||||
current_range_index = ~0u;
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert one command range
|
||||
*/
|
||||
|
||||
void append(u32 first, u32 count)
|
||||
{
|
||||
const bool barrier_enable_flag = primitive_barrier_enable;
|
||||
primitive_barrier_enable = false;
|
||||
|
||||
if (!draw_command_ranges.empty())
|
||||
{
|
||||
auto& last = draw_command_ranges[current_range_index];
|
||||
|
||||
if (last.count == 0)
|
||||
{
|
||||
// Special case, usually indicates an execution barrier
|
||||
last.first = first;
|
||||
last.count = count;
|
||||
return;
|
||||
}
|
||||
|
||||
if (last.first + last.count == first)
|
||||
{
|
||||
if (!is_disjoint_primitive && barrier_enable_flag)
|
||||
{
|
||||
// Insert barrier
|
||||
insert_command_barrier(primitive_restart_barrier, 0);
|
||||
}
|
||||
|
||||
last.count += count;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto index = last_execution_barrier_index; index < draw_command_ranges.size(); ++index)
|
||||
{
|
||||
if (draw_command_ranges[index].first == first &&
|
||||
draw_command_ranges[index].count == count)
|
||||
{
|
||||
// Duplicate entry? WTF!
|
||||
return;
|
||||
}
|
||||
|
||||
if (draw_command_ranges[index].first > first)
|
||||
{
|
||||
insert_draw_command(index, { 0, first, count });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
append_draw_command({ 0, first, count });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many vertex or index will be consumed by the draw clause.
|
||||
*/
|
||||
u32 get_elements_count() const
|
||||
{
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(command == rsx::draw_command::inlined_array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_range().count;
|
||||
}
|
||||
|
||||
u32 min_index() const
|
||||
{
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(command == rsx::draw_command::inlined_array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_range().first;
|
||||
}
|
||||
|
||||
bool is_single_draw() const
|
||||
{
|
||||
if (is_disjoint_primitive)
|
||||
return true;
|
||||
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(!inline_vertex_array.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
ensure(current_range_index != ~0u);
|
||||
for (const auto& barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id != current_range_index)
|
||||
continue;
|
||||
|
||||
if (barrier.type == primitive_restart_barrier)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return (command == rsx::draw_command::inlined_array) ? inline_vertex_array.empty() : draw_command_ranges.empty();
|
||||
}
|
||||
|
||||
u32 pass_count() const
|
||||
{
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(!inline_vertex_array.empty());
|
||||
return 1u;
|
||||
}
|
||||
|
||||
u32 count = ::size32(draw_command_ranges);
|
||||
if (draw_command_ranges.back().count == 0)
|
||||
{
|
||||
// Dangling barrier
|
||||
ensure(count > 1);
|
||||
count--;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
primitive_class classify_mode() const
|
||||
{
|
||||
return primitive >= rsx::primitive_type::triangles
|
||||
? primitive_class::polygon
|
||||
: primitive_class::non_polygon;
|
||||
}
|
||||
|
||||
|
||||
void reset(rsx::primitive_type type);
|
||||
|
||||
void begin()
|
||||
{
|
||||
current_range_index = 0;
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
current_range_index = draw_command_ranges.size() - 1;
|
||||
}
|
||||
|
||||
bool next()
|
||||
{
|
||||
current_range_index++;
|
||||
if (current_range_index >= draw_command_ranges.size())
|
||||
{
|
||||
current_range_index = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (draw_command_ranges[current_range_index].count == 0)
|
||||
{
|
||||
// Dangling execution barrier
|
||||
ensure(current_range_index > 0 && (current_range_index + 1) == draw_command_ranges.size());
|
||||
current_range_index = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call this once after the draw clause has been fully consumed to reconcile any conflicts
|
||||
*/
|
||||
void post_execute_cleanup(struct context* ctx)
|
||||
{
|
||||
ensure(current_range_index == 0);
|
||||
|
||||
if (draw_command_ranges.size() > 1)
|
||||
{
|
||||
if (draw_command_ranges.back().count == 0)
|
||||
{
|
||||
// Dangling execution barrier
|
||||
current_range_index = draw_command_ranges.size() - 1;
|
||||
execute_pipeline_dependencies(ctx);
|
||||
current_range_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes commands reqiured to make the current draw state valid
|
||||
*/
|
||||
u32 execute_pipeline_dependencies(struct context* ctx) const;
|
||||
|
||||
const draw_range_t& get_range() const
|
||||
{
|
||||
ensure(current_range_index < draw_command_ranges.size());
|
||||
return draw_command_ranges[current_range_index];
|
||||
}
|
||||
|
||||
simple_array<draw_range_t> get_subranges() const
|
||||
{
|
||||
ensure(!is_single_draw());
|
||||
|
||||
const auto range = get_range();
|
||||
const auto limit = range.first + range.count;
|
||||
|
||||
simple_array<draw_range_t> ret;
|
||||
u32 previous_barrier = range.first;
|
||||
u32 vertex_counter = 0;
|
||||
|
||||
for (const auto& barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id != current_range_index)
|
||||
continue;
|
||||
|
||||
if (barrier.type != primitive_restart_barrier)
|
||||
continue;
|
||||
|
||||
if (barrier.address <= range.first)
|
||||
continue;
|
||||
|
||||
if (barrier.address >= limit)
|
||||
break;
|
||||
|
||||
const u32 count = barrier.address - previous_barrier;
|
||||
ret.push_back({ 0, vertex_counter, count });
|
||||
previous_barrier = barrier.address;
|
||||
vertex_counter += count;
|
||||
}
|
||||
|
||||
ensure(!ret.empty());
|
||||
ensure(previous_barrier < limit);
|
||||
ret.push_back({ 0, vertex_counter, limit - previous_barrier });
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
68
rpcs3/Emu/RSX/NV47/FW/draw_call.inc.h
Normal file
68
rpcs3/Emu/RSX/NV47/FW/draw_call.inc.h
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
enum class draw_command
|
||||
{
|
||||
none,
|
||||
array,
|
||||
inlined_array,
|
||||
indexed,
|
||||
};
|
||||
|
||||
enum command_barrier_type : u32
|
||||
{
|
||||
primitive_restart_barrier,
|
||||
vertex_base_modifier_barrier,
|
||||
index_base_modifier_barrier,
|
||||
vertex_array_offset_modifier_barrier
|
||||
};
|
||||
|
||||
enum command_execution_flags : u32
|
||||
{
|
||||
vertex_base_changed = (1 << 0),
|
||||
index_base_changed = (1 << 1),
|
||||
vertex_arrays_changed = (1 << 2),
|
||||
};
|
||||
|
||||
enum class primitive_class
|
||||
{
|
||||
polygon,
|
||||
non_polygon
|
||||
};
|
||||
|
||||
struct barrier_t
|
||||
{
|
||||
u32 draw_id;
|
||||
u64 timestamp;
|
||||
|
||||
u32 address;
|
||||
u32 index;
|
||||
u32 arg;
|
||||
u32 flags;
|
||||
command_barrier_type type;
|
||||
|
||||
bool operator < (const barrier_t& other) const
|
||||
{
|
||||
if (address != ~0u)
|
||||
{
|
||||
return address < other.address;
|
||||
}
|
||||
|
||||
return timestamp < other.timestamp;
|
||||
}
|
||||
|
||||
ENABLE_BITWISE_SERIALIZATION;
|
||||
};
|
||||
|
||||
struct draw_range_t
|
||||
{
|
||||
u32 command_data_offset = 0;
|
||||
u32 first = 0;
|
||||
u32 count = 0;
|
||||
|
||||
ENABLE_BITWISE_SERIALIZATION;
|
||||
};
|
||||
}
|
1
rpcs3/Emu/RSX/NV47/FW/reg_context.cpp
Normal file
1
rpcs3/Emu/RSX/NV47/FW/reg_context.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "stdafx.h"
|
12
rpcs3/Emu/RSX/NV47/FW/reg_context.h
Normal file
12
rpcs3/Emu/RSX/NV47/FW/reg_context.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
// TODO: Basically replaces parts of the current "rsx_state" object
|
||||
struct reg_context
|
||||
{
|
||||
u32 registers[1];
|
||||
};
|
||||
}
|
@ -62,5 +62,25 @@ namespace rsx
|
||||
|
||||
return vm::cast(get_address(offset, location));
|
||||
}
|
||||
|
||||
void set_fragment_texture_dirty_bit(rsx::context* ctx, u32 index)
|
||||
{
|
||||
RSX(ctx)->m_textures_dirty[index] = true;
|
||||
|
||||
if (RSX(ctx)->current_fp_metadata.referenced_textures_mask & (1 << index))
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_program_state_dirty;
|
||||
}
|
||||
}
|
||||
|
||||
void set_vertex_texture_dirty_bit(rsx::context* ctx, u32 index)
|
||||
{
|
||||
RSX(ctx)->m_vertex_textures_dirty[index] = true;
|
||||
|
||||
if (RSX(ctx)->current_vp_metadata.referenced_textures_mask & (1 << index))
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::vertex_program_state_dirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
rpcs3/Emu/RSX/NV47/HW/common.h
Normal file
26
rpcs3/Emu/RSX/NV47/HW/common.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
#include "context.h"
|
||||
#include "context_accessors.define.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
enum command_barrier_type : u32;
|
||||
enum class vertex_base_type : u8;
|
||||
|
||||
namespace util
|
||||
{
|
||||
u32 get_report_data_impl(rsx::context* ctx, u32 offset);
|
||||
|
||||
void push_vertex_data(rsx::context* ctx, u32 attrib_index, u32 channel_select, int count, rsx::vertex_base_type vtype, u32 value);
|
||||
|
||||
void push_draw_parameter_change(rsx::context* ctx, rsx::command_barrier_type type, u32 reg, u32 arg);
|
||||
|
||||
void set_fragment_texture_dirty_bit(rsx::context* ctx, u32 index);
|
||||
|
||||
void set_vertex_texture_dirty_bit(rsx::context* ctx, u32 index);
|
||||
}
|
||||
}
|
||||
|
||||
#include "context_accessors.undef.h"
|
@ -5,6 +5,7 @@
|
||||
namespace rsx
|
||||
{
|
||||
class thread;
|
||||
struct rsx_state;
|
||||
|
||||
#if 0
|
||||
// TODO: Separate GRAPH context from RSX state
|
140
rpcs3/Emu/RSX/NV47/HW/nv0039.cpp
Normal file
140
rpcs3/Emu/RSX/NV47/HW/nv0039.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "stdafx.h"
|
||||
#include "nv0039.h"
|
||||
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/Core/RSXReservationLock.hpp"
|
||||
|
||||
#include "context_accessors.define.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace nv0039
|
||||
{
|
||||
void buffer_notify(context* ctx, u32, u32 arg)
|
||||
{
|
||||
s32 in_pitch = REGS(ctx)->nv0039_input_pitch();
|
||||
s32 out_pitch = REGS(ctx)->nv0039_output_pitch();
|
||||
const u32 line_length = REGS(ctx)->nv0039_line_length();
|
||||
const u32 line_count = REGS(ctx)->nv0039_line_count();
|
||||
const u8 out_format = REGS(ctx)->nv0039_output_format();
|
||||
const u8 in_format = REGS(ctx)->nv0039_input_format();
|
||||
const u32 notify = arg;
|
||||
|
||||
if (!line_count || !line_length)
|
||||
{
|
||||
rsx_log.warning("NV0039_BUFFER_NOTIFY NOPed out: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify);
|
||||
return;
|
||||
}
|
||||
|
||||
rsx_log.trace("NV0039_BUFFER_NOTIFY: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify);
|
||||
|
||||
u32 src_offset = REGS(ctx)->nv0039_input_offset();
|
||||
u32 src_dma = REGS(ctx)->nv0039_input_location();
|
||||
|
||||
u32 dst_offset = REGS(ctx)->nv0039_output_offset();
|
||||
u32 dst_dma = REGS(ctx)->nv0039_output_location();
|
||||
|
||||
const bool is_block_transfer = (in_pitch == out_pitch && out_pitch + 0u == line_length);
|
||||
const auto read_address = get_address(src_offset, src_dma);
|
||||
const auto write_address = get_address(dst_offset, dst_dma);
|
||||
const auto read_length = in_pitch * (line_count - 1) + line_length;
|
||||
const auto write_length = out_pitch * (line_count - 1) + line_length;
|
||||
|
||||
RSX(ctx)->invalidate_fragment_program(dst_dma, dst_offset, write_length);
|
||||
|
||||
if (const auto result = RSX(ctx)->read_barrier(read_address, read_length, !is_block_transfer);
|
||||
result == rsx::result_zcull_intr)
|
||||
{
|
||||
// This transfer overlaps will zcull data pool
|
||||
if (RSX(ctx)->copy_zcull_stats(read_address, read_length, write_address) == write_length)
|
||||
{
|
||||
// All writes deferred
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto res = ::rsx::reservation_lock<true>(write_address, write_length, read_address, read_length);
|
||||
|
||||
u8 *dst = vm::_ptr<u8>(write_address);
|
||||
const u8 *src = vm::_ptr<u8>(read_address);
|
||||
|
||||
const bool is_overlapping = dst_dma == src_dma && [&]() -> bool
|
||||
{
|
||||
const u32 src_max = src_offset + read_length;
|
||||
const u32 dst_max = dst_offset + (out_pitch * (line_count - 1) + line_length);
|
||||
return (src_offset >= dst_offset && src_offset < dst_max) ||
|
||||
(dst_offset >= src_offset && dst_offset < src_max);
|
||||
}();
|
||||
|
||||
if (in_format > 1 || out_format > 1) [[ unlikely ]]
|
||||
{
|
||||
// The formats are just input channel strides. You can use this to do cool tricks like gathering channels
|
||||
// Very rare, only seen in use by Destiny
|
||||
// TODO: Hw accel
|
||||
for (u32 row = 0; row < line_count; ++row)
|
||||
{
|
||||
auto dst_ptr = dst;
|
||||
auto src_ptr = src;
|
||||
while (src_ptr < src + line_length)
|
||||
{
|
||||
*dst_ptr = *src_ptr;
|
||||
|
||||
src_ptr += in_format;
|
||||
dst_ptr += out_format;
|
||||
}
|
||||
|
||||
dst += out_pitch;
|
||||
src += in_pitch;
|
||||
}
|
||||
}
|
||||
else if (is_overlapping) [[ unlikely ]]
|
||||
{
|
||||
if (is_block_transfer)
|
||||
{
|
||||
std::memmove(dst, src, read_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<u8> temp(line_length * line_count);
|
||||
u8* buf = temp.data();
|
||||
|
||||
for (u32 y = 0; y < line_count; ++y)
|
||||
{
|
||||
std::memcpy(buf, src, line_length);
|
||||
buf += line_length;
|
||||
src += in_pitch;
|
||||
}
|
||||
|
||||
buf = temp.data();
|
||||
|
||||
for (u32 y = 0; y < line_count; ++y)
|
||||
{
|
||||
std::memcpy(dst, buf, line_length);
|
||||
buf += line_length;
|
||||
dst += out_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_block_transfer)
|
||||
{
|
||||
std::memcpy(dst, src, read_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < line_count; ++i)
|
||||
{
|
||||
std::memcpy(dst, src, line_length);
|
||||
dst += out_pitch;
|
||||
src += in_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//res->release(0);
|
||||
}
|
||||
}
|
||||
}
|
12
rpcs3/Emu/RSX/NV47/HW/nv0039.h
Normal file
12
rpcs3/Emu/RSX/NV47/HW/nv0039.h
Normal file
@ -0,0 +1,12 @@
|
||||
// NV47 Buffer Management
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace nv0039
|
||||
{
|
||||
void buffer_notify(context* ctx, u32 reg, u32 arg);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
#include "nv3089.h"
|
||||
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/Core/RSXReservationLock.hpp"
|
||||
#include "Emu/RSX/Common/tiled_dma_copy.hpp"
|
||||
|
||||
#include "context_accessors.define.h"
|
||||
|
@ -1,4 +1,6 @@
|
||||
// NV47 2D Blit Engine
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
||||
|
||||
namespace rsx
|
@ -2,6 +2,7 @@
|
||||
#include "nv308a.h"
|
||||
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/Core/RSXReservationLock.hpp"
|
||||
|
||||
#include "context_accessors.define.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
// NV47 Format Conversion
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "nv406e.h"
|
||||
#include "common.h"
|
||||
#include "nv47_sync.hpp"
|
||||
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
// NV47 Sync Objects
|
||||
#pragma once
|
||||
|
||||
#include "context.h"
|
@ -1,5 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "nv4097.h"
|
||||
#include "nv47_sync.hpp"
|
||||
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/Common/BufferUtils.h"
|
||||
@ -10,13 +11,6 @@
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
template<typename Type> struct vertex_data_type_from_element_type;
|
||||
template<> struct vertex_data_type_from_element_type<float> { static const vertex_base_type type = vertex_base_type::f; };
|
||||
template<> struct vertex_data_type_from_element_type<f16> { static const vertex_base_type type = vertex_base_type::sf; };
|
||||
template<> struct vertex_data_type_from_element_type<u8> { static const vertex_base_type type = vertex_base_type::ub; };
|
||||
template<> struct vertex_data_type_from_element_type<u16> { static const vertex_base_type type = vertex_base_type::s32k; };
|
||||
template<> struct vertex_data_type_from_element_type<s16> { static const vertex_base_type type = vertex_base_type::s1; };
|
||||
|
||||
namespace nv4097
|
||||
{
|
||||
///// Program management
|
@ -3,13 +3,22 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "Emu/RSX/gcm_enums.h"
|
||||
#include "Emu/RSX/NV47/FW/draw_call.inc.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
enum command_barrier_type;
|
||||
enum vertex_base_type;
|
||||
enum command_barrier_type : u32;
|
||||
|
||||
namespace nv4097
|
||||
{
|
||||
template<typename Type> struct vertex_data_type_from_element_type;
|
||||
template<> struct vertex_data_type_from_element_type<float> { static const vertex_base_type type = vertex_base_type::f; };
|
||||
template<> struct vertex_data_type_from_element_type<f16> { static const vertex_base_type type = vertex_base_type::sf; };
|
||||
template<> struct vertex_data_type_from_element_type<u8> { static const vertex_base_type type = vertex_base_type::ub; };
|
||||
template<> struct vertex_data_type_from_element_type<u16> { static const vertex_base_type type = vertex_base_type::s32k; };
|
||||
template<> struct vertex_data_type_from_element_type<s16> { static const vertex_base_type type = vertex_base_type::s1; };
|
||||
|
||||
void clear(context* ctx, u32 reg, u32 arg);
|
||||
|
||||
void clear_zcull(context* ctx, u32 reg, u32 arg);
|
||||
@ -109,7 +118,7 @@ namespace rsx
|
||||
arg = (be_data << 16) | (be_data >> 16);
|
||||
}
|
||||
|
||||
util::push_vertex_data(attribute_index, vertex_subreg, count, vtype);
|
||||
util::push_vertex_data(ctx, attribute_index, vertex_subreg, count, vtype, arg);
|
||||
}
|
||||
|
||||
template<u32 index>
|
||||
@ -207,14 +216,9 @@ namespace rsx
|
||||
template<u32 index>
|
||||
struct set_texture_dirty_bit
|
||||
{
|
||||
static void impl(context* ctx, u32 reg, u32 arg)
|
||||
static void impl(context* ctx, u32 /*reg*/, u32 /*arg*/)
|
||||
{
|
||||
RSX(ctx)->m_textures_dirty[index] = true;
|
||||
|
||||
if (RSX(ctx)->current_fp_metadata.referenced_textures_mask & (1 << index))
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_program_state_dirty;
|
||||
}
|
||||
util::set_fragment_texture_dirty_bit(ctx, index);
|
||||
}
|
||||
};
|
||||
|
||||
@ -223,12 +227,7 @@ namespace rsx
|
||||
{
|
||||
static void impl(context* ctx, u32 reg, u32 arg)
|
||||
{
|
||||
RSX(ctx)->m_vertex_textures_dirty[index] = true;
|
||||
|
||||
if (RSX(ctx)->current_vp_metadata.referenced_textures_mask & (1 << index))
|
||||
{
|
||||
RSX(ctx)->m_graphics_state |= rsx::pipeline_state::vertex_program_state_dirty;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
8
rpcs3/Emu/RSX/NV47/HW/nv47.h
Normal file
8
rpcs3/Emu/RSX/NV47/HW/nv47.h
Normal file
@ -0,0 +1,8 @@
|
||||
// RSX Hardware definitions
|
||||
#pragma once
|
||||
|
||||
#include "nv0039.h" // Buffer objects
|
||||
#include "nv3089.h" // Blit engine (2D)
|
||||
#include "nv308a.h" // Format conversion
|
||||
#include "nv406e.h" // Sync objects
|
||||
#include "nv4097.h" // 3D engine (GRAPH)
|
@ -1,24 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
#include "context.h"
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
|
||||
#include "context_accessors.define.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
enum command_barrier_type : u32;
|
||||
enum vertex_base_type;
|
||||
|
||||
namespace util
|
||||
{
|
||||
u32 get_report_data_impl(rsx::context* ctx, u32 offset);
|
||||
|
||||
void push_vertex_data(rsx::context* ctx, u32 attrib_index, u32 channel_select, int count, rsx::vertex_base_type vtype, u32 value);
|
||||
|
||||
void push_draw_parameter_change(rsx::context* ctx, rsx::command_barrier_type type, u32 reg, u32 arg);
|
||||
|
||||
template <bool FlushDMA, bool FlushPipe>
|
||||
void write_gcm_label(context* ctx, u32 address, u32 data)
|
||||
static void write_gcm_label(context* ctx, u32 address, u32 data)
|
||||
{
|
||||
const bool is_flip_sema = (address == (RSX(ctx)->label_addr + 0x10) || address == (RSX(ctx)->device_addr + 0x30));
|
||||
if (!is_flip_sema)
|
@ -1,7 +0,0 @@
|
||||
// 3D Engine definitions
|
||||
#pragma once
|
||||
|
||||
#include "nv3089.h"
|
||||
#include "nv308a.h"
|
||||
#include "nv406e.h"
|
||||
#include "nv4097.h"
|
@ -7,7 +7,7 @@
|
||||
#include "Core/RSXReservationLock.hpp"
|
||||
#include "Emu/Memory/vm_reservation.h"
|
||||
#include "Emu/Cell/lv2/sys_rsx.h"
|
||||
#include "NV47/context.h"
|
||||
#include "NV47/HW/context.h"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
@ -810,9 +810,6 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This should be properly managed
|
||||
rsx::context ctx{ .rsxthr = this, .register_state = &method_registers };
|
||||
|
||||
if (m_flattener.is_enabled()) [[unlikely]]
|
||||
{
|
||||
switch(m_flattener.test(command))
|
||||
@ -825,14 +822,14 @@ namespace rsx
|
||||
{
|
||||
// Emit end command to close existing scope
|
||||
AUDIT(in_begin_end);
|
||||
methods[NV4097_SET_BEGIN_END](&ctx, NV4097_SET_BEGIN_END, 0);
|
||||
methods[NV4097_SET_BEGIN_END](m_ctx, NV4097_SET_BEGIN_END, 0);
|
||||
break;
|
||||
}
|
||||
case FIFO::EMIT_BARRIER:
|
||||
{
|
||||
AUDIT(in_begin_end);
|
||||
methods[NV4097_SET_BEGIN_END](&ctx, NV4097_SET_BEGIN_END, 0);
|
||||
methods[NV4097_SET_BEGIN_END](&ctx, NV4097_SET_BEGIN_END, m_flattener.get_primitive());
|
||||
methods[NV4097_SET_BEGIN_END](m_ctx, NV4097_SET_BEGIN_END, 0);
|
||||
methods[NV4097_SET_BEGIN_END](m_ctx, NV4097_SET_BEGIN_END, m_flattener.get_primitive());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -851,19 +848,19 @@ namespace rsx
|
||||
const u32 reg = (command.reg & 0xffff) >> 2;
|
||||
const u32 value = command.value;
|
||||
|
||||
ctx.register_state->decode(reg, value);
|
||||
m_ctx->register_state->decode(reg, value);
|
||||
|
||||
if (auto method = methods[reg])
|
||||
{
|
||||
method(&ctx, reg, value);
|
||||
method(m_ctx, reg, value);
|
||||
|
||||
if (state & cpu_flag::again)
|
||||
{
|
||||
ctx.register_state->decode(reg, ctx.register_state->latch);
|
||||
m_ctx->register_state->decode(reg, m_ctx->register_state->latch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ctx.register_state->latch != value)
|
||||
else if (m_ctx->register_state->latch != value)
|
||||
{
|
||||
// Something changed, set signal flags if any specified
|
||||
m_graphics_state |= state_signals[reg];
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Crypto/unzip.h"
|
||||
#include "NV47/HW/context.h"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
|
||||
@ -122,6 +123,9 @@ namespace rsx
|
||||
{
|
||||
std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
|
||||
// TODO: Proper context manager
|
||||
static rsx::context s_ctx{ .rsxthr = nullptr, .register_state = &method_registers };
|
||||
|
||||
rsx_iomap_table::rsx_iomap_table() noexcept
|
||||
: ea(fill_array(-1))
|
||||
, io(fill_array(-1))
|
||||
@ -675,6 +679,10 @@ namespace rsx
|
||||
|
||||
g_user_asked_for_frame_capture = false;
|
||||
|
||||
// TODO: Proper context management in the driver
|
||||
s_ctx.rsxthr = this;
|
||||
m_ctx = &s_ctx;
|
||||
|
||||
if (g_cfg.misc.use_native_interface && (g_cfg.video.renderer == video_renderer::opengl || g_cfg.video.renderer == video_renderer::vulkan))
|
||||
{
|
||||
m_overlay_manager = g_fxo->init<rsx::overlays::display_manager>(0);
|
||||
@ -813,7 +821,7 @@ namespace rsx
|
||||
in_begin_end = false;
|
||||
m_frame_stats.draw_calls++;
|
||||
|
||||
method_registers.current_draw_clause.post_execute_cleanup();
|
||||
method_registers.current_draw_clause.post_execute_cleanup(m_ctx);
|
||||
|
||||
m_graphics_state |= rsx::pipeline_state::framebuffer_reads_dirty;
|
||||
m_eng_interrupt_mask |= rsx::backend_interrupt;
|
||||
@ -848,7 +856,7 @@ namespace rsx
|
||||
method_registers.current_draw_clause.begin();
|
||||
do
|
||||
{
|
||||
method_registers.current_draw_clause.execute_pipeline_dependencies();
|
||||
method_registers.current_draw_clause.execute_pipeline_dependencies(m_ctx);
|
||||
}
|
||||
while (method_registers.current_draw_clause.next());
|
||||
}
|
||||
@ -918,7 +926,7 @@ namespace rsx
|
||||
|
||||
namespace nv4097
|
||||
{
|
||||
void set_render_mode(thread* rsx, u32, u32 arg);
|
||||
void set_render_mode(context* rsx, u32, u32 arg);
|
||||
}
|
||||
|
||||
void thread::on_task()
|
||||
@ -958,7 +966,7 @@ namespace rsx
|
||||
}
|
||||
|
||||
check_zcull_status(false);
|
||||
nv4097::set_render_mode(this, 0, method_registers.registers[NV4097_SET_RENDER_ENABLE]);
|
||||
nv4097::set_render_mode(m_ctx, 0, method_registers.registers[NV4097_SET_RENDER_ENABLE]);
|
||||
|
||||
performance_counters.state = FIFO::state::empty;
|
||||
|
||||
@ -2674,7 +2682,7 @@ namespace rsx
|
||||
{
|
||||
rsx::method_registers.reset();
|
||||
check_zcull_status(false);
|
||||
nv4097::set_render_mode(this, 0, method_registers.registers[NV4097_SET_RENDER_ENABLE]);
|
||||
nv4097::set_render_mode(m_ctx, 0, method_registers.registers[NV4097_SET_RENDER_ENABLE]);
|
||||
m_graphics_state |= pipeline_state::all_dirty;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,8 @@ extern rsx::frame_capture_data frame_capture;
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
struct context;
|
||||
|
||||
namespace overlays
|
||||
{
|
||||
class display_manager;
|
||||
@ -204,6 +206,9 @@ namespace rsx
|
||||
// Savestates related
|
||||
u32 m_pause_after_x_flips = 0;
|
||||
|
||||
// Context
|
||||
context* m_ctx = nullptr;
|
||||
|
||||
public:
|
||||
atomic_t<u64> new_get_put = u64{umax};
|
||||
u32 restore_point = 0;
|
||||
|
@ -707,7 +707,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
||||
m_profiler.start();
|
||||
|
||||
const rsx::flags32_t vertex_state_mask = rsx::vertex_base_changed | rsx::vertex_arrays_changed;
|
||||
const rsx::flags32_t vertex_state = (sub_index == 0) ? rsx::vertex_arrays_changed : draw_call.execute_pipeline_dependencies() & vertex_state_mask;
|
||||
const rsx::flags32_t vertex_state = (sub_index == 0) ? rsx::vertex_arrays_changed : draw_call.execute_pipeline_dependencies(m_ctx) & vertex_state_mask;
|
||||
|
||||
if (vertex_state & rsx::vertex_arrays_changed)
|
||||
{
|
||||
@ -738,7 +738,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
|
||||
// Execute remainining pipeline barriers with NOP draw
|
||||
do
|
||||
{
|
||||
draw_call.execute_pipeline_dependencies();
|
||||
draw_call.execute_pipeline_dependencies(m_ctx);
|
||||
}
|
||||
while (draw_call.next());
|
||||
|
||||
|
@ -4,14 +4,13 @@
|
||||
#include "rsx_utils.h"
|
||||
#include "rsx_decode.h"
|
||||
#include "Common/time.hpp"
|
||||
#include "Common/tiled_dma_copy.hpp"
|
||||
#include "Core/RSXReservationLock.hpp"
|
||||
#include "Emu/Cell/PPUCallback.h"
|
||||
#include "Emu/Cell/lv2/sys_rsx.h"
|
||||
#include "Emu/RSX/Common/BufferUtils.h"
|
||||
|
||||
#include "Emu/RSX/NV47/nv47.h"
|
||||
#include "Emu/RSX/NV47/context_accessors.define.h"
|
||||
#include "Emu/RSX/NV47/HW/nv47.h"
|
||||
#include "Emu/RSX/NV47/HW/nv47_sync.hpp"
|
||||
#include "Emu/RSX/NV47/HW/context_accessors.define.h" // TODO: Context objects belong in FW not HW
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
@ -42,132 +41,7 @@ namespace rsx
|
||||
|
||||
namespace nv0039
|
||||
{
|
||||
void buffer_notify(context* ctx, u32, u32 arg)
|
||||
{
|
||||
s32 in_pitch = REGS(ctx)->nv0039_input_pitch();
|
||||
s32 out_pitch = REGS(ctx)->nv0039_output_pitch();
|
||||
const u32 line_length = REGS(ctx)->nv0039_line_length();
|
||||
const u32 line_count = REGS(ctx)->nv0039_line_count();
|
||||
const u8 out_format = REGS(ctx)->nv0039_output_format();
|
||||
const u8 in_format = REGS(ctx)->nv0039_input_format();
|
||||
const u32 notify = arg;
|
||||
|
||||
if (!line_count || !line_length)
|
||||
{
|
||||
rsx_log.warning("NV0039_BUFFER_NOTIFY NOPed out: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify);
|
||||
return;
|
||||
}
|
||||
|
||||
rsx_log.trace("NV0039_BUFFER_NOTIFY: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify);
|
||||
|
||||
u32 src_offset = REGS(ctx)->nv0039_input_offset();
|
||||
u32 src_dma = REGS(ctx)->nv0039_input_location();
|
||||
|
||||
u32 dst_offset = REGS(ctx)->nv0039_output_offset();
|
||||
u32 dst_dma = REGS(ctx)->nv0039_output_location();
|
||||
|
||||
const bool is_block_transfer = (in_pitch == out_pitch && out_pitch + 0u == line_length);
|
||||
const auto read_address = get_address(src_offset, src_dma);
|
||||
const auto write_address = get_address(dst_offset, dst_dma);
|
||||
const auto read_length = in_pitch * (line_count - 1) + line_length;
|
||||
const auto write_length = out_pitch * (line_count - 1) + line_length;
|
||||
|
||||
RSX(ctx)->invalidate_fragment_program(dst_dma, dst_offset, write_length);
|
||||
|
||||
if (const auto result = RSX(ctx)->read_barrier(read_address, read_length, !is_block_transfer);
|
||||
result == rsx::result_zcull_intr)
|
||||
{
|
||||
// This transfer overlaps will zcull data pool
|
||||
if (RSX(ctx)->copy_zcull_stats(read_address, read_length, write_address) == write_length)
|
||||
{
|
||||
// All writes deferred
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto res = ::rsx::reservation_lock<true>(write_address, write_length, read_address, read_length);
|
||||
|
||||
u8 *dst = vm::_ptr<u8>(write_address);
|
||||
const u8 *src = vm::_ptr<u8>(read_address);
|
||||
|
||||
const bool is_overlapping = dst_dma == src_dma && [&]() -> bool
|
||||
{
|
||||
const u32 src_max = src_offset + read_length;
|
||||
const u32 dst_max = dst_offset + (out_pitch * (line_count - 1) + line_length);
|
||||
return (src_offset >= dst_offset && src_offset < dst_max) ||
|
||||
(dst_offset >= src_offset && dst_offset < src_max);
|
||||
}();
|
||||
|
||||
if (in_format > 1 || out_format > 1) [[ unlikely ]]
|
||||
{
|
||||
// The formats are just input channel strides. You can use this to do cool tricks like gathering channels
|
||||
// Very rare, only seen in use by Destiny
|
||||
// TODO: Hw accel
|
||||
for (u32 row = 0; row < line_count; ++row)
|
||||
{
|
||||
auto dst_ptr = dst;
|
||||
auto src_ptr = src;
|
||||
while (src_ptr < src + line_length)
|
||||
{
|
||||
*dst_ptr = *src_ptr;
|
||||
|
||||
src_ptr += in_format;
|
||||
dst_ptr += out_format;
|
||||
}
|
||||
|
||||
dst += out_pitch;
|
||||
src += in_pitch;
|
||||
}
|
||||
}
|
||||
else if (is_overlapping) [[ unlikely ]]
|
||||
{
|
||||
if (is_block_transfer)
|
||||
{
|
||||
std::memmove(dst, src, read_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<u8> temp(line_length * line_count);
|
||||
u8* buf = temp.data();
|
||||
|
||||
for (u32 y = 0; y < line_count; ++y)
|
||||
{
|
||||
std::memcpy(buf, src, line_length);
|
||||
buf += line_length;
|
||||
src += in_pitch;
|
||||
}
|
||||
|
||||
buf = temp.data();
|
||||
|
||||
for (u32 y = 0; y < line_count; ++y)
|
||||
{
|
||||
std::memcpy(dst, buf, line_length);
|
||||
buf += line_length;
|
||||
dst += out_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_block_transfer)
|
||||
{
|
||||
std::memcpy(dst, src, read_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < line_count; ++i)
|
||||
{
|
||||
std::memcpy(dst, src, line_length);
|
||||
dst += out_pitch;
|
||||
src += in_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//res->release(0);
|
||||
}
|
||||
}
|
||||
|
||||
void flip_command(context* ctx, u32, u32 arg)
|
||||
@ -1414,7 +1288,7 @@ namespace rsx
|
||||
is_disjoint_primitive = is_primitive_disjointed(primitive);
|
||||
}
|
||||
|
||||
u32 draw_clause::execute_pipeline_dependencies() const
|
||||
u32 draw_clause::execute_pipeline_dependencies(context* ctx) const
|
||||
{
|
||||
u32 result = 0;
|
||||
|
||||
@ -1974,7 +1848,8 @@ namespace rsx
|
||||
// FIFO
|
||||
bind(FIFO::FIFO_DRAW_BARRIER >> 2, fifo::draw_barrier);
|
||||
|
||||
REGS(ctx)->init();
|
||||
// REGS(ctx)->init();
|
||||
method_registers.init();
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
@ -10,372 +10,11 @@
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
#include "Program/program_util.h"
|
||||
|
||||
#include "NV47/FW/draw_call.hpp"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
enum class draw_command
|
||||
{
|
||||
none,
|
||||
array,
|
||||
inlined_array,
|
||||
indexed,
|
||||
};
|
||||
|
||||
enum command_barrier_type : u32
|
||||
{
|
||||
primitive_restart_barrier,
|
||||
vertex_base_modifier_barrier,
|
||||
index_base_modifier_barrier,
|
||||
vertex_array_offset_modifier_barrier
|
||||
};
|
||||
|
||||
enum command_execution_flags : u32
|
||||
{
|
||||
vertex_base_changed = (1 << 0),
|
||||
index_base_changed = (1 << 1),
|
||||
vertex_arrays_changed = (1 << 2),
|
||||
};
|
||||
|
||||
enum class primitive_class
|
||||
{
|
||||
polygon,
|
||||
non_polygon
|
||||
};
|
||||
|
||||
struct barrier_t
|
||||
{
|
||||
u32 draw_id;
|
||||
u64 timestamp;
|
||||
|
||||
u32 address;
|
||||
u32 index;
|
||||
u32 arg;
|
||||
u32 flags;
|
||||
command_barrier_type type;
|
||||
|
||||
bool operator < (const barrier_t& other) const
|
||||
{
|
||||
if (address != ~0u)
|
||||
{
|
||||
return address < other.address;
|
||||
}
|
||||
|
||||
return timestamp < other.timestamp;
|
||||
}
|
||||
|
||||
ENABLE_BITWISE_SERIALIZATION;
|
||||
};
|
||||
|
||||
struct draw_range_t
|
||||
{
|
||||
u32 command_data_offset = 0;
|
||||
u32 first = 0;
|
||||
u32 count = 0;
|
||||
|
||||
ENABLE_BITWISE_SERIALIZATION;
|
||||
};
|
||||
|
||||
class draw_clause
|
||||
{
|
||||
// Stores the first and count argument from draw/draw indexed parameters between begin/end clauses.
|
||||
simple_array<draw_range_t> draw_command_ranges{};
|
||||
|
||||
// Stores rasterization barriers for primitive types sensitive to adjacency
|
||||
simple_array<barrier_t> draw_command_barriers{};
|
||||
|
||||
// Counter used to parse the commands in order
|
||||
u32 current_range_index{};
|
||||
|
||||
// Location of last execution barrier
|
||||
u32 last_execution_barrier_index{};
|
||||
|
||||
// Helper functions
|
||||
// Add a new draw command
|
||||
void append_draw_command(const draw_range_t& range)
|
||||
{
|
||||
current_range_index = draw_command_ranges.size();
|
||||
draw_command_ranges.push_back(range);
|
||||
}
|
||||
|
||||
// Insert a new draw command within the others
|
||||
void insert_draw_command(u32 index, const draw_range_t& range)
|
||||
{
|
||||
auto range_It = draw_command_ranges.begin();
|
||||
std::advance(range_It, index);
|
||||
|
||||
current_range_index = index;
|
||||
draw_command_ranges.insert(range_It, range);
|
||||
|
||||
// Update all barrier draw ids after this one
|
||||
for (auto &barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id >= index)
|
||||
{
|
||||
barrier.draw_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
primitive_type primitive{};
|
||||
draw_command command{};
|
||||
|
||||
bool is_immediate_draw{}; // Set if part of the draw is submitted via push registers
|
||||
bool is_disjoint_primitive{}; // Set if primitive type does not rely on adjacency information
|
||||
bool primitive_barrier_enable{}; // Set once to signal that a primitive restart barrier can be inserted
|
||||
|
||||
simple_array<u32> inline_vertex_array{};
|
||||
|
||||
void operator()(utils::serial& ar);
|
||||
|
||||
void insert_command_barrier(command_barrier_type type, u32 arg, u32 register_index = 0);
|
||||
|
||||
/**
|
||||
* Optimize commands for rendering
|
||||
*/
|
||||
void compile()
|
||||
{
|
||||
// End draw call append mode
|
||||
current_range_index = ~0u;
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert one command range
|
||||
*/
|
||||
|
||||
void append(u32 first, u32 count)
|
||||
{
|
||||
const bool barrier_enable_flag = primitive_barrier_enable;
|
||||
primitive_barrier_enable = false;
|
||||
|
||||
if (!draw_command_ranges.empty())
|
||||
{
|
||||
auto& last = draw_command_ranges[current_range_index];
|
||||
|
||||
if (last.count == 0)
|
||||
{
|
||||
// Special case, usually indicates an execution barrier
|
||||
last.first = first;
|
||||
last.count = count;
|
||||
return;
|
||||
}
|
||||
|
||||
if (last.first + last.count == first)
|
||||
{
|
||||
if (!is_disjoint_primitive && barrier_enable_flag)
|
||||
{
|
||||
// Insert barrier
|
||||
insert_command_barrier(primitive_restart_barrier, 0);
|
||||
}
|
||||
|
||||
last.count += count;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto index = last_execution_barrier_index; index < draw_command_ranges.size(); ++index)
|
||||
{
|
||||
if (draw_command_ranges[index].first == first &&
|
||||
draw_command_ranges[index].count == count)
|
||||
{
|
||||
// Duplicate entry? WTF!
|
||||
return;
|
||||
}
|
||||
|
||||
if (draw_command_ranges[index].first > first)
|
||||
{
|
||||
insert_draw_command(index, { 0, first, count });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
append_draw_command({ 0, first, count });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many vertex or index will be consumed by the draw clause.
|
||||
*/
|
||||
u32 get_elements_count() const
|
||||
{
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(command == rsx::draw_command::inlined_array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_range().count;
|
||||
}
|
||||
|
||||
u32 min_index() const
|
||||
{
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(command == rsx::draw_command::inlined_array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_range().first;
|
||||
}
|
||||
|
||||
bool is_single_draw() const
|
||||
{
|
||||
if (is_disjoint_primitive)
|
||||
return true;
|
||||
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(!inline_vertex_array.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
ensure(current_range_index != ~0u);
|
||||
for (const auto &barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id != current_range_index)
|
||||
continue;
|
||||
|
||||
if (barrier.type == primitive_restart_barrier)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return (command == rsx::draw_command::inlined_array) ? inline_vertex_array.empty() : draw_command_ranges.empty();
|
||||
}
|
||||
|
||||
u32 pass_count() const
|
||||
{
|
||||
if (draw_command_ranges.empty())
|
||||
{
|
||||
ensure(!inline_vertex_array.empty());
|
||||
return 1u;
|
||||
}
|
||||
|
||||
u32 count = ::size32(draw_command_ranges);
|
||||
if (draw_command_ranges.back().count == 0)
|
||||
{
|
||||
// Dangling barrier
|
||||
ensure(count > 1);
|
||||
count--;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
primitive_class classify_mode() const
|
||||
{
|
||||
return primitive >= rsx::primitive_type::triangles
|
||||
? primitive_class::polygon
|
||||
: primitive_class::non_polygon;
|
||||
}
|
||||
|
||||
|
||||
void reset(rsx::primitive_type type);
|
||||
|
||||
void begin()
|
||||
{
|
||||
current_range_index = 0;
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
current_range_index = draw_command_ranges.size() - 1;
|
||||
}
|
||||
|
||||
bool next()
|
||||
{
|
||||
current_range_index++;
|
||||
if (current_range_index >= draw_command_ranges.size())
|
||||
{
|
||||
current_range_index = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (draw_command_ranges[current_range_index].count == 0)
|
||||
{
|
||||
// Dangling execution barrier
|
||||
ensure(current_range_index > 0 && (current_range_index + 1) == draw_command_ranges.size());
|
||||
current_range_index = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call this once after the draw clause has been fully consumed to reconcile any conflicts
|
||||
*/
|
||||
void post_execute_cleanup()
|
||||
{
|
||||
ensure(current_range_index == 0);
|
||||
|
||||
if (draw_command_ranges.size() > 1)
|
||||
{
|
||||
if (draw_command_ranges.back().count == 0)
|
||||
{
|
||||
// Dangling execution barrier
|
||||
current_range_index = draw_command_ranges.size() - 1;
|
||||
execute_pipeline_dependencies();
|
||||
current_range_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes commands reqiured to make the current draw state valid
|
||||
*/
|
||||
u32 execute_pipeline_dependencies() const;
|
||||
|
||||
const draw_range_t& get_range() const
|
||||
{
|
||||
ensure(current_range_index < draw_command_ranges.size());
|
||||
return draw_command_ranges[current_range_index];
|
||||
}
|
||||
|
||||
simple_array<draw_range_t> get_subranges() const
|
||||
{
|
||||
ensure(!is_single_draw());
|
||||
|
||||
const auto range = get_range();
|
||||
const auto limit = range.first + range.count;
|
||||
|
||||
simple_array<draw_range_t> ret;
|
||||
u32 previous_barrier = range.first;
|
||||
u32 vertex_counter = 0;
|
||||
|
||||
for (const auto &barrier : draw_command_barriers)
|
||||
{
|
||||
if (barrier.draw_id != current_range_index)
|
||||
continue;
|
||||
|
||||
if (barrier.type != primitive_restart_barrier)
|
||||
continue;
|
||||
|
||||
if (barrier.address <= range.first)
|
||||
continue;
|
||||
|
||||
if (barrier.address >= limit)
|
||||
break;
|
||||
|
||||
const u32 count = barrier.address - previous_barrier;
|
||||
ret.push_back({ 0, vertex_counter, count });
|
||||
previous_barrier = barrier.address;
|
||||
vertex_counter += count;
|
||||
}
|
||||
|
||||
ensure(!ret.empty());
|
||||
ensure(previous_barrier < limit);
|
||||
ret.push_back({ 0, vertex_counter, limit - previous_barrier });
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
using rsx_method_t = void(*)(class context*, u32 reg, u32 arg);
|
||||
using rsx_method_t = void(*)(struct context*, u32 reg, u32 arg);
|
||||
|
||||
//TODO
|
||||
union alignas(4) method_registers_t
|
||||
|
@ -95,11 +95,13 @@
|
||||
<ClCompile Include="Emu\perf_monitor.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\texture_cache.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Core\RSXContext.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\common.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\nv3089.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\nv308a.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\nv406e.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\nv4097.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\FW\reg_context.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\common.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv0039.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv3089.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv308a.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv406e.cpp" />
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv4097.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_components.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.cpp" />
|
||||
@ -589,15 +591,20 @@
|
||||
<ClInclude Include="Emu\RSX\Core\RSXDisplay.h" />
|
||||
<ClInclude Include="Emu\RSX\Core\RSXReservationLock.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Core\RSXVertexTypes.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\context.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\context_accessors.define.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\context_accessors.undef.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\nv3089.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\nv308a.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\nv406e.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\nv4097.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\nv47.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\common.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\FW\draw_call.hpp" />
|
||||
<ClInclude Include="Emu\RSX\NV47\FW\draw_call.inc.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\FW\reg_context.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\context.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\context_accessors.define.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\context_accessors.undef.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv0039.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv3089.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv308a.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv406e.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv4097.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv47.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\common.h" />
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv47_sync.hpp" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_components.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\HomeMenu\overlay_home_menu_message_box.h" />
|
||||
|
@ -100,6 +100,12 @@
|
||||
<Filter Include="Emu\GPU\RSX\NV47">
|
||||
<UniqueIdentifier>{213387bd-09c5-4247-8fb0-b3cae06ba34b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Emu\GPU\RSX\NV47\HW">
|
||||
<UniqueIdentifier>{24fc03a5-0469-4b6e-89df-44459e51855f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Emu\GPU\RSX\NV47\FW">
|
||||
<UniqueIdentifier>{fdb8ff8f-5a03-45a2-8c0a-16a89b7a574b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Crypto\aes.cpp">
|
||||
@ -1213,20 +1219,26 @@
|
||||
<ClCompile Include="Emu\RSX\Program\SPIRVCommon.cpp">
|
||||
<Filter>Emu\GPU\RSX\Program</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\nv4097.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\common.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\common.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv0039.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\nv406e.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv308a.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\nv308a.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv406e.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\nv3089.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv3089.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\HW\nv4097.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\NV47\FW\reg_context.cpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\FW</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -2467,32 +2479,47 @@
|
||||
<ClInclude Include="Emu\RSX\Program\SPIRVCommon.h">
|
||||
<Filter>Emu\GPU\RSX\Program</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\nv47.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\common.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\nv4097.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\context.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\nv406e.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\context_accessors.define.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\nv3089.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\context_accessors.undef.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\nv308a.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv0039.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\context.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv47.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\common.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv47_sync.hpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\context_accessors.define.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv308a.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\context_accessors.undef.h">
|
||||
<Filter>Emu\GPU\RSX\NV47</Filter>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv406e.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv3089.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\HW\nv4097.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\HW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\FW\draw_call.inc.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\FW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\FW\reg_context.h">
|
||||
<Filter>Emu\GPU\RSX\NV47\FW</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\NV47\FW\draw_call.hpp">
|
||||
<Filter>Emu\GPU\RSX\NV47\FW</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user