libdragon
Functions

RDP Command queue: debugging helpers. More...

Go to the source code of this file.

Functions

void rdpq_debug_start (void)
 Initialize the RDPQ debugging engine. More...
 
void rdpq_debug_stop (void)
 Stop the rdpq debugging engine.
 
void rdpq_debug_log (bool show_log)
 Show a full log of all the RDP commands. More...
 
void rdpq_debug_log_msg (const char *str)
 Add a custom message in the RDP logging. More...
 
surface_t rdpq_debug_get_tmem (void)
 Acquire a dump of the current contents of TMEM. More...
 
void rdpq_debug_install_hook (void(*hook)(void *ctx, uint64_t *cmd, int cmd_size), void *ctx)
 Install a custom hook that will be called every time a RDP command is processed. More...
 
bool rdpq_debug_disasm (uint64_t *buf, FILE *out)
 Disassemble a RDP command. More...
 
int rdpq_debug_disasm_size (uint64_t *buf)
 Return the size of the next RDP commands. More...
 

Detailed Description

RDP Command queue: debugging helpers.

Function Documentation

◆ rdpq_debug_start()

void rdpq_debug_start ( void  )

Initialize the RDPQ debugging engine.

This function initializes the RDP debugging engine. After calling this function, all RDP commands sent via the rspq/rdpq libraries and overlays will be analyzed and validated, providing insights in case of programming errors that trigger hardware undefined behaviors or corrupt graphics. The validation errors and warnings are emitted via debugf, so make sure to initialize the debugging library to see it.

This is especially important with RDP because the chips is very hard to program correctly, and it is common to do mistakes. While rdpq tries to shield the programmer from most common mistakes via the fixups, it is still possible to do mistakes (eg: creating non-working color combiners) that the debugging engine can help spotting.

Notice that the validator needs to maintain a representation of the RDP state, as it is not possible to query the RDP about it. So it is better to call rdpq_debug_start immediately after rdpq_init when required, so that it can track all commands from the start. Otherwise, some spurious validation error could be emitted.

Note
The validator does cause a measurable overhead. It is advised to enable it only in debugging builds.

◆ rdpq_debug_log()

void rdpq_debug_log ( bool  show_log)

Show a full log of all the RDP commands.

This function configures the debugging engine to also log all RDP commands to the debugging channel (via debugf). This is extremely verbose and should be used sparingly to debug specific issues.

This function does enqueue a command in the rspq queue, so it is executed in order with respect to all rspq/rdpq commands. You can thus delimit specific portions of your code with rdpq_debug_log(true) / rdpq_debug_log(false), to see only the RDP log produced by those code lines.

Parameters
show_logtrue/false to enable/disable the RDP log.

◆ rdpq_debug_log_msg()

void rdpq_debug_log_msg ( const char *  str)

Add a custom message in the RDP logging.

If the debug log is active, this function adds a custom message to the log. It can be useful to annotate different portions of the disassembly.

For instance, the following code:

rdpq_debug_log_msg("Black rectangle");
rdpq_fill_rectangle(0, 0, 320, 120);
rdpq_debug_log_msg("Red rectangle");
rdpq_fill_rectangle(0, 120, 320, 240);
#define RGBA32(rx, gx, bx, ax)
Create a color_t from the R,G,B,A components in the RGBA32 range (0-255).
Definition: graphics.h:49
void rdpq_set_fill_color(color_t color)
Enqueue a SET_FILL_COLOR RDP command.
Definition: rdpq.h:835
void rdpq_debug_log(bool show_log)
Show a full log of all the RDP commands.
void rdpq_debug_log_msg(const char *str)
Add a custom message in the RDP logging.
void rdpq_set_mode_fill(color_t color)
Reset render mode to FILL type.
Definition: rdpq_mode.h:299
#define rdpq_fill_rectangle(x0, y0, x1, y1)
Draw a filled rectangle (RDP command: FILL_RECTANGLE)
Definition: rdpq_rect.h:235

produces this output:

 [0xa00e7128] f1020000000332a8    RDPQ_MESSAGE     Black rectangle
 [0xa00e7130] ef30000000000000    SET_OTHER_MODES  fill
 [0xa00e7138] ed00000000000000    SET_SCISSOR      xy=(0.00,0.00)-(0.00,0.00)
 [0xa00e7140] f700000000000000    SET_FILL_COLOR   rgba16=(0,0,0,0) rgba32=(0,0,0,0)
 [0xa00e7148] f65001e000000000    FILL_RECT        xy=(0.00,0.00)-(320.00,120.00)
 [0xa00e7150] f1020000000332b8    RDPQ_MESSAGE     Red rectangle
 [0xa00e7158] e700000000000000    SYNC_PIPE
 [0xa00e7160] f7000000f800f800    SET_FILL_COLOR   rgba16=(31,0,0,0) rgba32=(248,0,248,0)
 [0xa00e7168] f65003c0000001e0    FILL_RECT        xy=(0.00,120.00)-(320.00,240.00)
 [0xa00e7170] f101000000000000    RDPQ_SHOWLOG     show=0

where you can see the RDPQ_MESSAGE lines which helps isolate portion of commands with respect to the source lines that generated them.

Parameters
strmessage to display

◆ rdpq_debug_get_tmem()

surface_t rdpq_debug_get_tmem ( void  )

Acquire a dump of the current contents of TMEM.

Inspecting TMEM can be useful for debugging purposes, so this function dumps it to RDRAM for inspection. It returns a surface that contains the contents of TMEM as a 32x64 FMT_RGBA16 (4K) buffer, but obviously the contents can vary and have nothing to do with this layout.

The function will do a full sync (via rspq_wait) to make sure the surface data has been fully written by RDP when the function returns.

For the debugging, you can easily dump the contents of the surface calling debug_hexdump.

The surface must be freed via surface_free when it is not useful anymore.

// Get the TMEM contents
// Dump TMEM in the debug spew
debug_hexdump(surf.buffer, 4096);
surface_free(&surf);
void debug_hexdump(const void *vbuf, int size)
Do a hexdump of the specified buffer via debugf.
Definition: debug.c:652
surface_t rdpq_debug_get_tmem(void)
Acquire a dump of the current contents of TMEM.
void surface_free(surface_t *surface)
Free the buffer allocated in a surface.
Definition: surface.c:48
void * buffer
Buffer pointer.
Definition: surface.h:143
A surface buffer for graphics.
Definition: surface.h:138
Returns
A surface with TMEM contents, that must be freed via surface_free.

◆ rdpq_debug_install_hook()

void rdpq_debug_install_hook ( void(*)(void *ctx, uint64_t *cmd, int cmd_size)  hook,
void *  ctx 
)

Install a custom hook that will be called every time a RDP command is processed.

This function can be used to perform custom analysis on the RDP stream. It allows you to register a callback that will be called any time a RDP command is processed by the debugging engine.

Parameters
hookHook function that will be called for each RDP command
ctxContext passed to the hook function
Note
You can currently install only one hook

◆ rdpq_debug_disasm()

bool rdpq_debug_disasm ( uint64_t *  buf,
FILE *  out 
)

Disassemble a RDP command.

This function allows to access directly the disassembler which is part of the rdpq debugging log. Normally, you don't need to use this function: just call rdpq_debug_log to see all RDP commands in disassembled format.

This function can be useful for writing tools or manually debugging a RDP stream.

Parameters
bufPointer to the RDP command
outOuput stream where to write the disassembled string
Returns
true if the command was disassembled, false if the command is being held in a buffer waiting for more commands to be appended.
See also
rdpq_debug_disasm_size

◆ rdpq_debug_disasm_size()

int rdpq_debug_disasm_size ( uint64_t *  buf)

Return the size of the next RDP commands.

Parameters
bufPointer to RDP command
Returns
Number of 64-bit words the command is composed of