#include "stdafx.h" #include "draw_call.hpp" #include "Emu/RSX/rsx_methods.h" // FIXME #include "Emu/RSX/rsx_utils.h" #include "Emu/RSX/RSXThread.h" #include "Emu/RSX/Common/BufferUtils.h" #include "Emu/RSX/NV47/HW/context.h" #include "Emu/RSX/NV47/HW/nv4097.h" // Always import this after other HW definitions #include "Emu/RSX/NV47/HW/context_accessors.define.h" #include namespace rsx { void draw_clause::operator()(utils::serial& ar) { ar(draw_command_ranges, draw_command_barriers, current_range_index, primitive, command, is_immediate_draw, is_disjoint_primitive, primitive_barrier_enable, inline_vertex_array); } void draw_clause::insert_command_barrier(command_barrier_type type, u32 arg0, u32 arg1, u32 index) { ensure(!draw_command_ranges.empty()); auto _do_barrier_insert = [this](barrier_t&& val) { if (draw_command_barriers.empty() || draw_command_barriers.back() < val) { draw_command_barriers.push_back(val); return; } for (auto it = draw_command_barriers.begin(); it != draw_command_barriers.end(); it++) { if (*it < val) { continue; } draw_command_barriers.insert(it, val); break; } }; if (type == primitive_restart_barrier) { // Rasterization flow barrier const auto& last = draw_command_ranges[current_range_index]; const auto address = last.first + last.count; _do_barrier_insert({ .draw_id = current_range_index, .timestamp = 0, .address = address, .index = index, .arg0 = arg0, .arg1 = arg1, .flags = 0, .type = type }); } else { // Execution dependency barrier. Requires breaking the current draw call sequence and start another. if (draw_command_ranges.back().count > 0) { append_draw_command({}); } else { // In case of back-to-back modifiers, do not add duplicates current_range_index = draw_command_ranges.size() - 1; } _do_barrier_insert({ .draw_id = current_range_index, .timestamp = rsx::get_shared_tag(), .address = ~0u, .index = index, .arg0 = arg0, .arg1 = arg1, .flags = 0, .type = type }); last_execution_barrier_index = current_range_index; } } void draw_clause::reset(primitive_type type) { current_range_index = ~0u; last_execution_barrier_index = 0; command = draw_command::none; primitive = type; primitive_barrier_enable = false; draw_command_ranges.clear(); draw_command_barriers.clear(); inline_vertex_array.clear(); is_disjoint_primitive = is_primitive_disjointed(primitive); } u32 draw_clause::execute_pipeline_dependencies(context* ctx) const { u32 result = 0u; for (; current_barrier_it != draw_command_barriers.end() && current_barrier_it->draw_id == current_range_index; current_barrier_it++) { const auto& barrier = *current_barrier_it; switch (barrier.type) { case primitive_restart_barrier: { break; } case index_base_modifier_barrier: { // Change index base offset REGS(ctx)->decode(NV4097_SET_VERTEX_DATA_BASE_INDEX, barrier.arg0); result |= index_base_changed; break; } case vertex_base_modifier_barrier: { // Change vertex base offset REGS(ctx)->decode(NV4097_SET_VERTEX_DATA_BASE_OFFSET, barrier.arg0); result |= vertex_base_changed; break; } case vertex_array_offset_modifier_barrier: { // Change vertex array offset REGS(ctx)->decode(NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + barrier.index, barrier.arg0); result |= vertex_arrays_changed; break; } case transform_constant_load_modifier_barrier: { // Change the transform load target. Does not change result mask. REGS(ctx)->decode(NV4097_SET_TRANSFORM_PROGRAM_LOAD, barrier.arg0); break; } case transform_constant_update_barrier: { // Update transform constants auto ptr = RSX(ctx)->fifo_ctrl->translate_address(barrier.arg0); auto buffer = std::span(static_cast(vm::base(ptr)), barrier.arg1); nv4097::set_transform_constant::batch_decode(ctx, NV4097_SET_TRANSFORM_CONSTANT + barrier.index, buffer); result |= transform_constants_changed; break; } default: fmt::throw_exception("Unreachable"); } } return result; } }