mirror of
https://github.com/Vita3K/Vita3K.git
synced 2026-07-11 01:34:23 +02:00
modules: implement avcdec and yuv format
This commit is contained in:
committed by
1whatleytay
parent
c2a014f1f2
commit
6463b34cc1
@@ -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
|
||||
|
||||
Vendored
+2
@@ -217,3 +217,5 @@ if (USE_VULKAN)
|
||||
add_library(vma INTERFACE)
|
||||
target_include_directories(vma INTERFACE VulkanMemoryAllocator/src)
|
||||
endif()
|
||||
|
||||
add_subdirectory(ffmpeg)
|
||||
|
||||
+1
Submodule external/ffmpeg added at e5fb13bbb0
Vendored
+1
-1
Submodule external/printf updated: b0585c7f8d...99f2ec5426
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user