ajm: added stubbed statistics instance (#1924)
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions

* ajm: added stubbed statistics instance

* fixed a typo, thanks poly

* fixed clang-format

* removed unused struct

* small fixes

* fixed typedefs, added per codec statistics
This commit is contained in:
Vladislav Mikhalin 2024-12-29 13:53:06 +03:00 committed by GitHub
parent f09a95453e
commit ee72d99947
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 231 additions and 42 deletions

View file

@ -189,6 +189,8 @@ set(AJM_LIB src/core/libraries/ajm/ajm.cpp
src/core/libraries/ajm/ajm_context.cpp
src/core/libraries/ajm/ajm_context.h
src/core/libraries/ajm/ajm_error.h
src/core/libraries/ajm/ajm_instance_statistics.cpp
src/core/libraries/ajm/ajm_instance_statistics.h
src/core/libraries/ajm/ajm_instance.cpp
src/core/libraries/ajm/ajm_instance.h
src/core/libraries/ajm/ajm_mp3.cpp

View file

@ -183,13 +183,15 @@ int PS4_SYSV_ABI sceAjmInstanceSwitch() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAjmMemoryRegister() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
int PS4_SYSV_ABI sceAjmMemoryRegister(u32 context_id, void* ptr, size_t num_pages) {
// All memory is already shared with our implementation since we do not use any hardware.
LOG_TRACE(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAjmMemoryUnregister() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
int PS4_SYSV_ABI sceAjmMemoryUnregister(u32 context_id, void* ptr) {
// All memory is already shared with our implementation since we do not use any hardware.
LOG_TRACE(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
}

View file

@ -74,6 +74,26 @@ union AjmJobFlags {
};
};
enum class AjmStatisticsFlags : u64 {
Memory = 1 << 0,
EnginePerCodec = 1 << 15,
Engine = 1 << 16,
};
DECLARE_ENUM_FLAG_OPERATORS(AjmStatisticsFlags)
union AjmStatisticsJobFlags {
AjmStatisticsJobFlags(AjmJobFlags job_flags) : raw(job_flags.raw) {}
u64 raw;
struct {
u64 version : 3;
u64 : 12;
AjmStatisticsFlags statistics_flags : 17;
u64 : 32;
};
};
static_assert(sizeof(AjmStatisticsJobFlags) == 8);
struct AjmSidebandResult {
s32 result;
s32 internal_result;
@ -126,6 +146,31 @@ union AjmSidebandInitParameters {
u8 reserved[8];
};
struct AjmSidebandStatisticsEngine {
float usage_batch;
float usage_interval[3];
};
struct AjmSidebandStatisticsEnginePerCodec {
u8 codec_count;
u8 codec_id[3];
float codec_percentage[3];
};
struct AjmSidebandStatisticsMemory {
u32 instance_free;
u32 buffer_free;
u32 batch_size;
u32 input_size;
u32 output_size;
u32 small_size;
};
struct AjmSidebandStatisticsEngineParameters {
u32 interval_count;
float interval[3];
};
union AjmInstanceFlags {
u64 raw;
struct {
@ -178,8 +223,8 @@ int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmI
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance);
int PS4_SYSV_ABI sceAjmInstanceExtend();
int PS4_SYSV_ABI sceAjmInstanceSwitch();
int PS4_SYSV_ABI sceAjmMemoryRegister();
int PS4_SYSV_ABI sceAjmMemoryUnregister();
int PS4_SYSV_ABI sceAjmMemoryRegister(u32 context_id, void* ptr, size_t num_pages);
int PS4_SYSV_ABI sceAjmMemoryUnregister(u32 context_id, void* ptr);
int PS4_SYSV_ABI sceAjmModuleRegister(u32 context, AjmCodecType codec_type, s64 reserved);
int PS4_SYSV_ABI sceAjmModuleUnregister();
int PS4_SYSV_ABI sceAjmStrError();

View file

@ -54,6 +54,8 @@ public:
: m_p_begin(begin), m_p_current(m_p_begin), m_size(size) {}
AjmBatchBuffer(std::span<u8> data)
: m_p_begin(data.data()), m_p_current(m_p_begin), m_size(data.size()) {}
AjmBatchBuffer(AjmChunkBuffer& buffer)
: AjmBatchBuffer(reinterpret_cast<u8*>(buffer.p_address), buffer.size) {}
AjmBatchBuffer SubBuffer(size_t size = s_dynamic_extent) {
auto current = m_p_current;
@ -113,6 +115,88 @@ private:
size_t m_size{};
};
AjmJob AjmStatisticsJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
std::optional<AjmJobFlags> job_flags = {};
std::optional<AjmChunkBuffer> input_control_buffer = {};
std::optional<AjmChunkBuffer> output_control_buffer = {};
AjmJob job;
job.instance_id = instance_id;
while (!batch_buffer.IsEmpty()) {
auto& header = batch_buffer.Peek<AjmChunkHeader>();
switch (header.ident) {
case Identifier::AjmIdentInputControlBuf: {
ASSERT_MSG(!input_control_buffer.has_value(),
"Only one instance of input control buffer is allowed per job");
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
input_control_buffer = buffer;
}
break;
}
case Identifier::AjmIdentControlFlags: {
ASSERT_MSG(!job_flags.has_value(), "Only one instance of job flags is allowed per job");
auto& chunk = batch_buffer.Consume<AjmChunkFlags>();
job_flags = AjmJobFlags{
.raw = (u64(chunk.header.payload) << 32) + chunk.flags_low,
};
break;
}
case Identifier::AjmIdentReturnAddressBuf: {
// Ignore return address buffers.
batch_buffer.Skip<AjmChunkBuffer>();
break;
}
case Identifier::AjmIdentOutputControlBuf: {
ASSERT_MSG(!output_control_buffer.has_value(),
"Only one instance of output control buffer is allowed per job");
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
output_control_buffer = buffer;
}
break;
}
default:
UNREACHABLE_MSG("Unknown chunk: {}", header.ident);
}
}
ASSERT(job_flags.has_value());
job.flags = job_flags.value();
AjmStatisticsJobFlags flags(job.flags);
if (input_control_buffer.has_value()) {
AjmBatchBuffer input_batch(input_control_buffer.value());
if (True(flags.statistics_flags & AjmStatisticsFlags::Engine)) {
job.input.statistics_engine_parameters =
input_batch.Consume<AjmSidebandStatisticsEngineParameters>();
}
}
if (output_control_buffer.has_value()) {
AjmBatchBuffer output_batch(output_control_buffer.value());
job.output.p_result = &output_batch.Consume<AjmSidebandResult>();
*job.output.p_result = AjmSidebandResult{};
if (True(flags.statistics_flags & AjmStatisticsFlags::Engine)) {
job.output.p_engine = &output_batch.Consume<AjmSidebandStatisticsEngine>();
*job.output.p_engine = AjmSidebandStatisticsEngine{};
}
if (True(flags.statistics_flags & AjmStatisticsFlags::EnginePerCodec)) {
job.output.p_engine_per_codec =
&output_batch.Consume<AjmSidebandStatisticsEnginePerCodec>();
*job.output.p_engine_per_codec = AjmSidebandStatisticsEnginePerCodec{};
}
if (True(flags.statistics_flags & AjmStatisticsFlags::Memory)) {
job.output.p_memory = &output_batch.Consume<AjmSidebandStatisticsMemory>();
*job.output.p_memory = AjmSidebandStatisticsMemory{};
}
}
return job;
}
AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
std::optional<AjmJobFlags> job_flags = {};
std::optional<AjmChunkBuffer> input_control_buffer = {};
@ -155,15 +239,6 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
batch_buffer.Skip<AjmChunkBuffer>();
break;
}
case Identifier::AjmIdentInlineBuf: {
ASSERT_MSG(!output_control_buffer.has_value(),
"Only one instance of inline buffer is allowed per job");
const auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
if (buffer.p_address != nullptr && buffer.size != 0) {
inline_buffer = buffer;
}
break;
}
case Identifier::AjmIdentOutputRunBuf: {
auto& buffer = batch_buffer.Consume<AjmChunkBuffer>();
u8* p_begin = reinterpret_cast<u8*>(buffer.p_address);
@ -186,13 +261,12 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
}
}
ASSERT(job_flags.has_value());
job.flags = job_flags.value();
// Initialize sideband input parameters
if (input_control_buffer.has_value()) {
AjmBatchBuffer input_batch(reinterpret_cast<u8*>(input_control_buffer->p_address),
input_control_buffer->size);
AjmBatchBuffer input_batch(input_control_buffer.value());
const auto sideband_flags = job_flags->sideband_flags;
if (True(sideband_flags & AjmJobSidebandFlags::Format) && !input_batch.IsEmpty()) {
job.input.format = input_batch.Consume<AjmSidebandFormat>();
@ -202,6 +276,9 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
}
const auto control_flags = job_flags.value().control_flags;
if (True(control_flags & AjmJobControlFlags::Resample)) {
job.input.resample_parameters = input_batch.Consume<AjmSidebandResampleParameters>();
}
if (True(control_flags & AjmJobControlFlags::Initialize)) {
job.input.init_params = AjmDecAt9InitializeParameters{};
std::memcpy(&job.input.init_params.value(), input_batch.GetCurrent(),
@ -209,21 +286,9 @@ AjmJob AjmJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buffer) {
}
}
if (inline_buffer.has_value()) {
AjmBatchBuffer inline_batch(reinterpret_cast<u8*>(inline_buffer->p_address),
inline_buffer->size);
const auto control_flags = job_flags.value().control_flags;
if (True(control_flags & AjmJobControlFlags::Resample)) {
job.input.resample_parameters = inline_batch.Consume<AjmSidebandResampleParameters>();
}
}
// Initialize sideband output parameters
if (output_control_buffer.has_value()) {
AjmBatchBuffer output_batch(reinterpret_cast<u8*>(output_control_buffer->p_address),
output_control_buffer->size);
AjmBatchBuffer output_batch(output_control_buffer.value());
job.output.p_result = &output_batch.Consume<AjmSidebandResult>();
*job.output.p_result = AjmSidebandResult{};
@ -260,9 +325,21 @@ std::shared_ptr<AjmBatch> AjmBatch::FromBatchBuffer(std::span<u8> data) {
AjmBatchBuffer buffer(data);
while (!buffer.IsEmpty()) {
auto& job_chunk = buffer.Consume<AjmChunkJob>();
if (job_chunk.header.ident == AjmIdentInlineBuf) {
// Inline buffers are used to store sideband input data.
// We should just skip them as they do not require any special handling.
buffer.Advance(job_chunk.size);
continue;
}
ASSERT(job_chunk.header.ident == AjmIdentJob);
auto instance_id = job_chunk.header.payload;
batch->jobs.push_back(AjmJobFromBatchBuffer(instance_id, buffer.SubBuffer(job_chunk.size)));
if (instance_id == AJM_INSTANCE_STATISTICS) {
batch->jobs.push_back(
AjmStatisticsJobFromBatchBuffer(instance_id, buffer.SubBuffer(job_chunk.size)));
} else {
batch->jobs.push_back(
AjmJobFromBatchBuffer(instance_id, buffer.SubBuffer(job_chunk.size)));
}
}
return batch;

View file

@ -23,6 +23,7 @@ struct AjmJob {
struct Input {
std::optional<AjmDecAt9InitializeParameters> init_params;
std::optional<AjmSidebandResampleParameters> resample_parameters;
std::optional<AjmSidebandStatisticsEngineParameters> statistics_engine_parameters;
std::optional<AjmSidebandFormat> format;
std::optional<AjmSidebandGaplessDecode> gapless_decode;
std::vector<u8> buffer;
@ -33,6 +34,9 @@ struct AjmJob {
AjmSidebandResult* p_result = nullptr;
AjmSidebandStream* p_stream = nullptr;
AjmSidebandFormat* p_format = nullptr;
AjmSidebandStatisticsMemory* p_memory = nullptr;
AjmSidebandStatisticsEnginePerCodec* p_engine_per_codec = nullptr;
AjmSidebandStatisticsEngine* p_engine = nullptr;
AjmSidebandGaplessDecode* p_gapless_decode = nullptr;
AjmSidebandMFrame* p_mframe = nullptr;
u8* p_codec_info = nullptr;

View file

@ -9,6 +9,7 @@
#include "core/libraries/ajm/ajm_context.h"
#include "core/libraries/ajm/ajm_error.h"
#include "core/libraries/ajm/ajm_instance.h"
#include "core/libraries/ajm/ajm_instance_statistics.h"
#include "core/libraries/ajm/ajm_mp3.h"
#include "core/libraries/error_codes.h"
@ -70,6 +71,9 @@ void AjmContext::ProcessBatch(u32 id, std::span<AjmJob> jobs) {
LOG_TRACE(Lib_Ajm, "Processing job {} for instance {}. flags = {:#x}", id, job.instance_id,
job.flags.raw);
if (job.instance_id == AJM_INSTANCE_STATISTICS) {
AjmInstanceStatistics::Getinstance().ExecuteJob(job);
} else {
std::shared_ptr<AjmInstance> instance;
{
std::shared_lock lock(instances_mutex);
@ -80,6 +84,7 @@ void AjmContext::ProcessBatch(u32 id, std::span<AjmJob> jobs) {
instance->ExecuteJob(job);
}
}
}
s32 AjmContext::BatchWait(const u32 batch_id, const u32 timeout, AjmBatchError* const batch_error) {

View file

@ -68,11 +68,11 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
m_codec->Initialize(&params, sizeof(params));
}
if (job.input.resample_parameters.has_value()) {
UNREACHABLE_MSG("Unimplemented: resample parameters");
LOG_ERROR(Lib_Ajm, "Unimplemented: resample parameters");
m_resample_parameters = job.input.resample_parameters.value();
}
if (job.input.format.has_value()) {
UNREACHABLE_MSG("Unimplemented: format parameters");
LOG_ERROR(Lib_Ajm, "Unimplemented: format parameters");
m_format = job.input.format.value();
}
if (job.input.gapless_decode.has_value()) {

View file

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/libraries/ajm/ajm.h"
#include "core/libraries/ajm/ajm_instance_statistics.h"
namespace Libraries::Ajm {
void AjmInstanceStatistics::ExecuteJob(AjmJob& job) {
if (job.output.p_engine) {
job.output.p_engine->usage_batch = 0.01;
const auto ic = job.input.statistics_engine_parameters->interval_count;
for (u32 idx = 0; idx < ic; ++idx) {
job.output.p_engine->usage_interval[idx] = 0.01;
}
}
if (job.output.p_engine_per_codec) {
job.output.p_engine_per_codec->codec_count = 1;
job.output.p_engine_per_codec->codec_id[0] = static_cast<u8>(AjmCodecType::At9Dec);
job.output.p_engine_per_codec->codec_percentage[0] = 0.01;
}
if (job.output.p_memory) {
job.output.p_memory->instance_free = 0x400000;
job.output.p_memory->buffer_free = 0x400000;
job.output.p_memory->batch_size = 0x4200;
job.output.p_memory->input_size = 0x2000;
job.output.p_memory->output_size = 0x2000;
job.output.p_memory->small_size = 0x200;
}
}
AjmInstanceStatistics& AjmInstanceStatistics::Getinstance() {
static AjmInstanceStatistics instance;
return instance;
}
} // namespace Libraries::Ajm

View file

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/libraries/ajm/ajm_batch.h"
namespace Libraries::Ajm {
class AjmInstanceStatistics {
public:
void ExecuteJob(AjmJob& job);
static AjmInstanceStatistics& Getinstance();
};
} // namespace Libraries::Ajm