mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-16 03:38:38 +12:00
rsx-capture: reduce capture size
* Dont bother capturing 'destination' blocks with no data. instead premap all main memory to ensure allocated * Capture zcull and tile state as their compressed gcm forms * Fix index array capturing, ignore empty sets * hle gcm: Fix byteswaping in cellGcmSetZcull
This commit is contained in:
parent
32059bfaa2
commit
b48a4b6459
6 changed files with 100 additions and 400 deletions
|
@ -13,40 +13,11 @@ namespace rsx
|
||||||
{
|
{
|
||||||
namespace capture
|
namespace capture
|
||||||
{
|
{
|
||||||
u32 get_io_offset(u32 offset, u32 location)
|
|
||||||
{
|
|
||||||
switch (location)
|
|
||||||
{
|
|
||||||
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
|
|
||||||
case CELL_GCM_LOCATION_MAIN:
|
|
||||||
{
|
|
||||||
if (u32 result = RSXIOMem.RealAddr(offset))
|
|
||||||
{
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
|
|
||||||
{
|
|
||||||
if (u32 result = RSXIOMem.RealAddr(0x0e000000 + offset))
|
|
||||||
{
|
|
||||||
return 0x0e000000 + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: return 0xFFFFFFFFu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert_mem_block_in_map(std::unordered_set<u64>& mem_changes, frame_capture_data::memory_block&& block, frame_capture_data::memory_block_data&& data)
|
void insert_mem_block_in_map(std::unordered_set<u64>& mem_changes, frame_capture_data::memory_block&& block, frame_capture_data::memory_block_data&& data)
|
||||||
{
|
{
|
||||||
u64 data_hash = 0;
|
|
||||||
if (data.data.size() > 0)
|
if (data.data.size() > 0)
|
||||||
{
|
{
|
||||||
data_hash = XXH64(data.data.data(), data.data.size(), 0);
|
u64 data_hash = XXH64(data.data.data(), data.data.size(), 0);
|
||||||
// using 0 to signify no block in use, so this one is 'reserved'
|
|
||||||
if (data_hash == 0)
|
|
||||||
fmt::throw_exception("Memory block data hash equal to 0");
|
|
||||||
|
|
||||||
block.size = data.data.size();
|
|
||||||
block.data_state = data_hash;
|
block.data_state = data_hash;
|
||||||
|
|
||||||
auto it = frame_capture.memory_data_map.find(data_hash);
|
auto it = frame_capture.memory_data_map.find(data_hash);
|
||||||
|
@ -58,13 +29,13 @@ namespace rsx
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
frame_capture.memory_data_map.insert(std::make_pair(data_hash, std::move(data)));
|
frame_capture.memory_data_map.insert(std::make_pair(data_hash, std::move(data)));
|
||||||
}
|
|
||||||
|
|
||||||
u64 block_hash = XXH64(&block, sizeof(frame_capture_data::memory_block), 0);
|
u64 block_hash = XXH64(&block, sizeof(frame_capture_data::memory_block), 0);
|
||||||
mem_changes.insert(block_hash);
|
mem_changes.insert(block_hash);
|
||||||
if (frame_capture.memory_map.find(block_hash) == frame_capture.memory_map.end())
|
if (frame_capture.memory_map.find(block_hash) == frame_capture.memory_map.end())
|
||||||
frame_capture.memory_map.insert(std::make_pair(block_hash, std::move(block)));
|
frame_capture.memory_map.insert(std::make_pair(block_hash, std::move(block)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void capture_draw_memory(thread* rsx)
|
void capture_draw_memory(thread* rsx)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +62,7 @@ namespace rsx
|
||||||
const u32 ucode_size = program_info.program_ucode_length;
|
const u32 ucode_size = program_info.program_ucode_length;
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = program_offset,
|
block.offset = program_offset;
|
||||||
block.location = program_location;
|
block.location = program_location;
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(ucode_size + program_start);
|
block_data.data.resize(ucode_size + program_start);
|
||||||
|
@ -118,9 +89,8 @@ namespace rsx
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = tex.offset();
|
block.offset = tex.offset();
|
||||||
block.location = tex.location();
|
block.location = tex.location();
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(texSize);
|
block_data.data.resize(texSize);
|
||||||
std::memcpy(block_data.data.data(), vm::base(texaddr), texSize);
|
std::memcpy(block_data.data.data(), vm::base(texaddr), texSize);
|
||||||
|
@ -145,7 +115,7 @@ namespace rsx
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = tex.offset();
|
block.offset = tex.offset();
|
||||||
block.location = tex.location();
|
block.location = tex.location();
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(texSize);
|
block_data.data.resize(texSize);
|
||||||
|
@ -183,12 +153,11 @@ namespace rsx
|
||||||
const size_t bufferSize = vertCount * vertStride + vertSize;
|
const size_t bufferSize = vertCount * vertStride + vertSize;
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = base_address;
|
block.offset = base_address + (range.first * vertStride);
|
||||||
block.location = memory_location;
|
block.location = memory_location;
|
||||||
block.offset = (range.first * vertStride);
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(bufferSize);
|
block_data.data.resize(bufferSize);
|
||||||
std::memcpy(block_data.data.data(), vm::base(addr + block.offset), bufferSize);
|
std::memcpy(block_data.data.data(), vm::base(addr + (range.first * vertStride)), bufferSize);
|
||||||
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
|
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
|
||||||
}
|
}
|
||||||
while (method_registers.current_draw_clause.next());
|
while (method_registers.current_draw_clause.next());
|
||||||
|
@ -207,9 +176,7 @@ namespace rsx
|
||||||
const auto index_type = method_registers.index_type();
|
const auto index_type = method_registers.index_type();
|
||||||
|
|
||||||
// manually parse index buffer and copy vertex buffer
|
// manually parse index buffer and copy vertex buffer
|
||||||
u32 min_index = 0xFFFF, max_index = 0;
|
u32 min_index = 0xFFFFFFFF, max_index = 0;
|
||||||
if (index_type == index_array_type::u32)
|
|
||||||
min_index = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
const bool is_primitive_restart_enabled = method_registers.restart_index_enabled();
|
const bool is_primitive_restart_enabled = method_registers.restart_index_enabled();
|
||||||
const u32 primitive_restart_index = method_registers.restart_index();
|
const u32 primitive_restart_index = method_registers.restart_index();
|
||||||
|
@ -225,10 +192,8 @@ namespace rsx
|
||||||
const size_t bufferSize = idxCount * type_size;
|
const size_t bufferSize = idxCount * type_size;
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = base_address;
|
block.offset = base_address + (idxFirst * type_size);
|
||||||
block.location = memory_location;
|
block.location = memory_location;
|
||||||
block.offset = (idxFirst * type_size);
|
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(bufferSize);
|
block_data.data.resize(bufferSize);
|
||||||
std::memcpy(block_data.data.data(), vm::base(idxAddr), bufferSize);
|
std::memcpy(block_data.data.data(), vm::base(idxAddr), bufferSize);
|
||||||
|
@ -268,11 +233,8 @@ namespace rsx
|
||||||
}
|
}
|
||||||
while (method_registers.current_draw_clause.next());
|
while (method_registers.current_draw_clause.next());
|
||||||
|
|
||||||
if (min_index > max_index)
|
if (min_index <= max_index)
|
||||||
{
|
{
|
||||||
// ignore?
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u8 index = 0; index < limits::vertex_count; ++index)
|
for (u8 index = 0; index < limits::vertex_count; ++index)
|
||||||
{
|
{
|
||||||
const bool enabled = !!(input_mask & (1 << index));
|
const bool enabled = !!(input_mask & (1 << index));
|
||||||
|
@ -285,28 +247,25 @@ namespace rsx
|
||||||
|
|
||||||
// vert buffer
|
// vert buffer
|
||||||
const u32 vertStride = info.stride();
|
const u32 vertStride = info.stride();
|
||||||
const u32 base_address = get_vertex_offset_from_base(method_registers.vertex_data_base_offset(), info.offset() & 0x7fffffff);
|
const u32 base_address = get_vertex_offset_from_base(method_registers.vertex_data_base_offset(), (info.offset() & 0x7fffffff));
|
||||||
const u32 memory_location = info.offset() >> 31;
|
const u32 memory_location = info.offset() >> 31;
|
||||||
|
|
||||||
const u32 addr = get_address(base_address, memory_location);
|
const u32 addr = get_address(base_address, memory_location);
|
||||||
const u32 vertSize = get_vertex_type_size_on_host(info.type(), info.size());
|
const u32 vertSize = get_vertex_type_size_on_host(info.type(), info.size());
|
||||||
|
|
||||||
const u32 bufferSize = vertStride * (max_index - min_index + 1) + vertSize;
|
const u32 bufferSize = vertStride * (max_index - min_index + 1) + vertSize;
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = base_address;
|
block.offset = base_address + (min_index * vertStride);
|
||||||
block.location = memory_location;
|
block.location = memory_location;
|
||||||
block.offset = (min_index * vertStride);
|
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(bufferSize);
|
block_data.data.resize(bufferSize);
|
||||||
std::memcpy(block_data.data.data(), vm::base(addr + block.offset), bufferSize);
|
std::memcpy(block_data.data.data(), vm::base(addr + (min_index * vertStride)), bufferSize);
|
||||||
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
|
insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
capture_display_tile_state(rsx, frame_capture.replay_commands.back());
|
capture_display_tile_state(rsx, frame_capture.replay_commands.back());
|
||||||
capture_surface_state(rsx, frame_capture.replay_commands.back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// i realize these are a slight copy pasta of the rsx_method implementations but its kinda unavoidable currently
|
// i realize these are a slight copy pasta of the rsx_method implementations but its kinda unavoidable currently
|
||||||
|
@ -314,8 +273,6 @@ namespace rsx
|
||||||
{
|
{
|
||||||
const rsx::blit_engine::transfer_operation operation = method_registers.blit_engine_operation();
|
const rsx::blit_engine::transfer_operation operation = method_registers.blit_engine_operation();
|
||||||
|
|
||||||
const u16 out_x = method_registers.blit_engine_output_x();
|
|
||||||
const u16 out_y = method_registers.blit_engine_output_y();
|
|
||||||
const u16 out_w = method_registers.blit_engine_output_width();
|
const u16 out_w = method_registers.blit_engine_output_width();
|
||||||
const u16 out_h = method_registers.blit_engine_output_height();
|
const u16 out_h = method_registers.blit_engine_output_height();
|
||||||
|
|
||||||
|
@ -344,7 +301,7 @@ namespace rsx
|
||||||
const tiled_region src_region = rsx->get_tiled_address(src_offset + in_offset, src_dma & 0xf);
|
const tiled_region src_region = rsx->get_tiled_address(src_offset + in_offset, src_dma & 0xf);
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = src_region.tile ? src_region.base : src_offset + in_offset;
|
block.offset = src_region.tile ? src_region.base : src_offset + in_offset;
|
||||||
block.location = src_dma & 0xf;
|
block.location = src_dma & 0xf;
|
||||||
|
|
||||||
u8* pixels_src = src_region.tile ? src_region.ptr + src_region.base : src_region.ptr;
|
u8* pixels_src = src_region.tile ? src_region.ptr + src_region.base : src_region.ptr;
|
||||||
|
@ -361,48 +318,6 @@ namespace rsx
|
||||||
std::memcpy(block_data.data.data(), pixels_src, in_pitch * in_h);
|
std::memcpy(block_data.data.data(), pixels_src, in_pitch * in_h);
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
||||||
|
|
||||||
// 'capture' destination to ensure memory is alloc'd and usable in replay
|
|
||||||
u32 dst_offset = 0;
|
|
||||||
u32 dst_dma = 0;
|
|
||||||
rsx::blit_engine::transfer_destination_format dst_color_format;
|
|
||||||
u32 out_pitch = 0;
|
|
||||||
u32 out_alignment = 64;
|
|
||||||
|
|
||||||
switch (method_registers.blit_engine_context_surface())
|
|
||||||
{
|
|
||||||
case blit_engine::context_surface::surface2d:
|
|
||||||
dst_dma = method_registers.blit_engine_output_location_nv3062();
|
|
||||||
dst_offset = method_registers.blit_engine_output_offset_nv3062();
|
|
||||||
dst_color_format = method_registers.blit_engine_nv3062_color_format();
|
|
||||||
out_pitch = method_registers.blit_engine_output_pitch_nv3062();
|
|
||||||
out_alignment = method_registers.blit_engine_output_alignment_nv3062();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blit_engine::context_surface::swizzle2d:
|
|
||||||
dst_dma = method_registers.blit_engine_nv309E_location();
|
|
||||||
dst_offset = method_registers.blit_engine_nv309E_offset();
|
|
||||||
dst_color_format = method_registers.blit_engine_output_format_nv309E();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 out_bpp = (dst_color_format == rsx::blit_engine::transfer_destination_format::r5g6b5) ? 2 : 4;
|
|
||||||
const s32 out_offset = out_x * out_bpp + out_pitch * out_y;
|
|
||||||
const tiled_region dst_region = rsx->get_tiled_address(dst_offset + out_offset, dst_dma & 0xf);
|
|
||||||
|
|
||||||
frame_capture_data::memory_block blockDst;
|
|
||||||
blockDst.ioOffset = dst_region.tile ? dst_region.base : dst_offset + out_offset;
|
|
||||||
blockDst.location = dst_dma & 0xf;
|
|
||||||
if (get_io_offset(blockDst.ioOffset, blockDst.location) != -1)
|
|
||||||
{
|
|
||||||
u32 blockSize = method_registers.blit_engine_context_surface() != blit_engine::context_surface::swizzle2d ? out_pitch * out_h : out_bpp * next_pow2(out_w) * next_pow2(out_h);
|
|
||||||
|
|
||||||
blockDst.size = blockSize;
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(blockDst), std::move(block_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
capture_display_tile_state(rsx, replay_command);
|
capture_display_tile_state(rsx, replay_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,9 +342,8 @@ namespace rsx
|
||||||
const u8* src = (u8*)vm::base(src_addr);
|
const u8* src = (u8*)vm::base(src_addr);
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
frame_capture_data::memory_block block;
|
||||||
block.ioOffset = src_offset;
|
block.offset = src_offset;
|
||||||
block.location = src_dma;
|
block.location = src_dma;
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
frame_capture_data::memory_block_data block_data;
|
||||||
block_data.data.resize(in_pitch * line_count);
|
block_data.data.resize(in_pitch * line_count);
|
||||||
|
|
||||||
|
@ -441,29 +355,6 @@ namespace rsx
|
||||||
|
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
||||||
|
|
||||||
// we 'capture' destination mostly to ensure that the location is allocated when replaying
|
|
||||||
u32 dst_offset = method_registers.nv0039_output_offset();
|
|
||||||
u32 dst_dma = method_registers.nv0039_output_location();
|
|
||||||
u32 dst_addr = get_address(dst_offset, dst_dma);
|
|
||||||
|
|
||||||
s32 out_pitch = method_registers.nv0039_output_pitch();
|
|
||||||
if (!out_pitch)
|
|
||||||
{
|
|
||||||
out_pitch = line_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame_capture_data::memory_block blockDst;
|
|
||||||
blockDst.ioOffset = dst_offset;
|
|
||||||
blockDst.location = dst_dma;
|
|
||||||
|
|
||||||
// check if allocated
|
|
||||||
if (get_io_offset(blockDst.ioOffset, blockDst.location) != -1)
|
|
||||||
{
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
|
||||||
blockDst.size = out_pitch * line_count;
|
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(blockDst), std::move(block_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
capture_display_tile_state(rsx, replay_command);
|
capture_display_tile_state(rsx, replay_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,34 +380,26 @@ namespace rsx
|
||||||
frame_capture_data::tile_state tilestate;
|
frame_capture_data::tile_state tilestate;
|
||||||
for (u32 i = 0; i < limits::tiles_count; ++i)
|
for (u32 i = 0; i < limits::tiles_count; ++i)
|
||||||
{
|
{
|
||||||
const auto& tile = rsx->tiles[i];
|
// Avoid byteswapping
|
||||||
|
auto tile = rsx->tiles[i].pack();
|
||||||
auto& tstate = tilestate.tiles[i];
|
auto& tstate = tilestate.tiles[i];
|
||||||
tstate.bank = tile.bank;
|
tstate.tile = *reinterpret_cast<u32*>(&tile.tile);
|
||||||
tstate.base = tile.base;
|
tstate.limit = *reinterpret_cast<u32*>(&tile.limit);
|
||||||
tstate.binded = tile.binded;
|
tstate.pitch = rsx->tiles[i].binded ? *reinterpret_cast<u32*>(&tile.pitch) : 0;
|
||||||
tstate.comp = tile.comp;
|
tstate.format = rsx->tiles[i].binded ? *reinterpret_cast<u32*>(&tile.format) : 0;
|
||||||
tstate.location = tile.location;
|
|
||||||
tstate.offset = tile.offset;
|
|
||||||
tstate.pitch = tile.pitch;
|
|
||||||
tstate.size = tile.size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < limits::zculls_count; ++i)
|
for (u32 i = 0; i < limits::zculls_count; ++i)
|
||||||
{
|
{
|
||||||
const auto& zc = rsx->zculls[i];
|
// Avoid byteswapping
|
||||||
|
auto zc = rsx->zculls[i].pack();
|
||||||
auto& zcstate = tilestate.zculls[i];
|
auto& zcstate = tilestate.zculls[i];
|
||||||
zcstate.aaFormat = zc.aaFormat;
|
zcstate.region = *reinterpret_cast<u32*>(&zc.region);
|
||||||
zcstate.binded = zc.binded;
|
zcstate.size = *reinterpret_cast<u32*>(&zc.size);
|
||||||
zcstate.cullStart = zc.cullStart;
|
zcstate.start = *reinterpret_cast<u32*>(&zc.start);
|
||||||
zcstate.height = zc.height;
|
zcstate.offset = *reinterpret_cast<u32*>(&zc.offset);
|
||||||
zcstate.offset = zc.offset;
|
zcstate.status0 = rsx->zculls[i].binded ? *reinterpret_cast<u32*>(&zc.status0) : 0;
|
||||||
zcstate.sFunc = zc.sFunc;
|
zcstate.status1 = rsx->zculls[i].binded ? *reinterpret_cast<u32*>(&zc.status1) : 0;
|
||||||
zcstate.sMask = zc.sMask;
|
|
||||||
zcstate.sRef = zc.sRef;
|
|
||||||
zcstate.width = zc.width;
|
|
||||||
zcstate.zcullDir = zc.zcullDir;
|
|
||||||
zcstate.zcullFormat = zc.zcullFormat;
|
|
||||||
zcstate.zFormat = zc.zFormat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 tsnum = XXH64(&tilestate, sizeof(frame_capture_data::tile_state), 0);
|
const u64 tsnum = XXH64(&tilestate, sizeof(frame_capture_data::tile_state), 0);
|
||||||
|
@ -527,104 +410,5 @@ namespace rsx
|
||||||
replay_command.display_buffer_state = dbnum;
|
replay_command.display_buffer_state = dbnum;
|
||||||
replay_command.tile_state = tsnum;
|
replay_command.tile_state = tsnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the most part capturing this is just to make sure the iomemory is recorded/allocated and accounted for in replay
|
|
||||||
void capture_get_report(thread* rsx, frame_capture_data::replay_command& replay_command, u32 arg)
|
|
||||||
{
|
|
||||||
u32 location = 0;
|
|
||||||
u32 offset = arg & 0xffffff;
|
|
||||||
|
|
||||||
blit_engine::context_dma report_dma = method_registers.context_dma_report();
|
|
||||||
|
|
||||||
switch (report_dma)
|
|
||||||
{
|
|
||||||
// ignore regular report location
|
|
||||||
case blit_engine::context_dma::to_memory_get_report: location = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL; return;
|
|
||||||
case blit_engine::context_dma::report_location_main: location = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN; break;
|
|
||||||
case blit_engine::context_dma::memory_host_buffer: location = CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER; break;
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 addr = get_address(offset, location);
|
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
|
||||||
block.ioOffset = offset;
|
|
||||||
block.location = location;
|
|
||||||
block.size = 16;
|
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
|
||||||
|
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This just checks the color/depth addresses and makes sure they are accounted for in io allocations
|
|
||||||
// Hopefully this works without fully having to calculate actual size
|
|
||||||
void capture_surface_state(thread* rsx, frame_capture_data::replay_command& replay_command)
|
|
||||||
{
|
|
||||||
const auto target = rsx::method_registers.surface_color_target();
|
|
||||||
|
|
||||||
u32 offset_color[] =
|
|
||||||
{
|
|
||||||
rsx::method_registers.surface_a_offset(),
|
|
||||||
rsx::method_registers.surface_b_offset(),
|
|
||||||
rsx::method_registers.surface_c_offset(),
|
|
||||||
rsx::method_registers.surface_d_offset(),
|
|
||||||
};
|
|
||||||
|
|
||||||
u32 context_dma_color[] =
|
|
||||||
{
|
|
||||||
rsx::method_registers.surface_a_dma(),
|
|
||||||
rsx::method_registers.surface_b_dma(),
|
|
||||||
rsx::method_registers.surface_c_dma(),
|
|
||||||
rsx::method_registers.surface_d_dma(),
|
|
||||||
};
|
|
||||||
|
|
||||||
auto check_add = [&replay_command](u32 offset, u32 dma) -> void
|
|
||||||
{
|
|
||||||
u32 ioOffset = get_io_offset(offset, dma);
|
|
||||||
if (ioOffset == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
|
||||||
block.ioOffset = offset;
|
|
||||||
block.location = dma;
|
|
||||||
block.size = 64;
|
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& index : utility::get_rtt_indexes(target))
|
|
||||||
{
|
|
||||||
check_add(offset_color[index], context_dma_color[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
check_add(rsx::method_registers.surface_z_offset(), rsx::method_registers.surface_z_dma());
|
|
||||||
}
|
|
||||||
|
|
||||||
void capture_inline_transfer(thread* rsx, frame_capture_data::replay_command& replay_command, u32 idx, u32 arg)
|
|
||||||
{
|
|
||||||
const u16 x = method_registers.nv308a_x();
|
|
||||||
const u16 y = method_registers.nv308a_y();
|
|
||||||
|
|
||||||
const u32 pixel_offset = (method_registers.blit_engine_output_pitch_nv3062() * y) + (x << 2);
|
|
||||||
const u32 addr_offset = method_registers.blit_engine_output_offset_nv3062() + pixel_offset + idx * 4;
|
|
||||||
|
|
||||||
// just need to capture dst for allocation later if in iomem
|
|
||||||
|
|
||||||
const u32 memory_location = method_registers.blit_engine_output_location_nv3062();
|
|
||||||
|
|
||||||
const u32 ioOffset = get_io_offset(addr_offset, memory_location);
|
|
||||||
if (ioOffset == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
frame_capture_data::memory_block block;
|
|
||||||
block.ioOffset = addr_offset;
|
|
||||||
block.location = memory_location;
|
|
||||||
block.size = 4;
|
|
||||||
|
|
||||||
frame_capture_data::memory_block_data block_data;
|
|
||||||
insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,5 @@ namespace rsx
|
||||||
void capture_image_in(thread* rsx, frame_capture_data::replay_command& replay_command);
|
void capture_image_in(thread* rsx, frame_capture_data::replay_command& replay_command);
|
||||||
void capture_buffer_notify(thread* rsx, frame_capture_data::replay_command& replay_command);
|
void capture_buffer_notify(thread* rsx, frame_capture_data::replay_command& replay_command);
|
||||||
void capture_display_tile_state(thread* rsx, frame_capture_data::replay_command& replay_command);
|
void capture_display_tile_state(thread* rsx, frame_capture_data::replay_command& replay_command);
|
||||||
void capture_surface_state(thread* rsx, frame_capture_data::replay_command& replay_command);
|
|
||||||
void capture_get_report(thread* rsx, frame_capture_data::replay_command& replay_command, u32 arg);
|
|
||||||
void capture_inline_transfer(thread* rsx, frame_capture_data::replay_command& replay_command, u32 idx, u32 arg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,16 +113,13 @@ namespace rsx
|
||||||
if (it == frame->memory_map.end())
|
if (it == frame->memory_map.end())
|
||||||
fmt::throw_exception("requested memory state for command not found in memory_map");
|
fmt::throw_exception("requested memory state for command not found in memory_map");
|
||||||
|
|
||||||
if (it->second.data_state != 0)
|
|
||||||
{
|
|
||||||
const auto& memblock = it->second;
|
const auto& memblock = it->second;
|
||||||
auto it_data = frame->memory_data_map.find(it->second.data_state);
|
auto it_data = frame->memory_data_map.find(it->second.data_state);
|
||||||
if (it_data == frame->memory_data_map.end())
|
if (it_data == frame->memory_data_map.end())
|
||||||
fmt::throw_exception("requested memory data state for command not found in memory_data_map");
|
fmt::throw_exception("requested memory data state for command not found in memory_data_map");
|
||||||
|
|
||||||
const auto& data_block = it_data->second;
|
const auto& data_block = it_data->second;
|
||||||
std::memcpy(vm::base(get_address(memblock.ioOffset + memblock.offset, memblock.location)), data_block.data.data(), data_block.data.size());
|
std::memcpy(vm::base(get_address(memblock.offset, memblock.location)), data_block.data.data(), data_block.data.size());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replay_cmd.display_buffer_state != 0 && replay_cmd.display_buffer_state != cs.display_buffer_hash)
|
if (replay_cmd.display_buffer_state != 0 && replay_cmd.display_buffer_state != cs.display_buffer_hash)
|
||||||
|
@ -154,50 +151,22 @@ namespace rsx
|
||||||
const auto& tstate = it->second;
|
const auto& tstate = it->second;
|
||||||
for (u32 i = 0; i < limits::tiles_count; ++i)
|
for (u32 i = 0; i < limits::tiles_count; ++i)
|
||||||
{
|
{
|
||||||
const auto& tstile = tstate.tiles[i];
|
const auto& ti = tstate.tiles[i];
|
||||||
if (cs.tile_hash != 0 && memcmp(&cs.tile_state.tiles[i], &tstile, sizeof(rsx::frame_capture_data::tile_info)) == 0)
|
if (cs.tile_hash != 0 && memcmp(&cs.tile_state.tiles[i], &ti, sizeof(rsx::frame_capture_data::tile_info)) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cs.tile_state.tiles[i] = tstile;
|
cs.tile_state.tiles[i] = ti;
|
||||||
|
sys_rsx_context_attribute(context_id, 0x300, i, (u64)ti.tile << 32 | ti.limit, (u64)ti.pitch << 32 | ti.format, 0);
|
||||||
GcmTileInfo t;
|
|
||||||
t.bank = tstile.bank;
|
|
||||||
t.base = tstile.base;
|
|
||||||
t.binded = tstile.binded;
|
|
||||||
t.comp = tstile.comp;
|
|
||||||
t.location = tstile.location;
|
|
||||||
t.offset = tstile.offset;
|
|
||||||
t.pitch = tstile.pitch;
|
|
||||||
t.size = tstile.size;
|
|
||||||
|
|
||||||
const auto& ti = t.pack();
|
|
||||||
sys_rsx_context_attribute(context_id, 0x300, i, (u64)ti.tile << 32 | ti.limit, t.binded ? (u64)ti.pitch << 32 | ti.format : 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < limits::zculls_count; ++i)
|
for (u32 i = 0; i < limits::zculls_count; ++i)
|
||||||
{
|
{
|
||||||
const auto& zctile = tstate.zculls[i];
|
const auto& zci = tstate.zculls[i];
|
||||||
if (cs.tile_hash != 0 && memcmp(&cs.tile_state.zculls[i], &zctile, sizeof(rsx::frame_capture_data::zcull_info)) == 0)
|
if (cs.tile_hash != 0 && memcmp(&cs.tile_state.zculls[i], &zci, sizeof(rsx::frame_capture_data::zcull_info)) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cs.tile_state.zculls[i] = zctile;
|
cs.tile_state.zculls[i] = zci;
|
||||||
|
sys_rsx_context_attribute(context_id, 0x301, i, (u64)zci.region << 32 | zci.size, (u64)zci.start << 32 | zci.offset, (u64)zci.status0 << 32 | zci.status1);
|
||||||
GcmZcullInfo zc;
|
|
||||||
zc.aaFormat = zctile.aaFormat;
|
|
||||||
zc.binded = zctile.binded;
|
|
||||||
zc.cullStart = zctile.cullStart;
|
|
||||||
zc.height = zctile.height;
|
|
||||||
zc.offset = zctile.offset;
|
|
||||||
zc.sFunc = zctile.sFunc;
|
|
||||||
zc.sMask = zctile.sMask;
|
|
||||||
zc.sRef = zctile.sRef;
|
|
||||||
zc.width = zctile.width;
|
|
||||||
zc.zcullDir = zctile.zcullDir;
|
|
||||||
zc.zcullFormat = zctile.zcullFormat;
|
|
||||||
zc.zFormat = zctile.zFormat;
|
|
||||||
|
|
||||||
const auto& zci = zc.pack();
|
|
||||||
sys_rsx_context_attribute(context_id, 0x301, i, (u64)zci.region << 32 | zci.size, (u64)zci.start << 32 | zci.offset, zc.binded ? (u64)zci.status0 << 32 | zci.status1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.tile_hash = replay_cmd.tile_state;
|
cs.tile_hash = replay_cmd.tile_state;
|
||||||
|
@ -211,23 +180,8 @@ namespace rsx
|
||||||
auto fifo_stops = alloc_write_fifo(context_id);
|
auto fifo_stops = alloc_write_fifo(context_id);
|
||||||
|
|
||||||
// map game io
|
// map game io
|
||||||
for (const auto it : frame->memory_map)
|
if (sys_rsx_context_iomap(context_id, 0x0, user_mem_addr, 0x10000000, 0) != CELL_OK)
|
||||||
{
|
fmt::throw_exception("rsx io map failed");
|
||||||
const auto& memblock = it.second;
|
|
||||||
if (memblock.location == CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN)
|
|
||||||
{
|
|
||||||
// Special area for reports
|
|
||||||
if (sys_rsx_context_iomap(context_id, (memblock.ioOffset & ~0xFFFFF) + 0x0e000000, (memblock.ioOffset & ~0xFFFFF) + user_mem_addr + 0x0e000000, 0x100000, 0) != CELL_OK)
|
|
||||||
fmt::throw_exception("rsx io map failed for block");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const u32 location = memblock.location; location != CELL_GCM_LOCATION_MAIN && location != CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sys_rsx_context_iomap(context_id, memblock.ioOffset & ~0xFFFFF, user_mem_addr + (memblock.ioOffset & ~0xFFFFF), ::align<u32>(memblock.size + memblock.offset, 0x100000), 0) != CELL_OK)
|
|
||||||
fmt::throw_exception("rsx io map failed for block");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!Emu.IsStopped())
|
while (!Emu.IsStopped())
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
#include "Emu/Cell/PPUModule.h"
|
#include "Emu/Cell/PPUModule.h"
|
||||||
#include "Emu/Cell/lv2/sys_sync.h"
|
#include "Emu/Cell/lv2/sys_sync.h"
|
||||||
#include "Emu/Cell/lv2/sys_ppu_thread.h"
|
|
||||||
#include "Emu/RSX/rsx_methods.h"
|
#include "Emu/RSX/rsx_methods.h"
|
||||||
#include "Emu/RSX/gcm_enums.h"
|
|
||||||
|
|
||||||
#include <cereal/types/vector.hpp>
|
#include <cereal/types/vector.hpp>
|
||||||
#include <cereal/types/array.hpp>
|
#include <cereal/types/array.hpp>
|
||||||
|
@ -17,10 +15,9 @@
|
||||||
namespace rsx
|
namespace rsx
|
||||||
{
|
{
|
||||||
constexpr u32 FRAME_CAPTURE_MAGIC = 0x52524300; // ascii 'RRC/0'
|
constexpr u32 FRAME_CAPTURE_MAGIC = 0x52524300; // ascii 'RRC/0'
|
||||||
constexpr u32 FRAME_CAPTURE_VERSION = 0x3;
|
constexpr u32 FRAME_CAPTURE_VERSION = 0x4;
|
||||||
struct frame_capture_data
|
struct frame_capture_data
|
||||||
{
|
{
|
||||||
|
|
||||||
struct memory_block_data
|
struct memory_block_data
|
||||||
{
|
{
|
||||||
std::vector<u8> data;
|
std::vector<u8> data;
|
||||||
|
@ -34,17 +31,14 @@ namespace rsx
|
||||||
// simple block to hold ps3 address and data
|
// simple block to hold ps3 address and data
|
||||||
struct memory_block
|
struct memory_block
|
||||||
{
|
{
|
||||||
u32 ioOffset{0xFFFFFFFF}; // rsx ioOffset, -1 signifies unused
|
u32 offset; // Offset in rsx address space
|
||||||
u32 offset{0}; // offset into addr/ioOffset to copy state into
|
u32 location; // rsx memory location of the block
|
||||||
u32 size{0}; // size of block needed
|
u64 data_state;
|
||||||
u32 location{0xFFFFFFFF}; // Location of the block in RSX memory space
|
|
||||||
u64 data_state{0}; // this can be 0, in which case its just needed as an alloc
|
|
||||||
template<typename Archive>
|
template<typename Archive>
|
||||||
void serialize(Archive & ar)
|
void serialize(Archive & ar)
|
||||||
{
|
{
|
||||||
ar(ioOffset);
|
|
||||||
ar(offset);
|
ar(offset);
|
||||||
ar(size);
|
|
||||||
ar(location);
|
ar(location);
|
||||||
ar(data_state);
|
ar(data_state);
|
||||||
}
|
}
|
||||||
|
@ -67,62 +61,41 @@ namespace rsx
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// same thing as gcmtileinfo
|
|
||||||
struct tile_info
|
struct tile_info
|
||||||
{
|
{
|
||||||
u32 location{0};
|
u32 tile;
|
||||||
u32 offset{0};
|
u32 limit;
|
||||||
u32 size{0};
|
u32 pitch;
|
||||||
u32 pitch{0};
|
u32 format;
|
||||||
u32 comp{0};
|
|
||||||
u32 base{0};
|
|
||||||
u32 bank{0};
|
|
||||||
bool binded{false};
|
|
||||||
|
|
||||||
template<typename Archive>
|
template<typename Archive>
|
||||||
void serialize(Archive & ar)
|
void serialize(Archive & ar)
|
||||||
{
|
{
|
||||||
ar(location);
|
ar(tile);
|
||||||
ar(offset);
|
ar(limit);
|
||||||
ar(size);
|
|
||||||
ar(pitch);
|
ar(pitch);
|
||||||
ar(comp);
|
ar(format);
|
||||||
ar(base);
|
|
||||||
ar(bank);
|
|
||||||
ar(binded);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// same thing as gcmzcullinfo
|
|
||||||
struct zcull_info
|
struct zcull_info
|
||||||
{
|
{
|
||||||
u32 offset{0};
|
u32 region;
|
||||||
u32 width{0};
|
u32 size;
|
||||||
u32 height{0};
|
u32 start;
|
||||||
u32 cullStart{0};
|
u32 offset;
|
||||||
u32 zFormat{0};
|
u32 status0;
|
||||||
u32 aaFormat{0};
|
u32 status1;
|
||||||
u32 zcullDir{0};
|
|
||||||
u32 zcullFormat{0};
|
|
||||||
u32 sFunc{0};
|
|
||||||
u32 sRef{0};
|
|
||||||
u32 sMask{0};
|
|
||||||
bool binded{false};
|
|
||||||
|
|
||||||
template<typename Archive>
|
template<typename Archive>
|
||||||
void serialize(Archive & ar)
|
void serialize(Archive & ar)
|
||||||
{
|
{
|
||||||
|
ar(region);
|
||||||
|
ar(size);
|
||||||
|
ar(start);
|
||||||
ar(offset);
|
ar(offset);
|
||||||
ar(width);
|
ar(status0);
|
||||||
ar(cullStart);
|
ar(status1);
|
||||||
ar(zFormat);
|
|
||||||
ar(aaFormat);
|
|
||||||
ar(zcullDir);
|
|
||||||
ar(zcullFormat);
|
|
||||||
ar(sFunc);
|
|
||||||
ar(sRef);
|
|
||||||
ar(sMask);
|
|
||||||
ar(binded);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -73,12 +73,12 @@ struct CellGcmReportData
|
||||||
|
|
||||||
struct CellGcmZcullInfo
|
struct CellGcmZcullInfo
|
||||||
{
|
{
|
||||||
u32 region;
|
be_t<u32> region;
|
||||||
u32 size;
|
be_t<u32> size;
|
||||||
u32 start;
|
be_t<u32> start;
|
||||||
u32 offset;
|
be_t<u32> offset;
|
||||||
u32 status0;
|
be_t<u32> status0;
|
||||||
u32 status1;
|
be_t<u32> status1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CellGcmDisplayInfo
|
struct CellGcmDisplayInfo
|
||||||
|
|
|
@ -523,21 +523,13 @@ namespace rsx
|
||||||
|
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
case NV4097_GET_REPORT:
|
|
||||||
capture::capture_get_report(this, *it, value);
|
|
||||||
break;
|
|
||||||
case NV3089_IMAGE_IN:
|
case NV3089_IMAGE_IN:
|
||||||
capture::capture_image_in(this, *it);
|
capture::capture_image_in(this, *it);
|
||||||
break;
|
break;
|
||||||
case NV0039_BUFFER_NOTIFY:
|
case NV0039_BUFFER_NOTIFY:
|
||||||
capture::capture_buffer_notify(this, *it);
|
capture::capture_buffer_notify(this, *it);
|
||||||
break;
|
break;
|
||||||
case NV4097_CLEAR_SURFACE:
|
|
||||||
capture::capture_surface_state(this, *it);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
if (reg >= NV308A_COLOR && reg < NV3089_SET_OBJECT)
|
|
||||||
capture::capture_inline_transfer(this, *it, reg - NV308A_COLOR, value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue