mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-09 02:28:10 +02:00
pvr: debug: Add "cs" debug option to dump control stream on job submit
With PVR_DEBUG=cs, the control stream will be dumped to stderr immediately prior to every render or compute job submission. Signed-off-by: Matt Coster <matt.coster@imgtec.com> Reviewed-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18948>
This commit is contained in:
parent
0432015265
commit
f9a234ef04
18 changed files with 2250 additions and 13 deletions
|
|
@ -24,11 +24,13 @@ libpowervr_common = static_library(
|
|||
[
|
||||
'pvr_debug.c',
|
||||
'pvr_device_info.c',
|
||||
'pvr_dump.c',
|
||||
'pvr_util.c',
|
||||
],
|
||||
include_directories : [
|
||||
inc_include,
|
||||
inc_src,
|
||||
inc_imagination,
|
||||
],
|
||||
c_args : [no_override_init_args],
|
||||
gnu_symbol_visibility : 'hidden',
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@
|
|||
|
||||
uint32_t PVR_DEBUG = 0;
|
||||
|
||||
/* clang-format off */
|
||||
static const struct debug_named_value debug_control[] = {
|
||||
/* Define debug values here in the same order as in "pvr_debug.h". Example:
|
||||
{ "some_option", PVR_DEBUG_SOME_OPTION,
|
||||
"This is a description for some option" },
|
||||
*/
|
||||
{ "cs", PVR_DEBUG_DUMP_CONTROL_STREAM,
|
||||
"Dump the contents of the control stream buffer on every job submit." },
|
||||
DEBUG_NAMED_VALUE_END
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
DEBUG_GET_ONCE_FLAGS_OPTION(pvr_debug, "PVR_DEBUG", debug_control, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@
|
|||
|
||||
extern uint32_t PVR_DEBUG;
|
||||
|
||||
/* Define debug values here. Example:
|
||||
#define PVR_DEBUG_SOME_OPTION BITFIELD_BIT(0)
|
||||
*/
|
||||
/* clang-format off */
|
||||
#define PVR_IS_DEBUG_SET(x) unlikely(PVR_DEBUG & PVR_DEBUG_##x)
|
||||
/* clang-format on */
|
||||
|
||||
#define PVR_DEBUG_DUMP_CONTROL_STREAM BITFIELD_BIT(0)
|
||||
|
||||
void pvr_process_debug_variable(void);
|
||||
|
||||
|
|
|
|||
276
src/imagination/common/pvr_dump.c
Normal file
276
src/imagination/common/pvr_dump.c
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pvr_dump.h"
|
||||
#include "pvr_util.h"
|
||||
|
||||
const struct pvr_dump_ctx __pvr_dump_ctx_invalid = {
|
||||
.active_child = &__pvr_dump_ctx_invalid,
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
Hex dumps
|
||||
*****************************************************************************/
|
||||
|
||||
#define HEX_WORD_SIZE ((unsigned)sizeof(uint32_t))
|
||||
#define HEX_WORD_FMT "%08" PRIx32
|
||||
|
||||
/* This must be even, and should probably always be a power of 2. */
|
||||
#define HEX_LINE_SIZE UINT32_C(8)
|
||||
|
||||
struct pvr_dump_hex_ctx {
|
||||
struct pvr_dump_ctx base;
|
||||
|
||||
const uint32_t *start_ptr;
|
||||
const uint32_t *end_ptr;
|
||||
|
||||
uint64_t nr_words;
|
||||
uint32_t offset_digits;
|
||||
|
||||
/* User-modifiable values */
|
||||
const uint32_t *line_ptr;
|
||||
|
||||
uint32_t prev_non_zero_trailing_zero_words;
|
||||
uint64_t prev_non_zero_leading_zero_lines;
|
||||
const uint32_t *prev_non_zero_line;
|
||||
uint64_t zero_lines;
|
||||
};
|
||||
|
||||
static bool pvr_dump_hex_ctx_push(struct pvr_dump_hex_ctx *const ctx,
|
||||
struct pvr_dump_buffer_ctx *const parent_ctx,
|
||||
const uint64_t nr_words)
|
||||
{
|
||||
const uint64_t real_nr_words =
|
||||
nr_words ? nr_words : parent_ctx->remaining_size / HEX_WORD_SIZE;
|
||||
const uint64_t nr_bytes = real_nr_words * HEX_WORD_SIZE;
|
||||
bool ret;
|
||||
|
||||
if (parent_ctx->remaining_size < nr_bytes ||
|
||||
(!nr_words && nr_bytes != parent_ctx->remaining_size) ||
|
||||
!ptr_is_aligned(parent_ctx->ptr, HEX_WORD_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = pvr_dump_ctx_push(&ctx->base, &parent_ctx->base);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
ctx->start_ptr = parent_ctx->ptr;
|
||||
ctx->end_ptr = ctx->start_ptr + real_nr_words;
|
||||
ctx->nr_words = real_nr_words;
|
||||
ctx->offset_digits = u64_hex_digits(nr_bytes);
|
||||
|
||||
ctx->line_ptr = ctx->start_ptr;
|
||||
|
||||
ctx->prev_non_zero_trailing_zero_words = 0;
|
||||
ctx->prev_non_zero_leading_zero_lines = 0;
|
||||
ctx->prev_non_zero_line = NULL;
|
||||
ctx->zero_lines = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct pvr_dump_buffer_ctx *
|
||||
pvr_dump_hex_ctx_pop(struct pvr_dump_hex_ctx *const ctx)
|
||||
{
|
||||
struct pvr_dump_buffer_ctx *parent;
|
||||
struct pvr_dump_ctx *parent_base;
|
||||
|
||||
if (ctx->line_ptr != ctx->end_ptr) {
|
||||
ctx->base.ok = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parent_base = pvr_dump_ctx_pop(&ctx->base);
|
||||
if (!parent_base)
|
||||
return NULL;
|
||||
|
||||
parent = container_of(parent_base, struct pvr_dump_buffer_ctx, base);
|
||||
|
||||
pvr_dump_buffer_advance(parent, ctx->nr_words * HEX_WORD_SIZE);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static inline void pvr_dump_hex_print_prefix(const struct pvr_dump_hex_ctx *ctx,
|
||||
const uint64_t offset)
|
||||
{
|
||||
pvr_dump_printf(&ctx->base,
|
||||
PVR_DUMP_OFFSET_PREFIX,
|
||||
ctx->offset_digits,
|
||||
offset * HEX_WORD_SIZE);
|
||||
}
|
||||
|
||||
#define pvr_dump_hex_println(ctx, offset, format, args...) \
|
||||
pvr_dump_println(&(ctx)->base, \
|
||||
PVR_DUMP_OFFSET_PREFIX format, \
|
||||
(ctx)->offset_digits, \
|
||||
offset, \
|
||||
##args);
|
||||
|
||||
#define pvr_dump_hex_println_no_prefix(ctx, format, args...) \
|
||||
pvr_dump_println(&(ctx)->base, \
|
||||
"%*c" format, \
|
||||
(ctx)->offset_digits + 3, \
|
||||
' ', \
|
||||
##args);
|
||||
|
||||
static void
|
||||
pvr_dump_hex_print_zero_lines(const struct pvr_dump_hex_ctx *const ctx,
|
||||
const uint64_t zero_lines)
|
||||
{
|
||||
const uint64_t zero_words = zero_lines * HEX_LINE_SIZE;
|
||||
const uint64_t zero_bytes = zero_words * HEX_WORD_SIZE;
|
||||
|
||||
if (zero_lines == 0)
|
||||
return;
|
||||
|
||||
pvr_dump_hex_println_no_prefix(ctx,
|
||||
" + %" PRIu64 " zero line%s (%" PRIu64
|
||||
" words; %" PRIu64 "/0x%" PRIx64 " bytes)",
|
||||
zero_lines,
|
||||
zero_lines == 1 ? "" : "s",
|
||||
zero_words,
|
||||
zero_bytes,
|
||||
zero_bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
pvr_dump_hex_print_trailing_zeroes(const struct pvr_dump_hex_ctx *const ctx)
|
||||
{
|
||||
const uint64_t zero_words =
|
||||
ctx->zero_lines * HEX_LINE_SIZE + ctx->prev_non_zero_trailing_zero_words;
|
||||
const uint64_t zero_bytes = zero_words * HEX_WORD_SIZE;
|
||||
|
||||
if (!ctx->prev_non_zero_trailing_zero_words)
|
||||
return pvr_dump_hex_print_zero_lines(ctx, ctx->zero_lines);
|
||||
|
||||
if (!ctx->zero_lines)
|
||||
return;
|
||||
|
||||
pvr_dump_hex_println_no_prefix(ctx,
|
||||
" + %" PRIu64 "+%" PRIu32
|
||||
" zero lines (%" PRIu64 " words; %" PRIu64
|
||||
"/0x%" PRIx64 " bytes)",
|
||||
ctx->zero_lines,
|
||||
ctx->prev_non_zero_trailing_zero_words,
|
||||
zero_words,
|
||||
zero_bytes,
|
||||
zero_bytes);
|
||||
}
|
||||
|
||||
static void pvr_dump_hex_print_line(struct pvr_dump_hex_ctx *ctx,
|
||||
const uint32_t *const line_ptr,
|
||||
const uint32_t truncate)
|
||||
{
|
||||
const uint32_t nr_words =
|
||||
MIN2(HEX_LINE_SIZE - truncate, ctx->end_ptr - line_ptr);
|
||||
|
||||
pvr_dump_hex_print_prefix(ctx, line_ptr - ctx->start_ptr);
|
||||
|
||||
for (uint32_t i = 0; i < nr_words; i++) {
|
||||
if (i == HEX_LINE_SIZE / 2)
|
||||
pvr_dump_printf_cont(&ctx->base, " ");
|
||||
|
||||
pvr_dump_printf_cont(&ctx->base, " " HEX_WORD_FMT, line_ptr[i]);
|
||||
}
|
||||
|
||||
pvr_dump_print_eol(&ctx->base);
|
||||
}
|
||||
|
||||
static void pvr_dump_hex_process_line(struct pvr_dump_hex_ctx *const ctx)
|
||||
{
|
||||
uint32_t trailing_zero_words = HEX_LINE_SIZE;
|
||||
|
||||
for (uint32_t i = HEX_LINE_SIZE; i > 0; i--) {
|
||||
if (ctx->line_ptr[i - 1]) {
|
||||
trailing_zero_words = HEX_LINE_SIZE - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trailing_zero_words == HEX_LINE_SIZE) {
|
||||
/* No non-zero words were found in this line; mark it and move on. */
|
||||
ctx->zero_lines++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have at least one non-zero word in this line. If we have a previous
|
||||
* non-zero line stored, collapse and print any leading zero-only lines
|
||||
* before it then print the stored line.
|
||||
*/
|
||||
if (ctx->prev_non_zero_line) {
|
||||
pvr_dump_hex_print_zero_lines(ctx, ctx->prev_non_zero_leading_zero_lines);
|
||||
pvr_dump_hex_print_line(ctx, ctx->prev_non_zero_line, 0);
|
||||
}
|
||||
|
||||
/* Now we store the current non-zero line for printing later. This way we
|
||||
* can treat the last non-zero line specially.
|
||||
*/
|
||||
ctx->prev_non_zero_line = ctx->line_ptr;
|
||||
ctx->prev_non_zero_leading_zero_lines = ctx->zero_lines;
|
||||
ctx->prev_non_zero_trailing_zero_words = trailing_zero_words;
|
||||
ctx->zero_lines = 0;
|
||||
}
|
||||
|
||||
static void pvr_dump_hex(struct pvr_dump_hex_ctx *const ctx)
|
||||
{
|
||||
while (ctx->end_ptr - ctx->line_ptr > 0) {
|
||||
pvr_dump_hex_process_line(ctx);
|
||||
ctx->line_ptr += HEX_LINE_SIZE;
|
||||
}
|
||||
|
||||
if (ctx->prev_non_zero_line) {
|
||||
pvr_dump_hex_print_zero_lines(ctx, ctx->prev_non_zero_leading_zero_lines);
|
||||
pvr_dump_hex_print_line(ctx,
|
||||
ctx->prev_non_zero_line,
|
||||
ctx->prev_non_zero_trailing_zero_words);
|
||||
|
||||
/* Collapse and print any trailing zeroes. */
|
||||
pvr_dump_hex_print_trailing_zeroes(ctx);
|
||||
} else {
|
||||
/* We made it to the end of the buffer without ever encountering a
|
||||
* non-zero word. Make this known.
|
||||
*/
|
||||
pvr_dump_hex_println(ctx, UINT64_C(0), " <empty buffer>");
|
||||
}
|
||||
|
||||
pvr_dump_hex_println(ctx, ctx->nr_words, " <end of buffer>");
|
||||
}
|
||||
|
||||
bool pvr_dump_buffer_hex(struct pvr_dump_buffer_ctx *const ctx,
|
||||
const uint64_t nr_words)
|
||||
{
|
||||
struct pvr_dump_hex_ctx hex_ctx;
|
||||
|
||||
if (!pvr_dump_hex_ctx_push(&hex_ctx, ctx, nr_words))
|
||||
return false;
|
||||
|
||||
pvr_dump_hex(&hex_ctx);
|
||||
|
||||
return !!pvr_dump_hex_ctx_pop(&hex_ctx);
|
||||
}
|
||||
594
src/imagination/common/pvr_dump.h
Normal file
594
src/imagination/common/pvr_dump.h
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PVR_DUMP_H
|
||||
#define PVR_DUMP_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pvr_types.h"
|
||||
#include "pvr_util.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/u_math.h"
|
||||
|
||||
/** BASIC PRINTING **/
|
||||
|
||||
#define PVR_DUMP_OFFSET_PREFIX "[%0*" PRIx64 "] "
|
||||
|
||||
/** CONTEXTS **/
|
||||
|
||||
#define PVR_DUMP_INDENT_SIZE 2U
|
||||
#define PVR_DUMP_FIELD_COLUMN_WIDTH 36U
|
||||
|
||||
/* This is an invalid context used to permanently mark popped contexts as
|
||||
* unusable. All operations on a context check that it's the "top" context
|
||||
* by ensuring it has no active child. The only way to remove the active child
|
||||
* of a context is by popping the active child directly. Assigning an invalid
|
||||
* context as the active child of a context therefore makes it impossible to
|
||||
* use.
|
||||
*/
|
||||
extern const struct pvr_dump_ctx __pvr_dump_ctx_invalid;
|
||||
|
||||
struct pvr_dump_ctx {
|
||||
/* This is const because only the "top" context should ever be modified. It's
|
||||
* fine to extract information from the parent context, but not to modify it.
|
||||
* There is *one* exception: pvr_dump_ctx_pop() must cast away the const to
|
||||
* return the parent context as the new "top" context. This is considered
|
||||
* sound because the parent context was not const when assigned here in
|
||||
* pvr_dump_ctx_push().
|
||||
*/
|
||||
const struct pvr_dump_ctx *parent;
|
||||
|
||||
/* This is const because it's not meant to be used for access - it's just a
|
||||
* way of checking if this context is the "top" context (see the comment on
|
||||
* __pvr_dump_ctx_invalid for more details). Unlike parent, the const
|
||||
* qualifier here should never be cast away.
|
||||
*/
|
||||
const struct pvr_dump_ctx *active_child;
|
||||
|
||||
FILE *file;
|
||||
const char *name;
|
||||
|
||||
uint32_t allowed_child_depth;
|
||||
uint32_t parent_indent;
|
||||
|
||||
/* User-modifiable values */
|
||||
uint32_t indent;
|
||||
bool ok;
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
__pvr_dump_ctx_get_indent(const struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
return (ctx->parent_indent + ctx->indent) * PVR_DUMP_INDENT_SIZE;
|
||||
}
|
||||
|
||||
struct pvr_dump_buffer_ctx {
|
||||
struct pvr_dump_ctx base;
|
||||
|
||||
const void *initial_ptr;
|
||||
uint64_t capacity;
|
||||
|
||||
/* User-modifiable values */
|
||||
const void *ptr;
|
||||
uint64_t remaining_size;
|
||||
};
|
||||
|
||||
#define pvr_dump_printf(ctx, format, args...) \
|
||||
pvr_dump_printf_cont(ctx, \
|
||||
"%*s" format, \
|
||||
__pvr_dump_ctx_get_indent(ctx), \
|
||||
"", \
|
||||
##args)
|
||||
|
||||
/* Same as pvr_dump_printf(), but with no indent.
|
||||
* Intended for continuation lines.
|
||||
*/
|
||||
#define pvr_dump_printf_cont(ctx, format, args...) \
|
||||
fprintf((ctx)->file, format, ##args)
|
||||
|
||||
#define pvr_dump_println(ctx, format, args...) \
|
||||
pvr_dump_printf(ctx, format "\n", ##args)
|
||||
|
||||
#define pvr_dump_println_cont(ctx, format, args...) \
|
||||
pvr_dump_printf_cont(ctx, format "\n", ##args)
|
||||
|
||||
#define pvr_dump_print_eol(ctx) fprintf((ctx)->file, "\n")
|
||||
|
||||
#define pvr_dump_mark_section(ctx, format, args...) \
|
||||
do { \
|
||||
pvr_dump_print_eol(ctx); \
|
||||
pvr_dump_println(ctx, "------- " format " -------", ##args); \
|
||||
} while (0)
|
||||
|
||||
#define pvr_dump_buffer_print_header_prefix(ctx) \
|
||||
do { \
|
||||
struct pvr_dump_buffer_ctx *_prefix_ctx = (ctx); \
|
||||
pvr_dump_printf(&_prefix_ctx->base, \
|
||||
PVR_DUMP_OFFSET_PREFIX, \
|
||||
u64_dec_digits(_prefix_ctx->capacity), \
|
||||
_prefix_ctx->capacity - _prefix_ctx->remaining_size); \
|
||||
} while (0)
|
||||
|
||||
#define pvr_dump_buffer_print_header_line(ctx, format, args...) \
|
||||
do { \
|
||||
struct pvr_dump_buffer_ctx *_ctx = (ctx); \
|
||||
pvr_dump_buffer_print_header_prefix(_ctx); \
|
||||
pvr_dump_printf_cont(&_ctx->base, format "\n", ##args); \
|
||||
} while (0)
|
||||
|
||||
#define pvr_dump_error(ctx, format, args...) \
|
||||
({ \
|
||||
struct pvr_dump_ctx *_ctx = (ctx); \
|
||||
pvr_dump_println(_ctx, "<!ERROR! " format ">", ##args); \
|
||||
_ctx->ok = false; \
|
||||
false; \
|
||||
})
|
||||
|
||||
static inline bool pvr_dump_ctx_require_top(struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
if (ctx->active_child != NULL)
|
||||
return pvr_dump_error(ctx, "use of non-top context");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void pvr_dump_indent(struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
ctx->indent++;
|
||||
}
|
||||
|
||||
static inline void pvr_dump_dedent(struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
if (ctx->indent)
|
||||
ctx->indent--;
|
||||
}
|
||||
|
||||
static inline void __pvr_dump_ctx_init(struct pvr_dump_ctx *const ctx,
|
||||
const struct pvr_dump_ctx *const parent,
|
||||
FILE *const file,
|
||||
const char *const name,
|
||||
const uint32_t allowed_child_depth,
|
||||
const uint32_t parent_indent)
|
||||
{
|
||||
ctx->parent = parent;
|
||||
ctx->active_child = NULL;
|
||||
|
||||
ctx->file = file;
|
||||
ctx->name = name;
|
||||
|
||||
ctx->allowed_child_depth = allowed_child_depth;
|
||||
ctx->parent_indent = parent_indent;
|
||||
ctx->indent = 0;
|
||||
ctx->ok = true;
|
||||
}
|
||||
|
||||
static inline void __pvr_dump_ctx_mark_popped(struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
ctx->active_child = &__pvr_dump_ctx_invalid;
|
||||
}
|
||||
|
||||
static inline void pvr_dump_begin(struct pvr_dump_ctx *const root_ctx,
|
||||
FILE *const file,
|
||||
const char *const name,
|
||||
const uint32_t max_depth)
|
||||
{
|
||||
__pvr_dump_ctx_init(root_ctx, NULL, file, name, max_depth, 0);
|
||||
|
||||
flockfile(file);
|
||||
pvr_dump_println(root_ctx, "======= BEGIN %s =======", name);
|
||||
}
|
||||
|
||||
static inline bool pvr_dump_end(struct pvr_dump_ctx *const root_ctx)
|
||||
{
|
||||
/* In order to end a dump, we must be in a root context (no parent) and have
|
||||
* no active child context.
|
||||
*/
|
||||
if (!pvr_dump_ctx_require_top(root_ctx))
|
||||
return false;
|
||||
|
||||
if (root_ctx->parent)
|
||||
return pvr_dump_error(root_ctx, "ending non-root context");
|
||||
|
||||
pvr_dump_println(root_ctx, "======= END %s =======", root_ctx->name);
|
||||
funlockfile(root_ctx->file);
|
||||
|
||||
__pvr_dump_ctx_mark_popped(root_ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pvr_dump_ctx_push(struct pvr_dump_ctx *const ctx,
|
||||
struct pvr_dump_ctx *const parent_ctx)
|
||||
{
|
||||
if (!parent_ctx->ok)
|
||||
return false;
|
||||
|
||||
if (!parent_ctx->allowed_child_depth)
|
||||
return pvr_dump_error(parent_ctx, "context stack depth limit reached");
|
||||
|
||||
__pvr_dump_ctx_init(ctx,
|
||||
parent_ctx,
|
||||
parent_ctx->file,
|
||||
parent_ctx->name,
|
||||
parent_ctx->allowed_child_depth - 1,
|
||||
parent_ctx->parent_indent + parent_ctx->indent);
|
||||
|
||||
parent_ctx->active_child = ctx;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline struct pvr_dump_ctx *
|
||||
pvr_dump_ctx_pop(struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
struct pvr_dump_ctx *const parent = (struct pvr_dump_ctx *)ctx->parent;
|
||||
|
||||
if (!pvr_dump_ctx_require_top(ctx))
|
||||
return NULL;
|
||||
|
||||
if (!parent) {
|
||||
pvr_dump_error(ctx, "popped root context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parent->active_child = NULL;
|
||||
|
||||
__pvr_dump_ctx_mark_popped(ctx);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pvr_dump_buffer_ctx_push(struct pvr_dump_buffer_ctx *const ctx,
|
||||
struct pvr_dump_ctx *const parent_ctx,
|
||||
const void *const initial_ptr,
|
||||
const uint64_t size)
|
||||
{
|
||||
if (!pvr_dump_ctx_push(&ctx->base, parent_ctx))
|
||||
return false;
|
||||
|
||||
ctx->initial_ptr = initial_ptr;
|
||||
ctx->capacity = size;
|
||||
|
||||
ctx->ptr = initial_ptr;
|
||||
ctx->remaining_size = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline struct pvr_dump_ctx *
|
||||
pvr_dump_buffer_ctx_pop(struct pvr_dump_buffer_ctx *const ctx)
|
||||
{
|
||||
return pvr_dump_ctx_pop(&ctx->base);
|
||||
}
|
||||
|
||||
bool pvr_dump_buffer_hex(struct pvr_dump_buffer_ctx *ctx, uint64_t nr_words);
|
||||
|
||||
static inline void __pvr_dump_buffer_advance(struct pvr_dump_buffer_ctx *ctx,
|
||||
const uint64_t nr_bytes)
|
||||
{
|
||||
ctx->ptr += nr_bytes;
|
||||
ctx->remaining_size -= nr_bytes;
|
||||
}
|
||||
|
||||
static inline bool pvr_dump_buffer_advance(struct pvr_dump_buffer_ctx *ctx,
|
||||
const uint64_t nr_bytes)
|
||||
{
|
||||
if (!ctx->base.ok || !pvr_dump_ctx_require_top(&ctx->base))
|
||||
return false;
|
||||
|
||||
if (nr_bytes > ctx->remaining_size)
|
||||
return pvr_dump_error(&ctx->base, "advanced past end of context buffer");
|
||||
|
||||
__pvr_dump_buffer_advance(ctx, nr_bytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool pvr_dump_buffer_truncate(struct pvr_dump_buffer_ctx *ctx,
|
||||
const uint64_t remaining_size)
|
||||
{
|
||||
if (!ctx->base.ok || !pvr_dump_ctx_require_top(&ctx->base))
|
||||
return false;
|
||||
|
||||
if (remaining_size > ctx->remaining_size)
|
||||
return pvr_dump_error(&ctx->base, "truncated to larger size");
|
||||
|
||||
ctx->remaining_size = remaining_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline const void *restrict
|
||||
pvr_dump_buffer_peek(struct pvr_dump_buffer_ctx *const restrict ctx,
|
||||
const uint64_t nr_bytes)
|
||||
{
|
||||
if (!ctx->base.ok || !pvr_dump_ctx_require_top(&ctx->base))
|
||||
return NULL;
|
||||
|
||||
if (nr_bytes > ctx->remaining_size) {
|
||||
pvr_dump_error(&ctx->base, "peeked past end of context buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx->ptr;
|
||||
}
|
||||
|
||||
static inline const void *restrict
|
||||
pvr_dump_buffer_take(struct pvr_dump_buffer_ctx *const restrict ctx,
|
||||
const uint64_t nr_bytes)
|
||||
{
|
||||
const void *const ptr = pvr_dump_buffer_peek(ctx, nr_bytes);
|
||||
|
||||
if (ptr)
|
||||
__pvr_dump_buffer_advance(ctx, nr_bytes);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pvr_dump_buffer_restart(struct pvr_dump_buffer_ctx *const ctx)
|
||||
{
|
||||
ctx->ptr = ctx->initial_ptr;
|
||||
ctx->remaining_size = ctx->capacity;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Field printers
|
||||
*****************************************************************************/
|
||||
|
||||
#define pvr_dump_field(ctx, name, format, args...) \
|
||||
pvr_dump_println(ctx, \
|
||||
"%-*s : " format, \
|
||||
PVR_DUMP_FIELD_COLUMN_WIDTH - \
|
||||
__pvr_dump_ctx_get_indent(ctx), \
|
||||
name, \
|
||||
##args)
|
||||
|
||||
#define pvr_dump_field_computed(ctx, name, format, raw_format, args...) \
|
||||
pvr_dump_field(ctx, name, format " (" raw_format ")", ##args)
|
||||
|
||||
#define pvr_dump_field_error(ctx, format, args...) \
|
||||
({ \
|
||||
struct pvr_dump_ctx *_ctx = (ctx); \
|
||||
pvr_dump_field(_ctx, "<!ERROR!>", "<" format ">", ##args); \
|
||||
_ctx->ok = false; \
|
||||
false; \
|
||||
})
|
||||
|
||||
/*****************************************************************************
|
||||
Field printers: integers
|
||||
*****************************************************************************/
|
||||
|
||||
static inline void pvr_dump_field_u32(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value)
|
||||
{
|
||||
pvr_dump_field(ctx, name, "%" PRIu32, value);
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_u32_units(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value,
|
||||
const char *const units)
|
||||
{
|
||||
pvr_dump_field(ctx, name, "%" PRIu32 " %s", value, units);
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_u32_offset(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value,
|
||||
const uint32_t offset)
|
||||
{
|
||||
pvr_dump_field_computed(ctx,
|
||||
name,
|
||||
"%" PRIu32,
|
||||
"%" PRIu32 " + %" PRIu32,
|
||||
value + offset,
|
||||
value,
|
||||
offset);
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_u32_scaled(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value,
|
||||
const uint32_t scale)
|
||||
{
|
||||
pvr_dump_field_computed(ctx,
|
||||
name,
|
||||
"%" PRIu32,
|
||||
"%" PRIu32 " x %" PRIu32,
|
||||
value * scale,
|
||||
value,
|
||||
scale);
|
||||
}
|
||||
|
||||
static inline void
|
||||
pvr_dump_field_u32_scaled_units(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value,
|
||||
const uint32_t scale,
|
||||
const char *const units)
|
||||
{
|
||||
pvr_dump_field_computed(ctx,
|
||||
name,
|
||||
"%" PRIu32 " %s",
|
||||
"%" PRIu32 " x %" PRIu32 " %s",
|
||||
value * scale,
|
||||
units,
|
||||
value,
|
||||
scale,
|
||||
units);
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_u32_zero(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value,
|
||||
const uint32_t zero_value)
|
||||
{
|
||||
if (value)
|
||||
pvr_dump_field_u32(ctx, name, value);
|
||||
else
|
||||
pvr_dump_field_computed(ctx, name, "%" PRIu32, "0", zero_value);
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_x32(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const uint32_t value,
|
||||
const uint32_t chars)
|
||||
{
|
||||
pvr_dump_field(ctx,
|
||||
name,
|
||||
"0x%0*" PRIx32,
|
||||
chars,
|
||||
value & BITFIELD_MASK(chars * 4));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Field printers: device address
|
||||
*****************************************************************************/
|
||||
|
||||
static inline void pvr_dump_field_addr_non_null(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const pvr_dev_addr_t value)
|
||||
{
|
||||
pvr_dump_field(ctx, name, PVR_DEV_ADDR_FMT, value.addr);
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_addr(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const pvr_dev_addr_t value)
|
||||
{
|
||||
if (value.addr)
|
||||
pvr_dump_field_addr_non_null(ctx, name, value);
|
||||
else
|
||||
pvr_dump_field(ctx, name, "<null>");
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_addr_split(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const pvr_dev_addr_t msb,
|
||||
const pvr_dev_addr_t lsb)
|
||||
{
|
||||
pvr_dump_field_addr(ctx, name, PVR_DEV_ADDR(msb.addr | lsb.addr));
|
||||
|
||||
pvr_dump_indent(ctx);
|
||||
pvr_dump_field_addr_non_null(ctx, "msb", msb);
|
||||
pvr_dump_field_addr_non_null(ctx, "lsb", lsb);
|
||||
pvr_dump_dedent(ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Field printers: enums
|
||||
*****************************************************************************/
|
||||
|
||||
#define pvr_dump_field_enum(ctx, name, value, to_str) \
|
||||
do { \
|
||||
__typeof__(value) _value = (value); \
|
||||
const char *_str = to_str(_value); \
|
||||
if (!_str) \
|
||||
_str = "<unknown>"; \
|
||||
pvr_dump_field_computed(ctx, name, "%s", "%u", _str, _value); \
|
||||
} while (0)
|
||||
|
||||
static inline const char *__bool_to_str(const bool b)
|
||||
{
|
||||
return b ? "yes" : "no";
|
||||
}
|
||||
|
||||
/* A bool is just an enum with two values. */
|
||||
static inline void pvr_dump_field_bool(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name,
|
||||
const bool value)
|
||||
{
|
||||
pvr_dump_field_enum(ctx, name, value, __bool_to_str);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Field printers: not present
|
||||
*****************************************************************************/
|
||||
|
||||
static inline void pvr_dump_field_no_fields(struct pvr_dump_ctx *const ctx)
|
||||
{
|
||||
pvr_dump_println(ctx, "<no fields>");
|
||||
}
|
||||
|
||||
static inline void pvr_dump_field_not_present(struct pvr_dump_ctx *const ctx,
|
||||
const char *const name)
|
||||
{
|
||||
pvr_dump_field(ctx, name, "<not present>");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Field printers: helpers for members
|
||||
*****************************************************************************/
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define pvr_dump_field_member_u32(ctx, compound, member) \
|
||||
pvr_dump_field_u32(ctx, #member, (compound)->member)
|
||||
|
||||
#define pvr_dump_field_member_u32_units(ctx, compound, member, units) \
|
||||
pvr_dump_field_u32_units(ctx, #member, (compound)->member, units)
|
||||
|
||||
#define pvr_dump_field_member_u32_offset(ctx, compound, member, offset) \
|
||||
pvr_dump_field_u32_offset(ctx, #member, (compound)->member, offset)
|
||||
|
||||
#define pvr_dump_field_member_u32_scaled(ctx, compound, member, scale) \
|
||||
pvr_dump_field_u32_scaled(ctx, #member, (compound)->member, scale)
|
||||
|
||||
#define pvr_dump_field_member_u32_scaled_units(ctx, compound, member, scale, units) \
|
||||
pvr_dump_field_u32_scaled_units(ctx, #member, (compound)->member, scale, units)
|
||||
|
||||
#define pvr_dump_field_member_u32_zero(ctx, compound, member, zero_value) \
|
||||
pvr_dump_field_u32_zero(ctx, #member, (compound)->member, zero_value)
|
||||
|
||||
#define pvr_dump_field_member_x32(ctx, compound, member, chars) \
|
||||
pvr_dump_field_x32(ctx, #member, (compound)->member, chars)
|
||||
|
||||
#define pvr_dump_field_member_f32(ctx, compound, member) \
|
||||
pvr_dump_field_f32(ctx, #member, (compound)->member)
|
||||
|
||||
#define pvr_dump_field_member_addr(ctx, compound, member) \
|
||||
pvr_dump_field_addr(ctx, #member, (compound)->member)
|
||||
|
||||
#define pvr_dump_field_member_enum(ctx, compound, member, to_str) \
|
||||
pvr_dump_field_enum(ctx, #member, (compound)->member, to_str)
|
||||
|
||||
#define pvr_dump_field_member_bool(ctx, compound, member) \
|
||||
pvr_dump_field_bool(ctx, #member, (compound)->member)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define pvr_dump_field_member_not_present(ctx, compound, member) \
|
||||
do { \
|
||||
(void)&(compound)->member; \
|
||||
pvr_dump_field_not_present(ctx, #member); \
|
||||
} while (0)
|
||||
|
||||
#endif /* PVR_DUMP_H */
|
||||
|
|
@ -24,9 +24,18 @@
|
|||
#ifndef PVR_UTIL_H
|
||||
#define PVR_UTIL_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/bitscan.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
static inline bool ptr_is_aligned(const void *const ptr,
|
||||
const uint32_t alignment)
|
||||
{
|
||||
assert(util_is_power_of_two_nonzero(alignment));
|
||||
return ((uintptr_t)(ptr) & (alignment - 1)) == 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Math functions
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef PVR_TYPES_H
|
||||
#define PVR_TYPES_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
@ -38,4 +39,7 @@ typedef struct pvr_dev_addr {
|
|||
#define PVR_DEV_ADDR_OFFSET(base, offset) PVR_DEV_ADDR((base).addr + (offset))
|
||||
#define PVR_DEV_ADDR_INVALID PVR_DEV_ADDR(0)
|
||||
|
||||
/* All currently supported devices use a 40-bit virtual address space. */
|
||||
#define PVR_DEV_ADDR_FMT "0x%010" PRIx64
|
||||
|
||||
#endif /* PVR_TYPES_H */
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ pvr_files = files(
|
|||
'pvr_csb.c',
|
||||
'pvr_descriptor_set.c',
|
||||
'pvr_device.c',
|
||||
'pvr_dump_bo.c',
|
||||
'pvr_dump_csb.c',
|
||||
'pvr_formats.c',
|
||||
'pvr_hardcode.c',
|
||||
'pvr_hw_pass.c',
|
||||
|
|
|
|||
|
|
@ -27,12 +27,62 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "pvr_bo.h"
|
||||
#include "pvr_dump.h"
|
||||
#include "pvr_private.h"
|
||||
#include "pvr_types.h"
|
||||
#include "pvr_winsys.h"
|
||||
#include "vk_alloc.h"
|
||||
#include "vk_log.h"
|
||||
|
||||
static void pvr_bo_dump_line(struct pvr_dump_ctx *const ctx,
|
||||
const struct pvr_bo *bo,
|
||||
const uint32_t index,
|
||||
const uint32_t nr_bos_log10)
|
||||
{
|
||||
static const char *const pretty_sizes[64 + 1] = {
|
||||
"", "1 B", "2 B", "4 B", "8 B", "16 B",
|
||||
"32 B", "64 B", "128 B", "256 B", "512 B", "1 KiB",
|
||||
"2 KiB", "4 KiB", "8 KiB", "16 KiB", "32 KiB", "64 KiB",
|
||||
"128 KiB", "256 KiB", "512 KiB", "1 MiB", "2 MiB", "4 MiB",
|
||||
"8 MiB", "16 MiB", "32 MiB", "64 MiB", "128 MiB", "256 MiB",
|
||||
"512 MiB", "1 GiB", "2 GiB", "4 GiB", "8 GiB", "16 GiB",
|
||||
"32 GiB", "64 GiB", "128 GiB", "256 GiB", "512 GiB", "1 TiB",
|
||||
"2 TiB", "4 TiB", "8 TiB", "16 TiB", "32 TiB", "64 TiB",
|
||||
"128 TiB", "256 TiB", "512 TiB", "1 PiB", "2 PiB", "4 PiB",
|
||||
"8 PiB", "16 PiB", "32 PiB", "64 PiB", "128 PiB", "256 PiB",
|
||||
"512 PiB", "1 EiB", "2 EiB", "4 EiB", "8 EiB",
|
||||
};
|
||||
|
||||
const uint64_t size = bo->vma->size;
|
||||
const uint32_t size_log2 =
|
||||
util_is_power_of_two_or_zero64(size) ? util_last_bit(size) : 0;
|
||||
|
||||
pvr_dump_println(ctx,
|
||||
"[%0*" PRIu32 "] " PVR_DEV_ADDR_FMT " -> %*p "
|
||||
"(%s%s0x%" PRIx64 " bytes)",
|
||||
nr_bos_log10,
|
||||
index,
|
||||
bo->vma->dev_addr.addr,
|
||||
(int)sizeof(void *) * 2 + 2, /* nr hex digits + 0x prefix */
|
||||
bo->bo->map,
|
||||
pretty_sizes[size_log2],
|
||||
size_log2 ? ", " : "",
|
||||
size);
|
||||
}
|
||||
|
||||
void pvr_bo_list_dump(struct pvr_dump_ctx *const ctx,
|
||||
const struct list_head *const bo_list,
|
||||
const uint32_t nr_bos)
|
||||
{
|
||||
const uint32_t real_nr_bos = nr_bos ? nr_bos : list_length(bo_list);
|
||||
const uint32_t nr_bos_log10 = u32_dec_digits(real_nr_bos);
|
||||
uint32_t bo_idx = 0;
|
||||
|
||||
list_for_each_entry (struct pvr_bo, bo, bo_list, link) {
|
||||
pvr_bo_dump_line(ctx, bo, bo_idx++, nr_bos_log10);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pvr_bo_alloc_to_winsys_flags(uint64_t flags)
|
||||
{
|
||||
uint32_t ws_flags = 0;
|
||||
|
|
@ -103,6 +153,9 @@ VkResult pvr_bo_alloc(struct pvr_device *device,
|
|||
result = VK_ERROR_MEMORY_MAP_FAILED;
|
||||
goto err_buffer_destroy;
|
||||
}
|
||||
|
||||
if (flags & PVR_BO_ALLOC_FLAG_ZERO_ON_ALLOC)
|
||||
VG(VALGRIND_MAKE_MEM_DEFINED(map, pvr_bo->bo->size));
|
||||
}
|
||||
|
||||
pvr_bo->vma = device->ws->ops->heap_alloc(heap, size, alignment);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "util/macros.h"
|
||||
|
||||
struct pvr_device;
|
||||
struct pvr_dump_ctx;
|
||||
struct pvr_winsys_bo;
|
||||
struct pvr_winsys_vma;
|
||||
struct pvr_winsys_heap;
|
||||
|
|
@ -98,4 +99,8 @@ static ALWAYS_INLINE void *pvr_bo_cpu_map_unchanged(struct pvr_device *device,
|
|||
}
|
||||
#endif /* defined(HAVE_VALGRIND) */
|
||||
|
||||
void pvr_bo_list_dump(struct pvr_dump_ctx *ctx,
|
||||
const struct list_head *bo_list,
|
||||
uint32_t bo_size);
|
||||
|
||||
#endif /* PVR_BO_H */
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "hwdef/rogue_hw_utils.h"
|
||||
#include "pvr_bo.h"
|
||||
#include "pvr_csb.h"
|
||||
#include "pvr_debug.h"
|
||||
#include "pvr_device_info.h"
|
||||
#include "pvr_private.h"
|
||||
#include "util/list.h"
|
||||
|
|
@ -61,11 +62,6 @@
|
|||
* type control streams.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Size of the individual csb buffer object.
|
||||
*/
|
||||
#define PVR_CMD_BUFFER_CSB_BO_SIZE 4096
|
||||
|
||||
/**
|
||||
* \brief Initializes the csb object.
|
||||
*
|
||||
|
|
@ -137,9 +133,17 @@ static bool pvr_csb_buffer_extend(struct pvr_csb *csb)
|
|||
sizeof(uint32_t);
|
||||
const uint32_t cache_line_size =
|
||||
rogue_get_slc_cache_line_size(&csb->device->pdevice->dev_info);
|
||||
uint64_t alloc_flags = PVR_BO_ALLOC_FLAG_CPU_MAPPED;
|
||||
struct pvr_bo *pvr_bo;
|
||||
VkResult result;
|
||||
|
||||
/* If we're dumping the control stream, ensure the buffer is zeroed to make
|
||||
* the contents deterministic. This keeps valgrind happy and makes for
|
||||
* cleaner dump output.
|
||||
*/
|
||||
if (PVR_IS_DEBUG_SET(DUMP_CONTROL_STREAM))
|
||||
alloc_flags |= PVR_BO_ALLOC_FLAG_ZERO_ON_ALLOC;
|
||||
|
||||
/* Make sure extra space allocated for stream links is sufficient for both
|
||||
* stream types.
|
||||
*/
|
||||
|
|
@ -152,7 +156,7 @@ static bool pvr_csb_buffer_extend(struct pvr_csb *csb)
|
|||
csb->device->heaps.general_heap,
|
||||
PVR_CMD_BUFFER_CSB_BO_SIZE,
|
||||
cache_line_size,
|
||||
PVR_BO_ALLOC_FLAG_CPU_MAPPED,
|
||||
alloc_flags,
|
||||
&pvr_bo);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_error(csb->device, result);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@
|
|||
|
||||
#include "csbgen/rogue_hwdefs.h"
|
||||
|
||||
/**
|
||||
* \brief Size of the individual csb buffer object.
|
||||
*/
|
||||
#define PVR_CMD_BUFFER_CSB_BO_SIZE 4096
|
||||
|
||||
struct pvr_device;
|
||||
|
||||
enum pvr_cmd_stream_type {
|
||||
|
|
@ -132,6 +137,10 @@ void pvr_csb_emit_link(struct pvr_csb *csb, pvr_dev_addr_t addr, bool ret);
|
|||
VkResult pvr_csb_emit_return(struct pvr_csb *csb);
|
||||
VkResult pvr_csb_emit_terminate(struct pvr_csb *csb);
|
||||
|
||||
void pvr_csb_dump(const struct pvr_csb *csb,
|
||||
uint32_t frame_num,
|
||||
uint32_t job_num);
|
||||
|
||||
#define PVRX(x) ROGUE_##x
|
||||
#define pvr_cmd_length(x) PVRX(x##_length)
|
||||
#define pvr_cmd_header(x) PVRX(x##_header)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,21 @@
|
|||
#include "rogue/rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
static const char *
|
||||
pvr_cmd_stream_type_to_str(const enum pvr_cmd_stream_type stream_type)
|
||||
{
|
||||
switch (stream_type) {
|
||||
case PVR_CMD_STREAM_TYPE_INVALID:
|
||||
return "INVALID";
|
||||
case PVR_CMD_STREAM_TYPE_GRAPHICS:
|
||||
return "GRAPHICS";
|
||||
case PVR_CMD_STREAM_TYPE_COMPUTE:
|
||||
return "COMPUTE";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
CR
|
||||
******************************************************************************/
|
||||
|
|
|
|||
82
src/imagination/vulkan/pvr_dump_bo.c
Normal file
82
src/imagination/vulkan/pvr_dump_bo.c
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pvr_bo.h"
|
||||
#include "pvr_dump_bo.h"
|
||||
#include "pvr_dump.h"
|
||||
#include "pvr_winsys.h"
|
||||
#include "util/u_math.h"
|
||||
|
||||
struct pvr_device;
|
||||
|
||||
bool pvr_dump_bo_ctx_push(struct pvr_dump_bo_ctx *const ctx,
|
||||
struct pvr_dump_ctx *const parent_ctx,
|
||||
struct pvr_device *const device,
|
||||
struct pvr_bo *const bo)
|
||||
{
|
||||
bool did_map_bo = false;
|
||||
|
||||
if (!bo->bo->map) {
|
||||
if (!pvr_bo_cpu_map_unchanged(device, bo))
|
||||
goto err_out;
|
||||
|
||||
did_map_bo = true;
|
||||
}
|
||||
|
||||
if (bo->bo->size > UINT32_MAX) {
|
||||
mesa_logw_once("Attempted to dump a BO larger than 4GiB; time to rework"
|
||||
"pvr_dump_buffer_ctx to use 64-bit sizes.");
|
||||
goto err_unmap_bo;
|
||||
}
|
||||
|
||||
if (!pvr_dump_buffer_ctx_push(&ctx->base,
|
||||
parent_ctx,
|
||||
bo->bo->map,
|
||||
bo->bo->size)) {
|
||||
goto err_unmap_bo;
|
||||
}
|
||||
|
||||
ctx->device = device;
|
||||
ctx->bo = bo;
|
||||
ctx->bo_mapped_in_ctx = did_map_bo;
|
||||
|
||||
return true;
|
||||
|
||||
err_unmap_bo:
|
||||
if (did_map_bo)
|
||||
pvr_bo_cpu_unmap(device, bo);
|
||||
|
||||
err_out:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pvr_dump_bo_ctx_pop(struct pvr_dump_bo_ctx *const ctx)
|
||||
{
|
||||
if (ctx->bo_mapped_in_ctx)
|
||||
pvr_bo_cpu_unmap(ctx->device, ctx->bo);
|
||||
|
||||
return pvr_dump_buffer_ctx_pop(&ctx->base);
|
||||
}
|
||||
50
src/imagination/vulkan/pvr_dump_bo.h
Normal file
50
src/imagination/vulkan/pvr_dump_bo.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PVR_DUMP_BO_H
|
||||
#define PVR_DUMP_BO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "pvr_dump.h"
|
||||
|
||||
struct pvr_bo;
|
||||
struct pvr_device;
|
||||
|
||||
struct pvr_dump_bo_ctx {
|
||||
struct pvr_dump_buffer_ctx base;
|
||||
|
||||
struct pvr_device *device;
|
||||
struct pvr_bo *bo;
|
||||
bool bo_mapped_in_ctx;
|
||||
|
||||
/* No user-modifiable values */
|
||||
};
|
||||
|
||||
bool pvr_dump_bo_ctx_push(struct pvr_dump_bo_ctx *ctx,
|
||||
struct pvr_dump_ctx *parent_ctx,
|
||||
struct pvr_device *device,
|
||||
struct pvr_bo *bo);
|
||||
bool pvr_dump_bo_ctx_pop(struct pvr_dump_bo_ctx *ctx);
|
||||
|
||||
#endif /* PVR_DUMP_BO_H */
|
||||
1108
src/imagination/vulkan/pvr_dump_csb.c
Normal file
1108
src/imagination/vulkan/pvr_dump_csb.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -27,6 +27,7 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "pvr_csb.h"
|
||||
#include "pvr_debug.h"
|
||||
#include "pvr_job_common.h"
|
||||
#include "pvr_job_context.h"
|
||||
#include "pvr_job_compute.h"
|
||||
|
|
@ -213,6 +214,12 @@ VkResult pvr_compute_job_submit(struct pvr_compute_ctx *ctx,
|
|||
stage_flags,
|
||||
&submit_info);
|
||||
|
||||
if (PVR_IS_DEBUG_SET(DUMP_CONTROL_STREAM)) {
|
||||
pvr_csb_dump(&sub_cmd->control_stream,
|
||||
submit_info.frame_num,
|
||||
submit_info.job_num);
|
||||
}
|
||||
|
||||
return device->ws->ops->compute_submit(ctx->ws_ctx,
|
||||
&submit_info,
|
||||
&device->pdevice->dev_info,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "hwdef/rogue_hw_utils.h"
|
||||
#include "pvr_bo.h"
|
||||
#include "pvr_csb.h"
|
||||
#include "pvr_debug.h"
|
||||
#include "pvr_csb_enum_helpers.h"
|
||||
#include "pvr_debug.h"
|
||||
#include "pvr_job_common.h"
|
||||
|
|
@ -1677,6 +1678,20 @@ VkResult pvr_render_job_submit(struct pvr_render_ctx *ctx,
|
|||
stage_flags,
|
||||
&submit_info);
|
||||
|
||||
if (PVR_IS_DEBUG_SET(DUMP_CONTROL_STREAM)) {
|
||||
/* FIXME: This isn't an ideal method of accessing the information we
|
||||
* need, but it's considered good enough for a debug code path. It can be
|
||||
* streamlined and made more correct if/when pvr_render_job becomes a
|
||||
* subclass of pvr_sub_cmd.
|
||||
*/
|
||||
const struct pvr_sub_cmd *sub_cmd =
|
||||
container_of(job, const struct pvr_sub_cmd, gfx.job);
|
||||
|
||||
pvr_csb_dump(&sub_cmd->gfx.control_stream,
|
||||
submit_info.frame_num,
|
||||
submit_info.job_num);
|
||||
}
|
||||
|
||||
result = device->ws->ops->render_submit(ctx->ws_ctx,
|
||||
&submit_info,
|
||||
&device->pdevice->dev_info,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue