diff --git a/src/imagination/pco/meson.build b/src/imagination/pco/meson.build index 484661cf8f7..35ff18dd744 100644 --- a/src/imagination/pco/meson.build +++ b/src/imagination/pco/meson.build @@ -10,7 +10,9 @@ libpowervr_compiler_files = files( 'pco_end.c', 'pco_ir.c', 'pco_nir.c', + 'pco_print.c', 'pco_trans_nir.c', + 'pco_validate.c', ) pco_pygen_dep_files = files('pco_pygen_common.py', 'pco_isa.py', 'pco_ops.py') diff --git a/src/imagination/pco/pco.h b/src/imagination/pco/pco.h index ad26b545977..32d33df515b 100644 --- a/src/imagination/pco/pco.h +++ b/src/imagination/pco/pco.h @@ -42,4 +42,9 @@ void pco_shader_finalize(pco_ctx *ctx, pco_shader *shader); unsigned pco_shader_binary_size(pco_shader *shader); const void *pco_shader_binary_data(pco_shader *shader); + +void pco_validate_shader(pco_shader *shader, const char *when); + +void pco_print_shader(pco_shader *shader, FILE *fp, const char *when); +void pco_print_binary(pco_shader *shader, FILE *fp, const char *when); #endif /* PCO_H */ diff --git a/src/imagination/pco/pco_binary.c b/src/imagination/pco/pco_binary.c index 794abb6d220..8e825e79074 100644 --- a/src/imagination/pco/pco_binary.c +++ b/src/imagination/pco/pco_binary.c @@ -25,6 +25,9 @@ void pco_encode_ir(pco_ctx *ctx, pco_shader *shader) { puts("finishme: pco_encode_ir"); + + if (pco_should_print_binary(shader)) + pco_print_binary(shader, stdout, "after encoding"); } /** @@ -36,6 +39,9 @@ void pco_encode_ir(pco_ctx *ctx, pco_shader *shader) void pco_shader_finalize(pco_ctx *ctx, pco_shader *shader) { puts("finishme: pco_shader_finalize"); + + if (pco_should_print_binary(shader)) + pco_print_binary(shader, stdout, "after finalize"); } /** diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 8bbf9d522c3..97020397fdb 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -616,6 +616,76 @@ static inline pco_igrp *pco_prev_igrp(pco_igrp *igrp) return list_entry(igrp->link.prev, pco_igrp, link); } +/* Debug printing helpers. */ +static inline bool pco_should_print_nir(nir_shader *nir) +{ + if (!PCO_DEBUG_PRINT(NIR)) + return false; + + if (nir->info.internal && !PCO_DEBUG_PRINT(INTERNAL)) + return false; + + if (nir->info.stage == MESA_SHADER_VERTEX && !PCO_DEBUG_PRINT(VS)) + return false; + else if (nir->info.stage == MESA_SHADER_FRAGMENT && !PCO_DEBUG_PRINT(FS)) + return false; + else if (nir->info.stage == MESA_SHADER_COMPUTE && !PCO_DEBUG_PRINT(CS)) + return false; + + return true; +} + +static inline bool pco_should_print_shader(pco_shader *shader) +{ + if (shader->is_internal && !PCO_DEBUG_PRINT(INTERNAL)) + return false; + + if (shader->stage == MESA_SHADER_VERTEX && !PCO_DEBUG_PRINT(VS)) + return false; + else if (shader->stage == MESA_SHADER_FRAGMENT && !PCO_DEBUG_PRINT(FS)) + return false; + else if (shader->stage == MESA_SHADER_COMPUTE && !PCO_DEBUG_PRINT(CS)) + return false; + + return true; +} + +static inline bool pco_should_print_shader_pass(pco_shader *shader) +{ + if (!PCO_DEBUG_PRINT(PASSES)) + return false; + + if (shader->is_internal && !PCO_DEBUG_PRINT(INTERNAL)) + return false; + + if (shader->stage == MESA_SHADER_VERTEX && !PCO_DEBUG_PRINT(VS)) + return false; + else if (shader->stage == MESA_SHADER_FRAGMENT && !PCO_DEBUG_PRINT(FS)) + return false; + else if (shader->stage == MESA_SHADER_COMPUTE && !PCO_DEBUG_PRINT(CS)) + return false; + + return true; +} + +static inline bool pco_should_print_binary(pco_shader *shader) +{ + if (!PCO_DEBUG_PRINT(BINARY)) + return false; + + if (shader->is_internal && !PCO_DEBUG_PRINT(INTERNAL)) + return false; + + if (shader->stage == MESA_SHADER_VERTEX && !PCO_DEBUG_PRINT(VS)) + return false; + else if (shader->stage == MESA_SHADER_FRAGMENT && !PCO_DEBUG_PRINT(FS)) + return false; + else if (shader->stage == MESA_SHADER_COMPUTE && !PCO_DEBUG_PRINT(CS)) + return false; + + return true; +} + /* PCO IR passes. */ bool pco_end(pco_shader *shader); #endif /* PCO_INTERNAL_H */ diff --git a/src/imagination/pco/pco_ir.c b/src/imagination/pco/pco_ir.c index b9ed6181e00..c880472fa26 100644 --- a/src/imagination/pco/pco_ir.c +++ b/src/imagination/pco/pco_ir.c @@ -22,17 +22,22 @@ static inline bool pco_should_skip_pass(const char *pass) return comma_separated_list_contains(pco_skip_passes, pass); } -#define PCO_PASS(progress, shader, pass, ...) \ - do { \ - if (pco_should_skip_pass(#pass)) { \ - fprintf(stdout, "Skipping pass '%s'\n", #pass); \ - break; \ - } \ - \ - if (pass(shader, ##__VA_ARGS__)) { \ - UNUSED bool _; \ - progress = true; \ - } \ +#define PCO_PASS(progress, shader, pass, ...) \ + do { \ + if (pco_should_skip_pass(#pass)) { \ + fprintf(stdout, "Skipping pass '%s'\n", #pass); \ + break; \ + } \ + \ + if (pass(shader, ##__VA_ARGS__)) { \ + UNUSED bool _; \ + progress = true; \ + \ + pco_validate_shader(shader, "after " #pass); \ + \ + if (pco_should_print_shader_pass(shader)) \ + pco_print_shader(shader, stdout, "after " #pass); \ + } \ } while (0) /** @@ -43,7 +48,14 @@ static inline bool pco_should_skip_pass(const char *pass) */ void pco_process_ir(pco_ctx *ctx, pco_shader *shader) { + pco_validate_shader(shader, "before passes"); + PCO_PASS(_, shader, pco_end); + pco_validate_shader(shader, "after passes"); + + if (pco_should_print_shader(shader)) + pco_print_shader(shader, stdout, "after passes"); + puts("finishme: pco_process_ir"); } diff --git a/src/imagination/pco/pco_print.c b/src/imagination/pco/pco_print.c new file mode 100644 index 00000000000..97b5f5c29a8 --- /dev/null +++ b/src/imagination/pco/pco_print.c @@ -0,0 +1,224 @@ +/* + * Copyright © 2024 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: MIT + */ + +/** + * \file pco_print.c + * + * \brief PCO printing functions. + */ + +#include "pco.h" +#include "pco_builder.h" +#include "pco_common.h" +#include "pco_internal.h" +#include "util/macros.h" +#include "util/u_hexdump.h" + +#include +#include +#include +#include + +typedef struct _pco_print_state { + FILE *fp; /** The print target file pointer. */ + pco_shader *shader; /** The shader being printed. */ + unsigned indent; /** The current printing indent. */ + bool is_grouped; /** Whether the shader uses igrps. */ +} pco_print_state; + +enum color_esc { + ESC_RESET = 0, + ESC_BLACK, + ESC_RED, + ESC_GREEN, + ESC_YELLOW, + ESC_BLUE, + ESC_PURPLE, + ESC_CYAN, + ESC_WHITE, + _ESC_COUNT, +}; + +static +const char *color_esc[2][_ESC_COUNT] = { + [0] = { + [ESC_RESET] = "", + [ESC_BLACK] = "", + [ESC_RED] = "", + [ESC_GREEN] = "", + [ESC_YELLOW] = "", + [ESC_BLUE] = "", + [ESC_PURPLE] = "", + [ESC_CYAN] = "", + [ESC_WHITE] = "", + }, + [1] = { + [ESC_RESET] = "\033[0m", + [ESC_BLACK] = "\033[0;30m", + [ESC_RED] = "\033[0;31m", + [ESC_GREEN] = "\033[0;32m", + [ESC_YELLOW] = "\033[0;33m", + [ESC_BLUE] = "\033[0;34m", + [ESC_PURPLE] = "\033[0;35m", + [ESC_CYAN] = "\033[0;36m", + [ESC_WHITE] = "\033[0;37m", + }, +}; + +static inline void RESET(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_RESET], state->fp); +} + +static inline void BLACK(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_BLACK], state->fp); +} + +static inline void RED(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_RED], state->fp); +} + +static inline void GREEN(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_GREEN], state->fp); +} + +static inline void YELLOW(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_YELLOW], state->fp); +} + +static inline void BLUE(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_BLUE], state->fp); +} + +static inline void PURPLE(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_PURPLE], state->fp); +} + +static inline void CYAN(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_CYAN], state->fp); +} + +static inline void WHITE(pco_print_state *state) +{ + fputs(color_esc[pco_color][ESC_WHITE], state->fp); +} + +inline static const char *true_false_str(bool b) +{ + return b ? "true" : "false"; +} + +static void +_pco_printf(pco_print_state *state, bool nl, const char *fmt, va_list args) +{ + if (nl) + for (unsigned u = 0; u < state->indent; ++u) + fputs(" ", state->fp); + + vfprintf(state->fp, fmt, args); +} + +/** + * \brief Formatted print. + * + * \param[in] state Print state. + * \param[in] fmt Print format. + */ +PRINTFLIKE(2, 3) +static void pco_printf(pco_print_state *state, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + _pco_printf(state, false, fmt, args); + va_end(args); +} + +/** + * \brief Formatted print, with indentation. + * + * \param[in] state Print state. + * \param[in] fmt Print format. + */ +PRINTFLIKE(2, 3) +static void pco_printfi(pco_print_state *state, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + _pco_printf(state, true, fmt, args); + va_end(args); +} + +/** + * \brief Print PCO shader info. + * + * \param[in] state Print state. + * \param[in] shader PCO shader. + */ +static void pco_print_shader_info(pco_print_state *state, pco_shader *shader) +{ + if (shader->name) + pco_printfi(state, "name: \"%s\"\n", shader->name); + pco_printfi(state, "stage: %s\n", gl_shader_stage_name(shader->stage)); + pco_printfi(state, "internal: %s\n", true_false_str(shader->is_internal)); + /* TODO: more info/stats, e.g. stage, temps/other regs used, etc.? */ +} + +/** + * \brief Print PCO shader. + * + * \param[in] shader PCO shader. + * \param[in] fp Print target file pointer. + * \param[in] when When the printing is being performed. + */ +void pco_print_shader(pco_shader *shader, FILE *fp, const char *when) +{ + pco_print_state state = { + .fp = fp, + .shader = shader, + .indent = 0, + .is_grouped = shader->is_grouped, + }; + + if (when) + fprintf(fp, "%s\n", when); + + pco_print_shader_info(&state, shader); + pco_printfi(&state, "finishme: pco_print_shader\n"); +} + +/** + * \brief Print PCO shader binary. + * + * \param[in] shader PCO shader. + * \param[in] fp Print target file pointer. + * \param[in] when When the printing is being performed. + */ +void pco_print_binary(pco_shader *shader, FILE *fp, const char *when) +{ + pco_print_state state = { + .fp = fp, + .shader = shader, + .indent = 0, + .is_grouped = shader->is_grouped, + }; + + if (when) + fprintf(fp, "%s\n", when); + + pco_print_shader_info(&state, shader); + + return u_hexdump(fp, + pco_shader_binary_data(shader), + pco_shader_binary_size(shader), + true); +} diff --git a/src/imagination/pco/pco_validate.c b/src/imagination/pco/pco_validate.c new file mode 100644 index 00000000000..ba70901efd1 --- /dev/null +++ b/src/imagination/pco/pco_validate.c @@ -0,0 +1,31 @@ +/* + * Copyright © 2024 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: MIT + */ + +/** + * \file pco_validate.c + * + * \brief PCO validation functions. + */ + +#include "pco.h" +#include "pco_internal.h" +#include "util/macros.h" + +/** + * \brief Validates a PCO shader. + * + * \param[in] shader PCO shader. + * \param[in] when When the validation check is being run. + */ +void pco_validate_shader(UNUSED pco_shader *shader, UNUSED const char *when) +{ +#ifndef NDEBUG + if (PCO_DEBUG(VAL_SKIP)) + return; + + puts("finishme: pco_validate_shader"); +#endif /* NDEBUG */ +}