mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-18 22:28:06 +02:00
These files shouldn't not be per-arch, so break them out to their own modules before we start making things multi-arch. Reviewed-by: Frank Binns <frank.binns@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38352>
2434 lines
82 KiB
C
2434 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.h"
|
|
#include "pvr_device_info.h"
|
|
#include "pvr_dump.h"
|
|
#include "pvr_dump_bo.h"
|
|
#include "pvr_physical_device.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);
|
|
}
|