Merge pull request #1285 from vlj/rsx-debug

Rsx debug: Record per frame draw calls.
This commit is contained in:
Ivan 2015-11-09 01:35:05 +03:00
commit 5dfc22a604
8 changed files with 736 additions and 129 deletions

View File

@ -214,4 +214,8 @@ protected:
virtual void load_vertex_data(u32 first, u32 count) override;
virtual void load_vertex_index_data(u32 first, u32 count) override;
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) override;
virtual void copy_depth_buffer_to_memory(void *buffer) override;
virtual void copy_stencil_buffer_to_memory(void *buffer) override;
};

View File

@ -587,4 +587,128 @@ void D3D12GSRender::copy_render_target_to_dma_location()
}
}
void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt)
{
ComPtr<ID3D12Resource> readback_buffer = create_readback_buffer_and_download(m_device.Get(), getCurrentResourceStorage().command_list.Get(), m_readbackResources, m_rtts.bound_render_targets[rtt], m_surface.color_format);
ThrowIfFailed(getCurrentResourceStorage().command_list->Close());
m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)getCurrentResourceStorage().command_list.GetAddressOf());
getCurrentResourceStorage().set_new_command_list();
wait_for_command_queue(m_device.Get(), m_commandQueueGraphic.Get());
m_readbackResources.m_get_pos = m_readbackResources.get_current_put_pos_minus_one();
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
size_t srcPitch, dstPitch;
switch (m_surface.color_format)
{
case CELL_GCM_SURFACE_A8R8G8B8:
srcPitch = align(clip_w * 4, 256);
dstPitch = clip_w * 4;
break;
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
srcPitch = align(clip_w * 8, 256);
dstPitch = clip_w * 8;
break;
}
copy_readback_buffer_to_dest(buffer, readback_buffer.Get(), srcPitch, dstPitch, clip_h);
}
void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer)
{
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
size_t row_pitch = align(clip_w * 4, 256);
ComPtr<ID3D12Resource> readback_buffer;
size_t buffer_size = row_pitch * clip_h;
assert(m_readbackResources.can_alloc(buffer_size));
size_t heapOffset = m_readbackResources.alloc(buffer_size);
ThrowIfFailed(
m_device->CreatePlacedResource(
m_readbackResources.m_heap,
heapOffset,
&CD3DX12_RESOURCE_DESC::Buffer(buffer_size),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(readback_buffer.GetAddressOf())
)
);
getCurrentResourceStorage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
getCurrentResourceStorage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_buffer.Get(), { 0,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
&CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 0), nullptr);
getCurrentResourceStorage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
ThrowIfFailed(getCurrentResourceStorage().command_list->Close());
m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)getCurrentResourceStorage().command_list.GetAddressOf());
getCurrentResourceStorage().set_new_command_list();
wait_for_command_queue(m_device.Get(), m_commandQueueGraphic.Get());
m_readbackResources.m_get_pos = m_readbackResources.get_current_put_pos_minus_one();
void *mapped_buffer;
ThrowIfFailed(readback_buffer->Map(0, nullptr, &mapped_buffer));
for (unsigned row = 0; row < clip_h; row++)
{
u32 *casted_dest = (u32*)((char*)buffer + row * clip_w * 4);
u32 *casted_src = (u32*)((char*)mapped_buffer + row * row_pitch);
for (unsigned col = 0; col < row_pitch / 4; col++)
*casted_dest++ = *casted_src++;
}
readback_buffer->Unmap(0, nullptr);
}
void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer)
{
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
size_t row_pitch = align(clip_w * 4, 256);
ComPtr<ID3D12Resource> readback_buffer;
size_t buffer_size = row_pitch * clip_h;
assert(m_readbackResources.can_alloc(buffer_size));
size_t heapOffset = m_readbackResources.alloc(buffer_size);
ThrowIfFailed(
m_device->CreatePlacedResource(
m_readbackResources.m_heap,
heapOffset,
&CD3DX12_RESOURCE_DESC::Buffer(buffer_size),
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(readback_buffer.GetAddressOf())
)
);
getCurrentResourceStorage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE));
getCurrentResourceStorage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(readback_buffer.Get(), { 0,{ DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0,
&CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 1), nullptr);
getCurrentResourceStorage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
ThrowIfFailed(getCurrentResourceStorage().command_list->Close());
m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)getCurrentResourceStorage().command_list.GetAddressOf());
getCurrentResourceStorage().set_new_command_list();
wait_for_command_queue(m_device.Get(), m_commandQueueGraphic.Get());
m_readbackResources.m_get_pos = m_readbackResources.get_current_put_pos_minus_one();
void *mapped_buffer;
ThrowIfFailed(readback_buffer->Map(0, nullptr, &mapped_buffer));
for (unsigned row = 0; row < clip_h; row++)
{
char *casted_dest = (char*)buffer + row * clip_w;
char *casted_src = (char*)mapped_buffer + row * row_pitch;
for (unsigned col = 0; col < row_pitch; col++)
*casted_dest++ = *casted_src++;
}
readback_buffer->Unmap(0, nullptr);
}
#endif

View File

@ -1,6 +1,7 @@
#pragma once
#include "Utilities/types.h"
#include "Emu/Memory/vm.h"
#include <sstream>
enum
{
@ -1644,4 +1645,353 @@ namespace rsx
return fmt::format("unknown/illegal method [0x%08x]", id);
}
static std::string get_blend_factor(u16 factor) noexcept
{
switch (factor)
{
case CELL_GCM_ZERO: return "0";
case CELL_GCM_ONE: return "1";
case CELL_GCM_SRC_COLOR: return "src.rgb";
case CELL_GCM_ONE_MINUS_SRC_COLOR: return "(1 - src.rgb)";
case CELL_GCM_SRC_ALPHA: return "src.a";
case CELL_GCM_ONE_MINUS_SRC_ALPHA: return "(1 - src.a)";
case CELL_GCM_DST_ALPHA: return "dst.a";
case CELL_GCM_ONE_MINUS_DST_ALPHA: return "(1 - dst.a)";
case CELL_GCM_DST_COLOR: return "dst.rgb";
case CELL_GCM_ONE_MINUS_DST_COLOR: return "(1 - dst.rgb)";
case CELL_GCM_SRC_ALPHA_SATURATE: return "sat(src.a)";
case CELL_GCM_CONSTANT_COLOR: return "const.rgb";
case CELL_GCM_ONE_MINUS_CONSTANT_COLOR: return "(1 - const.rgb)";
case CELL_GCM_CONSTANT_ALPHA: return "const.a";
case CELL_GCM_ONE_MINUS_CONSTANT_ALPHA: return "(1 - const.a)";
}
return "Error";
}
static std::string get_blend_op(u16 op) noexcept
{
switch (op)
{
case CELL_GCM_FUNC_ADD: return "Add";
case CELL_GCM_FUNC_SUBTRACT: return "Substract";
case CELL_GCM_FUNC_REVERSE_SUBTRACT: return "Reverse_substract";
case CELL_GCM_MIN: return "Min";
case CELL_GCM_MAX: return "Max";
case CELL_GCM_FUNC_ADD_SIGNED: return "Add_signed";
case CELL_GCM_FUNC_REVERSE_ADD_SIGNED: return "Reverse_add_signed";
case CELL_GCM_FUNC_REVERSE_SUBTRACT_SIGNED: return "Reverse_substract_signed";
}
return "Error";
}
static std::string get_logic_op(u32 op) noexcept
{
switch (op)
{
case CELL_GCM_CLEAR: return "Clear";
case CELL_GCM_AND: return "And";
case CELL_GCM_AND_REVERSE: return "And_reverse";
case CELL_GCM_COPY: return "Copy";
case CELL_GCM_AND_INVERTED: return "And_inverted";
case CELL_GCM_NOOP: return "Noop";
case CELL_GCM_XOR: return "Xor";
case CELL_GCM_OR: return "Or";
case CELL_GCM_NOR: return "Nor";
case CELL_GCM_EQUIV: return "Equiv";
case CELL_GCM_INVERT: return "Invert";
case CELL_GCM_OR_REVERSE: return "Or_reverse";
case CELL_GCM_COPY_INVERTED: return "Copy_inverted";
case CELL_GCM_OR_INVERTED: return "Or_inverted";
case CELL_GCM_NAND: return "Nand";
}
return "Error";
}
static std::string get_compare_func(u32 op) noexcept
{
switch (op)
{
case CELL_GCM_NEVER: return "Never";
case CELL_GCM_LESS: return "Less";
case CELL_GCM_EQUAL: return "Equal";
case CELL_GCM_LEQUAL: return "Less_equal";
case CELL_GCM_GREATER: return "Greater";
case CELL_GCM_NOTEQUAL: return "Not_equal";
case CELL_GCM_GEQUAL: return "Greater_equal";
case CELL_GCM_ALWAYS: return "Always";
}
return "Error";
}
static std::string get_primitive_mode(u8 draw_mode) noexcept
{
switch (draw_mode)
{
case CELL_GCM_PRIMITIVE_POINTS: return "Points";
case CELL_GCM_PRIMITIVE_LINES: return "Lines";
case CELL_GCM_PRIMITIVE_LINE_LOOP: return "Line_loop";
case CELL_GCM_PRIMITIVE_LINE_STRIP: return "Line_strip";
case CELL_GCM_PRIMITIVE_TRIANGLES: return "Triangles";
case CELL_GCM_PRIMITIVE_TRIANGLE_STRIP: return "Triangle_strip";
case CELL_GCM_PRIMITIVE_TRIANGLE_FAN: return "Triangle_fan";
case CELL_GCM_PRIMITIVE_QUADS: return "Quads";
case CELL_GCM_PRIMITIVE_QUAD_STRIP: return "Quad_strip";
case CELL_GCM_PRIMITIVE_POLYGON: return "Polygon";
}
return "Error";
}
static std::string ptr_to_string(u32 ptr) noexcept
{
std::stringstream ss;
ss << (void*)(u64)ptr;
return ss.str();
}
static std::string dma_mode(u32 arg) noexcept
{
switch (arg)
{
case CELL_GCM_LOCATION_LOCAL:
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER: return "Local memory";
case CELL_GCM_LOCATION_MAIN:
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER: return "Main memory";
}
return "Error";
}
static std::string depth_stencil_surface_format(u32 format) noexcept
{
switch (format)
{
case CELL_GCM_SURFACE_Z16: return "CELL_GCM_SURFACE_Z16";
case CELL_GCM_SURFACE_Z24S8: return "CELL_GCM_SURFACE_Z24S8";
}
return "Error";
}
static std::string color_surface_format(u32 format) noexcept
{
switch (format)
{
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5: return "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5";
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5: return "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5";
case CELL_GCM_SURFACE_R5G6B5: return "CELL_GCM_SURFACE_R5G6B5";
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8: return "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8";
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8: return "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8";
case CELL_GCM_SURFACE_A8R8G8B8: return "CELL_GCM_SURFACE_A8R8G8B8";
case CELL_GCM_SURFACE_B8: return "CELL_GCM_SURFACE_B8";
case CELL_GCM_SURFACE_G8B8: return "CELL_GCM_SURFACE_G8B8";
case CELL_GCM_SURFACE_F_W16Z16Y16X16: return "CELL_GCM_SURFACE_F_W16Z16Y16X16";
case CELL_GCM_SURFACE_F_W32Z32Y32X32: return "CELL_GCM_SURFACE_F_W32Z32Y32X32";
case CELL_GCM_SURFACE_F_X32: return "CELL_GCM_SURFACE_F_X32";
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8: return "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8";
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8: return "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8";
case CELL_GCM_SURFACE_A8B8G8R8: return "CELL_GCM_SURFACE_A8B8G8R8";
}
return "Error";
}
static std::string surface_target(u32 target) noexcept
{
switch (target)
{
case CELL_GCM_SURFACE_TARGET_0: return "surface A";
case CELL_GCM_SURFACE_TARGET_1: return "surface B";
case CELL_GCM_SURFACE_TARGET_MRT1: return "surfaces A and B";
case CELL_GCM_SURFACE_TARGET_MRT2: return "surfaces A, B and C";
case CELL_GCM_SURFACE_TARGET_MRT3: return "surfaces A,B, C and D";
}
return "Error";
}
static std::string get_clear_color(u32 clear_color) noexcept
{
u8 clear_a = clear_color >> 24;
u8 clear_r = clear_color >> 16;
u8 clear_g = clear_color >> 8;
u8 clear_b = clear_color;
return "A = " + std::to_string(clear_a / 255.0f) + " R = " + std::to_string(clear_r / 255.0f) + " G = " + std::to_string(clear_g / 255.0f) + " B = " + std::to_string(clear_b / 255.0f);
}
static std::string get_zstencil_clear(u32 zstencil) noexcept
{
u32 depth = zstencil >> 8;
u32 stencil = zstencil & 0xff;
return "Z = " + std::to_string(depth) + " S = " + std::to_string(stencil);
}
static std::string get_stencil_op(u32 op) noexcept
{
switch (op)
{
case CELL_GCM_KEEP: return "Keep";
case CELL_GCM_ZERO: return "Zero";
case CELL_GCM_REPLACE: return "Replace";
case CELL_GCM_INCR: return "Incr";
case CELL_GCM_DECR: return "Decr";
case CELL_GCM_INCR_WRAP: return "Incr_wrap";
case CELL_GCM_DECR_WRAP: return "Decr_wrap";
}
return "Error";
}
static std::string get_vertex_attribute_format(u8 type) noexcept
{
switch (type)
{
case CELL_GCM_VERTEX_S1: return "Short";
case CELL_GCM_VERTEX_F: return "Float";
case CELL_GCM_VERTEX_SF: return "Half float";
case CELL_GCM_VERTEX_UB: return "Unsigned byte";
case CELL_GCM_VERTEX_S32K: return "Signed int";
case CELL_GCM_VERTEX_CMP: return "CMP";
case CELL_GCM_VERTEX_UB256: return "UB256";
}
return "Error";
}
static std::string unpack_vertex_format(u32 arg) noexcept
{
u32 frequency = arg >> 16;
u32 stride = (arg >> 8) & 0xff;
u32 size = (arg >> 4) & 0xf;
u32 type = arg & 0xf;
if (size == 0)
return "(disabled)";
return "Type = " + get_vertex_attribute_format(type) + " size = " + std::to_string(size) + " stride = " + std::to_string(stride) + " frequency = " + std::to_string(frequency);
}
static std::string index_type(u16 arg) noexcept
{
switch (arg)
{
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: return "unsigned short";
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: return "unsigned int";
}
return "Error";
}
static std::function<std::string(u32)> get_pretty_printing_function(const u32 id)
{
static const std::unordered_map<u32, std::function<std::string(u32)> > printing_functions =
{
{ NV4097_NO_OPERATION , [](u32) { return "(nop)"; } },
{ NV4097_SET_ALPHA_TEST_ENABLE, [](u32 arg) { return (!!arg) ? "Alpha: enable" : "Alpha: disable"; } },
{ NV4097_SET_DEPTH_TEST_ENABLE, [](u32 arg) { return (!!arg) ? "Depth: enable" : "Depth: disable"; } },
{ NV4097_SET_DEPTH_MASK, [](u32 arg) { return (!!arg) ? "Depth: write enabled" : "Depth: write disabled"; } },
{ NV4097_SET_DEPTH_FUNC, [](u32 arg) { return "Depth: " + get_compare_func(arg); } },
{ NV4097_SET_LOGIC_OP_ENABLE, [](u32 arg) { return (!!arg) ? "Logic Op: enable" : "Logic Op: disable"; } },
{ NV4097_SET_LOGIC_OP, [](u32 arg) { return "Logic Op: " + get_logic_op(arg); } },
{ NV4097_SET_BLEND_ENABLE , [](u32 arg) { return (!!arg) ? "Blend: enable" : "Blend: disable"; } },
{ NV4097_SET_BLEND_FUNC_SFACTOR, [](u32 arg) { return "Blend: sfactor.rgb = " + get_blend_factor(arg & 0xFFFF) + " sfactor.a = " + get_blend_factor(arg >> 16); } },
{ NV4097_SET_BLEND_FUNC_DFACTOR, [](u32 arg) { return "Blend: dfactor.rgb = " + get_blend_factor(arg & 0xFFFF) + " dfactor.a = " + get_blend_factor(arg >> 16); } },
{ NV4097_SET_BLEND_EQUATION , [](u32 arg) { return "Blend: op.rgb = " + get_blend_op(arg & 0xFFFF) + " op.a = " + get_blend_op(arg >> 16); } },
{ NV4097_SET_BLEND_ENABLE_MRT, [](u32 arg) { return "Blend: mrt0 = " + std::to_string(!!(arg & 0x2)) + " mrt1 = " + std::to_string(!!(arg & 0x4)) + " mrt2 = " + std::to_string(!!(arg & 0x8)); } },
{ NV4097_SET_COLOR_MASK , [](u32 arg) { return "Color mask: A = " + std::to_string(!!(arg & 0x1000000)) + " R = " + std::to_string(!!(arg & 0x10000)) + " G = " + std::to_string(!!(arg & 0x100)) + " B = " + std::to_string(!!(arg & 0x1)); } },
{ NV4097_SET_VIEWPORT_HORIZONTAL, [](u32 arg) { return "Viewport: x = " + std::to_string(arg & 0xFFFF) + " width = " + std::to_string(arg >> 16); } },
{ NV4097_SET_VIEWPORT_VERTICAL, [](u32 arg) { return "Viewport: y = " + std::to_string(arg & 0xFFFF) + " height = " + std::to_string(arg >> 16); } },
{ NV4097_SET_BEGIN_END, [](u32 arg) { return arg ? "- Begin: " + get_primitive_mode(arg) + " -" : "- End -"; } },
{ NV4097_DRAW_ARRAYS, [](u32 arg) { return "Draw " + std::to_string((arg >> 24) + 1) + " vertex starting from " + std::to_string(arg & 0xFFFFFF); } },
{ NV4097_DRAW_INDEX_ARRAY, [](u32 arg) { return "Draw " + std::to_string((arg >> 24) + 1) + " index starting from " + std::to_string(arg & 0xFFFFFF); } },
{ NV4097_SET_SEMAPHORE_OFFSET, [](u32 arg) { return "Semaphore: @ " + ptr_to_string(arg); } },
{ NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, [](u32 arg) { return "Write semaphore value " + std::to_string(arg); } },
{ NV4097_CLEAR_SURFACE, [](u32 arg) { return "Clear surface " + std::string(arg & 0x1 ? "Depth " : "") + std::string(arg & 0x2 ? "Stencil " : "") + std::string(arg & 0xF0 ? "Color " : ""); } },
{ NV4097_SET_CONTEXT_DMA_COLOR_A, [](u32 arg) { return "Surface A: DMA mode = " + dma_mode(arg);} },
{ NV4097_SET_SURFACE_PITCH_A, [](u32 arg) { return "Surface A: Pitch = " + std::to_string(arg); } },
{ NV4097_SET_SURFACE_COLOR_AOFFSET, [](u32 arg) { return "Surface A: Offset = " + std::to_string(arg); } },
{ NV4097_SET_CONTEXT_DMA_COLOR_B, [](u32 arg) { return "Surface B: DMA mode = " + dma_mode(arg);} },
{ NV4097_SET_SURFACE_PITCH_B, [](u32 arg) { return "Surface B: Pitch = " + std::to_string(arg); } },
{ NV4097_SET_SURFACE_COLOR_BOFFSET, [](u32 arg) { return "Surface B: Offset = " + std::to_string(arg); } },
{ NV4097_SET_CONTEXT_DMA_COLOR_C, [](u32 arg) { return "Surface C: DMA mode = " + dma_mode(arg);} },
{ NV4097_SET_SURFACE_PITCH_C, [](u32 arg) { return "Surface C: Pitch = " + std::to_string(arg); } },
{ NV4097_SET_SURFACE_COLOR_COFFSET, [](u32 arg) { return "Surface C: Offset = " + std::to_string(arg); } },
{ NV4097_SET_SURFACE_PITCH_D, [](u32 arg) { return "Surface D: Pitch = " + std::to_string(arg); } },
{ NV4097_SET_SURFACE_COLOR_DOFFSET, [](u32 arg) { return "Surface D: Offset = " + std::to_string(arg); } },
{ NV4097_SET_CONTEXT_DMA_COLOR_D, [](u32 arg) { return "Surface D: DMA mode = " + dma_mode(arg);} },
{ NV4097_SET_SURFACE_PITCH_Z, [](u32 arg) { return "Surface Zeta: Pitch = " + std::to_string(arg); } },
{ NV4097_SET_SURFACE_ZETA_OFFSET, [](u32 arg) { return "Surface Zeta: Offset = " + std::to_string(arg); } },
{ NV4097_SET_CONTEXT_DMA_ZETA, [](u32 arg) { return "Surface Zeta: DMA mode = " + dma_mode(arg);} },
{ NV4097_SET_SURFACE_FORMAT, [](u32 arg) { return "Surface: Color format = " + color_surface_format(arg & 0x1F) + " DepthStencil format = " + depth_stencil_surface_format((arg >> 5) & 0x7); } },
{ NV4097_SET_SURFACE_CLIP_HORIZONTAL, [](u32 arg) { return "Surface: clip x = " + std::to_string(arg & 0xFFFF) + " width = " + std::to_string(arg >> 16); } },
{ NV4097_SET_SURFACE_CLIP_VERTICAL, [](u32 arg) { return "Surface: clip y = " + std::to_string(arg & 0xFFFF) + " height = " + std::to_string(arg >> 16); } },
{ NV4097_SET_SURFACE_COLOR_TARGET, [](u32 arg) { return "Surface: Targets " + surface_target(arg); } },
{ NV4097_SET_COLOR_CLEAR_VALUE, [](u32 arg) { return "Clear: " + get_clear_color(arg); } },
{ NV4097_SET_ZSTENCIL_CLEAR_VALUE, [](u32 arg) { return "Clear: " + get_zstencil_clear(arg); } },
{ NV4097_SET_CLIP_MIN, [](u32 arg) { return "Depth: Min = " + std::to_string((f32&)arg); } },
{ NV4097_SET_CLIP_MAX, [](u32 arg) { return "Depth: Max = " + std::to_string((f32&)arg); } },
{ NV4097_SET_VIEWPORT_SCALE, [](u32 arg) { return "Viewport: x scale = " + std::to_string((f32&)arg); } },
{ NV4097_SET_VIEWPORT_SCALE + 1, [](u32 arg) { return "Viewport: y scale = " + std::to_string((f32&)arg); } },
{ NV4097_SET_VIEWPORT_SCALE + 2, [](u32 arg) { return "Viewport: z scale = " + std::to_string((f32&)arg); } },
{ NV4097_SET_VIEWPORT_OFFSET, [](u32 arg) { return "Viewport: x offset = " + std::to_string((f32&)arg); } },
{ NV4097_SET_VIEWPORT_OFFSET + 1, [](u32 arg) { return "Viewport: y offset = " + std::to_string((f32&)arg); } },
{ NV4097_SET_VIEWPORT_OFFSET + 2, [](u32 arg) { return "Viewport: z offset = " + std::to_string((f32&)arg); } },
{ NV4097_SET_SCISSOR_HORIZONTAL, [](u32 arg) { return "Scissor: x = " + std::to_string(arg & 0xFFFF) + " width = " + std::to_string(arg >> 16); } },
{ NV4097_SET_SCISSOR_VERTICAL, [](u32 arg) { return "Scissor: y = " + std::to_string(arg & 0xFFFF) + " height = " + std::to_string(arg >> 16); } },
{ NV4097_SET_STENCIL_TEST_ENABLE, [](u32 arg) { return (!!arg) ? "Stencil: Enable" : "Stencil : Disable"; } },
{ NV4097_SET_STENCIL_FUNC, [](u32 arg) { return "Stencil: " + get_compare_func(arg); } },
{ NV4097_SET_BACK_STENCIL_OP_ZPASS, [](u32 arg) { return "Stencil: Back ZPass = " + get_stencil_op(arg); } },
{ NV4097_SET_BACK_STENCIL_OP_ZFAIL, [](u32 arg) { return "Stencil: Back ZFail = " + get_stencil_op(arg); } },
{ NV4097_SET_BACK_STENCIL_OP_FAIL, [](u32 arg) { return "Stencil: Back Fail = " + get_stencil_op(arg); } },
{ NV4097_SET_STENCIL_OP_ZPASS, [](u32 arg) { return "Stencil: ZPass = " + get_stencil_op(arg); } },
{ NV4097_SET_STENCIL_OP_ZFAIL, [](u32 arg) { return "Stencil: ZFail = " + get_stencil_op(arg); } },
{ NV4097_SET_STENCIL_OP_FAIL, [](u32 arg) { return "Stencil: Fail = " + get_stencil_op(arg); } },
{ NV4097_SET_STENCIL_FUNC_MASK, [](u32 arg) { return "Stencil: Func mask = " + ptr_to_string(arg); } },
{ NV4097_SET_STENCIL_MASK, [](u32 arg) { return "Stencil: Mask = " + ptr_to_string(arg); } },
{ NV4097_SET_STENCIL_FUNC_REF, [](u32 arg) { return "Stencil: Ref = " + std::to_string(arg); } },
{ NV4097_INVALIDATE_VERTEX_CACHE_FILE, [](u32) { return "(invalidate vertex cache file)"; } },
{ NV4097_INVALIDATE_VERTEX_FILE, [](u32) { return "(invalidate vertex file)"; } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, [](u32 arg) { return "Vertex array 0: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 1, [](u32 arg) { return "Vertex array 1: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 2, [](u32 arg) { return "Vertex array 2: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 3, [](u32 arg) { return "Vertex array 3: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 4, [](u32 arg) { return "Vertex array 4: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 5, [](u32 arg) { return "Vertex array 5: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 6, [](u32 arg) { return "Vertex array 6: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 7, [](u32 arg) { return "Vertex array 7: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 8, [](u32 arg) { return "Vertex array 8: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 9, [](u32 arg) { return "Vertex array 9: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 10, [](u32 arg) { return "Vertex array 10: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 11, [](u32 arg) { return "Vertex array 11: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 12, [](u32 arg) { return "Vertex array 12: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 13, [](u32 arg) { return "Vertex array 13: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 14, [](u32 arg) { return "Vertex array 14: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_FORMAT + 15, [](u32 arg) { return "Vertex array 15: " + unpack_vertex_format(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET, [](u32 arg) { return "Vertex array 0: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 1, [](u32 arg) { return "Vertex array 1: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 2, [](u32 arg) { return "Vertex array 2: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 3, [](u32 arg) { return "Vertex array 3: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 4, [](u32 arg) { return "Vertex array 4: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 5, [](u32 arg) { return "Vertex array 5: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 6, [](u32 arg) { return "Vertex array 6: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 7, [](u32 arg) { return "Vertex array 7: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 8, [](u32 arg) { return "Vertex array 8: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 9, [](u32 arg) { return "Vertex array 9: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 10, [](u32 arg) { return "Vertex array 10: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 11, [](u32 arg) { return "Vertex array 11: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 12, [](u32 arg) { return "Vertex array 12: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 13, [](u32 arg) { return "Vertex array 13: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 14, [](u32 arg) { return "Vertex array 14: Offset = " + std::to_string(arg); } },
{ NV4097_SET_VERTEX_DATA_ARRAY_OFFSET + 15, [](u32 arg) { return "Vertex array 15: Offset = " + std::to_string(arg); } },
{ NV4097_SET_INDEX_ARRAY_ADDRESS, [](u32 arg) { return "Index array: Address = " + ptr_to_string(arg); } },
{ NV4097_SET_INDEX_ARRAY_DMA, [](u32 arg) { return "Index array: DMA mode = " + dma_mode(arg & 0xF) + " type = " + index_type(arg >> 4); } },
};
auto found = printing_functions.find(id);
if (found != printing_functions.end())
{
return found->second;
}
return [=](u32 v)
{
std::stringstream ss;
ss << rsx::get_method_name(id) << " : " << (void*)(u64)v;
return ss.str();
};
}
}

View File

@ -21,7 +21,8 @@ extern "C"
#define CMD_DEBUG 0
extern u64 get_system_time();
bool user_asked_for_frame_capture = false;
frame_capture_data frame_debug;
namespace rsx
{
@ -552,6 +553,18 @@ namespace rsx
void flip_command(thread* rsx, u32 arg)
{
if (user_asked_for_frame_capture)
{
rsx->capture_current_frame = true;
user_asked_for_frame_capture = false;
frame_debug.reset();
}
else if (rsx->capture_current_frame)
{
rsx->capture_current_frame = false;
Emu.Pause();
}
rsx->gcm_current_buffer = arg;
rsx->flip(arg);
@ -625,7 +638,11 @@ namespace rsx
{
// try process using gpu
if (rsx->domethod(id, arg))
{
if (rsx->capture_current_frame && id == NV4097_CLEAR_SURFACE)
rsx->capture_frame();
return;
}
// not handled by renderer
// try process using cpu
@ -872,6 +889,53 @@ namespace rsx
}
}
void thread::capture_frame()
{
frame_capture_data::draw_state draw_state = {};
int clip_w = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] >> 16;
int clip_h = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] >> 16;
size_t pitch = clip_w * 4;
std::vector<size_t> color_index_to_record;
switch (method_registers[NV4097_SET_SURFACE_COLOR_TARGET])
{
case CELL_GCM_SURFACE_TARGET_0:
color_index_to_record = { 0 };
break;
case CELL_GCM_SURFACE_TARGET_1:
color_index_to_record = { 1 };
break;
case CELL_GCM_SURFACE_TARGET_MRT1:
color_index_to_record = { 0, 1 };
break;
case CELL_GCM_SURFACE_TARGET_MRT2:
color_index_to_record = { 0, 1, 2 };
break;
case CELL_GCM_SURFACE_TARGET_MRT3:
color_index_to_record = { 0, 1, 2, 3 };
break;
}
for (size_t i : color_index_to_record)
{
draw_state.color_buffer[i].width = clip_w;
draw_state.color_buffer[i].height = clip_h;
draw_state.color_buffer[i].data.resize(pitch * clip_h);
copy_render_targets_to_memory(draw_state.color_buffer[i].data.data(), i);
}
if (get_address(method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], method_registers[NV4097_SET_CONTEXT_DMA_ZETA]))
{
draw_state.depth.width = clip_w;
draw_state.depth.height = clip_h;
draw_state.depth.data.resize(clip_w * clip_h * 4);
copy_depth_buffer_to_memory(draw_state.depth.data.data());
draw_state.stencil.width = clip_w;
draw_state.stencil.height = clip_h;
draw_state.stencil.data.resize(clip_w * clip_h * 4);
copy_stencil_buffer_to_memory(draw_state.stencil.data.data());
}
frame_debug.draw_calls.push_back(draw_state);
}
void thread::begin()
{
draw_mode = method_registers[NV4097_SET_BEGIN_END];
@ -884,6 +948,9 @@ namespace rsx
vertex_array.clear();
transform_constants.clear();
if (capture_current_frame)
capture_frame();
}
void thread::task()
@ -1006,6 +1073,8 @@ namespace rsx
}
method_registers[reg] = value;
if (capture_current_frame)
frame_debug.command_queue.push_back(std::make_pair(reg, value));
if (auto method = methods[reg])
method(this, value);

View File

@ -10,6 +10,36 @@
#include "Utilities/Timer.h"
#include "Utilities/types.h"
extern u64 get_system_time();
struct frame_capture_data
{
struct buffer
{
std::vector<u8> data;
size_t width = 0, height = 0;
};
struct draw_state
{
buffer color_buffer[4];
buffer depth;
buffer stencil;
};
std::vector<std::pair<u32, u32> > command_queue;
std::vector<draw_state> draw_calls;
void reset() noexcept
{
command_queue.clear();
draw_calls.clear();
}
};
extern bool user_asked_for_frame_capture;
extern frame_capture_data frame_debug;
namespace rsx
{
namespace limits
@ -169,6 +199,8 @@ namespace rsx
virtual void load_vertex_data(u32 first, u32 count);
virtual void load_vertex_index_data(u32 first, u32 count);
bool capture_current_frame = false;
void capture_frame();
public:
u32 ioAddress, ioSize;
int flip_status;
@ -233,6 +265,23 @@ namespace rsx
*/
void fill_vertex_program_constants_data(void *buffer) noexcept;
/**
* Copy rtt values to buffer.
* TODO: It's more efficient to combine multiple call of this function into one.
*/
virtual void copy_render_targets_to_memory(void *buffer, u8 rtt) {};
/**
* Copy depth content to buffer.
* TODO: It's more efficient to combine multiple call of this function into one.
*/
virtual void copy_depth_buffer_to_memory(void *buffer) {};
/**
* Copy stencil content to buffer.
* TODO: It's more efficient to combine multiple call of this function into one.
*/
virtual void copy_stencil_buffer_to_memory(void *buffer) {};
public:
void reset();
void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);

View File

@ -9,12 +9,14 @@
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/CPU/CPUThread.h"
extern bool user_asked_for_frame_capture;
class DbgEmuPanel : public wxPanel
{
wxButton* m_btn_run;
wxButton* m_btn_stop;
wxButton* m_btn_restart;
wxButton* m_btn_capture_frame;
public:
DbgEmuPanel(wxWindow* parent) : wxPanel(parent)
@ -28,11 +30,15 @@ public:
m_btn_restart = new wxButton(this, wxID_ANY, "Restart");
m_btn_restart->Bind(wxEVT_BUTTON, &DbgEmuPanel::OnRestart, this);
m_btn_capture_frame = new wxButton(this, wxID_ANY, "Capture frame");
m_btn_capture_frame->Bind(wxEVT_BUTTON, &DbgEmuPanel::OnCaptureFrame, this);
wxBoxSizer* s_b_main = new wxBoxSizer(wxHORIZONTAL);
s_b_main->Add(m_btn_run, wxSizerFlags().Border(wxALL, 5));
s_b_main->Add(m_btn_stop, wxSizerFlags().Border(wxALL, 5));
s_b_main->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL), 0, wxEXPAND);
s_b_main->Add(m_btn_restart, wxSizerFlags().Border(wxALL, 5));
s_b_main->Add(m_btn_capture_frame, wxSizerFlags().Border(wxALL, 5));
SetSizerAndFit(s_b_main);
Layout();
@ -75,6 +81,11 @@ public:
Emu.Load();
}
void OnCaptureFrame(wxCommandEvent& event)
{
user_asked_for_frame_capture = true;
}
void HandleCommand(wxCommandEvent& event)
{
event.Skip();

View File

@ -82,6 +82,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
//Tabs
wxNotebook* nb_rsx = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(732, 732));
wxPanel* p_commands = new wxPanel(nb_rsx, wxID_ANY);
wxPanel* p_captured_frame = new wxPanel(nb_rsx, wxID_ANY);
wxPanel* p_captured_draw_calls = new wxPanel(nb_rsx, wxID_ANY);
wxPanel* p_flags = new wxPanel(nb_rsx, wxID_ANY);
wxPanel* p_programs = new wxPanel(nb_rsx, wxID_ANY);
wxPanel* p_lightning = new wxPanel(nb_rsx, wxID_ANY);
@ -89,6 +91,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
wxPanel* p_settings = new wxPanel(nb_rsx, wxID_ANY);
nb_rsx->AddPage(p_commands, wxT("RSX Commands"));
nb_rsx->AddPage(p_captured_frame, wxT("Captured Frame"));
nb_rsx->AddPage(p_captured_draw_calls, wxT("Captured Draw Calls"));
nb_rsx->AddPage(p_flags, wxT("Flags"));
nb_rsx->AddPage(p_programs, wxT("Programs"));
nb_rsx->AddPage(p_lightning, wxT("Lightning"));
@ -97,6 +101,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
//Tabs: Lists
m_list_commands = new wxListView(p_commands, wxID_ANY, wxPoint(1,3), wxSize(720, 720));
m_list_captured_frame = new wxListView(p_captured_frame, wxID_ANY, wxPoint(1, 3), wxSize(720, 720));
m_list_captured_draw_calls = new wxListView(p_captured_draw_calls, wxID_ANY, wxPoint(1, 3), wxSize(720, 720));
m_list_flags = new wxListView(p_flags, wxID_ANY, wxPoint(1,3), wxSize(720, 720));
m_list_programs = new wxListView(p_programs, wxID_ANY, wxPoint(1,3), wxSize(720, 720));
m_list_lightning = new wxListView(p_lightning, wxID_ANY, wxPoint(1,3), wxSize(720, 720));
@ -105,6 +111,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
//Tabs: List Style
m_list_commands ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_list_captured_frame->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_list_captured_draw_calls->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_list_flags ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_list_programs ->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
m_list_lightning->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
@ -116,6 +124,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
m_list_commands->InsertColumn(1, "Value", 0, 80);
m_list_commands->InsertColumn(2, "Command", 0, 500);
m_list_commands->InsertColumn(3, "Count", 0, 40);
m_list_captured_frame->InsertColumn(0, "Column", 0, 720);
m_list_captured_draw_calls->InsertColumn(0, "Draw calls", 0, 720);
m_list_flags->InsertColumn(0, "Name", 0, 170);
m_list_flags->InsertColumn(1, "Value", 0, 270);
m_list_programs->InsertColumn(0, "ID", 0, 70);
@ -144,6 +154,8 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
{
m_list_commands->InsertItem(m_list_commands->GetItemCount(), wxEmptyString);
}
for (u32 i = 0; i<frame_debug.command_queue.size(); i++)
m_list_captured_frame->InsertItem(1, wxEmptyString);
//Tools: Tools = Controls + Notebook Tabs
s_tools->AddSpacer(10);
@ -228,6 +240,7 @@ RSXDebugger::RSXDebugger(wxWindow* parent)
//p_buffer_depth->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this);
//p_buffer_stencil->Bind(wxEVT_BUTTON, &RSXDebugger::OnClickBuffer, this);
p_buffer_tex->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickBuffer, this);
m_list_captured_draw_calls->Bind(wxEVT_LEFT_DOWN, &RSXDebugger::OnClickDrawCalls, this);
m_list_commands->Bind(wxEVT_MOUSEWHEEL, &RSXDebugger::OnScrollMemory, this);
m_list_flags->Bind(wxEVT_LIST_ITEM_ACTIVATED, &RSXDebugger::SetFlags, this);
@ -330,6 +343,107 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
#undef SHOW_BUFFER
}
namespace
{
/**
* Return a new buffer that can be passed to wxImage ctor.
* The pointer seems to be freed by wxImage.
*/
u8* convert_to_wximage_buffer(u8 *orig_buffer, size_t width, size_t height) noexcept
{
unsigned char* buffer = (unsigned char*)malloc(width * height * 3);
for (u32 i = 0; i < width * height; i++)
{
buffer[0 + i * 3] = orig_buffer[3 + i * 4];
buffer[1 + i * 3] = orig_buffer[2 + i * 4];
buffer[2 + i * 3] = orig_buffer[1 + i * 4];
}
return buffer;
}
};
void RSXDebugger::OnClickDrawCalls(wxMouseEvent& event)
{
size_t draw_id = m_list_captured_draw_calls->GetFirstSelected();
wxPanel* p_buffers[] =
{
p_buffer_colorA,
p_buffer_colorB,
p_buffer_colorC,
p_buffer_colorD,
};
for (size_t i = 0; i < 4; i++)
{
size_t width = frame_debug.draw_calls[draw_id].color_buffer[i].width, height = frame_debug.draw_calls[draw_id].color_buffer[i].height;
if (width && height)
{
unsigned char *orig_buffer = frame_debug.draw_calls[draw_id].color_buffer[i].data.data();
wxImage img(width, height, convert_to_wximage_buffer(orig_buffer, width, height));
wxClientDC dc_canvas(p_buffers[i]);
if (img.IsOk())
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
}
}
// Buffer Z
{
size_t width = frame_debug.draw_calls[draw_id].depth.width, height = frame_debug.draw_calls[draw_id].depth.height;
if (width && height)
{
u32 *orig_buffer = (u32*)frame_debug.draw_calls[draw_id].depth.data.data();
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
for (u32 row = 0; row < height; row++)
{
for (u32 col = 0; col < width; col++)
{
u32 depth_val = orig_buffer[row * width + col];
u8 displayed_depth_val = 255 * depth_val / 0xFFFFFF;
buffer[3 * col + 0 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 1 + width * row * 3] = displayed_depth_val;
buffer[3 * col + 2 + width * row * 3] = displayed_depth_val;
}
}
wxImage img(width, height, buffer);
wxClientDC dc_canvas(p_buffer_depth);
if (img.IsOk())
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
}
}
// Buffer S
{
size_t width = frame_debug.draw_calls[draw_id].stencil.width, height = frame_debug.draw_calls[draw_id].stencil.height;
if (width && height)
{
u8 *orig_buffer = frame_debug.draw_calls[draw_id].stencil.data.data();
unsigned char *buffer = (unsigned char *)malloc(width * height * 3);
for (u32 row = 0; row < height; row++)
{
for (u32 col = 0; col < width; col++)
{
u32 stencil_val = orig_buffer[row * width + col];
buffer[3 * col + 0 + width * row * 3] = stencil_val;
buffer[3 * col + 1 + width * row * 3] = stencil_val;
buffer[3 * col + 2 + width * row * 3] = stencil_val;
}
}
wxImage img(width, height, buffer);
wxClientDC dc_canvas(p_buffer_stencil);
if (img.IsOk())
dc_canvas.DrawBitmap(img.Scale(m_panel_width, m_panel_height), 0, 0, false);
}
}
}
void RSXDebugger::GoToGet(wxCommandEvent& event)
{
if (!RSXReady()) return;
@ -401,6 +515,15 @@ void RSXDebugger::GetMemory()
m_list_commands->SetItem(i, 1, "????????");
}
}
for (u32 i = 0; i < frame_debug.command_queue.size(); i++)
{
std::string str = rsx::get_pretty_printing_function(frame_debug.command_queue[i].first)(frame_debug.command_queue[i].second);
m_list_captured_frame->SetItem(i, 0, str);
}
for (u32 i = 0;i < frame_debug.draw_calls.size(); i++)
m_list_captured_draw_calls->InsertItem(0, std::to_string(frame_debug.draw_calls.size() - i - 1));
}
void RSXDebugger::GetBuffers()
@ -842,120 +965,10 @@ wxString RSXDebugger::DisAsmCommand(u32 cmd, u32 count, u32 currentAddr, u32 ioA
u32 index = 0;
switch((cmd & 0x3ffff) >> 2)
{
case NV4097_SET_SURFACE_FORMAT:
{
const u32 a0 = (u32)args[0];
const u32 surface_format = a0 & 0x1f;
const u32 surface_depth_format = (a0 >> 5) & 0x7;
const char *depth_type_name, *color_type_name;
switch (surface_depth_format)
{
case CELL_GCM_SURFACE_Z16:
depth_type_name = "CELL_GCM_SURFACE_Z16";
break;
case CELL_GCM_SURFACE_Z24S8:
depth_type_name = "CELL_GCM_SURFACE_Z24S8";
break;
default: depth_type_name = "";
break;
}
switch (surface_format)
{
case CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5:
color_type_name = "CELL_GCM_SURFACE_X1R5G5B5_Z1R5G5B5";
break;
case CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5:
color_type_name = "CELL_GCM_SURFACE_X1R5G5B5_O1R5G5B5";
break;
case CELL_GCM_SURFACE_R5G6B5:
color_type_name = "CELL_GCM_SURFACE_R5G6B5";
break;
case CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8:
color_type_name = "CELL_GCM_SURFACE_X8R8G8B8_Z8R8G8B8";
break;
case CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8:
color_type_name = "CELL_GCM_SURFACE_X8R8G8B8_O8R8G8B8";
break;
case CELL_GCM_SURFACE_A8R8G8B8:
color_type_name = "CELL_GCM_SURFACE_A8R8G8B8";
break;
case CELL_GCM_SURFACE_B8:
color_type_name = "CELL_GCM_SURFACE_B8";
break;
case CELL_GCM_SURFACE_G8B8:
color_type_name = "CELL_GCM_SURFACE_G8B8";
break;
case CELL_GCM_SURFACE_F_W16Z16Y16X16:
color_type_name = "CELL_GCM_SURFACE_F_W16Z16Y16X16";
break;
case CELL_GCM_SURFACE_F_W32Z32Y32X32:
color_type_name = "CELL_GCM_SURFACE_F_W32Z32Y32X32";
break;
case CELL_GCM_SURFACE_F_X32:
color_type_name = "CELL_GCM_SURFACE_F_X32";
break;
case CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8:
color_type_name = "CELL_GCM_SURFACE_X8B8G8R8_Z8B8G8R8";
break;
case CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8:
color_type_name = "CELL_GCM_SURFACE_X8B8G8R8_O8B8G8R8";
break;
case CELL_GCM_SURFACE_A8B8G8R8:
color_type_name = "CELL_GCM_SURFACE_A8B8G8R8";
break;
default: color_type_name = "";
break;
}
DISASM("Set surface format : C %s Z %s", color_type_name, depth_type_name);
}
break;
case NV4097_SET_VIEWPORT_HORIZONTAL:
{
u32 m_viewport_x = (u32)args[0] & 0xffff;
u32 m_viewport_w = (u32)args[0] >> 16;
if (count == 2)
{
u32 m_viewport_y = (u32)args[1] & 0xffff;
u32 m_viewport_h = (u32)args[1] >> 16;
DISASM("Set viewport horizontal %d %d", m_viewport_w, m_viewport_h);
}
else
DISASM("Set viewport horizontal %d", m_viewport_w);
break;
}
case NV4097_SET_SURFACE_CLIP_HORIZONTAL:
{
const u32 a0 = (u32)args[0];
u32 clip_x = a0;
u32 clip_w = a0 >> 16;
if (count == 2)
{
const u32 a1 = (u32)args[1];
u32 clip_y = a1;
u32 clip_h = a1 >> 16;
DISASM("Set surface clip horizontal : %d %d", clip_w, clip_h);
}
else
DISASM("Set surface clip horizontal : %d", clip_w);
break;
}
break;
case 0x3fead:
DISASM("Flip and change current buffer: %d", (u32)args[0]);
break;
case NV4097_NO_OPERATION:
DISASM("NOP");
break;
case_16(NV4097_SET_TEXTURE_OFFSET, 0x20):
DISASM("Texture Offset[%d]: %08x", index, (u32)args[0]);
switch ((args[1] & 0x3) - 1)
@ -971,29 +984,13 @@ wxString RSXDebugger::DisAsmCommand(u32 cmd, u32 count, u32 currentAddr, u32 ioA
((args[1] >> 16) & 0xffff));
break;
case NV4097_SET_COLOR_MASK:
DISASM(" Color mask: True (A:%c, R:%c, G:%c, B:%c)",
args[0] & 0x1000000 ? '1' : '0',
args[0] & 0x0010000 ? '1' : '0',
args[0] & 0x0000100 ? '1' : '0',
args[0] & 0x0000001 ? '1' : '0');
break;
case NV4097_SET_ALPHA_TEST_ENABLE:
DISASM(args[0] ? "Alpha test: Enable" : "Alpha test: Disable");
break;
case NV4097_SET_BLEND_ENABLE:
DISASM(args[0] ? "Blend: Enable" : "Blend: Disable");
break;
case NV4097_SET_DEPTH_BOUNDS_TEST_ENABLE:
DISASM(args[0] ? "Depth bounds test: Enable" : "Depth bounds test: Disable");
break;
default:
{
std::string str = rsx::get_method_name((cmd & 0x3ffff) >> 2);
DISASM("%s : 0x%x", str.c_str(), (u32)args[0]);
std::string str = rsx::get_pretty_printing_function((cmd & 0x3ffff) >> 2)((u32)args[0]);
DISASM("%s", str.c_str());
}
}

View File

@ -15,6 +15,8 @@ class RSXDebugger : public wxFrame
u32 m_item_count;
wxListView* m_list_commands;
wxListView* m_list_captured_frame;
wxListView* m_list_captured_draw_calls;
wxListView* m_list_flags;
wxListView* m_list_programs;
wxListView* m_list_lightning;
@ -43,6 +45,7 @@ public:
virtual void OnChangeToolsAddr(wxCommandEvent& event);
virtual void OnScrollMemory(wxMouseEvent& event);
virtual void OnClickBuffer(wxMouseEvent& event);
virtual void OnClickDrawCalls(wxMouseEvent &event);
virtual void GoToGet(wxCommandEvent& event);
virtual void GoToPut(wxCommandEvent& event);