modules: implement avcdec and yuv format

This commit is contained in:
Taylor Whatley
2019-10-24 20:39:56 -04:00
committed by 1whatleytay
parent c2a014f1f2
commit 6463b34cc1
20 changed files with 564 additions and 73 deletions
+3
View File
@@ -84,3 +84,6 @@
[submodule "external/VulkanMemoryAllocator"]
path = external/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
[submodule "external/ffmpeg"]
path = external/ffmpeg
url = https://github.com/Vita3K/ffmpeg-core.git
+2
View File
@@ -217,3 +217,5 @@ if (USE_VULKAN)
add_library(vma INTERFACE)
target_include_directories(vma INTERFACE VulkanMemoryAllocator/src)
endif()
add_subdirectory(ffmpeg)
Vendored Submodule
+1
Submodule external/ffmpeg added at e5fb13bbb0
+1
View File
@@ -12,6 +12,7 @@ size_t get_height(const emu::SceGxmTexture *texture);
SceGxmTextureFormat get_format(const emu::SceGxmTexture *texture);
SceGxmTextureBaseFormat get_base_format(SceGxmTextureFormat src);
bool is_paletted_format(SceGxmTextureFormat src);
bool is_yuv_format(SceGxmTextureFormat src);
size_t attribute_format_size(SceGxmAttributeFormat format);
} // namespace gxm
+8
View File
@@ -29,4 +29,12 @@ bool is_paletted_format(SceGxmTextureFormat src) {
return base_format == SCE_GXM_TEXTURE_BASE_FORMAT_P8 || base_format == SCE_GXM_TEXTURE_BASE_FORMAT_P4;
}
bool is_yuv_format(SceGxmTextureFormat src) {
const auto base_format = get_base_format(src);
return base_format == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2 ||
base_format == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3 ||
base_format == SCE_GXM_TEXTURE_BASE_FORMAT_YUV422;
}
} // namespace gxm
+48
View File
@@ -170,6 +170,52 @@ struct WaitingThreadState {
typedef std::map<SceUID, WaitingThreadState> KernelWaitingThreadStates;
struct AVCodecContext;
struct AVCodecParserContext;
struct DecoderState {
AVCodecContext *context{};
AVCodecParserContext *parser{};
uint32_t frame_width;
uint32_t frame_height;
uint32_t frame_ref_count;
};
typedef std::shared_ptr<DecoderState> DecoderPtr;
typedef std::map<SceUID, DecoderPtr> DecoderStates;
struct TimerState {
std::string name;
enum class ThreadBehaviour {
FIFO,
PRIORITY,
};
enum class NotifyBehaviour {
ALL,
ONLY_WAKE
};
enum class ResetBehaviour {
MANUAL,
AUTOMATIC,
};
bool openable = false;
ThreadBehaviour thread_behaviour = ThreadBehaviour::FIFO;
NotifyBehaviour notify_behaviour = NotifyBehaviour::ALL;
ResetBehaviour reset_behaviour = ResetBehaviour::MANUAL;
bool is_started = false;
bool repeats = false;
uint64_t time = 0;
};
typedef std::shared_ptr<TimerState> TimerPtr;
typedef std::map<SceUID, TimerPtr> TimerStates;
using LoadedSysmodules = std::vector<SceSysmoduleModuleId>;
struct KernelState {
@@ -190,6 +236,8 @@ struct KernelState {
LoadedSysmodules loaded_sysmodules;
ExportNids export_nids;
SceRtcTick base_tick;
DecoderStates decoders;
TimerStates timers;
Ptr<uint32_t> process_param;
bool wait_for_debugger = false;
+1 -1
View File
@@ -169,4 +169,4 @@ add_library(modules STATIC
SceWlanBt/SceWlan.cpp SceWlanBt/SceWlan.h
)
target_include_directories(modules PUBLIC include)
target_link_libraries(modules PUBLIC module)
target_link_libraries(modules PUBLIC module ffmpeg)
+31 -2
View File
@@ -17,8 +17,37 @@
#include "SceDbg.h"
EXPORT(int, sceDbgAssertionHandler) {
return UNIMPLEMENTED();
#include <v3kprintf.h>
#include <util/lock_and_find.h>
#include <kernel/functions.h>
#include <psp2/kernel/error.h>
EXPORT(int, sceDbgAssertionHandler, const char *filename, int line, bool do_stop, const char *component, module::vargs messages) {
const ThreadStatePtr thread = lock_and_find(thread_id, host.kernel.threads, host.kernel.mutex);
if (!thread) {
return SCE_KERNEL_ERROR_UNKNOWN_THREAD_ID;
}
std::vector<char> buffer(1024);
const char *main_message = messages.next<Ptr<const char>>(*(thread->cpu), host.mem).get(host.mem);
const int result = utils::snprintf(buffer.data(), buffer.size(), main_message, *(thread->cpu), host.mem, messages);
LOG_INFO("file {}, line {}, {}", filename, line, buffer.data());
if (do_stop)
stop_all_threads(host.kernel);
if (!result) {
return SCE_KERNEL_ERROR_INVALID_ARGUMENT;
}
assert(!do_stop);
return 0;
}
EXPORT(int, sceDbgLoggingHandler) {
+16 -18
View File
@@ -1757,7 +1757,7 @@ EXPORT(int, sceGxmTextureInitCubeArbitrary) {
return UNIMPLEMENTED();
}
static int init_texture_base(const char *export_name, emu::SceGxmTexture *texture, Ptr<const void> data, SceGxmTextureFormat texFormat, unsigned int width, unsigned int height, unsigned int mipCount,
static int init_texture_base(const char *export_name, emu::SceGxmTexture *texture, Ptr<const void> data, SceGxmTextureFormat tex_format, unsigned int width, unsigned int height, unsigned int mipCount,
const SceGxmTextureType &texture_type) {
if (width > 4096 || height > 4096 || mipCount > 13) {
return RET_ERROR(SCE_GXM_ERROR_INVALID_VALUE);
@@ -1769,7 +1769,7 @@ static int init_texture_base(const char *export_name, emu::SceGxmTexture *textur
// Add supported formats here
switch (texFormat) {
switch (tex_format) {
case SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR:
case SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ARGB:
case SCE_GXM_TEXTURE_FORMAT_U4U4U4U4_ABGR:
@@ -1783,21 +1783,28 @@ static int init_texture_base(const char *export_name, emu::SceGxmTexture *textur
break;
default:
if (gxm::is_paletted_format(texFormat)) {
switch (texFormat) {
if (gxm::is_paletted_format(tex_format)) {
switch (tex_format) {
case SCE_GXM_TEXTURE_FORMAT_P8_ABGR:
case SCE_GXM_TEXTURE_FORMAT_P8_1BGR:
case SCE_GXM_TEXTURE_FORMAT_P4_ABGR:
break;
default:
LOG_WARN("Initialized texture with untested paletted texture format: {}", log_hex(texFormat));
LOG_WARN("Initialized texture with untested paletted texture format: {}", log_hex(tex_format));
}
} else if (gxm::is_yuv_format(tex_format)) {
switch (tex_format) {
case SCE_GXM_TEXTURE_FORMAT_YUV420P2_CSC1:
break;
default:
LOG_WARN("Iniitlaized texture with untested YUV texture format: {}", log_hex(tex_format));
}
} else
LOG_ERROR("Initialized texture with unsupported texture format: {}", log_hex(texFormat));
LOG_ERROR("Initialized texture with unsupported texture format: {}", log_hex(tex_format));
}
texture->mip_count = std::min<std::uint32_t>(0, mipCount - 1);
texture->format0 = (texFormat & 0x80000000) >> 31;
texture->format0 = (tex_format & 0x80000000) >> 31;
texture->uaddr_mode = texture->vaddr_mode = SCE_GXM_TEXTURE_ADDR_CLAMP;
texture->lod_bias = 31;
@@ -1820,10 +1827,10 @@ static int init_texture_base(const char *export_name, emu::SceGxmTexture *textur
texture->width = width - 1;
}
texture->base_format = (texFormat & 0x1F000000) >> 24;
texture->base_format = (tex_format & 0x1F000000) >> 24;
texture->type = texture_type >> 29;
texture->data_addr = data.address() >> 2;
texture->swizzle_format = (texFormat & 0x7000) >> 12;
texture->swizzle_format = (tex_format & 0x7000) >> 12;
texture->normalize_mode = 1;
texture->min_filter = SCE_GXM_TEXTURE_FILTER_POINT;
texture->mag_filter = SCE_GXM_TEXTURE_FILTER_POINT;
@@ -1834,9 +1841,6 @@ static int init_texture_base(const char *export_name, emu::SceGxmTexture *textur
EXPORT(int, sceGxmTextureInitLinear, emu::SceGxmTexture *texture, Ptr<const void> data, SceGxmTextureFormat texFormat, unsigned int width, unsigned int height, unsigned int mipCount) {
const int result = init_texture_base(export_name, texture, data, texFormat, width, height, mipCount, SCE_GXM_TEXTURE_LINEAR);
if (result == 0)
return 0;
return result;
}
@@ -1847,9 +1851,6 @@ EXPORT(int, sceGxmTextureInitLinearStrided) {
EXPORT(int, sceGxmTextureInitSwizzled, emu::SceGxmTexture *texture, Ptr<const void> data, SceGxmTextureFormat texFormat, unsigned int width, unsigned int height, unsigned int mipCount) {
const int result = init_texture_base(export_name, texture, data, texFormat, width, height, mipCount, SCE_GXM_TEXTURE_SWIZZLED);
if (result == 0)
return 0;
return result;
}
@@ -1860,9 +1861,6 @@ EXPORT(int, sceGxmTextureInitSwizzledArbitrary) {
EXPORT(int, sceGxmTextureInitTiled, emu::SceGxmTexture *texture, Ptr<const void> data, SceGxmTextureFormat texFormat, unsigned int width, unsigned int height, unsigned int mipCount) {
const int result = init_texture_base(export_name, texture, data, texFormat, width, height, mipCount, SCE_GXM_TEXTURE_TILED);
if (result == 0)
return 0;
return result;
}
@@ -28,6 +28,11 @@
#include <chrono>
#include <thread>
inline uint64_t get_current_time() {
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}
EXPORT(int, __sceKernelCreateLwMutex) {
return UNIMPLEMENTED();
}
@@ -471,7 +476,7 @@ EXPORT(int, sceKernelCloseSimpleEvent) {
}
EXPORT(int, sceKernelCloseTimer) {
return UNIMPLEMENTED();
return STUBBED("References not implemented.");
}
EXPORT(int, sceKernelCreateCallback) {
@@ -553,8 +558,10 @@ EXPORT(int, sceKernelDeleteThread, SceUID thid) {
return 0;
}
EXPORT(int, sceKernelDeleteTimer) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelDeleteTimer, SceUID timer_handle) {
host.kernel.timers.erase(timer_handle);
return 0;
}
EXPORT(int, sceKernelExitDeleteThread, int status) {
@@ -619,12 +626,22 @@ EXPORT(int, sceKernelGetThreadmgrUIDClass) {
return UNIMPLEMENTED();
}
EXPORT(int, sceKernelGetTimerBaseWide) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelGetTimerBaseWide, SceUID timer_handle) {
const TimerPtr timer_info = lock_and_find(timer_handle, host.kernel.timers, host.kernel.mutex);
if (!timer_info)
return -1;
return timer_info->time;
}
EXPORT(int, sceKernelGetTimerTimeWide) {
return UNIMPLEMENTED();
EXPORT(uint64_t, sceKernelGetTimerTimeWide, SceUID timer_handle) {
const TimerPtr timer_info = lock_and_find(timer_handle, host.kernel.timers, host.kernel.mutex);
if (!timer_info)
return -1;
return get_current_time() - timer_info->time;
}
EXPORT(int, sceKernelNotifyCallback) {
@@ -663,8 +680,25 @@ EXPORT(int, sceKernelOpenSimpleEvent) {
return UNIMPLEMENTED();
}
EXPORT(int, sceKernelOpenTimer) {
return UNIMPLEMENTED();
EXPORT(SceUID, sceKernelOpenTimer, const char *name) {
STUBBED("References not implemented.");
SceUID timer_handle = -1;
TimerPtr timer_info;
host.kernel.mutex.lock();
for (const auto &timer : host.kernel.timers) {
if (timer.second->name == name) {
timer_handle = timer.first;
timer_info = timer.second;
break;
}
}
host.kernel.mutex.unlock();
assert(timer_info->openable);
return timer_handle;
}
EXPORT(int, sceKernelPollSema) {
@@ -718,12 +752,28 @@ EXPORT(int, sceKernelSignalSema, SceUID semaid, int signal) {
return semaphore_signal(host.kernel, export_name, thread_id, semaid, signal);
}
EXPORT(int, sceKernelStartTimer) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelStartTimer, SceUID timer_handle) {
const TimerPtr &timer_info = host.kernel.timers[timer_handle];
if (timer_info->is_started)
return false;
timer_info->is_started = true;
timer_info->time = get_current_time();
return true;
}
EXPORT(int, sceKernelStopTimer) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelStopTimer, SceUID timer_handle) {
const TimerPtr timer_info = lock_and_find(timer_handle, host.kernel.timers, host.kernel.mutex);
if (!timer_info->is_started)
return false;
timer_info->is_started = false;
timer_info->time = get_current_time();
return true;
}
EXPORT(int, sceKernelSuspendThreadForVM) {
+79 -12
View File
@@ -39,6 +39,22 @@
#include <algorithm>
#include <cstdlib>
enum class TimerFlags : uint32_t {
FIFO_THREAD = 0x00000000,
PRIORITY_THREAD = 0x00002000,
MANUAL_RESET = 0x00000000,
AUTOMATIC_RESET = 0x00000100,
ALL_NOTIFY = 0x00000000,
WAKE_ONLY_NOTIFY = 0x00000800,
OPENABLE = 0x00000080,
};
inline uint64_t get_current_time() {
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}
EXPORT(int, SceKernelStackChkGuard) {
return UNIMPLEMENTED();
}
@@ -177,8 +193,7 @@ EXPORT(int, sceClibMspaceReallocalign) {
}
EXPORT(int, sceClibPrintf, const char *format, module::vargs args) {
std::string buffer;
buffer.resize(1024);
std::vector<char> buffer(1024);
const ThreadStatePtr thread = lock_and_find(thread_id, host.kernel.threads, host.kernel.mutex);
@@ -186,13 +201,13 @@ EXPORT(int, sceClibPrintf, const char *format, module::vargs args) {
return SCE_KERNEL_ERROR_UNKNOWN_THREAD_ID;
}
const int result = utils::sprintf(&buffer[0], format, *(thread->cpu), host.mem, args);
const int result = utils::snprintf(buffer.data(), buffer.size(), format, *(thread->cpu), host.mem, args);
if (!result) {
return SCE_KERNEL_ERROR_INVALID_ARGUMENT;
}
LOG_INFO("{}", buffer);
LOG_INFO("{}", buffer.data());
return SCE_KERNEL_OK;
}
@@ -909,8 +924,35 @@ EXPORT(SceUID, sceKernelCreateThread, const char *name, emu::SceKernelThreadEntr
return thid;
}
EXPORT(int, sceKernelCreateTimer) {
return UNIMPLEMENTED();
EXPORT(SceUID, sceKernelCreateTimer, const char *name, uint32_t flags, const void *next) {
assert(!next);
SceUID handle = host.kernel.get_next_uid();
host.kernel.timers[handle] = std::make_shared<TimerState>();
TimerPtr &timer_info = host.kernel.timers[handle];
timer_info->name = name;
if (flags & static_cast<uint32_t>(TimerFlags::PRIORITY_THREAD))
timer_info->thread_behaviour = TimerState::ThreadBehaviour::PRIORITY;
else
timer_info->thread_behaviour = TimerState::ThreadBehaviour::FIFO;
if (flags & static_cast<uint32_t>(TimerFlags::AUTOMATIC_RESET))
timer_info->reset_behaviour = TimerState::ResetBehaviour::AUTOMATIC;
else
timer_info->reset_behaviour = TimerState::ResetBehaviour::MANUAL;
if (flags & static_cast<uint32_t>(TimerFlags::WAKE_ONLY_NOTIFY))
timer_info->notify_behaviour = TimerState::NotifyBehaviour::ONLY_WAKE;
else
timer_info->notify_behaviour = TimerState::NotifyBehaviour::ALL;
if (flags & static_cast<uint32_t>(TimerFlags::OPENABLE))
timer_info->openable = true;
return handle;
}
EXPORT(int, sceKernelDeleteLwCond, Ptr<emu::SceKernelLwCondWork> workarea) {
@@ -1072,8 +1114,15 @@ EXPORT(int, sceKernelGetThreadRunStatus) {
return UNIMPLEMENTED();
}
EXPORT(int, sceKernelGetTimerBase) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelGetTimerBase, SceUID timer_handle, SceKernelSysClock *time) {
const TimerPtr timer_info = lock_and_find(timer_handle, host.kernel.timers, host.kernel.mutex);
if (!timer_info)
return SCE_KERNEL_ERROR_UNKNOWN_TIMER_ID;
*time = timer_info->time;
return 0;
}
EXPORT(int, sceKernelGetTimerEventRemainingTime) {
@@ -1084,8 +1133,15 @@ EXPORT(int, sceKernelGetTimerInfo) {
return UNIMPLEMENTED();
}
EXPORT(int, sceKernelGetTimerTime) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelGetTimerTime, SceUID timer_handle, SceKernelSysClock *time) {
const TimerPtr timer_info = lock_and_find(timer_handle, host.kernel.timers, host.kernel.mutex);
if (!timer_info)
return SCE_KERNEL_ERROR_UNKNOWN_TIMER_ID;
*time = get_current_time() - timer_info->time;
return 0;
}
/**
@@ -1303,8 +1359,19 @@ EXPORT(int, sceKernelSetThreadContextForVM) {
return UNIMPLEMENTED();
}
EXPORT(int, sceKernelSetTimerEvent) {
return UNIMPLEMENTED();
EXPORT(int, sceKernelSetTimerEvent, SceUID timer_handle, int32_t type, SceKernelSysClock *clock, int32_t repeats) {
STUBBED("Type not implemented.");
const TimerPtr timer_info = lock_and_find(timer_handle, host.kernel.timers, host.kernel.mutex);
if (!timer_info)
return SCE_KERNEL_ERROR_UNKNOWN_TIMER_ID;
//TODO: Timer values for type.
timer_info->repeats = repeats;
return SCE_KERNEL_OK;
}
EXPORT(int, sceKernelSetTimerTime) {
+188 -15
View File
@@ -17,8 +17,152 @@
#include "SceVideodecUser.h"
EXPORT(int, sceAvcdecCreateDecoder) {
return UNIMPLEMENTED();
#include <psp2/videodec.h>
extern "C" {
#include <libavcodec/avcodec.h>
}
namespace emu {
struct SceAvcdecBuf {
Ptr<void> pBuf;
uint32_t size;
};
struct SceAvcdecCtrl {
uint32_t handle;
emu::SceAvcdecBuf frameBuf;
};
struct SceAvcdecAu {
SceVideodecTimeStamp pts;
SceVideodecTimeStamp dts;
emu::SceAvcdecBuf es;
};
struct SceAvcdecFrame {
uint32_t pixelType;
uint32_t framePitch;
uint32_t frameWidth;
uint32_t frameHeight;
uint32_t horizontalSize;
uint32_t verticalSize;
uint32_t frameCropLeftOffset;
uint32_t frameCropRightOffset;
uint32_t frameCropTopOffset;
uint32_t frameCropBottomOffset;
SceAvcdecFrameOption opt;
Ptr<void> pPicture[2];
};
struct SceAvcdecPicture {
uint32_t size;
SceAvcdecFrame frame;
SceAvcdecInfo info;
};
struct SceAvcdecArrayPicture {
uint32_t numOfOutput;
uint32_t numOfElm;
Ptr<Ptr<emu::SceAvcdecPicture>> pPicture;
};
}
inline uint32_t calculate_buffer_size(uint32_t width, uint32_t height, uint32_t frameRefs) {
return width * height * 3 / 2 * frameRefs;
}
void send_decoder_data(MemState &mem, DecoderPtr &decoder_info, const emu::SceAvcdecAu *au) {
int error = 0;
std::vector<uint8_t> au_frame(au->es.size + AV_INPUT_BUFFER_PADDING_SIZE);
memcpy(au_frame.data(), au->es.pBuf.get(mem), au->es.size);
uint64_t pts = static_cast<uint64_t>(au->pts.upper) << 32u | static_cast<uint64_t>(au->pts.lower);
uint64_t dts = static_cast<uint64_t>(au->dts.upper) << 32u | static_cast<uint64_t>(au->dts.lower);
if (pts == ~0ull)
pts = AV_NOPTS_VALUE;
if (dts == ~0ull)
dts = AV_NOPTS_VALUE;
AVPacket *packet = av_packet_alloc();
error = av_parser_parse2(
decoder_info->parser, // AVCodecParserContext *s,
decoder_info->context, // AVCodecContext *avctx,
&packet->data, // uint8_t **poutbuf,
&packet->size, // int *poutbuf_size,
au_frame.data(), // const uint8_t *buf,
au_frame.size(), // int buf_size,
pts, // int64_t pts,
dts, // int64_t dts,
0 // int64_t pos
);
assert(error >= 0);
error = avcodec_send_packet(decoder_info->context, packet);
assert(error == 0);
av_packet_free(&packet);
}
void receive_decoder_data(MemState &mem, DecoderPtr &decoder_info, emu::SceAvcdecArrayPicture *picture) {
AVFrame *frame = av_frame_alloc();
if (avcodec_receive_frame(decoder_info->context, frame) == 0) {
emu::SceAvcdecFrame *avc_frame = &picture->pPicture.get(mem)[0].get(mem)->frame;
auto *avc_data = reinterpret_cast<uint8_t *>(avc_frame->pPicture[0].get(mem));
for (uint32_t a = 0; a < frame->height; a++) {
memcpy(avc_data, &frame->data[0][frame->linesize[0] * a], frame->width);
avc_data += frame->width;
}
for (uint32_t a = 0; a < frame->height / 2; a++) {
memcpy(avc_data, &frame->data[1][frame->linesize[1] * a], frame->width / 2);
avc_data += frame->width / 2;
}
for (uint32_t a = 0; a < frame->height / 2; a++) {
memcpy(avc_data, &frame->data[2][frame->linesize[2] * a], frame->width / 2);
avc_data += frame->width / 2;
}
picture->numOfOutput++;
}
av_frame_free(&frame);
}
EXPORT(int, sceAvcdecCreateDecoder, uint32_t codec_type, emu::SceAvcdecCtrl *decoder, const SceAvcdecQueryDecoderInfo *query) {
assert(codec_type == SCE_VIDEODEC_TYPE_HW_AVCDEC);
SceUID handle = host.kernel.get_next_uid();
decoder->handle = handle;
host.kernel.decoders[handle] = std::make_shared<DecoderState>();
DecoderPtr &decoder_info = host.kernel.decoders[handle];
decoder_info->frame_width = query->horizontal;
decoder_info->frame_height = query->vertical;
decoder_info->frame_ref_count = query->numOfRefFrames;
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
assert(codec);
decoder_info->parser = av_parser_init(codec->id);
assert(decoder_info->parser);
decoder_info->frame_width = decoder_info->frame_width;
decoder_info->frame_height = decoder_info->frame_height;
decoder_info->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
decoder_info->context = avcodec_alloc_context3(codec);
assert(decoder_info->context);
decoder_info->context->width = query->horizontal;
decoder_info->context->height = query->vertical;
int result = avcodec_open2(decoder_info->context, codec, nullptr);
assert(result == 0);
return 0;
}
EXPORT(int, sceAvcdecCreateDecoderInternal) {
@@ -37,8 +181,14 @@ EXPORT(int, sceAvcdecCscInternal) {
return UNIMPLEMENTED();
}
EXPORT(int, sceAvcdecDecode) {
return UNIMPLEMENTED();
EXPORT(int, sceAvcdecDecode, emu::SceAvcdecCtrl *decoder, const emu::SceAvcdecAu *au, emu::SceAvcdecArrayPicture *picture) {
DecoderPtr &decoder_info = host.kernel.decoders[decoder->handle];
// TODO: decoding can be done async I think
send_decoder_data(host.mem, decoder_info, au);
receive_decoder_data(host.mem, decoder_info, picture);
return 0;
}
EXPORT(int, sceAvcdecDecodeAuInternal) {
@@ -57,12 +207,19 @@ EXPORT(int, sceAvcdecDecodeAuNongameapp) {
return UNIMPLEMENTED();
}
EXPORT(int, sceAvcdecDecodeAvailableSize) {
return UNIMPLEMENTED();
EXPORT(int, sceAvcdecDecodeAvailableSize, emu::SceAvcdecCtrl *decoder) {
DecoderPtr &decoder_info = host.kernel.decoders[decoder->handle];
return calculate_buffer_size(
decoder_info->frame_width, decoder_info->frame_height, decoder_info->frame_ref_count);
}
EXPORT(int, sceAvcdecDecodeFlush) {
return UNIMPLEMENTED();
EXPORT(int, sceAvcdecDecodeFlush, emu::SceAvcdecCtrl *decoder) {
auto &decoder_info = host.kernel.decoders[decoder->handle];
avcodec_flush_buffers(decoder_info->context);
return 0;
}
EXPORT(int, sceAvcdecDecodeGetPictureInternal) {
@@ -93,8 +250,12 @@ EXPORT(int, sceAvcdecDecodeSetUserDataSei1FieldMemSizeNongameapp) {
return UNIMPLEMENTED();
}
EXPORT(int, sceAvcdecDecodeStop) {
return UNIMPLEMENTED();
EXPORT(int, sceAvcdecDecodeStop, emu::SceAvcdecCtrl *decoder, emu::SceAvcdecArrayPicture *picture) {
auto &decoder_info = host.kernel.decoders[decoder->handle];
receive_decoder_data(host.mem, decoder_info, picture);
return 0;
}
EXPORT(int, sceAvcdecDecodeStopWithWorkPicture) {
@@ -105,8 +266,15 @@ EXPORT(int, sceAvcdecDecodeWithWorkPicture) {
return UNIMPLEMENTED();
}
EXPORT(int, sceAvcdecDeleteDecoder) {
return UNIMPLEMENTED();
EXPORT(int, sceAvcdecDeleteDecoder, emu::SceAvcdecCtrl *decoder) {
auto &decoder_info = host.kernel.decoders[decoder->handle];
avcodec_close(decoder_info->context);
av_parser_close(decoder_info->parser);
host.kernel.decoders.erase(decoder->handle);
return 0;
}
EXPORT(int, sceAvcdecGetSeiPictureTimingInternal) {
@@ -117,8 +285,13 @@ EXPORT(int, sceAvcdecGetSeiUserDataNongameapp) {
return UNIMPLEMENTED();
}
EXPORT(int, sceAvcdecQueryDecoderMemSize) {
return UNIMPLEMENTED();
EXPORT(int, sceAvcdecQueryDecoderMemSize, uint32_t codec_type, const SceAvcdecQueryDecoderInfo *query_info, SceAvcdecDecoderInfo *decoder_info) {
assert(codec_type == SCE_VIDEODEC_TYPE_HW_AVCDEC);
decoder_info->frameMemSize =
calculate_buffer_size(query_info->horizontal, query_info->vertical, query_info->numOfRefFrames);
return 0;
}
EXPORT(int, sceAvcdecQueryDecoderMemSizeInternal) {
@@ -222,7 +395,7 @@ EXPORT(int, sceM4vdecQueryDecoderMemSizeInternal) {
}
EXPORT(int, sceVideodecInitLibrary) {
return UNIMPLEMENTED();
return STUBBED("EMPTY");
}
EXPORT(int, sceVideodecInitLibraryInternal) {
+1
View File
@@ -49,6 +49,7 @@ add_library(
src/texture_cache.cpp
src/texture_format.cpp
src/texture_palette.cpp
src/texture_yuv.cpp
src/uniforms.cpp
)
@@ -143,6 +143,7 @@ namespace texture {
// Paletted textures.
void palette_texture_to_rgba_4(uint32_t *dst, const uint8_t *src, size_t width, size_t height, const uint32_t *palette);
void palette_texture_to_rgba_8(uint32_t *dst, const uint8_t *src, size_t width, size_t height, const uint32_t *palette);
void yuv420_texture_to_rgb(uint8_t *dst, const uint8_t *src, size_t width, size_t height);
const uint32_t *get_texture_palette(const emu::SceGxmTexture &texture, const MemState &mem);
/**
+36 -2
View File
@@ -120,6 +120,7 @@ void upload_bound_texture(const emu::SceGxmTexture &gxm_texture, const MemState
std::vector<uint8_t> texture_data_decompressed;
std::vector<uint8_t> texture_pixels_lineared; // TODO Move to context to avoid frequent allocation?
std::vector<uint32_t> palette_texture_pixels;
std::vector<uint8_t> yuv_texture_pixels;
const void *pixels = nullptr;
@@ -182,16 +183,49 @@ void upload_bound_texture(const emu::SceGxmTexture &gxm_texture, const MemState
const uint32_t *const palette_bytes = renderer::texture::get_texture_palette(gxm_texture, mem);
palette_texture_pixels.resize(width * height * 4);
if (base_format == SCE_GXM_TEXTURE_BASE_FORMAT_P8) {
renderer::texture::palette_texture_to_rgba_8(reinterpret_cast<uint32_t *>(palette_texture_pixels.data()),
renderer::texture::palette_texture_to_rgba_8(palette_texture_pixels.data(),
reinterpret_cast<const uint8_t *>(pixels), width, height, palette_bytes);
} else {
renderer::texture::palette_texture_to_rgba_4(reinterpret_cast<uint32_t *>(palette_texture_pixels.data()),
renderer::texture::palette_texture_to_rgba_4(palette_texture_pixels.data(),
reinterpret_cast<const uint8_t *>(pixels), width, height, palette_bytes);
}
pixels = palette_texture_pixels.data();
stride = width;
}
if (gxm::is_yuv_format(fmt)) {
switch (fmt) {
case SCE_GXM_TEXTURE_FORMAT_YUV420P2_CSC0:
case SCE_GXM_TEXTURE_FORMAT_YVU420P2_CSC0:
case SCE_GXM_TEXTURE_FORMAT_YUV420P2_CSC1:
case SCE_GXM_TEXTURE_FORMAT_YVU420P2_CSC1: {
yuv_texture_pixels.resize(width * height * 3);
renderer::texture::yuv420_texture_to_rgb(yuv_texture_pixels.data(),
reinterpret_cast<const uint8_t *>(pixels), width, height);
pixels = yuv_texture_pixels.data();
stride = width;
break;
}
case SCE_GXM_TEXTURE_FORMAT_YUV420P3_CSC0:
case SCE_GXM_TEXTURE_FORMAT_YVU420P3_CSC0:
case SCE_GXM_TEXTURE_FORMAT_YUV420P3_CSC1:
case SCE_GXM_TEXTURE_FORMAT_YVU420P3_CSC1:
case SCE_GXM_TEXTURE_FORMAT_YUYV422_CSC0:
case SCE_GXM_TEXTURE_FORMAT_YVYU422_CSC0:
case SCE_GXM_TEXTURE_FORMAT_UYVY422_CSC0:
case SCE_GXM_TEXTURE_FORMAT_VYUY422_CSC0:
case SCE_GXM_TEXTURE_FORMAT_YUYV422_CSC1:
case SCE_GXM_TEXTURE_FORMAT_YVYU422_CSC1:
case SCE_GXM_TEXTURE_FORMAT_UYVY422_CSC1:
case SCE_GXM_TEXTURE_FORMAT_VYUY422_CSC1:
assert(false);
default:
assert(false);
}
}
const GLenum format = translate_format(fmt);
const GLenum type = translate_type(fmt);
+9 -7
View File
@@ -312,14 +312,16 @@ GLenum translate_format(SceGxmTextureFormat src) {
case SCE_GXM_TEXTURE_BASE_FORMAT_PVRT4BPP:
case SCE_GXM_TEXTURE_BASE_FORMAT_PVRTII2BPP:
case SCE_GXM_TEXTURE_BASE_FORMAT_PVRTII4BPP:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV422:
case SCE_GXM_TEXTURE_BASE_FORMAT_P4:
case SCE_GXM_TEXTURE_BASE_FORMAT_P8:
case SCE_GXM_TEXTURE_BASE_FORMAT_U2F10F10F10:
return GL_RGBA;
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV422:
return GL_RGB;
case SCE_GXM_TEXTURE_BASE_FORMAT_UBC1:
return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
@@ -422,11 +424,11 @@ GLenum translate_type(SceGxmTextureFormat format) {
case SCE_GXM_TEXTURE_BASE_FORMAT_UBC3:
return GL_UNSIGNED_BYTE;
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2:
LOG_WARN("Unhandled base format SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2");
return GL_BYTE;
// LOG_WARN("Unhandled base format SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2");
return GL_UNSIGNED_BYTE;
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3:
LOG_WARN("Unhandled base format SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3");
return GL_BYTE;
// LOG_WARN("Unhandled base format SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3");
return GL_UNSIGNED_BYTE;
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV422:
LOG_WARN("Unhandled base format SCE_GXM_TEXTURE_BASE_FORMAT_YUV422");
return GL_BYTE;
+2 -1
View File
@@ -75,8 +75,9 @@ size_t bits_per_pixel(SceGxmTextureBaseFormat base_format) {
return 8;
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3:
return 12;
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV422:
return 16; // NOTE: I'm not sure this is right.
return 16;
case SCE_GXM_TEXTURE_BASE_FORMAT_P4:
return 4;
case SCE_GXM_TEXTURE_BASE_FORMAT_P8:
+72
View File
@@ -0,0 +1,72 @@
#include <renderer/functions.h>
#include <util/log.h>
#include <vector>
#include <algorithm>
namespace renderer {
namespace texture {
struct Color {
uint8_t x = 0;
uint8_t y = 0;
uint8_t z = 0;
};
static Color yuv_color_to_rgb(Color yuv) {
double y = (double)yuv.x / 255.0f;
double u = (double)yuv.y / 255.0f;
double v = (double)yuv.z / 255.0f;
y = 1.1643 * (y - 0.0625);
u = u - 0.5;
v = v - 0.5;
double r = std::min(std::max(y + 1.5958 * v, 0.0), 1.0);
double g = std::min(std::max(y - 0.39173 * u - 0.8129 * v, 0.0), 1.0);
double b = std::min(std::max(y + 2.017 * u, 0.0), 1.0);
Color result;
result.x = r * 255;
result.y = g * 255;
result.z = b * 255;
return result;
}
void yuv420_texture_to_rgb(uint8_t *dst, const uint8_t *src, size_t width, size_t height) {
auto *dst_colors = reinterpret_cast<Color *>(dst);
std::vector<Color> yuvLayout(width * height);
auto *yData = (uint8_t *)&src[0];
auto *uData = (uint8_t *)&src[width * height];
auto *vData = (uint8_t *)&src[width * height + width * height / 4];
for (size_t y = 0; y < height; y++) {
for (size_t x = 0; x < width; x++) {
yuvLayout[x + y * width].x = yData[x + y * width];
}
}
for (size_t y = 0; y < height / 2; y++) {
for (size_t x = 0; x < width / 2; x++) {
uint8_t u = uData[x + y * width / 2];
uint8_t v = vData[x + y * width / 2];
yuvLayout[(x * 2) + (y * 2 * width)].y = u;
yuvLayout[(x * 2) + (y * 2 * width)].z = v;
yuvLayout[(x * 2 + 1) + (y * 2 * width)].y = u;
yuvLayout[(x * 2 + 1) + (y * 2 * width)].z = v;
yuvLayout[(x * 2) + ((y * 2 + 1) * width)].y = u;
yuvLayout[(x * 2) + ((y * 2 + 1) * width)].z = v;
yuvLayout[(x * 2 + 1) + ((y * 2 + 1) * width)].y = u;
yuvLayout[(x * 2 + 1) + ((y * 2 + 1) * width)].z = v;
}
}
for (size_t a = 0; a < yuvLayout.size(); a++) {
dst_colors[a] = yuv_color_to_rgb(yuvLayout[a]);
}
}
}
}
+1 -1
View File
@@ -1012,7 +1012,7 @@ bool USSETranslatorVisitor::sop2(
return true;
}
static auto apply_opcode = [&](Opcode op, spv::Id type, spv::Id lhs, spv::Id rhs) {
auto apply_opcode = [&](Opcode op, spv::Id type, spv::Id lhs, spv::Id rhs) {
switch (op) {
case Opcode::FADD: {
return m_b.createBinOp(spv::OpFAdd, type, lhs, rhs);