Compare commits
23 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e673a2e5c7 | ||
|
|
720970c4c1 | ||
|
|
30442d8a89 | ||
|
|
7f256392a1 | ||
|
|
0eacc362dd | ||
|
|
c50f170597 | ||
|
|
1994edfeb6 | ||
|
|
d35391b9f4 | ||
|
|
b39b33b1fe | ||
|
|
852858c2cb | ||
|
|
50acc0da20 | ||
|
|
bdabd17c76 | ||
|
|
3af2117c88 | ||
|
|
84934693cf | ||
|
|
1af499c15b | ||
|
|
ced1302975 | ||
|
|
70d51f72ec | ||
|
|
f2a4204245 | ||
|
|
d6b5f64484 | ||
|
|
49f9a44235 | ||
|
|
36c21ff6cb | ||
|
|
92bebecf46 | ||
|
|
b04c7b6343 |
@@ -1,7 +1,7 @@
|
||||
# Download all pull requests as patches that match a specific label
|
||||
# Usage: python download-patches-by-label.py <Label to Match> <Root Path Folder to DL to>
|
||||
|
||||
import requests, sys, json, urllib3.request, shutil, subprocess, os
|
||||
import requests, sys, json, urllib3.request, shutil, subprocess, os, traceback
|
||||
|
||||
tagline = sys.argv[2]
|
||||
|
||||
@@ -33,4 +33,5 @@ try:
|
||||
for i in range(1,30):
|
||||
do_page(i)
|
||||
except:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
sys.exit(-1)
|
||||
|
||||
@@ -600,6 +600,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
${LIBVA_LIBRARIES})
|
||||
set(FFmpeg_HWACCEL_FLAGS
|
||||
--enable-hwaccel=h264_vaapi
|
||||
--enable-hwaccel=vp8_vaapi
|
||||
--enable-hwaccel=vp9_vaapi
|
||||
--enable-libdrm)
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
@@ -620,6 +621,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
--enable-ffnvcodec
|
||||
--enable-nvdec
|
||||
--enable-hwaccel=h264_nvdec
|
||||
--enable-hwaccel=vp8_nvdec
|
||||
--enable-hwaccel=vp9_nvdec
|
||||
--extra-cflags=-I${CUDA_INCLUDE_DIRS}
|
||||
)
|
||||
@@ -670,6 +672,7 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
--disable-postproc
|
||||
--disable-swresample
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp8
|
||||
--enable-decoder=vp9
|
||||
--cc="${CMAKE_C_COMPILER}"
|
||||
--cxx="${CMAKE_CXX_COMPILER}"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <exception>
|
||||
#include <stop_token>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
@@ -186,6 +187,10 @@ public:
|
||||
initialization_in_progress_suppress_logging = false;
|
||||
}
|
||||
|
||||
static void Start() {
|
||||
instance->StartBackendThread();
|
||||
}
|
||||
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
@@ -201,7 +206,7 @@ public:
|
||||
}
|
||||
|
||||
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
|
||||
const char* function, std::string message) {
|
||||
const char* function, std::string&& message) {
|
||||
if (!filter.CheckMessage(log_class, log_level))
|
||||
return;
|
||||
const Entry& entry =
|
||||
@@ -211,40 +216,41 @@ public:
|
||||
|
||||
private:
|
||||
Impl(const std::filesystem::path& file_backend_filename, const Filter& filter_)
|
||||
: filter{filter_}, file_backend{file_backend_filename}, backend_thread{std::thread([this] {
|
||||
Common::SetCurrentThreadName("yuzu:Log");
|
||||
Entry entry;
|
||||
const auto write_logs = [this, &entry]() {
|
||||
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
|
||||
};
|
||||
while (true) {
|
||||
entry = message_queue.PopWait();
|
||||
if (entry.final_entry) {
|
||||
break;
|
||||
}
|
||||
write_logs();
|
||||
}
|
||||
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
|
||||
// case where a system is repeatedly spamming logs even on close.
|
||||
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
|
||||
while (max_logs_to_write-- && message_queue.Pop(entry)) {
|
||||
write_logs();
|
||||
}
|
||||
})} {}
|
||||
: filter{filter_}, file_backend{file_backend_filename} {}
|
||||
|
||||
~Impl() {
|
||||
StopBackendThread();
|
||||
}
|
||||
|
||||
void StartBackendThread() {
|
||||
backend_thread = std::thread([this] {
|
||||
Common::SetCurrentThreadName("yuzu:Log");
|
||||
Entry entry;
|
||||
const auto write_logs = [this, &entry]() {
|
||||
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
|
||||
};
|
||||
while (!stop.stop_requested()) {
|
||||
entry = message_queue.PopWait(stop.get_token());
|
||||
if (entry.filename != nullptr) {
|
||||
write_logs();
|
||||
}
|
||||
}
|
||||
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
|
||||
// case where a system is repeatedly spamming logs even on close.
|
||||
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
|
||||
while (max_logs_to_write-- && message_queue.Pop(entry)) {
|
||||
write_logs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void StopBackendThread() {
|
||||
Entry stop_entry{};
|
||||
stop_entry.final_entry = true;
|
||||
message_queue.Push(stop_entry);
|
||||
stop.request_stop();
|
||||
backend_thread.join();
|
||||
}
|
||||
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, std::string message) const {
|
||||
const char* function, std::string&& message) const {
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::microseconds;
|
||||
using std::chrono::steady_clock;
|
||||
@@ -257,7 +263,6 @@ private:
|
||||
.line_num = line_nr,
|
||||
.function = function,
|
||||
.message = std::move(message),
|
||||
.final_entry = false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -278,8 +283,9 @@ private:
|
||||
ColorConsoleBackend color_console_backend{};
|
||||
FileBackend file_backend;
|
||||
|
||||
std::stop_source stop;
|
||||
std::thread backend_thread;
|
||||
MPSCQueue<Entry> message_queue{};
|
||||
MPSCQueue<Entry, true> message_queue{};
|
||||
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
|
||||
};
|
||||
} // namespace
|
||||
@@ -288,6 +294,10 @@ void Initialize() {
|
||||
Impl::Initialize();
|
||||
}
|
||||
|
||||
void Start() {
|
||||
Impl::Start();
|
||||
}
|
||||
|
||||
void DisableLoggingInTests() {
|
||||
initialization_in_progress_suppress_logging = true;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ class Filter;
|
||||
/// Initializes the logging system. This should be the first thing called in main.
|
||||
void Initialize();
|
||||
|
||||
void Start();
|
||||
|
||||
void DisableLoggingInTests();
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,6 @@ struct Entry {
|
||||
unsigned int line_num = 0;
|
||||
std::string function;
|
||||
std::string message;
|
||||
bool final_entry = false;
|
||||
};
|
||||
|
||||
} // namespace Common::Log
|
||||
|
||||
@@ -58,7 +58,8 @@ u64 NativeClock::GetRTSC() {
|
||||
TimePoint new_time_point{};
|
||||
TimePoint current_time_point{};
|
||||
do {
|
||||
current_time_point.pack = time_point.pack;
|
||||
std::ignore = Common::AtomicCompareAndSwap(current_time_point.pack.data(), time_point.pack,
|
||||
u128{0}); // comparison value doesn't matter
|
||||
_mm_mfence();
|
||||
const u64 current_measure = __rdtsc();
|
||||
u64 diff = current_measure - current_time_point.inner.last_measure;
|
||||
@@ -78,7 +79,9 @@ void NativeClock::Pause(bool is_paused) {
|
||||
TimePoint current_time_point{};
|
||||
TimePoint new_time_point{};
|
||||
do {
|
||||
current_time_point.pack = time_point.pack;
|
||||
std::ignore =
|
||||
Common::AtomicCompareAndSwap(current_time_point.pack.data(), time_point.pack,
|
||||
u128{0}); // comparison value doesn't matter
|
||||
new_time_point.pack = current_time_point.pack;
|
||||
_mm_mfence();
|
||||
new_time_point.inner.last_measure = __rdtsc();
|
||||
|
||||
@@ -53,13 +53,16 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
}
|
||||
|
||||
/*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
|
||||
// Allow use of cores 0~3 and thread priorities 1~63.
|
||||
constexpr u32 default_thread_info_capability = 0x30007F7;
|
||||
|
||||
ProgramMetadata result;
|
||||
|
||||
result.LoadManual(
|
||||
true /*is_64_bit*/, FileSys::ProgramAddressSpaceType::Is39Bit /*address_space*/,
|
||||
0x2c /*main_thread_prio*/, 0 /*main_thread_core*/, 0x00100000 /*main_thread_stack_size*/,
|
||||
0 /*title_id*/, 0xFFFFFFFFFFFFFFFF /*filesystem_permissions*/,
|
||||
0x1FE00000 /*system_resource_size*/, {} /*capabilities*/);
|
||||
0x1FE00000 /*system_resource_size*/, {default_thread_info_capability} /*capabilities*/);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) {
|
||||
if (is_inline) {
|
||||
@@ -128,7 +129,7 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
|
||||
}
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
|
||||
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
|
||||
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true);
|
||||
}
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
|
||||
virtual void InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) = 0;
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
|
||||
void InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) override;
|
||||
@@ -106,7 +106,7 @@ private:
|
||||
|
||||
KeyboardInitializeParameters parameters;
|
||||
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback;
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
@@ -19,7 +20,7 @@ public:
|
||||
explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
|
||||
|
||||
bool IsLockedByCurrentThread() const {
|
||||
return owner_thread == GetCurrentThreadPointer(kernel);
|
||||
return owner_thread.load(std::memory_order::consume) == GetCurrentThreadPointer(kernel);
|
||||
}
|
||||
|
||||
void Lock() {
|
||||
@@ -38,7 +39,7 @@ public:
|
||||
|
||||
// Increment count, take ownership.
|
||||
lock_count = 1;
|
||||
owner_thread = GetCurrentThreadPointer(kernel);
|
||||
owner_thread.store(GetCurrentThreadPointer(kernel), std::memory_order::release);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +54,7 @@ public:
|
||||
SchedulerType::UpdateHighestPriorityThreads(kernel);
|
||||
|
||||
// Note that we no longer hold the lock, and unlock the spinlock.
|
||||
owner_thread = nullptr;
|
||||
owner_thread.store(nullptr, std::memory_order::release);
|
||||
spin_lock.Unlock();
|
||||
|
||||
// Enable scheduling, and perform a rescheduling operation.
|
||||
@@ -65,7 +66,7 @@ private:
|
||||
KernelCore& kernel;
|
||||
KAlignedSpinLock spin_lock{};
|
||||
s32 lock_count{};
|
||||
KThread* owner_thread{};
|
||||
std::atomic<KThread*> owner_thread{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -109,13 +109,18 @@ void SoftwareKeyboard::Execute() {
|
||||
ShowNormalKeyboard();
|
||||
}
|
||||
|
||||
void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text) {
|
||||
void SoftwareKeyboard::SubmitTextNormal(SwkbdResult result, std::u16string submitted_text,
|
||||
bool confirmed) {
|
||||
if (complete) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (swkbd_config_common.use_text_check && result == SwkbdResult::Ok) {
|
||||
SubmitForTextCheck(submitted_text);
|
||||
if (confirmed) {
|
||||
SubmitNormalOutputAndExit(result, submitted_text);
|
||||
} else {
|
||||
SubmitForTextCheck(submitted_text);
|
||||
}
|
||||
} else {
|
||||
SubmitNormalOutputAndExit(result, submitted_text);
|
||||
}
|
||||
@@ -273,13 +278,21 @@ void SoftwareKeyboard::ProcessTextCheck() {
|
||||
|
||||
std::memcpy(&swkbd_text_check, text_check_data.data(), sizeof(SwkbdTextCheck));
|
||||
|
||||
std::u16string text_check_message =
|
||||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
|
||||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm
|
||||
? Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_text_check.text_check_message.data(),
|
||||
swkbd_text_check.text_check_message.size())
|
||||
: u"";
|
||||
std::u16string text_check_message = [this, &swkbd_text_check]() -> std::u16string {
|
||||
if (swkbd_text_check.text_check_result == SwkbdTextCheckResult::Failure ||
|
||||
swkbd_text_check.text_check_result == SwkbdTextCheckResult::Confirm) {
|
||||
return swkbd_config_common.use_utf8
|
||||
? Common::UTF8ToUTF16(Common::StringFromFixedZeroTerminatedBuffer(
|
||||
reinterpret_cast<const char*>(
|
||||
swkbd_text_check.text_check_message.data()),
|
||||
swkbd_text_check.text_check_message.size() * sizeof(char16_t)))
|
||||
: Common::UTF16StringFromFixedZeroTerminatedBuffer(
|
||||
swkbd_text_check.text_check_message.data(),
|
||||
swkbd_text_check.text_check_message.size());
|
||||
} else {
|
||||
return u"";
|
||||
}
|
||||
}();
|
||||
|
||||
LOG_INFO(Service_AM, "\nTextCheckResult: {}\nTextCheckMessage: {}",
|
||||
GetTextCheckResultName(swkbd_text_check.text_check_result),
|
||||
@@ -583,11 +596,12 @@ void SoftwareKeyboard::InitializeFrontendKeyboard() {
|
||||
.disable_cancel_button{disable_cancel_button},
|
||||
};
|
||||
|
||||
frontend.InitializeKeyboard(false, std::move(initialize_parameters),
|
||||
[this](SwkbdResult result, std::u16string submitted_text) {
|
||||
SubmitTextNormal(result, submitted_text);
|
||||
},
|
||||
{});
|
||||
frontend.InitializeKeyboard(
|
||||
false, std::move(initialize_parameters),
|
||||
[this](SwkbdResult result, std::u16string submitted_text, bool confirmed) {
|
||||
SubmitTextNormal(result, submitted_text, confirmed);
|
||||
},
|
||||
{});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,9 @@ public:
|
||||
*
|
||||
* @param result SwkbdResult enum
|
||||
* @param submitted_text UTF-16 encoded string
|
||||
* @param confirmed Whether the text has been confirmed after TextCheckResult::Confirm
|
||||
*/
|
||||
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
|
||||
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text, bool confirmed);
|
||||
|
||||
/**
|
||||
* Submits the input text to the application.
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
|
||||
{1015, nullptr, "ConfirmPlayableApplicationVideo"},
|
||||
{1016, nullptr, "ConfirmShowNewsPermission"},
|
||||
{1017, nullptr, "EndFreeCommunication"},
|
||||
{1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
|
||||
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
|
||||
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
|
||||
{1032, nullptr, "GetSafetyLevel"},
|
||||
@@ -236,6 +236,13 @@ private:
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void EndFreeCommunication(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -430,15 +430,33 @@ Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t FindNextUnusedLocation(const std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t start_offset) {
|
||||
size_t FindAndSetNextUnusedLocation(std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t& start_offset) {
|
||||
for (size_t location = start_offset; location < used_locations.size(); ++location) {
|
||||
if (!used_locations.test(location)) {
|
||||
start_offset = location;
|
||||
used_locations.set(location);
|
||||
return location;
|
||||
}
|
||||
}
|
||||
throw RuntimeError("Unable to get an unused location for legacy attribute");
|
||||
}
|
||||
|
||||
Id DefineLegacyInput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t& start_offset) {
|
||||
const Id id{DefineInput(ctx, ctx.F32[4], true)};
|
||||
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
|
||||
ctx.Decorate(id, spv::Decoration::Location, location);
|
||||
return id;
|
||||
}
|
||||
|
||||
Id DefineLegacyOutput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t& start_offset, std::optional<u32> invocations) {
|
||||
const Id id{DefineOutput(ctx, ctx.F32[4], invocations)};
|
||||
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
|
||||
ctx.Decorate(id, spv::Decoration::Location, location);
|
||||
return id;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
|
||||
@@ -520,6 +538,64 @@ Id EmitContext::BitOffset16(const IR::Value& offset) {
|
||||
return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u));
|
||||
}
|
||||
|
||||
Id EmitContext::InputLegacyAttribute(IR::Attribute attribute) {
|
||||
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorFrontDiffuseA) {
|
||||
return input_front_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
|
||||
attribute <= IR::Attribute::ColorFrontSpecularA) {
|
||||
return input_front_secondary_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackDiffuseA) {
|
||||
return input_back_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackSpecularR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) {
|
||||
return input_back_secondary_color;
|
||||
}
|
||||
if (attribute == IR::Attribute::FogCoordinate) {
|
||||
return input_fog_frag_coord;
|
||||
}
|
||||
if (attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q) {
|
||||
u32 index =
|
||||
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
|
||||
return input_fixed_fnc_textures[index];
|
||||
}
|
||||
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
|
||||
}
|
||||
|
||||
Id EmitContext::OutputLegacyAttribute(IR::Attribute attribute) {
|
||||
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorFrontDiffuseA) {
|
||||
return output_front_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
|
||||
attribute <= IR::Attribute::ColorFrontSpecularA) {
|
||||
return output_front_secondary_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackDiffuseA) {
|
||||
return output_back_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackSpecularR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) {
|
||||
return output_back_secondary_color;
|
||||
}
|
||||
if (attribute == IR::Attribute::FogCoordinate) {
|
||||
return output_fog_frag_coord;
|
||||
}
|
||||
if (attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q) {
|
||||
u32 index =
|
||||
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
|
||||
return output_fixed_fnc_textures[index];
|
||||
}
|
||||
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
|
||||
}
|
||||
|
||||
void EmitContext::DefineCommonTypes(const Info& info) {
|
||||
void_id = TypeVoid();
|
||||
|
||||
@@ -1279,22 +1355,26 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
}
|
||||
size_t previous_unused_location = 0;
|
||||
if (loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
|
||||
const size_t location = FindNextUnusedLocation(used_locations, previous_unused_location);
|
||||
previous_unused_location = location;
|
||||
used_locations.set(location);
|
||||
const Id id{DefineInput(*this, F32[4], true)};
|
||||
Decorate(id, spv::Decoration::Location, location);
|
||||
input_front_color = id;
|
||||
input_front_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
|
||||
input_front_secondary_color =
|
||||
DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
|
||||
input_back_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
|
||||
input_back_secondary_color =
|
||||
DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::FogCoordinate)) {
|
||||
input_fog_frag_coord = DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
|
||||
if (loads.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
|
||||
const size_t location =
|
||||
FindNextUnusedLocation(used_locations, previous_unused_location);
|
||||
previous_unused_location = location;
|
||||
used_locations.set(location);
|
||||
const Id id{DefineInput(*this, F32[4], true)};
|
||||
Decorate(id, spv::Decoration::Location, location);
|
||||
input_fixed_fnc_textures[index] = id;
|
||||
input_fixed_fnc_textures[index] =
|
||||
DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
}
|
||||
if (stage == Stage::TessellationEval) {
|
||||
@@ -1356,22 +1436,29 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
|
||||
}
|
||||
size_t previous_unused_location = 0;
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
|
||||
const size_t location = FindNextUnusedLocation(used_locations, previous_unused_location);
|
||||
previous_unused_location = location;
|
||||
used_locations.set(location);
|
||||
const Id id{DefineOutput(*this, F32[4], invocations)};
|
||||
Decorate(id, spv::Decoration::Location, static_cast<u32>(location));
|
||||
output_front_color = id;
|
||||
output_front_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
|
||||
output_front_secondary_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
|
||||
output_back_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
|
||||
output_back_secondary_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::FogCoordinate)) {
|
||||
output_fog_frag_coord =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
|
||||
if (info.stores.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
|
||||
const size_t location =
|
||||
FindNextUnusedLocation(used_locations, previous_unused_location);
|
||||
previous_unused_location = location;
|
||||
used_locations.set(location);
|
||||
const Id id{DefineOutput(*this, F32[4], invocations)};
|
||||
Decorate(id, spv::Decoration::Location, location);
|
||||
output_fixed_fnc_textures[index] = id;
|
||||
output_fixed_fnc_textures[index] =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
}
|
||||
switch (stage) {
|
||||
|
||||
@@ -113,6 +113,9 @@ public:
|
||||
[[nodiscard]] Id BitOffset8(const IR::Value& offset);
|
||||
[[nodiscard]] Id BitOffset16(const IR::Value& offset);
|
||||
|
||||
Id InputLegacyAttribute(IR::Attribute attribute);
|
||||
Id OutputLegacyAttribute(IR::Attribute attribute);
|
||||
|
||||
Id Const(u32 value) {
|
||||
return Constant(U32[1], value);
|
||||
}
|
||||
@@ -269,12 +272,20 @@ public:
|
||||
|
||||
Id input_position{};
|
||||
Id input_front_color{};
|
||||
Id input_front_secondary_color{};
|
||||
Id input_back_color{};
|
||||
Id input_back_secondary_color{};
|
||||
Id input_fog_frag_coord{};
|
||||
std::array<Id, 10> input_fixed_fnc_textures{};
|
||||
std::array<Id, 32> input_generics{};
|
||||
|
||||
Id output_point_size{};
|
||||
Id output_position{};
|
||||
Id output_front_color{};
|
||||
Id output_front_secondary_color{};
|
||||
Id output_back_color{};
|
||||
Id output_back_secondary_color{};
|
||||
Id output_fog_frag_coord{};
|
||||
std::array<Id, 10> output_fixed_fnc_textures{};
|
||||
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
|
||||
|
||||
|
||||
@@ -43,23 +43,12 @@ Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&...
|
||||
}
|
||||
}
|
||||
|
||||
bool IsFixedFncTexture(IR::Attribute attribute) {
|
||||
return attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q;
|
||||
}
|
||||
|
||||
u32 FixedFncTextureAttributeIndex(IR::Attribute attribute) {
|
||||
if (!IsFixedFncTexture(attribute)) {
|
||||
throw InvalidArgument("Attribute {} is not a FixedFncTexture", attribute);
|
||||
}
|
||||
return (static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4u;
|
||||
}
|
||||
|
||||
u32 FixedFncTextureAttributeElement(IR::Attribute attribute) {
|
||||
if (!IsFixedFncTexture(attribute)) {
|
||||
throw InvalidArgument("Attribute {} is not a FixedFncTexture", attribute);
|
||||
}
|
||||
return static_cast<u32>(attribute) % 4u;
|
||||
bool IsLegacyAttribute(IR::Attribute attribute) {
|
||||
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) ||
|
||||
attribute == IR::Attribute::FogCoordinate ||
|
||||
(attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -93,12 +82,16 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||
return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id);
|
||||
}
|
||||
}
|
||||
if (IsFixedFncTexture(attr)) {
|
||||
const u32 index{FixedFncTextureAttributeIndex(attr)};
|
||||
const u32 element{FixedFncTextureAttributeElement(attr)};
|
||||
const Id element_id{ctx.Const(element)};
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.output_fixed_fnc_textures[index],
|
||||
element_id);
|
||||
if (IsLegacyAttribute(attr)) {
|
||||
if (attr == IR::Attribute::FogCoordinate) {
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
|
||||
ctx.Const(0u));
|
||||
} else {
|
||||
const u32 element{static_cast<u32>(attr) % 4};
|
||||
const Id element_id{ctx.Const(element)};
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
|
||||
element_id);
|
||||
}
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PointSize:
|
||||
@@ -111,14 +104,6 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||
const Id element_id{ctx.Const(element)};
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.output_position, element_id);
|
||||
}
|
||||
case IR::Attribute::ColorFrontDiffuseR:
|
||||
case IR::Attribute::ColorFrontDiffuseG:
|
||||
case IR::Attribute::ColorFrontDiffuseB:
|
||||
case IR::Attribute::ColorFrontDiffuseA: {
|
||||
const u32 element{static_cast<u32>(attr) % 4};
|
||||
const Id element_id{ctx.Const(element)};
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.output_front_color, element_id);
|
||||
}
|
||||
case IR::Attribute::ClipDistance0:
|
||||
case IR::Attribute::ClipDistance1:
|
||||
case IR::Attribute::ClipDistance2:
|
||||
@@ -341,11 +326,17 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
|
||||
const Id value{ctx.OpLoad(type->id, pointer)};
|
||||
return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
|
||||
}
|
||||
if (IsFixedFncTexture(attr)) {
|
||||
const u32 index{FixedFncTextureAttributeIndex(attr)};
|
||||
const Id attr_id{ctx.input_fixed_fnc_textures[index]};
|
||||
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex, attr_id, ctx.Const(element))};
|
||||
return ctx.OpLoad(ctx.F32[1], attr_ptr);
|
||||
if (IsLegacyAttribute(attr)) {
|
||||
if (attr == IR::Attribute::FogCoordinate) {
|
||||
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
|
||||
ctx.InputLegacyAttribute(attr), ctx.Const(0u))};
|
||||
return ctx.OpLoad(ctx.F32[1], attr_ptr);
|
||||
} else {
|
||||
const Id element_id{ctx.Const(element)};
|
||||
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
|
||||
ctx.InputLegacyAttribute(attr), element_id)};
|
||||
return ctx.OpLoad(ctx.F32[1], attr_ptr);
|
||||
}
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PrimitiveId:
|
||||
@@ -356,13 +347,6 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
|
||||
case IR::Attribute::PositionW:
|
||||
return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
|
||||
ctx.Const(element)));
|
||||
case IR::Attribute::ColorFrontDiffuseR:
|
||||
case IR::Attribute::ColorFrontDiffuseG:
|
||||
case IR::Attribute::ColorFrontDiffuseB:
|
||||
case IR::Attribute::ColorFrontDiffuseA: {
|
||||
return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_front_color,
|
||||
ctx.Const(element)));
|
||||
}
|
||||
case IR::Attribute::InstanceId:
|
||||
if (ctx.profile.support_vertex_instance_id) {
|
||||
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_id));
|
||||
|
||||
@@ -15,6 +15,8 @@ add_library(video_core STATIC
|
||||
command_classes/codecs/codec.h
|
||||
command_classes/codecs/h264.cpp
|
||||
command_classes/codecs/h264.h
|
||||
command_classes/codecs/vp8.cpp
|
||||
command_classes/codecs/vp8.h
|
||||
command_classes/codecs/vp9.cpp
|
||||
command_classes/codecs/vp9.h
|
||||
command_classes/codecs/vp9_types.h
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "common/settings.h"
|
||||
#include "video_core/command_classes/codecs/codec.h"
|
||||
#include "video_core/command_classes/codecs/h264.h"
|
||||
#include "video_core/command_classes/codecs/vp8.h"
|
||||
#include "video_core/command_classes/codecs/vp9.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
@@ -46,6 +47,7 @@ void AVFrameDeleter(AVFrame* ptr) {
|
||||
|
||||
Codec::Codec(GPU& gpu_, const NvdecCommon::NvdecRegisters& regs)
|
||||
: gpu(gpu_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(gpu)),
|
||||
vp8_decoder(std::make_unique<Decoder::VP8>(gpu)),
|
||||
vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {}
|
||||
|
||||
Codec::~Codec() {
|
||||
@@ -135,7 +137,9 @@ void Codec::Initialize() {
|
||||
switch (current_codec) {
|
||||
case NvdecCommon::VideoCodec::H264:
|
||||
return AV_CODEC_ID_H264;
|
||||
case NvdecCommon::VideoCodec::Vp9:
|
||||
case NvdecCommon::VideoCodec::VP8:
|
||||
return AV_CODEC_ID_VP8;
|
||||
case NvdecCommon::VideoCodec::VP9:
|
||||
return AV_CODEC_ID_VP9;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
|
||||
@@ -176,19 +180,27 @@ void Codec::Decode() {
|
||||
return;
|
||||
}
|
||||
bool vp9_hidden_frame = false;
|
||||
std::vector<u8> frame_data;
|
||||
if (current_codec == NvdecCommon::VideoCodec::H264) {
|
||||
frame_data = h264_decoder->ComposeFrameHeader(state, is_first_frame);
|
||||
} else if (current_codec == NvdecCommon::VideoCodec::Vp9) {
|
||||
frame_data = vp9_decoder->ComposeFrameHeader(state);
|
||||
vp9_hidden_frame = vp9_decoder->WasFrameHidden();
|
||||
}
|
||||
const auto& frame_data = [&]() {
|
||||
switch (current_codec) {
|
||||
case Tegra::NvdecCommon::VideoCodec::H264:
|
||||
return h264_decoder->ComposeFrame(state, is_first_frame);
|
||||
case Tegra::NvdecCommon::VideoCodec::VP8:
|
||||
return vp8_decoder->ComposeFrame(state);
|
||||
case Tegra::NvdecCommon::VideoCodec::VP9:
|
||||
vp9_decoder->ComposeFrame(state);
|
||||
vp9_hidden_frame = vp9_decoder->WasFrameHidden();
|
||||
return vp9_decoder->GetFrameBytes();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return std::vector<u8>{};
|
||||
}
|
||||
}();
|
||||
AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};
|
||||
if (!packet) {
|
||||
LOG_ERROR(Service_NVDRV, "av_packet_alloc failed");
|
||||
return;
|
||||
}
|
||||
packet->data = frame_data.data();
|
||||
packet->data = const_cast<u8*>(frame_data.data());
|
||||
packet->size = static_cast<s32>(frame_data.size());
|
||||
if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) {
|
||||
LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res);
|
||||
@@ -252,11 +264,11 @@ std::string_view Codec::GetCurrentCodecName() const {
|
||||
return "None";
|
||||
case NvdecCommon::VideoCodec::H264:
|
||||
return "H264";
|
||||
case NvdecCommon::VideoCodec::Vp8:
|
||||
case NvdecCommon::VideoCodec::VP8:
|
||||
return "VP8";
|
||||
case NvdecCommon::VideoCodec::H265:
|
||||
return "H265";
|
||||
case NvdecCommon::VideoCodec::Vp9:
|
||||
case NvdecCommon::VideoCodec::VP9:
|
||||
return "VP9";
|
||||
default:
|
||||
return "Unknown";
|
||||
|
||||
@@ -29,6 +29,7 @@ using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>;
|
||||
|
||||
namespace Decoder {
|
||||
class H264;
|
||||
class VP8;
|
||||
class VP9;
|
||||
} // namespace Decoder
|
||||
|
||||
@@ -72,6 +73,7 @@ private:
|
||||
GPU& gpu;
|
||||
const NvdecCommon::NvdecRegisters& state;
|
||||
std::unique_ptr<Decoder::H264> h264_decoder;
|
||||
std::unique_ptr<Decoder::VP8> vp8_decoder;
|
||||
std::unique_ptr<Decoder::VP9> vp9_decoder;
|
||||
|
||||
std::queue<AVFramePtr> av_frames{};
|
||||
|
||||
@@ -45,8 +45,8 @@ H264::H264(GPU& gpu_) : gpu(gpu_) {}
|
||||
|
||||
H264::~H264() = default;
|
||||
|
||||
const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state,
|
||||
bool is_first_frame) {
|
||||
const std::vector<u8>& H264::ComposeFrame(const NvdecCommon::NvdecRegisters& state,
|
||||
bool is_first_frame) {
|
||||
H264DecoderContext context;
|
||||
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext));
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ public:
|
||||
explicit H264(GPU& gpu);
|
||||
~H264();
|
||||
|
||||
/// Compose the H264 header of the frame for FFmpeg decoding
|
||||
[[nodiscard]] const std::vector<u8>& ComposeFrameHeader(
|
||||
const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
|
||||
/// Compose the H264 frame for FFmpeg decoding
|
||||
[[nodiscard]] const std::vector<u8>& ComposeFrame(const NvdecCommon::NvdecRegisters& state,
|
||||
bool is_first_frame = false);
|
||||
|
||||
private:
|
||||
std::vector<u8> frame;
|
||||
|
||||
55
src/video_core/command_classes/codecs/vp8.cpp
Normal file
55
src/video_core/command_classes/codecs/vp8.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "video_core/command_classes/codecs/vp8.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra::Decoder {
|
||||
VP8::VP8(GPU& gpu_) : gpu(gpu_) {}
|
||||
|
||||
VP8::~VP8() = default;
|
||||
|
||||
const std::vector<u8>& VP8::ComposeFrame(const NvdecCommon::NvdecRegisters& state) {
|
||||
VP8PictureInfo info;
|
||||
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo));
|
||||
|
||||
const bool is_key_frame = info.key_frame == 1u;
|
||||
const auto bitstream_size = static_cast<size_t>(info.vld_buffer_size);
|
||||
const size_t header_size = is_key_frame ? 10u : 3u;
|
||||
frame.resize(header_size + bitstream_size);
|
||||
|
||||
// Based on page 30 of the VP8 specification.
|
||||
// https://datatracker.ietf.org/doc/rfc6386/
|
||||
frame[0] = is_key_frame ? 0u : 1u; // 1-bit frame type (0: keyframe, 1: interframes).
|
||||
frame[0] |= static_cast<u8>((info.version & 7u) << 1u); // 3-bit version number
|
||||
frame[0] |= static_cast<u8>(1u << 4u); // 1-bit show_frame flag
|
||||
|
||||
// The next 19-bits are the first partition size
|
||||
frame[0] |= static_cast<u8>((info.first_part_size & 7u) << 5u);
|
||||
frame[1] = static_cast<u8>((info.first_part_size & 0x7f8u) >> 3u);
|
||||
frame[2] = static_cast<u8>((info.first_part_size & 0x7f800u) >> 11u);
|
||||
|
||||
if (is_key_frame) {
|
||||
frame[3] = 0x9du;
|
||||
frame[4] = 0x01u;
|
||||
frame[5] = 0x2au;
|
||||
// TODO(ameerj): Horizontal/Vertical Scale
|
||||
// 16 bits: (2 bits Horizontal Scale << 14) | Width (14 bits)
|
||||
frame[6] = static_cast<u8>(info.frame_width & 0xff);
|
||||
frame[7] = static_cast<u8>(((info.frame_width >> 8) & 0x3f));
|
||||
// 16 bits:(2 bits Vertical Scale << 14) | Height (14 bits)
|
||||
frame[8] = static_cast<u8>(info.frame_height & 0xff);
|
||||
frame[9] = static_cast<u8>(((info.frame_height >> 8) & 0x3f));
|
||||
}
|
||||
const u64 bitstream_offset = state.frame_bitstream_offset;
|
||||
gpu.MemoryManager().ReadBlock(bitstream_offset, frame.data() + header_size, bitstream_size);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
} // namespace Tegra::Decoder
|
||||
74
src/video_core/command_classes/codecs/vp8.h
Normal file
74
src/video_core/command_classes/codecs/vp8.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/command_classes/nvdec_common.h"
|
||||
|
||||
namespace Tegra {
|
||||
class GPU;
|
||||
namespace Decoder {
|
||||
|
||||
class VP8 {
|
||||
public:
|
||||
explicit VP8(GPU& gpu);
|
||||
~VP8();
|
||||
|
||||
/// Compose the VP8 frame for FFmpeg decoding
|
||||
[[nodiscard]] const std::vector<u8>& ComposeFrame(const NvdecCommon::NvdecRegisters& state);
|
||||
|
||||
private:
|
||||
std::vector<u8> frame;
|
||||
GPU& gpu;
|
||||
|
||||
struct VP8PictureInfo {
|
||||
INSERT_PADDING_WORDS_NOINIT(14);
|
||||
u16 frame_width; // actual frame width
|
||||
u16 frame_height; // actual frame height
|
||||
u8 key_frame;
|
||||
u8 version;
|
||||
union {
|
||||
u8 raw;
|
||||
BitField<0, 2, u8> tile_format;
|
||||
BitField<2, 3, u8> gob_height;
|
||||
BitField<5, 3, u8> reserverd_surface_format;
|
||||
};
|
||||
u8 error_conceal_on; // 1: error conceal on; 0: off
|
||||
u32 first_part_size; // the size of first partition(frame header and mb header partition)
|
||||
u32 hist_buffer_size; // in units of 256
|
||||
u32 vld_buffer_size; // in units of 1
|
||||
// Current frame buffers
|
||||
std::array<u32, 2> frame_stride; // [y_c]
|
||||
u32 luma_top_offset; // offset of luma top field in units of 256
|
||||
u32 luma_bot_offset; // offset of luma bottom field in units of 256
|
||||
u32 luma_frame_offset; // offset of luma frame in units of 256
|
||||
u32 chroma_top_offset; // offset of chroma top field in units of 256
|
||||
u32 chroma_bot_offset; // offset of chroma bottom field in units of 256
|
||||
u32 chroma_frame_offset; // offset of chroma frame in units of 256
|
||||
|
||||
INSERT_PADDING_BYTES_NOINIT(0x1c); // NvdecDisplayParams
|
||||
|
||||
// Decode picture buffer related
|
||||
s8 current_output_memory_layout;
|
||||
// output NV12/NV24 setting. index 0: golden; 1: altref; 2: last
|
||||
std::array<s8, 3> output_memory_layout;
|
||||
|
||||
u8 segmentation_feature_data_update;
|
||||
INSERT_PADDING_BYTES_NOINIT(3);
|
||||
|
||||
// ucode return result
|
||||
u32 result_value;
|
||||
std::array<u32, 8> partition_offset;
|
||||
INSERT_PADDING_WORDS_NOINIT(3);
|
||||
};
|
||||
static_assert(sizeof(VP8PictureInfo) == 0xc0, "PictureInfo is an invalid size");
|
||||
};
|
||||
|
||||
} // namespace Decoder
|
||||
} // namespace Tegra
|
||||
@@ -770,7 +770,7 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
|
||||
return uncomp_writer;
|
||||
}
|
||||
|
||||
const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state) {
|
||||
void VP9::ComposeFrame(const NvdecCommon::NvdecRegisters& state) {
|
||||
std::vector<u8> bitstream;
|
||||
{
|
||||
Vp9FrameContainer curr_frame = GetCurrentFrame(state);
|
||||
@@ -792,7 +792,6 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
|
||||
frame.begin() + uncompressed_header.size());
|
||||
std::copy(bitstream.begin(), bitstream.end(),
|
||||
frame.begin() + uncompressed_header.size() + compressed_header.size());
|
||||
return frame;
|
||||
}
|
||||
|
||||
VpxRangeEncoder::VpxRangeEncoder() {
|
||||
|
||||
@@ -116,16 +116,20 @@ public:
|
||||
VP9(VP9&&) = default;
|
||||
VP9& operator=(VP9&&) = delete;
|
||||
|
||||
/// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec
|
||||
/// documentation
|
||||
[[nodiscard]] const std::vector<u8>& ComposeFrameHeader(
|
||||
const NvdecCommon::NvdecRegisters& state);
|
||||
/// Composes the VP9 frame from the GPU state information.
|
||||
/// Based on the official VP9 spec documentation
|
||||
void ComposeFrame(const NvdecCommon::NvdecRegisters& state);
|
||||
|
||||
/// Returns true if the most recent frame was a hidden frame.
|
||||
[[nodiscard]] bool WasFrameHidden() const {
|
||||
return !current_frame_info.show_frame;
|
||||
}
|
||||
|
||||
/// Returns a const reference to the composed frame data.
|
||||
[[nodiscard]] const std::vector<u8>& GetFrameBytes() const {
|
||||
return frame;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Generates compressed header probability updates in the bitstream writer
|
||||
template <typename T, std::size_t N>
|
||||
|
||||
@@ -35,7 +35,8 @@ AVFramePtr Nvdec::GetFrame() {
|
||||
void Nvdec::Execute() {
|
||||
switch (codec->GetCurrentCodec()) {
|
||||
case NvdecCommon::VideoCodec::H264:
|
||||
case NvdecCommon::VideoCodec::Vp9:
|
||||
case NvdecCommon::VideoCodec::VP8:
|
||||
case NvdecCommon::VideoCodec::VP9:
|
||||
codec->Decode();
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace Tegra::NvdecCommon {
|
||||
enum class VideoCodec : u64 {
|
||||
None = 0x0,
|
||||
H264 = 0x3,
|
||||
Vp8 = 0x5,
|
||||
VP8 = 0x5,
|
||||
H265 = 0x7,
|
||||
Vp9 = 0x9,
|
||||
VP9 = 0x9,
|
||||
};
|
||||
|
||||
// NVDEC should use a 32-bit address space, but is mapped to 64-bit,
|
||||
@@ -50,7 +50,10 @@ struct NvdecRegisters {
|
||||
u64 h264_last_surface_chroma_offset; ///< 0x0858
|
||||
std::array<u64, 17> surface_luma_offset; ///< 0x0860
|
||||
std::array<u64, 17> surface_chroma_offset; ///< 0x08E8
|
||||
INSERT_PADDING_WORDS_NOINIT(132); ///< 0x0970
|
||||
INSERT_PADDING_WORDS_NOINIT(68); ///< 0x0970
|
||||
u64 vp8_prob_data_offset; ///< 0x0A80
|
||||
u64 vp8_header_partition_buf_offset; ///< 0x0A88
|
||||
INSERT_PADDING_WORDS_NOINIT(60); ///< 0x0A90
|
||||
u64 vp9_entropy_probs_offset; ///< 0x0B80
|
||||
u64 vp9_backward_updates_offset; ///< 0x0B88
|
||||
u64 vp9_last_frame_segmap_offset; ///< 0x0B90
|
||||
@@ -81,6 +84,8 @@ ASSERT_REG_POSITION(h264_last_surface_luma_offset, 0x10A);
|
||||
ASSERT_REG_POSITION(h264_last_surface_chroma_offset, 0x10B);
|
||||
ASSERT_REG_POSITION(surface_luma_offset, 0x10C);
|
||||
ASSERT_REG_POSITION(surface_chroma_offset, 0x11D);
|
||||
ASSERT_REG_POSITION(vp8_prob_data_offset, 0x150);
|
||||
ASSERT_REG_POSITION(vp8_header_partition_buf_offset, 0x151);
|
||||
ASSERT_REG_POSITION(vp9_entropy_probs_offset, 0x170);
|
||||
ASSERT_REG_POSITION(vp9_backward_updates_offset, 0x171);
|
||||
ASSERT_REG_POSITION(vp9_last_frame_segmap_offset, 0x172);
|
||||
|
||||
@@ -413,7 +413,7 @@ void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
|
||||
? ui->text_edit_osk->toPlainText().toStdU16String()
|
||||
: ui->line_edit_osk->text().toStdU16String();
|
||||
|
||||
emit SubmitNormalText(SwkbdResult::Ok, std::move(text));
|
||||
emit SubmitNormalText(SwkbdResult::Ok, std::move(text), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1510,7 +1510,8 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
|
||||
|
||||
void QtSoftwareKeyboard::InitializeKeyboard(
|
||||
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) {
|
||||
if (is_inline) {
|
||||
@@ -1609,8 +1610,8 @@ void QtSoftwareKeyboard::ExitKeyboard() const {
|
||||
}
|
||||
|
||||
void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result,
|
||||
std::u16string submitted_text) const {
|
||||
submit_normal_callback(result, submitted_text);
|
||||
std::u16string submitted_text, bool confirmed) const {
|
||||
submit_normal_callback(result, submitted_text, confirmed);
|
||||
}
|
||||
|
||||
void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
|
||||
|
||||
@@ -51,8 +51,8 @@ public:
|
||||
void ExitKeyboard();
|
||||
|
||||
signals:
|
||||
void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
|
||||
std::u16string submitted_text) const;
|
||||
void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
|
||||
bool confirmed = false) const;
|
||||
|
||||
void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
|
||||
std::u16string submitted_text, s32 cursor_position) const;
|
||||
@@ -234,7 +234,7 @@ public:
|
||||
|
||||
void InitializeKeyboard(
|
||||
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) override;
|
||||
@@ -272,13 +272,13 @@ signals:
|
||||
void MainWindowExitKeyboard() const;
|
||||
|
||||
private:
|
||||
void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
|
||||
std::u16string submitted_text) const;
|
||||
void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
|
||||
bool confirmed) const;
|
||||
|
||||
void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
|
||||
std::u16string submitted_text, s32 cursor_position) const;
|
||||
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>
|
||||
submit_normal_callback;
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback;
|
||||
|
||||
@@ -299,6 +299,8 @@ GMainWindow::GMainWindow()
|
||||
SDL_EnableScreenSaver();
|
||||
#endif
|
||||
|
||||
Common::Log::Start();
|
||||
|
||||
QStringList args = QApplication::arguments();
|
||||
|
||||
if (args.size() < 2) {
|
||||
@@ -483,8 +485,9 @@ void GMainWindow::SoftwareKeyboardInitialize(
|
||||
} else {
|
||||
connect(
|
||||
software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
|
||||
[this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text) {
|
||||
emit SoftwareKeyboardSubmitNormalText(result, submitted_text);
|
||||
[this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text,
|
||||
bool confirmed) {
|
||||
emit SoftwareKeyboardSubmitNormalText(result, submitted_text, confirmed);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ signals:
|
||||
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
|
||||
|
||||
void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result,
|
||||
std::u16string submitted_text);
|
||||
std::u16string submitted_text, bool confirmed);
|
||||
void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
|
||||
std::u16string submitted_text, s32 cursor_position);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user