mesa/src/imagination/vulkan/pvr_dump_csb.c
Antonio Ospite ddf2aa3a4d build: avoid redefining unreachable() which is standard in C23
In the C23 standard unreachable() is now a predefined function-like
macro in <stddef.h>

See https://android.googlesource.com/platform/bionic/+/HEAD/docs/c23.md#is-now-a-predefined-function_like-macro-in

And this causes build errors when building for C23:

-----------------------------------------------------------------------
In file included from ../src/util/log.h:30,
                 from ../src/util/log.c:30:
../src/util/macros.h:123:9: warning: "unreachable" redefined
  123 | #define unreachable(str)    \
      |         ^~~~~~~~~~~
In file included from ../src/util/macros.h:31:
/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h:456:9: note: this is the location of the previous definition
  456 | #define unreachable() (__builtin_unreachable ())
      |         ^~~~~~~~~~~
-----------------------------------------------------------------------

So don't redefine it with the same name, but use the name UNREACHABLE()
to also signify it's a macro.

Using a different name also makes sense because the behavior of the
macro was extending the one of __builtin_unreachable() anyway, and it
also had a different signature, accepting one argument, compared to the
standard unreachable() with no arguments.

This change improves the chances of building mesa with the C23 standard,
which for instance is the default in recent AOSP versions.

All the instances of the macro, including the definition, were updated
with the following command line:

  git grep -l '[^_]unreachable(' -- "src/**" | sort | uniq | \
  while read file; \
  do \
    sed -e 's/\([^_]\)unreachable(/\1UNREACHABLE(/g' -i "$file"; \
  done && \
  sed -e 's/#undef unreachable/#undef UNREACHABLE/g' -i src/intel/isl/isl_aux_info.c

Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36437>
2025-07-31 17:49:42 +00:00

2433 lines
82 KiB
C

/*
* 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 <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <vulkan/vulkan.h>
#include "pvr_bo.h"
#include "pvr_csb.h"
#include "pvr_csb_enum_helpers.h"
#include "pvr_device_info.h"
#include "pvr_dump.h"
#include "pvr_dump_bo.h"
#include "pvr_private.h"
#include "pvr_util.h"
#include "util/list.h"
#include "util/macros.h"
#include "util/u_math.h"
#include "vk_enum_to_str.h"
/*****************************************************************************
Utilities
******************************************************************************/
#define PVR_DUMP_CSB_WORD_SIZE ((unsigned)sizeof(uint32_t))
enum buffer_type {
BUFFER_TYPE_NONE = 0,
BUFFER_TYPE_CDMCTRL,
BUFFER_TYPE_VDMCTRL,
BUFFER_TYPE_PPP,
BUFFER_TYPE_INVALID, /* Must be last. */
};
struct pvr_dump_csb_ctx {
struct pvr_dump_buffer_ctx base;
/* User-modifiable values */
uint32_t next_block_idx;
};
static inline bool
pvr_dump_csb_ctx_push(struct pvr_dump_csb_ctx *const ctx,
struct pvr_dump_buffer_ctx *const parent_ctx)
{
if (!pvr_dump_buffer_ctx_push(&ctx->base,
&parent_ctx->base,
parent_ctx->ptr,
parent_ctx->remaining_size)) {
return false;
}
ctx->next_block_idx = 0;
return true;
}
static inline struct pvr_dump_buffer_ctx *
pvr_dump_csb_ctx_pop(struct pvr_dump_csb_ctx *const ctx, bool advance_parent)
{
struct pvr_dump_buffer_ctx *parent;
struct pvr_dump_ctx *parent_base;
const uint64_t unused_words =
ctx->base.remaining_size / PVR_DUMP_CSB_WORD_SIZE;
if (unused_words) {
pvr_dump_buffer_print_header_line(&ctx->base,
"<%" PRIu64 " unused word%s (%" PRIu64
" bytes)>",
unused_words,
unused_words == 1 ? "" : "s",
unused_words * PVR_DUMP_CSB_WORD_SIZE);
pvr_dump_buffer_advance(&ctx->base,
unused_words * PVR_DUMP_CSB_WORD_SIZE);
}
pvr_dump_buffer_print_header_line(&ctx->base, "<end of buffer>");
parent_base = pvr_dump_buffer_ctx_pop(&ctx->base);
if (!parent_base)
return NULL;
parent = container_of(parent_base, struct pvr_dump_buffer_ctx, base);
if (advance_parent)
pvr_dump_buffer_advance(parent, ctx->base.capacity);
return parent;
}
struct pvr_dump_csb_block_ctx {
struct pvr_dump_buffer_ctx base;
};
#define pvr_dump_csb_block_ctx_push(ctx, \
parent_ctx, \
header_format, \
header_args...) \
({ \
struct pvr_dump_csb_ctx *const _csb_ctx = (parent_ctx); \
pvr_dump_buffer_print_header_line(&_csb_ctx->base, \
"%" PRIu32 ": " header_format, \
_csb_ctx->next_block_idx, \
##header_args); \
__pvr_dump_csb_block_ctx_push(ctx, _csb_ctx); \
})
static inline bool
__pvr_dump_csb_block_ctx_push(struct pvr_dump_csb_block_ctx *const ctx,
struct pvr_dump_csb_ctx *const parent_ctx)
{
pvr_dump_indent(&parent_ctx->base.base);
if (!pvr_dump_buffer_ctx_push(&ctx->base,
&parent_ctx->base.base,
parent_ctx->base.ptr,
parent_ctx->base.remaining_size)) {
return false;
}
parent_ctx->next_block_idx++;
return true;
}
static inline struct pvr_dump_csb_ctx *
pvr_dump_csb_block_ctx_pop(struct pvr_dump_csb_block_ctx *const ctx)
{
const uint64_t used_size = ctx->base.capacity - ctx->base.remaining_size;
struct pvr_dump_csb_ctx *parent_ctx;
struct pvr_dump_ctx *parent_base;
parent_base = pvr_dump_buffer_ctx_pop(&ctx->base);
if (!parent_base)
return NULL;
parent_ctx = container_of(parent_base, struct pvr_dump_csb_ctx, base.base);
/* No need to check this since it can never fail. */
pvr_dump_buffer_advance(&parent_ctx->base, used_size);
pvr_dump_dedent(parent_base);
return parent_ctx;
}
static inline const uint32_t *
pvr_dump_csb_block_take(struct pvr_dump_csb_block_ctx *const restrict ctx,
const uint32_t nr_words)
{
return pvr_dump_buffer_take(&ctx->base, nr_words * PVR_DUMP_CSB_WORD_SIZE);
}
#define pvr_dump_csb_block_take_packed(ctx, cmd, dest) \
({ \
struct pvr_dump_csb_block_ctx *const _block_ctx = (ctx); \
struct ROGUE_##cmd *const _dest = (dest); \
const void *const _ptr = \
pvr_dump_csb_block_take(_block_ctx, pvr_cmd_length(cmd)); \
if (_ptr) { \
pvr_cmd_unpack(cmd)(_ptr, _dest); \
} else { \
pvr_dump_field_error(&_block_ctx->base.base, \
"failed to unpack word(s)"); \
} \
!!_ptr; \
})
/*****************************************************************************
Feature dumping
******************************************************************************/
static inline void
__pvr_dump_field_needs_feature(struct pvr_dump_ctx *const ctx,
const char *const name,
const char *const feature)
{
pvr_dump_field(ctx, name, "<feature %s not present>", feature);
}
#define pvr_dump_field_needs_feature(ctx, name, feature) \
do { \
(void)PVR_HAS_FEATURE((struct pvr_device_info *)NULL, feature); \
__pvr_dump_field_needs_feature(ctx, name, #feature); \
} while (0)
#define pvr_dump_field_member_needs_feature(ctx, compound, member, feature) \
do { \
(void)&(compound)->member; \
pvr_dump_field_needs_feature(ctx, #member, feature); \
} while (0)
/******************************************************************************
Sub buffer printer declaration
******************************************************************************/
static bool print_sub_buffer(struct pvr_dump_ctx *ctx,
struct pvr_device *device,
enum buffer_type type,
pvr_dev_addr_t addr,
uint64_t expected_size,
char const *size_src);
/******************************************************************************
Block printers
******************************************************************************/
static uint32_t
print_block_cdmctrl_kernel(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device)
{
const pvr_dev_addr_t pds_heap_base = device->heaps.pds_heap->base_addr;
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_CDMCTRL_KERNEL0 kernel0 = { 0 };
struct ROGUE_CDMCTRL_KERNEL1 kernel1 = { 0 };
struct ROGUE_CDMCTRL_KERNEL2 kernel2 = { 0 };
struct ROGUE_CDMCTRL_KERNEL3 kernel3 = { 0 };
struct ROGUE_CDMCTRL_KERNEL4 kernel4 = { 0 };
struct ROGUE_CDMCTRL_KERNEL5 kernel5 = { 0 };
struct ROGUE_CDMCTRL_KERNEL6 kernel6 = { 0 };
struct ROGUE_CDMCTRL_KERNEL7 kernel7 = { 0 };
struct ROGUE_CDMCTRL_KERNEL8 kernel8 = { 0 };
struct ROGUE_CDMCTRL_KERNEL9 kernel9 = { 0 };
struct ROGUE_CDMCTRL_KERNEL10 kernel10 = { 0 };
struct ROGUE_CDMCTRL_KERNEL11 kernel11 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "KERNEL"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL0, &kernel0) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL1, &kernel1) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL2, &kernel2)) {
goto end_pop_ctx;
}
words_read += 3;
if (!kernel0.indirect_present) {
if (!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL3, &kernel3) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL4, &kernel4) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL5, &kernel5)) {
goto end_pop_ctx;
}
words_read += 3;
} else {
if (!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL6, &kernel6) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL7, &kernel7)) {
goto end_pop_ctx;
}
words_read += 2;
}
if (!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL8, &kernel8))
goto end_pop_ctx;
words_read += 1;
if (!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL9, &kernel9) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL10, &kernel10) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_KERNEL11, &kernel11)) {
goto end_pop_ctx;
}
words_read += 3;
pvr_dump_field_member_bool(base_ctx, &kernel0, indirect_present);
pvr_dump_field_member_bool(base_ctx, &kernel0, global_offsets_present);
pvr_dump_field_member_bool(base_ctx, &kernel0, event_object_present);
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&kernel0,
usc_common_size,
ROGUE_CDMCTRL_KERNEL0_USC_COMMON_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&kernel0,
usc_unified_size,
ROGUE_CDMCTRL_KERNEL0_USC_UNIFIED_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&kernel0,
pds_temp_size,
ROGUE_CDMCTRL_KERNEL0_PDS_TEMP_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&kernel0,
pds_data_size,
ROGUE_CDMCTRL_KERNEL0_PDS_DATA_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_enum(base_ctx,
&kernel0,
usc_target,
pvr_cmd_enum_to_str(CDMCTRL_USC_TARGET));
pvr_dump_field_member_bool(base_ctx, &kernel0, fence);
pvr_dump_field_member_addr_offset(base_ctx,
&kernel1,
data_addr,
pds_heap_base);
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base, kernel1.data_addr.addr),
kernel0.pds_data_size * ROGUE_CDMCTRL_KERNEL0_PDS_DATA_SIZE_UNIT_SIZE,
"pds_data_size");
if (!ret)
goto end_pop_ctx;
pvr_dump_field_member_enum(base_ctx,
&kernel1,
sd_type,
pvr_cmd_enum_to_str(CDMCTRL_SD_TYPE));
pvr_dump_field_member_bool(base_ctx, &kernel1, usc_common_shared);
pvr_dump_field_member_addr_offset(base_ctx,
&kernel2,
code_addr,
pds_heap_base);
/* FIXME: Determine the exact size of the PDS code section once disassembly
* is implemented.
*/
ret = print_sub_buffer(base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base,
kernel2.code_addr.addr),
0,
NULL);
if (!ret)
goto end_pop_ctx;
pvr_dump_field_member_bool(base_ctx, &kernel2, one_wg_per_task);
if (!kernel0.indirect_present) {
pvr_dump_field_member_u32_offset(base_ctx, &kernel3, workgroup_x, 1);
pvr_dump_field_member_u32_offset(base_ctx, &kernel4, workgroup_y, 1);
pvr_dump_field_member_u32_offset(base_ctx, &kernel5, workgroup_z, 1);
pvr_dump_field_not_present(base_ctx, "indirect_addr");
} else {
pvr_dump_field_member_not_present(base_ctx, &kernel3, workgroup_x);
pvr_dump_field_member_not_present(base_ctx, &kernel4, workgroup_y);
pvr_dump_field_member_not_present(base_ctx, &kernel5, workgroup_z);
pvr_dump_field_addr_split(base_ctx,
"indirect_addr",
kernel6.indirect_addrmsb,
kernel7.indirect_addrlsb);
}
pvr_dump_field_member_u32_zero(base_ctx, &kernel8, max_instances, 32);
pvr_dump_field_member_u32_offset(base_ctx, &kernel8, workgroup_size_x, 1);
pvr_dump_field_member_u32_offset(base_ctx, &kernel8, workgroup_size_y, 1);
pvr_dump_field_member_u32_offset(base_ctx, &kernel8, workgroup_size_z, 1);
if (kernel0.event_object_present) {
pvr_dump_field_member_u32(base_ctx, &kernel9, global_offset_x);
pvr_dump_field_member_u32(base_ctx, &kernel10, global_offset_y);
pvr_dump_field_member_u32(base_ctx, &kernel11, global_offset_z);
} else {
pvr_dump_field_member_not_present(base_ctx, &kernel9, global_offset_x);
pvr_dump_field_member_not_present(base_ctx, &kernel10, global_offset_y);
pvr_dump_field_member_not_present(base_ctx, &kernel11, global_offset_z);
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_cdmctrl_stream_link(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_CDMCTRL_STREAM_LINK0 link0 = { 0 };
struct ROGUE_CDMCTRL_STREAM_LINK1 link1 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STREAM_LINK"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_STREAM_LINK0, &link0) ||
!pvr_dump_csb_block_take_packed(&ctx, CDMCTRL_STREAM_LINK1, &link1)) {
goto end_pop_ctx;
}
words_read += 2;
pvr_dump_field_addr_split(base_ctx,
"link_addr",
link0.link_addrmsb,
link1.link_addrlsb);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_cdmctrl_stream_terminate(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_CDMCTRL_STREAM_TERMINATE terminate = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "TERMINATE"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx,
CDMCTRL_STREAM_TERMINATE,
&terminate)) {
goto end_pop_ctx;
}
words_read += 1;
pvr_dump_field_no_fields(base_ctx);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_ppp_state_update(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_PPP_STATE0 state0 = { 0 };
struct ROGUE_VDMCTRL_PPP_STATE1 state1 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "PPP_STATE_UPDATE"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_PPP_STATE0, &state0) ||
!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_PPP_STATE1, &state1)) {
goto end_pop_ctx;
}
words_read += 2;
pvr_dump_field_member_u32_zero(base_ctx, &state0, word_count, 256);
pvr_dump_field_addr_split(base_ctx, "addr", state0.addrmsb, state1.addrlsb);
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_PPP,
PVR_DEV_ADDR(state0.addrmsb.addr | state1.addrlsb.addr),
(state0.word_count ? state0.word_count : 256) * PVR_DUMP_CSB_WORD_SIZE,
"word_count");
if (!ret)
goto end_pop_ctx;
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_pds_state_update(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device)
{
const pvr_dev_addr_t pds_heap_base = device->heaps.pds_heap->base_addr;
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_PDS_STATE0 state0 = { 0 };
struct ROGUE_VDMCTRL_PDS_STATE1 state1 = { 0 };
struct ROGUE_VDMCTRL_PDS_STATE2 state2 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "PDS_STATE_UPDATE"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_PDS_STATE0, &state0) ||
!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_PDS_STATE1, &state1) ||
!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_PDS_STATE2, &state2)) {
goto end_pop_ctx;
}
words_read += 3;
pvr_dump_field_member_enum(base_ctx,
&state0,
dm_target,
pvr_cmd_enum_to_str(VDMCTRL_DM_TARGET));
pvr_dump_field_member_enum(base_ctx,
&state0,
usc_target,
pvr_cmd_enum_to_str(VDMCTRL_USC_TARGET));
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state0,
usc_common_size,
ROGUE_VDMCTRL_PDS_STATE0_USC_COMMON_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state0,
usc_unified_size,
ROGUE_VDMCTRL_PDS_STATE0_USC_UNIFIED_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state0,
pds_temp_size,
ROGUE_VDMCTRL_PDS_STATE0_PDS_TEMP_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state0,
pds_data_size,
ROGUE_VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_addr_offset(base_ctx,
&state1,
pds_data_addr,
pds_heap_base);
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base, state1.pds_data_addr.addr),
state0.pds_data_size * ROGUE_VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE,
"pds_data_size");
if (!ret)
goto end_pop_ctx;
pvr_dump_field_member_enum(base_ctx,
&state1,
sd_type,
pvr_cmd_enum_to_str(VDMCTRL_SD_TYPE));
pvr_dump_field_member_enum(base_ctx,
&state1,
sd_next_type,
pvr_cmd_enum_to_str(VDMCTRL_SD_TYPE));
pvr_dump_field_member_addr_offset(base_ctx,
&state2,
pds_code_addr,
pds_heap_base);
/* FIXME: Determine the exact size of the PDS code section once disassembly
* is implemented.
*/
ret = print_sub_buffer(base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base,
state2.pds_code_addr.addr),
0,
NULL);
if (!ret)
goto end_pop_ctx;
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_vdm_state_update(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device)
{
const pvr_dev_addr_t pds_heap_base = device->heaps.pds_heap->base_addr;
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_VDM_STATE0 state0 = { 0 };
struct ROGUE_VDMCTRL_VDM_STATE1 state1 = { 0 };
struct ROGUE_VDMCTRL_VDM_STATE2 state2 = { 0 };
struct ROGUE_VDMCTRL_VDM_STATE3 state3 = { 0 };
struct ROGUE_VDMCTRL_VDM_STATE4 state4 = { 0 };
struct ROGUE_VDMCTRL_VDM_STATE5 state5 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "VDM_STATE_UPDATE"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_VDM_STATE0, &state0))
goto end_pop_ctx;
words_read += 1;
if (state0.cut_index_present) {
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_VDM_STATE1, &state1))
goto end_pop_ctx;
words_read += 1;
}
if (state0.vs_data_addr_present) {
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_VDM_STATE2, &state2))
goto end_pop_ctx;
words_read += 1;
}
if (state0.vs_other_present) {
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_VDM_STATE3, &state3) ||
!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_VDM_STATE4, &state4) ||
!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_VDM_STATE5, &state5)) {
goto end_pop_ctx;
}
words_read += 3;
}
if (state0.cut_index_present) {
pvr_dump_field_member_x32(base_ctx, &state1, cut_index, 8);
} else {
pvr_dump_field_member_not_present(base_ctx, &state1, cut_index);
}
if (state0.vs_data_addr_present) {
pvr_dump_field_member_addr_offset(base_ctx,
&state2,
vs_pds_data_base_addr,
pds_heap_base);
if (state0.vs_other_present) {
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base,
state2.vs_pds_data_base_addr.addr),
state5.vs_pds_data_size *
ROGUE_VDMCTRL_VDM_STATE5_VS_PDS_DATA_SIZE_UNIT_SIZE,
"pds_data_size");
} else {
/* FIXME: Determine the exact size of the PDS data section when no
* code section is present once disassembly is implemented.
*/
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base,
state2.vs_pds_data_base_addr.addr),
0,
NULL);
}
if (!ret)
goto end_pop_ctx;
} else {
pvr_dump_field_member_not_present(base_ctx,
&state2,
vs_pds_data_base_addr);
}
if (state0.vs_other_present) {
pvr_dump_field_member_addr_offset(base_ctx,
&state3,
vs_pds_code_base_addr,
pds_heap_base);
/* FIXME: Determine the exact size of the PDS code section once
* disassembly is implemented.
*/
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base, state3.vs_pds_code_base_addr.addr),
0,
NULL);
if (!ret)
goto end_pop_ctx;
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state4,
vs_output_size,
ROGUE_VDMCTRL_VDM_STATE4_VS_OUTPUT_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_zero(base_ctx, &state5, vs_max_instances, 32);
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state5,
vs_usc_common_size,
ROGUE_VDMCTRL_VDM_STATE5_VS_USC_COMMON_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state5,
vs_usc_unified_size,
ROGUE_VDMCTRL_VDM_STATE5_VS_USC_UNIFIED_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state5,
vs_pds_temp_size,
ROGUE_VDMCTRL_VDM_STATE5_VS_PDS_TEMP_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&state5,
vs_pds_data_size,
ROGUE_VDMCTRL_VDM_STATE5_VS_PDS_DATA_SIZE_UNIT_SIZE,
"bytes");
} else {
pvr_dump_field_member_not_present(base_ctx,
&state3,
vs_pds_code_base_addr);
pvr_dump_field_member_not_present(base_ctx, &state4, vs_output_size);
pvr_dump_field_member_not_present(base_ctx, &state5, vs_max_instances);
pvr_dump_field_member_not_present(base_ctx, &state5, vs_usc_common_size);
pvr_dump_field_member_not_present(base_ctx, &state5, vs_usc_unified_size);
pvr_dump_field_member_not_present(base_ctx, &state5, vs_pds_temp_size);
pvr_dump_field_member_not_present(base_ctx, &state5, vs_pds_data_size);
}
pvr_dump_field_member_bool(base_ctx, &state0, ds_present);
pvr_dump_field_member_bool(base_ctx, &state0, gs_present);
pvr_dump_field_member_bool(base_ctx, &state0, hs_present);
pvr_dump_field_member_u32_offset(base_ctx, &state0, cam_size, 1);
pvr_dump_field_member_enum(
base_ctx,
&state0,
uvs_scratch_size_select,
pvr_cmd_enum_to_str(VDMCTRL_UVS_SCRATCH_SIZE_SELECT));
pvr_dump_field_member_bool(base_ctx, &state0, cut_index_enable);
pvr_dump_field_member_bool(base_ctx, &state0, tess_enable);
pvr_dump_field_member_bool(base_ctx, &state0, gs_enable);
pvr_dump_field_member_enum(base_ctx,
&state0,
flatshade_control,
pvr_cmd_enum_to_str(VDMCTRL_FLATSHADE_CONTROL));
pvr_dump_field_member_bool(base_ctx, &state0, generate_primitive_id);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_index_list(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device)
{
const struct pvr_device_info *const dev_info = &device->pdevice->dev_info;
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_INDEX_LIST0 index_list0 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST1 index_list1 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST2 index_list2 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST3 index_list3 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST4 index_list4 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST5 index_list5 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST6 index_list6 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST7 index_list7 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST8 index_list8 = { 0 };
struct ROGUE_VDMCTRL_INDEX_LIST9 index_list9 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "INDEX_LIST"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_INDEX_LIST0, &index_list0))
goto end_pop_ctx;
words_read += 1;
if (index_list0.index_addr_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST1,
&index_list1)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (index_list0.index_count_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST2,
&index_list2)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (index_list0.index_instance_count_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST3,
&index_list3)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (index_list0.index_offset_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST4,
&index_list4)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (index_list0.start_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST5,
&index_list5) ||
!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST6,
&index_list6)) {
goto end_pop_ctx;
}
words_read += 2;
}
if (index_list0.indirect_addr_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST7,
&index_list7) ||
!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST8,
&index_list8)) {
goto end_pop_ctx;
}
words_read += 2;
}
if (index_list0.split_count_present) {
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_INDEX_LIST9,
&index_list9))
goto end_pop_ctx;
words_read += 1;
}
if (PVR_HAS_FEATURE(dev_info, vdm_degenerate_culling)) {
pvr_dump_field_member_bool(base_ctx, &index_list0, degen_cull_enable);
} else {
pvr_dump_field_member_needs_feature(base_ctx,
&index_list0,
degen_cull_enable,
vdm_degenerate_culling);
}
pvr_dump_field_member_enum(base_ctx,
&index_list0,
index_size,
pvr_cmd_enum_to_str(VDMCTRL_INDEX_SIZE));
pvr_dump_field_member_u32_offset(base_ctx, &index_list0, patch_count, 1);
pvr_dump_field_member_enum(base_ctx,
&index_list0,
primitive_topology,
pvr_cmd_enum_to_str(VDMCTRL_PRIMITIVE_TOPOLOGY));
if (index_list0.index_addr_present) {
pvr_dump_field_addr_split(base_ctx,
"index_base_addr",
index_list0.index_base_addrmsb,
index_list1.index_base_addrlsb);
const uint32_t index_size =
pvr_vdmctrl_index_size_nr_bytes(index_list0.index_size);
if (!index_list0.index_count_present) {
ret = pvr_dump_error(base_ctx, "index_addr requires index_count");
goto end_pop_ctx;
}
ret = print_sub_buffer(base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR(index_list0.index_base_addrmsb.addr |
index_list1.index_base_addrlsb.addr),
index_list2.index_count * index_size,
"index_count * index_size");
if (!ret)
goto end_pop_ctx;
} else {
pvr_dump_field_not_present(base_ctx, "index_base_addr");
}
if (index_list0.index_count_present) {
pvr_dump_field_member_u32(base_ctx, &index_list2, index_count);
} else {
pvr_dump_field_member_not_present(base_ctx, &index_list2, index_count);
}
if (index_list0.index_instance_count_present) {
pvr_dump_field_member_u32_offset(base_ctx,
&index_list3,
instance_count,
1);
} else {
pvr_dump_field_member_not_present(base_ctx, &index_list3, instance_count);
}
if (index_list0.index_offset_present) {
pvr_dump_field_member_u32(base_ctx, &index_list4, index_offset);
} else {
pvr_dump_field_member_not_present(base_ctx, &index_list4, index_offset);
}
if (index_list0.start_present) {
pvr_dump_field_member_u32(base_ctx, &index_list5, start_index);
pvr_dump_field_member_u32(base_ctx, &index_list6, start_instance);
} else {
pvr_dump_field_member_not_present(base_ctx, &index_list5, start_index);
pvr_dump_field_member_not_present(base_ctx, &index_list6, start_instance);
}
if (index_list0.indirect_addr_present) {
pvr_dump_field_addr_split(base_ctx,
"indirect_base_addr",
index_list7.indirect_base_addrmsb,
index_list8.indirect_base_addrlsb);
ret =
print_sub_buffer(base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR(index_list7.indirect_base_addrmsb.addr |
index_list8.indirect_base_addrlsb.addr),
0,
NULL);
if (!ret)
goto end_pop_ctx;
} else {
pvr_dump_field_not_present(base_ctx, "indirect_base_addr");
}
if (index_list0.split_count_present) {
pvr_dump_field_member_u32(base_ctx, &index_list9, split_count);
} else {
pvr_dump_field_member_not_present(base_ctx, &index_list9, split_count);
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_stream_link(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_STREAM_LINK0 link0 = { 0 };
struct ROGUE_VDMCTRL_STREAM_LINK1 link1 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STREAM_LINK"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_STREAM_LINK0, &link0) ||
!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_STREAM_LINK1, &link1)) {
goto end_pop_ctx;
}
words_read += 2;
pvr_dump_field_member_bool(base_ctx, &link0, with_return);
if (link0.compare_present) {
pvr_dump_field_member_u32(base_ctx, &link0, compare_mode);
pvr_dump_field_member_u32(base_ctx, &link0, compare_data);
} else {
pvr_dump_field_member_not_present(base_ctx, &link0, compare_mode);
pvr_dump_field_member_not_present(base_ctx, &link0, compare_data);
}
pvr_dump_field_addr_split(base_ctx,
"link_addr",
link0.link_addrmsb,
link1.link_addrlsb);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_stream_return(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_STREAM_RETURN return_ = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STREAM_RETURN"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, VDMCTRL_STREAM_RETURN, &return_))
goto end_pop_ctx;
words_read += 1;
pvr_dump_field_no_fields(base_ctx);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_vdmctrl_stream_terminate(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_VDMCTRL_STREAM_TERMINATE terminate = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "TERMINATE"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx,
VDMCTRL_STREAM_TERMINATE,
&terminate)) {
goto end_pop_ctx;
}
words_read += 1;
pvr_dump_field_member_bool(base_ctx, &terminate, context);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_state_header(struct pvr_dump_csb_ctx *const csb_ctx,
struct ROGUE_TA_STATE_HEADER *const header_out)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_HEADER header = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_HEADER"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_HEADER, &header))
goto end_pop_ctx;
words_read += 1;
pvr_dump_field_member_bool(base_ctx, &header, pres_ispctl);
pvr_dump_field_member_bool(base_ctx, &header, pres_ispctl_fa);
pvr_dump_field_member_bool(base_ctx, &header, pres_ispctl_fb);
pvr_dump_field_member_bool(base_ctx, &header, pres_ispctl_ba);
pvr_dump_field_member_bool(base_ctx, &header, pres_ispctl_bb);
pvr_dump_field_member_bool(base_ctx, &header, pres_ispctl_dbsc);
pvr_dump_field_member_bool(base_ctx, &header, pres_pds_state_ptr0);
pvr_dump_field_member_bool(base_ctx, &header, pres_pds_state_ptr1);
pvr_dump_field_member_bool(base_ctx, &header, pres_pds_state_ptr2);
pvr_dump_field_member_bool(base_ctx, &header, pres_pds_state_ptr3);
pvr_dump_field_member_bool(base_ctx, &header, pres_region_clip);
pvr_dump_field_member_bool(base_ctx, &header, pres_viewport);
pvr_dump_field_member_u32_offset(base_ctx, &header, view_port_count, 1);
pvr_dump_field_member_bool(base_ctx, &header, pres_wclamp);
pvr_dump_field_member_bool(base_ctx, &header, pres_outselects);
pvr_dump_field_member_bool(base_ctx, &header, pres_varying_word0);
pvr_dump_field_member_bool(base_ctx, &header, pres_varying_word1);
pvr_dump_field_member_bool(base_ctx, &header, pres_varying_word2);
pvr_dump_field_member_bool(base_ctx, &header, pres_ppp_ctrl);
pvr_dump_field_member_bool(base_ctx, &header, pres_stream_out_size);
pvr_dump_field_member_bool(base_ctx, &header, pres_stream_out_program);
pvr_dump_field_member_bool(base_ctx, &header, context_switch);
pvr_dump_field_member_bool(base_ctx, &header, pres_terminate);
pvr_dump_field_member_bool(base_ctx, &header, not_final_term);
if (header_out)
*header_out = header;
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static void print_block_ppp_state_isp_one_side(
struct pvr_dump_csb_block_ctx *const ctx,
const struct ROGUE_TA_STATE_ISPA *const isp_a,
const struct ROGUE_TA_STATE_ISPB *const isp_b,
const bool has_b)
{
struct pvr_dump_ctx *const base_ctx = &ctx->base.base;
pvr_dump_indent(base_ctx);
pvr_dump_field_member_enum(base_ctx,
isp_a,
objtype,
pvr_cmd_enum_to_str(TA_OBJTYPE));
pvr_dump_field_member_enum(base_ctx,
isp_a,
passtype,
pvr_cmd_enum_to_str(TA_PASSTYPE));
pvr_dump_field_member_bool(base_ctx, isp_a, ovgvispassmaskop);
pvr_dump_field_member_bool(base_ctx, isp_a, maskval);
pvr_dump_field_member_bool(base_ctx, isp_a, dwritedisable);
pvr_dump_field_member_bool(base_ctx, isp_a, dfbztestenable);
pvr_dump_field_member_enum(base_ctx,
isp_a,
dcmpmode,
pvr_cmd_enum_to_str(TA_CMPMODE));
pvr_dump_field_member_bool(base_ctx, isp_a, linefilllastpixel);
pvr_dump_field_member_uq4_4_offset(base_ctx, isp_a, pointlinewidth, 0x01);
pvr_dump_field_member_u32(base_ctx, isp_a, sref);
if (has_b) {
pvr_dump_field_member_enum(base_ctx,
isp_b,
scmpmode,
pvr_cmd_enum_to_str(TA_CMPMODE));
pvr_dump_field_member_enum(base_ctx,
isp_b,
sop1,
pvr_cmd_enum_to_str(TA_ISPB_STENCILOP));
pvr_dump_field_member_enum(base_ctx,
isp_b,
sop2,
pvr_cmd_enum_to_str(TA_ISPB_STENCILOP));
pvr_dump_field_member_enum(base_ctx,
isp_b,
sop3,
pvr_cmd_enum_to_str(TA_ISPB_STENCILOP));
pvr_dump_field_member_x32(base_ctx, isp_b, scmpmask, 2);
pvr_dump_field_member_x32(base_ctx, isp_b, swmask, 2);
} else {
pvr_dump_field_member_not_present(base_ctx, isp_b, scmpmode);
pvr_dump_field_member_not_present(base_ctx, isp_b, sop1);
pvr_dump_field_member_not_present(base_ctx, isp_b, sop2);
pvr_dump_field_member_not_present(base_ctx, isp_b, sop3);
pvr_dump_field_member_not_present(base_ctx, isp_b, scmpmask);
pvr_dump_field_member_not_present(base_ctx, isp_b, swmask);
}
pvr_dump_dedent(base_ctx);
}
static uint32_t
print_block_ppp_state_isp(struct pvr_dump_csb_ctx *const csb_ctx,
const bool has_fa,
const bool has_fb,
const bool has_ba,
const bool has_bb,
const bool has_dbsc)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_ISPCTL isp_ctl = { 0 };
struct ROGUE_TA_STATE_ISPA isp_fa = { 0 };
struct ROGUE_TA_STATE_ISPB isp_fb = { 0 };
struct ROGUE_TA_STATE_ISPA isp_ba = { 0 };
struct ROGUE_TA_STATE_ISPB isp_bb = { 0 };
struct ROGUE_TA_STATE_ISPDBSC isp_dbsc = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_ISP"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_ISPCTL, &isp_ctl))
goto end_pop_ctx;
words_read += 1;
/* In most blocks, we try to read all words before printing anything. In
* this case, there can be ambiguity in which words to parse (which results
* in an error from the conditional below). To aid in debugging when this
* ambiguity is present, print the control word's contents before continuing
* so the fields which create the ambiguity are dumped even when the rest of
* the block isn't.
*/
pvr_dump_field_member_u32(base_ctx, &isp_ctl, visreg);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, visbool);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, vistest);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, scenable);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, dbenable);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, bpres);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, two_sided);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, ovgmtestdisable);
pvr_dump_field_member_bool(base_ctx, &isp_ctl, tagwritedisable);
pvr_dump_field_member_u32(base_ctx, &isp_ctl, upass);
pvr_dump_field_member_u32(base_ctx, &isp_ctl, validid);
if (!has_fa || has_fb != isp_ctl.bpres || has_ba != isp_ctl.two_sided ||
has_bb != (isp_ctl.bpres && isp_ctl.two_sided)) {
pvr_dump_error(
base_ctx,
"words declared by ppp header do not match requirements of ispctl word");
goto end_pop_ctx;
}
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_ISPA, &isp_fa))
return false;
words_read += 1;
if (has_fb) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_ISPB, &isp_fb))
return false;
words_read += 1;
}
if (has_ba) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_ISPA, &isp_ba))
return false;
words_read += 1;
}
if (has_bb) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_ISPB, &isp_bb))
return false;
words_read += 1;
}
if (has_dbsc) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_ISPDBSC, &isp_dbsc))
goto end_pop_ctx;
words_read += 1;
}
pvr_dump_println(base_ctx, "front");
print_block_ppp_state_isp_one_side(&ctx, &isp_fa, &isp_fb, isp_ctl.bpres);
if (isp_ctl.two_sided) {
pvr_dump_println(base_ctx, "back");
print_block_ppp_state_isp_one_side(&ctx, &isp_ba, &isp_bb, isp_ctl.bpres);
} else {
pvr_dump_field_not_present(base_ctx, "back");
}
if (has_dbsc) {
pvr_dump_field_member_u32(base_ctx, &isp_dbsc, dbindex);
pvr_dump_field_member_u32(base_ctx, &isp_dbsc, scindex);
} else {
pvr_dump_field_member_not_present(base_ctx, &isp_dbsc, dbindex);
pvr_dump_field_member_not_present(base_ctx, &isp_dbsc, scindex);
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_state_pds(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device,
const bool has_initial_words,
const bool has_varying,
const bool has_texturedata,
const bool has_uniformdata)
{
const pvr_dev_addr_t pds_heap_base = device->heaps.pds_heap->base_addr;
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_PDS_SHADERBASE shader_base = { 0 };
struct ROGUE_TA_STATE_PDS_TEXUNICODEBASE tex_unicode_base = { 0 };
struct ROGUE_TA_STATE_PDS_SIZEINFO1 size_info1 = { 0 };
struct ROGUE_TA_STATE_PDS_SIZEINFO2 size_info2 = { 0 };
struct ROGUE_TA_STATE_PDS_VARYINGBASE varying_base = { 0 };
struct ROGUE_TA_STATE_PDS_TEXTUREDATABASE texture_data_base = { 0 };
struct ROGUE_TA_STATE_PDS_UNIFORMDATABASE uniform_data_base = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_PDS"))
goto end_out;
if (has_initial_words) {
if (!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_SHADERBASE,
&shader_base) ||
!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_TEXUNICODEBASE,
&tex_unicode_base) ||
!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_SIZEINFO1,
&size_info1) ||
!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_SIZEINFO2,
&size_info2)) {
goto end_pop_ctx;
}
words_read += 4;
}
if (has_varying) {
if (!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_VARYINGBASE,
&varying_base)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (has_texturedata) {
if (!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_TEXTUREDATABASE,
&texture_data_base)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (has_uniformdata) {
if (!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_PDS_UNIFORMDATABASE,
&uniform_data_base)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (has_initial_words) {
pvr_dump_field_addr_offset(base_ctx,
"shaderbase",
shader_base.addr,
pds_heap_base);
pvr_dump_field_addr_offset(base_ctx,
"texunicodebase",
tex_unicode_base.addr,
pds_heap_base);
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&size_info1,
pds_uniformsize,
ROGUE_TA_STATE_PDS_SIZEINFO1_PDS_UNIFORMSIZE_UNIT_SIZE,
"words");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&size_info1,
pds_texturestatesize,
ROGUE_TA_STATE_PDS_SIZEINFO1_PDS_TEXTURESTATESIZE_UNIT_SIZE,
"words");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&size_info1,
pds_varyingsize,
ROGUE_TA_STATE_PDS_SIZEINFO1_PDS_VARYINGSIZE_UNIT_SIZE,
"words");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&size_info1,
usc_varyingsize,
ROGUE_TA_STATE_PDS_SIZEINFO1_USC_VARYINGSIZE_UNIT_SIZE,
"words");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&size_info1,
pds_tempsize,
ROGUE_TA_STATE_PDS_SIZEINFO1_PDS_TEMPSIZE_UNIT_SIZE,
"words");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&size_info2,
usc_sharedsize,
ROGUE_TA_STATE_PDS_SIZEINFO2_USC_SHAREDSIZE_UNIT_SIZE,
"words");
pvr_dump_field_member_bool(base_ctx, &size_info2, pds_tri_merge_disable);
pvr_dump_field_member_u32(base_ctx, &size_info2, pds_batchnum);
} else {
pvr_dump_field_not_present(base_ctx, "shaderbase");
pvr_dump_field_not_present(base_ctx, "texunicodebase");
pvr_dump_field_member_not_present(base_ctx, &size_info1, pds_uniformsize);
pvr_dump_field_member_not_present(base_ctx,
&size_info1,
pds_texturestatesize);
pvr_dump_field_member_not_present(base_ctx, &size_info1, pds_varyingsize);
pvr_dump_field_member_not_present(base_ctx, &size_info1, usc_varyingsize);
pvr_dump_field_member_not_present(base_ctx, &size_info1, pds_tempsize);
pvr_dump_field_member_not_present(base_ctx, &size_info2, usc_sharedsize);
pvr_dump_field_member_not_present(base_ctx,
&size_info2,
pds_tri_merge_disable);
pvr_dump_field_member_not_present(base_ctx, &size_info2, pds_batchnum);
}
if (has_varying) {
pvr_dump_field_addr_offset(base_ctx,
"varyingbase",
varying_base.addr,
pds_heap_base);
} else {
pvr_dump_field_not_present(base_ctx, "varyingbase");
}
if (has_texturedata) {
pvr_dump_field_addr_offset(base_ctx,
"texturedatabase",
texture_data_base.addr,
pds_heap_base);
} else {
pvr_dump_field_not_present(base_ctx, "texturedatabase");
}
if (has_uniformdata) {
pvr_dump_field_addr_offset(base_ctx,
"uniformdatabase",
uniform_data_base.addr,
pds_heap_base);
} else {
pvr_dump_field_not_present(base_ctx, "uniformdatabase");
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_region_clip(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_REGION_CLIP0 clip0 = { 0 };
struct ROGUE_TA_REGION_CLIP1 clip1 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "REGION_CLIP"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, TA_REGION_CLIP0, &clip0) ||
!pvr_dump_csb_block_take_packed(&ctx, TA_REGION_CLIP1, &clip1)) {
goto end_pop_ctx;
}
words_read += 2;
pvr_dump_field_member_enum(base_ctx,
&clip0,
mode,
pvr_cmd_enum_to_str(TA_REGION_CLIP_MODE));
pvr_dump_field_member_u32_scaled_units(base_ctx, &clip0, left, 32, "pixels");
pvr_dump_field_member_u32_scaled_units(base_ctx, &clip0, right, 32, "pixels");
pvr_dump_field_member_u32_scaled_units(base_ctx, &clip1, top, 32, "pixels");
pvr_dump_field_member_u32_scaled_units(base_ctx,
&clip1,
bottom,
32,
"pixels");
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t print_block_ppp_viewport(struct pvr_dump_csb_ctx *const csb_ctx,
const uint32_t idx)
{
static char const *const field_names[] = {
"a0", "m0", "a1", "m1", "a2", "m2"
};
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
STATIC_ASSERT(sizeof(float) == 4);
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "VIEWPORT %" PRIu32, idx))
goto end_out;
for (uint32_t i = 0; i < ARRAY_SIZE(field_names); i++) {
const uint32_t *const value = pvr_dump_csb_block_take(&ctx, 1);
if (!value)
goto end_pop_ctx;
words_read += 1;
pvr_dump_field_f32(base_ctx, field_names[i], uif(*value));
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t print_block_ppp_wclamp(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
STATIC_ASSERT(sizeof(float) == 4);
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "WCLAMP"))
goto end_out;
const uint32_t *const value = pvr_dump_csb_block_take(&ctx, 1);
if (!value)
goto end_pop_ctx;
words_read += 1;
pvr_dump_field_f32(base_ctx, "value", uif(*value));
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_output_sel(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_OUTPUT_SEL output_sel = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "OUTPUT_SEL"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, TA_OUTPUT_SEL, &output_sel))
goto end_pop_ctx;
words_read += 1;
pvr_dump_field_member_bool(base_ctx, &output_sel, plane0);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane1);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane2);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane3);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane4);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane5);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane6);
pvr_dump_field_member_bool(base_ctx, &output_sel, plane7);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane0);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane1);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane2);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane3);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane4);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane5);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane6);
pvr_dump_field_member_bool(base_ctx, &output_sel, cullplane7);
pvr_dump_field_member_bool(base_ctx, &output_sel, rhw_pres);
pvr_dump_field_member_bool(base_ctx,
&output_sel,
isp_position_depth_clamp_z);
pvr_dump_field_member_bool(base_ctx, &output_sel, psprite_size_pres);
pvr_dump_field_member_bool(base_ctx, &output_sel, vpt_tgt_pres);
pvr_dump_field_member_bool(base_ctx, &output_sel, render_tgt_pres);
pvr_dump_field_member_bool(base_ctx, &output_sel, tsp_unclamped_z_pres);
pvr_dump_field_member_u32(base_ctx, &output_sel, vtxsize);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_state_varying(struct pvr_dump_csb_ctx *const csb_ctx,
const bool has_word0,
const bool has_word1,
const bool has_word2)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_VARYING0 varying0 = { 0 };
struct ROGUE_TA_STATE_VARYING1 varying1 = { 0 };
struct ROGUE_TA_STATE_VARYING2 varying2 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_VARYING"))
goto end_out;
if (has_word0) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_VARYING0, &varying0))
goto end_pop_ctx;
words_read += 1;
}
if (has_word1) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_VARYING1, &varying1))
goto end_pop_ctx;
words_read += 1;
}
if (has_word2) {
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_VARYING2, &varying2))
goto end_pop_ctx;
words_read += 1;
}
if (has_word0) {
pvr_dump_field_member_u32(base_ctx, &varying0, f32_linear);
pvr_dump_field_member_u32(base_ctx, &varying0, f32_flat);
pvr_dump_field_member_u32(base_ctx, &varying0, f32_npc);
} else {
pvr_dump_field_member_not_present(base_ctx, &varying0, f32_linear);
pvr_dump_field_member_not_present(base_ctx, &varying0, f32_flat);
pvr_dump_field_member_not_present(base_ctx, &varying0, f32_npc);
}
if (has_word1) {
pvr_dump_field_member_u32(base_ctx, &varying1, f16_linear);
pvr_dump_field_member_u32(base_ctx, &varying1, f16_flat);
pvr_dump_field_member_u32(base_ctx, &varying1, f16_npc);
} else {
pvr_dump_field_member_not_present(base_ctx, &varying1, f16_linear);
pvr_dump_field_member_not_present(base_ctx, &varying1, f16_flat);
pvr_dump_field_member_not_present(base_ctx, &varying1, f16_npc);
}
if (has_word2) {
pvr_dump_field_member_u32(base_ctx, &varying2, output_clip_planes);
} else {
pvr_dump_field_member_not_present(base_ctx,
&varying2,
output_clip_planes);
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_state_ppp_ctrl(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_PPP_CTRL ppp_ctrl = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_PPP_CTRL"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_PPP_CTRL, &ppp_ctrl))
goto end_pop_ctx;
words_read += 1;
pvr_dump_field_member_enum(base_ctx,
&ppp_ctrl,
cullmode,
pvr_cmd_enum_to_str(TA_CULLMODE));
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, updatebbox);
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, resetbbox);
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, wbuffen);
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, wclampen);
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, pretransform);
pvr_dump_field_member_enum(base_ctx,
&ppp_ctrl,
flatshade_vtx,
pvr_cmd_enum_to_str(TA_FLATSHADE));
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, drawclippededges);
pvr_dump_field_member_enum(base_ctx,
&ppp_ctrl,
clip_mode,
pvr_cmd_enum_to_str(TA_CLIP_MODE));
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, pres_prim_id);
pvr_dump_field_member_enum(base_ctx,
&ppp_ctrl,
gs_output_topology,
pvr_cmd_enum_to_str(TA_GS_OUTPUT_TOPOLOGY));
pvr_dump_field_member_bool(base_ctx, &ppp_ctrl, prim_msaa);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_state_stream_out(struct pvr_dump_csb_ctx *const csb_ctx,
struct pvr_device *const device,
const bool has_word0,
const bool has_words12)
{
const pvr_dev_addr_t pds_heap_base = device->heaps.pds_heap->base_addr;
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_STREAM_OUT0 stream_out0 = { 0 };
struct ROGUE_TA_STATE_STREAM_OUT1 stream_out1 = { 0 };
struct ROGUE_TA_STATE_STREAM_OUT2 stream_out2 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_STREAM_OUT"))
goto end_out;
if (has_word0) {
if (!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_STREAM_OUT0,
&stream_out0)) {
goto end_pop_ctx;
}
words_read += 1;
}
if (has_words12) {
if (!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_STREAM_OUT1,
&stream_out1) ||
!pvr_dump_csb_block_take_packed(&ctx,
TA_STATE_STREAM_OUT2,
&stream_out2)) {
goto end_pop_ctx;
}
words_read += 2;
}
if (has_word0) {
pvr_dump_field_member_bool(base_ctx, &stream_out0, stream0_ta_output);
pvr_dump_field_member_bool(base_ctx, &stream_out0, stream0_mem_output);
pvr_dump_field_member_u32_units(base_ctx,
&stream_out0,
stream1_size,
"words");
pvr_dump_field_member_u32_units(base_ctx,
&stream_out0,
stream2_size,
"words");
pvr_dump_field_member_u32_units(base_ctx,
&stream_out0,
stream3_size,
"words");
} else {
pvr_dump_field_member_not_present(base_ctx,
&stream_out0,
stream0_ta_output);
pvr_dump_field_member_not_present(base_ctx,
&stream_out0,
stream0_mem_output);
pvr_dump_field_member_not_present(base_ctx, &stream_out0, stream1_size);
pvr_dump_field_member_not_present(base_ctx, &stream_out0, stream2_size);
pvr_dump_field_member_not_present(base_ctx, &stream_out0, stream3_size);
}
if (has_words12) {
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&stream_out1,
pds_temp_size,
ROGUE_TA_STATE_STREAM_OUT1_PDS_TEMP_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_u32_scaled_units(
base_ctx,
&stream_out1,
pds_data_size,
ROGUE_TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE,
"bytes");
pvr_dump_field_member_bool(base_ctx, &stream_out1, sync);
pvr_dump_field_member_addr_offset(base_ctx,
&stream_out2,
pds_data_addr,
pds_heap_base);
ret = print_sub_buffer(
base_ctx,
device,
BUFFER_TYPE_NONE,
PVR_DEV_ADDR_OFFSET(pds_heap_base, stream_out2.pds_data_addr.addr),
stream_out1.pds_data_size,
"pds_data_size");
if (!ret)
goto end_pop_ctx;
} else {
pvr_dump_field_member_not_present(base_ctx, &stream_out1, pds_temp_size);
pvr_dump_field_member_not_present(base_ctx, &stream_out1, pds_data_size);
pvr_dump_field_member_not_present(base_ctx, &stream_out1, sync);
pvr_dump_field_member_not_present(base_ctx, &stream_out2, pds_data_addr);
}
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
static uint32_t
print_block_ppp_state_terminate(struct pvr_dump_csb_ctx *const csb_ctx)
{
struct pvr_dump_csb_block_ctx ctx;
struct pvr_dump_ctx *const base_ctx = &ctx.base.base;
uint32_t words_read = 0;
bool ret = false;
struct ROGUE_TA_STATE_TERMINATE0 terminate0 = { 0 };
struct ROGUE_TA_STATE_TERMINATE1 terminate1 = { 0 };
if (!pvr_dump_csb_block_ctx_push(&ctx, csb_ctx, "STATE_TERMINATE"))
goto end_out;
if (!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_TERMINATE0, &terminate0) ||
!pvr_dump_csb_block_take_packed(&ctx, TA_STATE_TERMINATE1, &terminate1)) {
goto end_pop_ctx;
}
words_read += 2;
pvr_dump_field_member_u32_scaled_units(base_ctx,
&terminate0,
clip_right,
32,
"pixels");
pvr_dump_field_member_u32_scaled_units(base_ctx,
&terminate0,
clip_top,
32,
"pixels");
pvr_dump_field_member_u32_scaled_units(base_ctx,
&terminate0,
clip_bottom,
32,
"pixels");
pvr_dump_field_member_u32_scaled_units(base_ctx,
&terminate1,
clip_left,
32,
"pixels");
pvr_dump_field_member_u32(base_ctx, &terminate1, render_target);
ret = true;
end_pop_ctx:
pvr_dump_csb_block_ctx_pop(&ctx);
end_out:
return ret ? words_read : 0;
}
/******************************************************************************
Buffer printers
******************************************************************************/
static bool print_block_hex(struct pvr_dump_buffer_ctx *const ctx,
const uint32_t nr_words)
{
const uint32_t nr_bytes = nr_words * PVR_DUMP_CSB_WORD_SIZE;
if (!nr_words)
return false;
pvr_dump_indent(&ctx->base);
pvr_dump_field_u32_units(&ctx->base, "<raw>", nr_bytes, "bytes");
pvr_dump_indent(&ctx->base);
pvr_dump_buffer_rewind(ctx, nr_bytes);
pvr_dump_buffer_hex(ctx, nr_bytes);
pvr_dump_dedent(&ctx->base);
pvr_dump_dedent(&ctx->base);
return true;
}
static bool print_cdmctrl_buffer(struct pvr_dump_buffer_ctx *const parent_ctx,
struct pvr_device *const device)
{
struct pvr_dump_csb_ctx ctx;
bool ret = true;
/* All blocks contain a block_type member in the first word at the same
* position. We could unpack any block to pick out this discriminant field,
* but this one has been chosen because it's only one word long.
*/
STATIC_ASSERT(pvr_cmd_length(CDMCTRL_STREAM_TERMINATE) == 1);
if (!pvr_dump_csb_ctx_push(&ctx, parent_ctx))
return false;
do {
enum ROGUE_CDMCTRL_BLOCK_TYPE block_type;
const uint32_t *next_word;
uint32_t words_read = 0;
next_word = pvr_dump_buffer_peek(&ctx.base, sizeof(*next_word));
if (!next_word) {
ret = false;
goto end_pop_ctx;
}
block_type =
pvr_csb_unpack(next_word, CDMCTRL_STREAM_TERMINATE).block_type;
switch (block_type) {
case ROGUE_CDMCTRL_BLOCK_TYPE_COMPUTE_KERNEL:
words_read = print_block_cdmctrl_kernel(&ctx, device);
break;
case ROGUE_CDMCTRL_BLOCK_TYPE_STREAM_LINK:
words_read = print_block_cdmctrl_stream_link(&ctx);
break;
case ROGUE_CDMCTRL_BLOCK_TYPE_STREAM_TERMINATE:
words_read = print_block_cdmctrl_stream_terminate(&ctx);
break;
default:
pvr_dump_buffer_print_header_line(
&ctx.base,
"<could not decode CDMCTRL block (%u)>",
block_type);
break;
}
if (!print_block_hex(&ctx.base, words_read))
ret = false;
if (block_type == ROGUE_CDMCTRL_BLOCK_TYPE_STREAM_TERMINATE)
break;
} while (ret);
end_pop_ctx:
pvr_dump_csb_ctx_pop(&ctx, true);
return ret;
}
static bool print_vdmctrl_buffer(struct pvr_dump_buffer_ctx *const parent_ctx,
struct pvr_device *const device)
{
struct pvr_dump_csb_ctx ctx;
bool ret = true;
/* All blocks contain a block_type member in the first word at the same
* position. We could unpack any block to pick out this discriminant field,
* but this one has been chosen because it's only one word long.
*/
STATIC_ASSERT(pvr_cmd_length(VDMCTRL_STREAM_RETURN) == 1);
if (!pvr_dump_csb_ctx_push(&ctx, parent_ctx))
return false;
do {
enum ROGUE_VDMCTRL_BLOCK_TYPE block_type;
const uint32_t *next_word;
uint32_t words_read = 0;
next_word = pvr_dump_buffer_peek(&ctx.base, sizeof(*next_word));
if (!next_word) {
ret = false;
goto end_pop_ctx;
}
block_type = pvr_csb_unpack(next_word, VDMCTRL_STREAM_RETURN).block_type;
switch (block_type) {
case ROGUE_VDMCTRL_BLOCK_TYPE_PPP_STATE_UPDATE:
words_read = print_block_vdmctrl_ppp_state_update(&ctx, device);
break;
case ROGUE_VDMCTRL_BLOCK_TYPE_PDS_STATE_UPDATE:
words_read = print_block_vdmctrl_pds_state_update(&ctx, device);
break;
case ROGUE_VDMCTRL_BLOCK_TYPE_VDM_STATE_UPDATE:
words_read = print_block_vdmctrl_vdm_state_update(&ctx, device);
break;
case ROGUE_VDMCTRL_BLOCK_TYPE_INDEX_LIST:
words_read = print_block_vdmctrl_index_list(&ctx, device);
break;
case ROGUE_VDMCTRL_BLOCK_TYPE_STREAM_LINK:
words_read = print_block_vdmctrl_stream_link(&ctx);
break;
case ROGUE_VDMCTRL_BLOCK_TYPE_STREAM_RETURN:
words_read = print_block_vdmctrl_stream_return(&ctx);
break;
case ROGUE_VDMCTRL_BLOCK_TYPE_STREAM_TERMINATE:
words_read = print_block_vdmctrl_stream_terminate(&ctx);
break;
default:
pvr_dump_buffer_print_header_line(
&ctx.base,
"<could not decode VDMCTRL block (%u)>",
block_type);
break;
}
if (!print_block_hex(&ctx.base, words_read))
ret = false;
if (block_type == ROGUE_VDMCTRL_BLOCK_TYPE_STREAM_TERMINATE)
break;
} while (ret);
end_pop_ctx:
pvr_dump_csb_ctx_pop(&ctx, true);
return ret;
}
static bool print_ppp_buffer(struct pvr_dump_buffer_ctx *const parent_ctx,
struct pvr_device *const device)
{
struct pvr_dump_csb_ctx ctx;
uint32_t words_read;
bool ret = false;
struct ROGUE_TA_STATE_HEADER header = { 0 };
if (!pvr_dump_csb_ctx_push(&ctx, parent_ctx))
goto end_out;
words_read = print_block_ppp_state_header(&ctx, &header);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
if (header.pres_ispctl_fa || header.pres_ispctl_fb ||
header.pres_ispctl_ba || header.pres_ispctl_bb ||
header.pres_ispctl_dbsc) {
if (!header.pres_ispctl) {
ret =
pvr_dump_field_error(&ctx.base.base, "missing ispctl control word");
goto end_pop_ctx;
}
words_read = print_block_ppp_state_isp(&ctx,
header.pres_ispctl_fa,
header.pres_ispctl_fb,
header.pres_ispctl_ba,
header.pres_ispctl_bb,
header.pres_ispctl_dbsc);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_pds_state_ptr0 || header.pres_pds_state_ptr1 ||
header.pres_pds_state_ptr2 || header.pres_pds_state_ptr3) {
words_read = print_block_ppp_state_pds(&ctx,
device,
header.pres_pds_state_ptr0,
header.pres_pds_state_ptr1,
header.pres_pds_state_ptr2,
header.pres_pds_state_ptr3);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_region_clip) {
words_read = print_block_ppp_region_clip(&ctx);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_viewport) {
for (uint32_t i = 0; i < header.view_port_count + 1; i++) {
words_read = print_block_ppp_viewport(&ctx, i);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
}
if (header.pres_wclamp) {
words_read = print_block_ppp_wclamp(&ctx);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_outselects) {
words_read = print_block_ppp_output_sel(&ctx);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_varying_word0 || header.pres_varying_word1 ||
header.pres_varying_word2) {
words_read = print_block_ppp_state_varying(&ctx,
header.pres_varying_word0,
header.pres_varying_word1,
header.pres_varying_word2);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_ppp_ctrl) {
words_read = print_block_ppp_state_ppp_ctrl(&ctx);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_stream_out_size || header.pres_stream_out_program) {
words_read =
print_block_ppp_state_stream_out(&ctx,
device,
header.pres_stream_out_size,
header.pres_stream_out_program);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
if (header.pres_terminate) {
words_read = print_block_ppp_state_terminate(&ctx);
if (!print_block_hex(&ctx.base, words_read))
goto end_pop_ctx;
}
ret = true;
end_pop_ctx:
pvr_dump_csb_ctx_pop(&ctx, true);
end_out:
return ret;
}
/******************************************************************************
Sub buffer printer definition
******************************************************************************/
static bool print_sub_buffer(struct pvr_dump_ctx *const ctx,
struct pvr_device *const device,
const enum buffer_type type,
const pvr_dev_addr_t addr,
const uint64_t expected_size,
const char *const size_src)
{
struct pvr_dump_bo_ctx sub_ctx;
struct pvr_dump_ctx *base_ctx;
struct pvr_bo *bo;
uint64_t real_size;
uint64_t offset;
bool ret = false;
pvr_dump_indent(ctx);
bo = pvr_bo_store_lookup(device, addr);
if (!bo) {
if (expected_size) {
pvr_dump_field(ctx,
"<buffer size>",
"%" PRIu64 " bytes (from %s)",
expected_size,
size_src);
} else {
pvr_dump_field(ctx, "<buffer size>", "<unknown>");
}
/* FIXME: Trace pvr_buffer allocations with pvr_bo_store. */
pvr_dump_warn(ctx, "no mapping found at " PVR_DEV_ADDR_FMT, addr.addr);
/* Not a fatal error; don't let a single bad address halt the dump. */
ret = true;
goto end_out;
}
offset = addr.addr - bo->vma->dev_addr.addr;
if (!pvr_dump_bo_ctx_push(&sub_ctx, ctx, device, bo)) {
pvr_dump_println(&sub_ctx.base.base, "<unable to read buffer>");
goto end_out;
}
base_ctx = &sub_ctx.base.base;
if (!pvr_dump_buffer_advance(&sub_ctx.base, offset))
goto end_pop_ctx;
real_size = sub_ctx.base.remaining_size;
if (!expected_size) {
pvr_dump_field(base_ctx,
"<buffer size>",
"%" PRIu64 " bytes mapped",
real_size);
} else if (expected_size > real_size) {
pvr_dump_field(base_ctx,
"<buffer size>",
"%" PRIu64 " bytes mapped, expected %" PRIu64
" bytes (from %s)",
real_size,
expected_size,
size_src);
} else {
pvr_dump_field(base_ctx,
"<buffer size>",
"%" PRIu64 " bytes (from %s)",
expected_size,
size_src);
pvr_dump_buffer_truncate(&sub_ctx.base, expected_size);
}
if (sub_ctx.bo_mapped_in_ctx)
pvr_dump_field(base_ctx, "<host addr>", "<unmapped>");
else
pvr_dump_field(base_ctx, "<host addr>", "%p", sub_ctx.base.ptr);
switch (type) {
case BUFFER_TYPE_NONE:
pvr_dump_field(base_ctx, "<content>", "<not decoded>");
ret = true;
break;
case BUFFER_TYPE_PPP:
pvr_dump_field(base_ctx, "<content>", "<decoded as PPP>");
ret = print_ppp_buffer(&sub_ctx.base, device);
break;
default:
pvr_dump_field(base_ctx, "<content>", "<unsupported format>");
ret = false;
}
pvr_dump_field_u32_units(&sub_ctx.base.base,
"<raw>",
sub_ctx.base.capacity,
"bytes");
pvr_dump_indent(&sub_ctx.base.base);
pvr_dump_buffer_restart(&sub_ctx.base);
pvr_dump_buffer_hex(&sub_ctx.base, 0);
pvr_dump_dedent(&sub_ctx.base.base);
end_pop_ctx:
pvr_dump_bo_ctx_pop(&sub_ctx);
end_out:
pvr_dump_dedent(ctx);
return ret;
}
/******************************************************************************
Top-level dumping
******************************************************************************/
static bool dump_first_buffer(struct pvr_dump_buffer_ctx *const ctx,
const enum pvr_cmd_stream_type stream_type,
struct pvr_device *const device)
{
bool ret = false;
pvr_dump_mark_section(&ctx->base, "First buffer content");
switch (stream_type) {
case PVR_CMD_STREAM_TYPE_GRAPHICS:
ret = print_vdmctrl_buffer(ctx, device);
break;
case PVR_CMD_STREAM_TYPE_COMPUTE:
ret = print_cdmctrl_buffer(ctx, device);
break;
default:
UNREACHABLE("Unknown stream type");
}
if (!ret)
pvr_dump_println(&ctx->base,
"<error while decoding at 0x%tx>",
(uint8_t *)ctx->ptr - (uint8_t *)ctx->initial_ptr);
pvr_dump_buffer_restart(ctx);
pvr_dump_mark_section(&ctx->base, "First buffer hexdump");
return pvr_dump_buffer_hex(ctx, 0);
}
/******************************************************************************
Public functions
******************************************************************************/
void pvr_csb_dump(const struct pvr_csb *const csb,
const uint32_t frame_num,
const uint32_t job_num)
{
const uint32_t nr_bos = list_length(&csb->pvr_bo_list);
struct pvr_device *const device = csb->device;
struct pvr_dump_bo_ctx first_bo_ctx;
struct pvr_dump_ctx root_ctx;
pvr_bo_store_dump(device);
pvr_dump_begin(&root_ctx, stderr, "CONTROL STREAM DUMP", 6);
pvr_dump_field_u32(&root_ctx, "Frame num", frame_num);
pvr_dump_field_u32(&root_ctx, "Job num", job_num);
pvr_dump_field_enum(&root_ctx, "Status", csb->status, vk_Result_to_str);
pvr_dump_field_enum(&root_ctx,
"Stream type",
csb->stream_type,
pvr_cmd_stream_type_to_str);
if (nr_bos <= 1) {
pvr_dump_field_u32(&root_ctx, "Nr of BOs", nr_bos);
} else {
/* TODO: Implement multi-buffer dumping. */
pvr_dump_field_computed(&root_ctx,
"Nr of BOs",
"%" PRIu32,
"only the first buffer will be dumped",
nr_bos);
}
if (nr_bos == 0)
goto end_dump;
pvr_dump_mark_section(&root_ctx, "Buffer objects");
pvr_bo_list_dump(&root_ctx, &csb->pvr_bo_list, nr_bos);
if (!pvr_dump_bo_ctx_push(
&first_bo_ctx,
&root_ctx,
device,
list_first_entry(&csb->pvr_bo_list, struct pvr_bo, link))) {
pvr_dump_mark_section(&root_ctx, "First buffer");
pvr_dump_println(&root_ctx, "<unable to read buffer>");
goto end_dump;
}
dump_first_buffer(&first_bo_ctx.base, csb->stream_type, device);
pvr_dump_bo_ctx_pop(&first_bo_ctx);
end_dump:
pvr_dump_end(&root_ctx);
}