blob: 3f512fd1acbba98d501e85eb3aecf41be32031d8 [file] [log] [blame]
/*
* 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);
}