Compare commits
62 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd236c6c1d | ||
|
|
7a2f60df26 | ||
|
|
cedbe925cd | ||
|
|
e84b760016 | ||
|
|
744b207d92 | ||
|
|
950b6dbc80 | ||
|
|
3194f14aca | ||
|
|
8244536f7a | ||
|
|
23c7dda710 | ||
|
|
e6aff11057 | ||
|
|
aa41fcc04e | ||
|
|
ac4154bfde | ||
|
|
f8382c9d9d | ||
|
|
6ca8637d4c | ||
|
|
497f593525 | ||
|
|
7981910746 | ||
|
|
dc4415811c | ||
|
|
4afebf26b6 | ||
|
|
5a5c6d4ed8 | ||
|
|
e731c4b991 | ||
|
|
fc37672f26 | ||
|
|
977418c65b | ||
|
|
f66743cd0c | ||
|
|
d4e93cf38c | ||
|
|
bdcedc8506 | ||
|
|
22f4268c2f | ||
|
|
7051dc1902 | ||
|
|
01af036c1f | ||
|
|
63c2635e6f | ||
|
|
dbfbe352e0 | ||
|
|
e5bb5d13c4 | ||
|
|
e70451d967 | ||
|
|
81fa492825 | ||
|
|
bdddbe2daa | ||
|
|
06dea163fa | ||
|
|
bc681dc555 | ||
|
|
9418b983bd | ||
|
|
76d6178e4a | ||
|
|
38c1e77f01 | ||
|
|
b6b2e31e5e | ||
|
|
fc51ece7bf | ||
|
|
98d85cdc20 | ||
|
|
dab450ec46 | ||
|
|
351816ac38 | ||
|
|
acf328a71f | ||
|
|
9f46066bda | ||
|
|
ba9674862d | ||
|
|
ac7ee21331 | ||
|
|
56ea0f8acb | ||
|
|
f5658a9fda | ||
|
|
cdeadd448b | ||
|
|
2fd3b328ae | ||
|
|
230ac6a4e8 | ||
|
|
eae2ed6b07 | ||
|
|
38036eb1c8 | ||
|
|
5afc397d52 | ||
|
|
6442e02c5d | ||
|
|
8e6e55d6f8 | ||
|
|
464bd5fad7 | ||
|
|
829f424618 | ||
|
|
a166217480 | ||
|
|
7cbe6748c3 |
@@ -6,9 +6,9 @@ function(copy_yuzu_Qt5_deps target_dir)
|
||||
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
|
||||
set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
|
||||
set(Qt5_RESOURCES_DIR "${Qt5_DIR}/../../../resources/")
|
||||
set(PLATFORMS ${DLL_DEST}platforms/)
|
||||
set(STYLES ${DLL_DEST}styles/)
|
||||
set(IMAGEFORMATS ${DLL_DEST}imageformats/)
|
||||
set(PLATFORMS ${DLL_DEST}plugins/platforms/)
|
||||
set(STYLES ${DLL_DEST}plugins/styles/)
|
||||
set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/)
|
||||
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
|
||||
icudt*.dll
|
||||
icuin*.dll
|
||||
@@ -42,11 +42,15 @@ function(copy_yuzu_Qt5_deps target_dir)
|
||||
icudtl.dat
|
||||
)
|
||||
endif ()
|
||||
|
||||
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
|
||||
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
|
||||
qjpeg$<$<CONFIG:Debug>:d>.*
|
||||
qgif$<$<CONFIG:Debug>:d>.*
|
||||
)
|
||||
# Create an empty qt.conf file. Qt will detect that this file exists, and use the folder that its in as the root folder.
|
||||
# This way it'll look for plugins in the root/plugins/ folder
|
||||
add_custom_command(TARGET yuzu POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${DLL_DEST}qt.conf
|
||||
)
|
||||
endfunction(copy_yuzu_Qt5_deps)
|
||||
|
||||
@@ -2,6 +2,7 @@ yuzu emulator
|
||||
=============
|
||||
[](https://travis-ci.com/yuzu-emu/yuzu)
|
||||
[](https://dev.azure.com/yuzu-emu/yuzu/)
|
||||
[](https://discord.gg/XQV6dn9)
|
||||
|
||||
yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/).
|
||||
|
||||
@@ -21,7 +22,7 @@ For development discussion, please join us on [Discord](https://discord.gg/XQV6d
|
||||
|
||||
Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted.
|
||||
|
||||
If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator.
|
||||
If you want to contribute please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator.
|
||||
|
||||
### Building
|
||||
|
||||
|
||||
6
dist/license.md
vendored
6
dist/license.md
vendored
@@ -2,8 +2,8 @@ The icons in this folder and its subfolders have the following licenses:
|
||||
|
||||
Icon Name | License | Origin/Author
|
||||
--- | --- | ---
|
||||
qt_themes/default/icons/16x16/checked.png | Free for non-commercial use
|
||||
qt_themes/default/icons/16x16/failed.png | Free for non-commercial use
|
||||
qt_themes/default/icons/16x16/checked.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/16x16/failed.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
@@ -11,8 +11,6 @@ qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
||||
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/16x16/checked.png | Free for non-commercial use
|
||||
qt_themes/qdarkstyle/icons/16x16/failed.png | Free for non-commercial use
|
||||
qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||
|
||||
BIN
dist/qt_themes/default/icons/16x16/checked.png
vendored
BIN
dist/qt_themes/default/icons/16x16/checked.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 657 B |
BIN
dist/qt_themes/default/icons/16x16/failed.png
vendored
BIN
dist/qt_themes/default/icons/16x16/failed.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 524 B |
6
externals/microprofile/microprofile.h
vendored
6
externals/microprofile/microprofile.h
vendored
@@ -828,7 +828,7 @@ inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfi
|
||||
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
|
||||
int t = MicroProfileLogType(Entry);
|
||||
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
|
||||
MP_ASSERT(t == nBegin);
|
||||
MP_ASSERT((uint64_t)t == nBegin);
|
||||
MP_ASSERT(nTimerIndex == (nToken&0x3fff));
|
||||
return Entry;
|
||||
|
||||
@@ -1556,10 +1556,10 @@ void MicroProfileFlip()
|
||||
|
||||
pFramePut->nFrameStartCpu = MP_TICK();
|
||||
pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp();
|
||||
if(pFrameNext->nFrameStartGpu != (uint64_t)-1)
|
||||
if(pFrameNext->nFrameStartGpu != -1)
|
||||
pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu);
|
||||
|
||||
if(pFrameCurrent->nFrameStartGpu == (uint64_t)-1)
|
||||
if(pFrameCurrent->nFrameStartGpu == -1)
|
||||
pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1;
|
||||
|
||||
uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
|
||||
|
||||
@@ -343,8 +343,8 @@ The icons used in this project have the following licenses:
|
||||
|
||||
Icon Name | License | Origin/Author
|
||||
--- | --- | ---
|
||||
checked.png | Free for non-commercial use
|
||||
failed.png | Free for non-commercial use
|
||||
checked.png | CC BY-ND 3.0 | https://icons8.com
|
||||
failed.png | CC BY-ND 3.0 | https://icons8.com
|
||||
lock.png | CC BY-ND 3.0 | https://icons8.com
|
||||
plus_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
|
||||
bad_folder.png (Default, Dark) | CC BY-ND 3.0 | https://icons8.com
|
||||
|
||||
@@ -166,7 +166,7 @@ struct System::Impl {
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||
|
||||
Service::Init(service_manager, system);
|
||||
GDBStub::Init();
|
||||
GDBStub::DeferStart();
|
||||
|
||||
renderer = VideoCore::CreateRenderer(emu_window, system);
|
||||
if (!renderer->Init()) {
|
||||
|
||||
@@ -141,6 +141,7 @@ constexpr char target_xml[] =
|
||||
)";
|
||||
|
||||
int gdbserver_socket = -1;
|
||||
bool defer_start = false;
|
||||
|
||||
u8 command_buffer[GDB_BUFFER_SIZE];
|
||||
u32 command_length;
|
||||
@@ -1166,6 +1167,9 @@ static void RemoveBreakpoint() {
|
||||
|
||||
void HandlePacket() {
|
||||
if (!IsConnected()) {
|
||||
if (defer_start) {
|
||||
ToggleServer(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1256,6 +1260,10 @@ void ToggleServer(bool status) {
|
||||
}
|
||||
}
|
||||
|
||||
void DeferStart() {
|
||||
defer_start = true;
|
||||
}
|
||||
|
||||
static void Init(u16 port) {
|
||||
if (!server_enabled) {
|
||||
// Set the halt loop to false in case the user enabled the gdbstub mid-execution.
|
||||
@@ -1341,6 +1349,7 @@ void Shutdown() {
|
||||
if (!server_enabled) {
|
||||
return;
|
||||
}
|
||||
defer_start = false;
|
||||
|
||||
LOG_INFO(Debug_GDBStub, "Stopping GDB ...");
|
||||
if (gdbserver_socket != -1) {
|
||||
|
||||
@@ -43,6 +43,13 @@ void ToggleServer(bool status);
|
||||
/// Start the gdbstub server.
|
||||
void Init();
|
||||
|
||||
/**
|
||||
* Defer initialization of the gdbstub to the first packet processing functions.
|
||||
* This avoids a case where the gdbstub thread is frozen after initialization
|
||||
* and fails to respond in time to packets.
|
||||
*/
|
||||
void DeferStart();
|
||||
|
||||
/// Stop gdbstub server.
|
||||
void Shutdown();
|
||||
|
||||
|
||||
@@ -254,6 +254,12 @@ void WebBrowser::Execute() {
|
||||
|
||||
if (status != RESULT_SUCCESS) {
|
||||
complete = true;
|
||||
|
||||
// This is a workaround in order not to softlock yuzu when an error happens during the
|
||||
// webapplet init. In order to avoid an svcBreak, the status is set to RESULT_SUCCESS
|
||||
Finalize();
|
||||
status = RESULT_SUCCESS;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +111,14 @@ void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushEnum(available_language_codes[Settings::values.language_index]);
|
||||
}
|
||||
|
||||
void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(Settings::values.region_index);
|
||||
}
|
||||
|
||||
SET::SET() : ServiceFramework("set") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
@@ -118,7 +126,7 @@ SET::SET() : ServiceFramework("set") {
|
||||
{1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
|
||||
{2, &SET::MakeLanguageCode, "MakeLanguageCode"},
|
||||
{3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
|
||||
{4, nullptr, "GetRegionCode"},
|
||||
{4, &SET::GetRegionCode, "GetRegionCode"},
|
||||
{5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
|
||||
{6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"},
|
||||
{7, nullptr, "GetKeyCodeMap"},
|
||||
|
||||
@@ -43,6 +43,7 @@ private:
|
||||
void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
|
||||
void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
|
||||
void GetQuestFlag(Kernel::HLERequestContext& ctx);
|
||||
void GetRegionCode(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
|
||||
@@ -44,7 +44,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u16>(0x500);
|
||||
rb.Push<u16>(0x1000);
|
||||
}
|
||||
|
||||
Controller::Controller() : ServiceFramework("IpcController") {
|
||||
|
||||
@@ -53,7 +53,7 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<char> raw_data(binary_list->GetSize());
|
||||
std::vector<char> raw_data(binary_list->GetSize() + 1);
|
||||
binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize());
|
||||
|
||||
std::stringstream data_stream{raw_data.data()};
|
||||
|
||||
@@ -86,6 +86,7 @@ void LogSettings() {
|
||||
LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0));
|
||||
LogSetting("System_CurrentUser", Settings::values.current_user);
|
||||
LogSetting("System_LanguageIndex", Settings::values.language_index);
|
||||
LogSetting("System_RegionIndex", Settings::values.region_index);
|
||||
LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);
|
||||
LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);
|
||||
LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);
|
||||
|
||||
@@ -387,6 +387,8 @@ struct Values {
|
||||
|
||||
s32 current_user;
|
||||
s32 language_index;
|
||||
s32 region_index;
|
||||
s32 sound_index;
|
||||
|
||||
// Controls
|
||||
std::array<PlayerInput, 10> players;
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
pad_index(pad_index) {
|
||||
boost::system::error_code ec{};
|
||||
auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
|
||||
if (ec.failed()) {
|
||||
if (ec.value() != boost::system::errc::success) {
|
||||
LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided to socket", host);
|
||||
ipv4 = boost::asio::ip::address_v4{};
|
||||
}
|
||||
|
||||
@@ -18,10 +18,14 @@ struct SamplerDescriptor {
|
||||
union {
|
||||
u32 raw = 0;
|
||||
BitField<0, 2, Tegra::Shader::TextureType> texture_type;
|
||||
BitField<2, 3, Tegra::Texture::ComponentType> component_type;
|
||||
BitField<2, 3, Tegra::Texture::ComponentType> r_type;
|
||||
BitField<5, 1, u32> is_array;
|
||||
BitField<6, 1, u32> is_buffer;
|
||||
BitField<7, 1, u32> is_shadow;
|
||||
BitField<8, 3, Tegra::Texture::ComponentType> g_type;
|
||||
BitField<11, 3, Tegra::Texture::ComponentType> b_type;
|
||||
BitField<14, 3, Tegra::Texture::ComponentType> a_type;
|
||||
BitField<17, 7, Tegra::Texture::TextureFormat> format;
|
||||
};
|
||||
|
||||
bool operator==(const SamplerDescriptor& rhs) const noexcept {
|
||||
@@ -36,9 +40,11 @@ struct SamplerDescriptor {
|
||||
using Tegra::Shader::TextureType;
|
||||
SamplerDescriptor result;
|
||||
|
||||
// This is going to be used to determine the shading language type.
|
||||
// Because of that we don't care about all component types on color textures.
|
||||
result.component_type.Assign(tic.r_type.Value());
|
||||
result.format.Assign(tic.format.Value());
|
||||
result.r_type.Assign(tic.r_type.Value());
|
||||
result.g_type.Assign(tic.g_type.Value());
|
||||
result.b_type.Assign(tic.b_type.Value());
|
||||
result.a_type.Assign(tic.a_type.Value());
|
||||
|
||||
switch (tic.texture_type.Value()) {
|
||||
case Tegra::Texture::TextureType::Texture1D:
|
||||
|
||||
@@ -119,14 +119,6 @@ Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
|
||||
Texture::TICEntry tic_entry;
|
||||
memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
|
||||
|
||||
const auto r_type{tic_entry.r_type.Value()};
|
||||
const auto g_type{tic_entry.g_type.Value()};
|
||||
const auto b_type{tic_entry.b_type.Value()};
|
||||
const auto a_type{tic_entry.a_type.Value()};
|
||||
|
||||
// TODO(Subv): Different data types for separate components are not supported
|
||||
DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
|
||||
|
||||
return tic_entry;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,8 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
regs.framebuffer_srgb = 1;
|
||||
regs.front_face = Maxwell3D::Regs::FrontFace::ClockWise;
|
||||
|
||||
shadow_state = regs;
|
||||
|
||||
mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true;
|
||||
mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true;
|
||||
mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
|
||||
@@ -160,8 +162,17 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||
ASSERT_MSG(method < Regs::NUM_REGS,
|
||||
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
||||
|
||||
if (regs.reg_array[method] != method_call.argument) {
|
||||
regs.reg_array[method] = method_call.argument;
|
||||
u32 arg = method_call.argument;
|
||||
// Keep track of the register value in shadow_state when requested.
|
||||
if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Track ||
|
||||
shadow_state.shadow_ram_control == Regs::ShadowRamControl::TrackWithFilter) {
|
||||
shadow_state.reg_array[method] = arg;
|
||||
} else if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Replay) {
|
||||
arg = shadow_state.reg_array[method];
|
||||
}
|
||||
|
||||
if (regs.reg_array[method] != arg) {
|
||||
regs.reg_array[method] = arg;
|
||||
|
||||
for (const auto& table : dirty.tables) {
|
||||
dirty.flags[table[method]] = true;
|
||||
@@ -169,12 +180,16 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(shadow_ram_control): {
|
||||
shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(method_call.argument);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(macros.data): {
|
||||
ProcessMacroUpload(method_call.argument);
|
||||
ProcessMacroUpload(arg);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(macros.bind): {
|
||||
ProcessMacroBind(method_call.argument);
|
||||
ProcessMacroBind(arg);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(firmware[4]): {
|
||||
@@ -250,7 +265,7 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(data_upload): {
|
||||
const bool is_last_call = method_call.IsLastCall();
|
||||
upload_state.ProcessData(method_call.argument, is_last_call);
|
||||
upload_state.ProcessData(arg, is_last_call);
|
||||
if (is_last_call) {
|
||||
OnMemoryWrite();
|
||||
}
|
||||
|
||||
@@ -531,6 +531,17 @@ public:
|
||||
Fill = 0x1b02,
|
||||
};
|
||||
|
||||
enum class ShadowRamControl : u32 {
|
||||
// write value to shadow ram
|
||||
Track = 0,
|
||||
// write value to shadow ram ( with validation ??? )
|
||||
TrackWithFilter = 1,
|
||||
// only write to real hw register
|
||||
Passthrough = 2,
|
||||
// write value from shadow ram to real hw register
|
||||
Replay = 3,
|
||||
};
|
||||
|
||||
struct RenderTargetConfig {
|
||||
u32 address_high;
|
||||
u32 address_low;
|
||||
@@ -674,7 +685,9 @@ public:
|
||||
u32 bind;
|
||||
} macros;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0x17);
|
||||
ShadowRamControl shadow_ram_control;
|
||||
|
||||
INSERT_UNION_PADDING_WORDS(0x16);
|
||||
|
||||
Upload::Registers upload;
|
||||
struct {
|
||||
@@ -1263,7 +1276,12 @@ public:
|
||||
};
|
||||
std::array<u32, NUM_REGS> reg_array;
|
||||
};
|
||||
} regs{};
|
||||
};
|
||||
|
||||
Regs regs{};
|
||||
|
||||
/// Store temporary hw register values, used by some calls to restore state after a operation
|
||||
Regs shadow_state;
|
||||
|
||||
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size");
|
||||
static_assert(std::is_trivially_copyable_v<Regs>, "Maxwell3D Regs must be trivially copyable");
|
||||
@@ -1458,6 +1476,7 @@ private:
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
ASSERT_REG_POSITION(macros, 0x45);
|
||||
ASSERT_REG_POSITION(shadow_ram_control, 0x49);
|
||||
ASSERT_REG_POSITION(upload, 0x60);
|
||||
ASSERT_REG_POSITION(exec_upload, 0x6C);
|
||||
ASSERT_REG_POSITION(data_upload, 0x6D);
|
||||
|
||||
@@ -82,6 +82,10 @@ union Attribute {
|
||||
Position = 7,
|
||||
Attribute_0 = 8,
|
||||
Attribute_31 = 39,
|
||||
FrontColor = 40,
|
||||
FrontSecondaryColor = 41,
|
||||
BackColor = 42,
|
||||
BackSecondaryColor = 43,
|
||||
ClipDistances0123 = 44,
|
||||
ClipDistances4567 = 45,
|
||||
PointCoord = 46,
|
||||
@@ -89,6 +93,8 @@ union Attribute {
|
||||
// shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
|
||||
// shader.
|
||||
TessCoordInstanceIDVertexID = 47,
|
||||
TexCoord_0 = 48,
|
||||
TexCoord_7 = 55,
|
||||
// This attribute contains a tuple of (Unk, Unk, Unk, gl_FrontFacing) when inside a fragment
|
||||
// shader. It is unknown what the other values contain.
|
||||
FrontFacing = 63,
|
||||
|
||||
@@ -93,10 +93,6 @@ void oglEnable(GLenum cap, bool state) {
|
||||
(state ? glEnable : glDisable)(cap);
|
||||
}
|
||||
|
||||
void oglEnablei(GLenum cap, bool state, GLuint index) {
|
||||
(state ? glEnablei : glDisablei)(cap, index);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
|
||||
@@ -478,7 +474,6 @@ void RasterizerOpenGL::Clear() {
|
||||
void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Drawing);
|
||||
auto& gpu = system.GPU().Maxwell3D();
|
||||
const auto& regs = gpu.regs;
|
||||
|
||||
query_cache.UpdateCounters();
|
||||
|
||||
@@ -529,7 +524,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||
// Upload vertex and index data.
|
||||
SetupVertexBuffer();
|
||||
SetupVertexInstances();
|
||||
GLintptr index_buffer_offset;
|
||||
GLintptr index_buffer_offset = 0;
|
||||
if (is_indexed) {
|
||||
index_buffer_offset = SetupIndexBuffer();
|
||||
}
|
||||
@@ -555,7 +550,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||
ConfigureFramebuffers();
|
||||
|
||||
// Signal the buffer cache that we are not going to upload more things.
|
||||
const bool invalidate = buffer_cache.Unmap();
|
||||
buffer_cache.Unmap();
|
||||
|
||||
// Now that we are no longer uploading data, we can safely bind the buffers to OpenGL.
|
||||
vertex_array_pushbuffer.Bind();
|
||||
@@ -938,13 +933,15 @@ void RasterizerOpenGL::SyncViewport() {
|
||||
}
|
||||
flags[Dirty::Viewport0 + i] = false;
|
||||
|
||||
const Common::Rectangle<f32> rect{regs.viewport_transform[i].GetRect()};
|
||||
const auto& src = regs.viewport_transform[i];
|
||||
const Common::Rectangle<f32> rect{src.GetRect()};
|
||||
glViewportIndexedf(static_cast<GLuint>(i), rect.left, rect.bottom, rect.GetWidth(),
|
||||
rect.GetHeight());
|
||||
|
||||
const auto& src = regs.viewports[i];
|
||||
glDepthRangeIndexed(static_cast<GLuint>(i), static_cast<GLdouble>(src.depth_range_near),
|
||||
static_cast<GLdouble>(src.depth_range_far));
|
||||
const GLdouble reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne;
|
||||
const GLdouble near_depth = src.translate_z - src.scale_z * reduce_z;
|
||||
const GLdouble far_depth = src.translate_z + src.scale_z;
|
||||
glDepthRangeIndexed(static_cast<GLuint>(i), near_depth, far_depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,10 +366,19 @@ constexpr bool IsGenericAttribute(Attribute::Index index) {
|
||||
return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31;
|
||||
}
|
||||
|
||||
constexpr bool IsLegacyTexCoord(Attribute::Index index) {
|
||||
return static_cast<int>(index) >= static_cast<int>(Attribute::Index::TexCoord_0) &&
|
||||
static_cast<int>(index) <= static_cast<int>(Attribute::Index::TexCoord_7);
|
||||
}
|
||||
|
||||
constexpr Attribute::Index ToGenericAttribute(u64 value) {
|
||||
return static_cast<Attribute::Index>(value + static_cast<u64>(Attribute::Index::Attribute_0));
|
||||
}
|
||||
|
||||
constexpr int GetLegacyTexCoordIndex(Attribute::Index index) {
|
||||
return static_cast<int>(index) - static_cast<int>(Attribute::Index::TexCoord_0);
|
||||
}
|
||||
|
||||
u32 GetGenericAttributeIndex(Attribute::Index index) {
|
||||
ASSERT(IsGenericAttribute(index));
|
||||
return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0);
|
||||
@@ -393,10 +402,6 @@ std::string FlowStackTopName(MetaStackClass stack) {
|
||||
return fmt::format("{}_flow_stack_top", GetFlowStackPrefix(stack));
|
||||
}
|
||||
|
||||
[[deprecated]] constexpr bool IsVertexShader(ShaderType stage) {
|
||||
return stage == ShaderType::Vertex;
|
||||
}
|
||||
|
||||
struct GenericVaryingDescription {
|
||||
std::string name;
|
||||
u8 first_element = 0;
|
||||
@@ -502,7 +507,7 @@ private:
|
||||
if (!identifier.empty()) {
|
||||
code.AddLine("// {}", identifier);
|
||||
}
|
||||
code.AddLine("#version 440 core");
|
||||
code.AddLine("#version 440 {}", ir.UsesLegacyVaryings() ? "compatibility" : "core");
|
||||
code.AddLine("#extension GL_ARB_separate_shader_objects : enable");
|
||||
if (device.HasShaderBallot()) {
|
||||
code.AddLine("#extension GL_ARB_shader_ballot : require");
|
||||
@@ -529,8 +534,9 @@ private:
|
||||
}
|
||||
|
||||
void DeclareVertex() {
|
||||
if (!IsVertexShader(stage))
|
||||
if (stage != ShaderType::Vertex) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeclareVertexRedeclarations();
|
||||
}
|
||||
@@ -564,6 +570,16 @@ private:
|
||||
if (stage != ShaderType::Fragment) {
|
||||
return;
|
||||
}
|
||||
if (ir.UsesLegacyVaryings()) {
|
||||
code.AddLine("in gl_PerFragment {{");
|
||||
++code.scope;
|
||||
code.AddLine("vec4 gl_TexCoord[8];");
|
||||
code.AddLine("vec4 gl_Color;");
|
||||
code.AddLine("vec4 gl_SecondaryColor;");
|
||||
--code.scope;
|
||||
code.AddLine("}};");
|
||||
}
|
||||
|
||||
for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
|
||||
code.AddLine("layout (location = {}) out vec4 frag_color{};", rt, rt);
|
||||
}
|
||||
@@ -602,14 +618,14 @@ private:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!IsVertexShader(stage) || device.HasVertexViewportLayer()) {
|
||||
if (stage != ShaderType::Vertex || device.HasVertexViewportLayer()) {
|
||||
if (ir.UsesLayer()) {
|
||||
code.AddLine("int gl_Layer;");
|
||||
}
|
||||
if (ir.UsesViewportIndex()) {
|
||||
code.AddLine("int gl_ViewportIndex;");
|
||||
}
|
||||
} else if ((ir.UsesLayer() || ir.UsesViewportIndex()) && IsVertexShader(stage) &&
|
||||
} else if ((ir.UsesLayer() || ir.UsesViewportIndex()) && stage == ShaderType::Vertex &&
|
||||
!device.HasVertexViewportLayer()) {
|
||||
LOG_ERROR(
|
||||
Render_OpenGL,
|
||||
@@ -620,12 +636,12 @@ private:
|
||||
code.AddLine("float gl_PointSize;");
|
||||
}
|
||||
|
||||
if (ir.UsesInstanceId()) {
|
||||
code.AddLine("int gl_InstanceID;");
|
||||
}
|
||||
|
||||
if (ir.UsesVertexId()) {
|
||||
code.AddLine("int gl_VertexID;");
|
||||
if (ir.UsesLegacyVaryings()) {
|
||||
code.AddLine("vec4 gl_TexCoord[8];");
|
||||
code.AddLine("vec4 gl_FrontColor;");
|
||||
code.AddLine("vec4 gl_FrontSecondaryColor;");
|
||||
code.AddLine("vec4 gl_BackColor;");
|
||||
code.AddLine("vec4 gl_BackSecondaryColor;");
|
||||
}
|
||||
|
||||
--code.scope;
|
||||
@@ -1131,6 +1147,10 @@ private:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
case Attribute::Index::FrontColor:
|
||||
return {"gl_Color"s + GetSwizzle(element), Type::Float};
|
||||
case Attribute::Index::FrontSecondaryColor:
|
||||
return {"gl_SecondaryColor"s + GetSwizzle(element), Type::Float};
|
||||
case Attribute::Index::PointCoord:
|
||||
switch (element) {
|
||||
case 0:
|
||||
@@ -1147,7 +1167,7 @@ private:
|
||||
// TODO(Subv): Find out what the values are for the first two elements when inside a
|
||||
// vertex shader, and what's the value of the fourth element when inside a Tess Eval
|
||||
// shader.
|
||||
ASSERT(IsVertexShader(stage));
|
||||
ASSERT(stage == ShaderType::Vertex);
|
||||
switch (element) {
|
||||
case 2:
|
||||
// Config pack's first value is instance_id.
|
||||
@@ -1171,6 +1191,12 @@ private:
|
||||
return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element),
|
||||
Type::Float};
|
||||
}
|
||||
if (IsLegacyTexCoord(attribute)) {
|
||||
UNIMPLEMENTED_IF(stage == ShaderType::Geometry);
|
||||
return {fmt::format("gl_TexCoord[{}]{}", GetLegacyTexCoordIndex(attribute),
|
||||
GetSwizzle(element)),
|
||||
Type::Float};
|
||||
}
|
||||
break;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
|
||||
@@ -1209,21 +1235,22 @@ private:
|
||||
}
|
||||
|
||||
std::optional<Expression> GetOutputAttribute(const AbufNode* abuf) {
|
||||
const u32 element = abuf->GetElement();
|
||||
switch (const auto attribute = abuf->GetIndex()) {
|
||||
case Attribute::Index::Position:
|
||||
return {{"gl_Position"s + GetSwizzle(abuf->GetElement()), Type::Float}};
|
||||
return {{"gl_Position"s + GetSwizzle(element), Type::Float}};
|
||||
case Attribute::Index::LayerViewportPointSize:
|
||||
switch (abuf->GetElement()) {
|
||||
switch (element) {
|
||||
case 0:
|
||||
UNIMPLEMENTED();
|
||||
return {};
|
||||
case 1:
|
||||
if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) {
|
||||
if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) {
|
||||
return {};
|
||||
}
|
||||
return {{"gl_Layer", Type::Int}};
|
||||
case 2:
|
||||
if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) {
|
||||
if (stage == ShaderType::Vertex && !device.HasVertexViewportLayer()) {
|
||||
return {};
|
||||
}
|
||||
return {{"gl_ViewportIndex", Type::Int}};
|
||||
@@ -1231,13 +1258,26 @@ private:
|
||||
return {{"gl_PointSize", Type::Float}};
|
||||
}
|
||||
return {};
|
||||
case Attribute::Index::FrontColor:
|
||||
return {{"gl_FrontColor"s + GetSwizzle(element), Type::Float}};
|
||||
case Attribute::Index::FrontSecondaryColor:
|
||||
return {{"gl_FrontSecondaryColor"s + GetSwizzle(element), Type::Float}};
|
||||
case Attribute::Index::BackColor:
|
||||
return {{"gl_BackColor"s + GetSwizzle(element), Type::Float}};
|
||||
case Attribute::Index::BackSecondaryColor:
|
||||
return {{"gl_BackSecondaryColor"s + GetSwizzle(element), Type::Float}};
|
||||
case Attribute::Index::ClipDistances0123:
|
||||
return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), Type::Float}};
|
||||
return {{fmt::format("gl_ClipDistance[{}]", element), Type::Float}};
|
||||
case Attribute::Index::ClipDistances4567:
|
||||
return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}};
|
||||
return {{fmt::format("gl_ClipDistance[{}]", element + 4), Type::Float}};
|
||||
default:
|
||||
if (IsGenericAttribute(attribute)) {
|
||||
return {{GetGenericOutputAttribute(attribute, abuf->GetElement()), Type::Float}};
|
||||
return {{GetGenericOutputAttribute(attribute, element), Type::Float}};
|
||||
}
|
||||
if (IsLegacyTexCoord(attribute)) {
|
||||
return {{fmt::format("gl_TexCoord[{}]{}", GetLegacyTexCoordIndex(attribute),
|
||||
GetSwizzle(element)),
|
||||
Type::Float}};
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
|
||||
return {};
|
||||
@@ -2532,7 +2572,7 @@ private:
|
||||
}
|
||||
|
||||
u32 GetNumPhysicalInputAttributes() const {
|
||||
return IsVertexShader(stage) ? GetNumPhysicalAttributes() : GetNumPhysicalVaryings();
|
||||
return stage == ShaderType::Vertex ? GetNumPhysicalAttributes() : GetNumPhysicalVaryings();
|
||||
}
|
||||
|
||||
u32 GetNumPhysicalAttributes() const {
|
||||
|
||||
@@ -257,6 +257,8 @@ vk::ShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage) {
|
||||
return vk::ShaderStageFlagBits::eGeometry;
|
||||
case Tegra::Engines::ShaderType::Fragment:
|
||||
return vk::ShaderStageFlagBits::eFragment;
|
||||
case Tegra::Engines::ShaderType::Compute:
|
||||
return vk::ShaderStageFlagBits::eCompute;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented shader stage={}", static_cast<u32>(stage));
|
||||
return {};
|
||||
@@ -399,6 +401,26 @@ vk::Format VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttr
|
||||
}
|
||||
break;
|
||||
case Maxwell::VertexAttribute::Type::SignedScaled:
|
||||
switch (size) {
|
||||
case Maxwell::VertexAttribute::Size::Size_8:
|
||||
return vk::Format::eR8Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_8_8:
|
||||
return vk::Format::eR8G8Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_8_8_8:
|
||||
return vk::Format::eR8G8B8Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
|
||||
return vk::Format::eR8G8B8A8Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_16:
|
||||
return vk::Format::eR16Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_16_16:
|
||||
return vk::Format::eR16G16Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_16_16_16:
|
||||
return vk::Format::eR16G16B16Sscaled;
|
||||
case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
|
||||
return vk::Format::eR16G16B16A16Sscaled;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Maxwell::VertexAttribute::Type::Float:
|
||||
switch (size) {
|
||||
|
||||
@@ -192,7 +192,6 @@ std::array<Shader, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
|
||||
|
||||
std::array<Shader, Maxwell::MaxShaderProgram> shaders;
|
||||
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
||||
const auto& shader_config = gpu.regs.shader_config[index];
|
||||
const auto program{static_cast<Maxwell::ShaderProgram>(index)};
|
||||
|
||||
// Skip stages that are not enabled
|
||||
|
||||
@@ -548,8 +548,6 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
|
||||
|
||||
// Verify that the cached surface is the same size and format as the requested framebuffer
|
||||
const auto& params{surface->GetSurfaceParams()};
|
||||
const auto& pixel_format{
|
||||
VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
|
||||
ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
|
||||
ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
|
||||
|
||||
|
||||
@@ -100,7 +100,6 @@ void VKStagingBufferPool::ReleaseCache(bool host_visible) {
|
||||
}
|
||||
|
||||
u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t log2) {
|
||||
static constexpr u64 epochs_to_destroy = 180;
|
||||
static constexpr std::size_t deletions_per_tick = 16;
|
||||
|
||||
auto& staging = cache[log2];
|
||||
@@ -108,6 +107,7 @@ u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t lo
|
||||
const std::size_t old_size = entries.size();
|
||||
|
||||
const auto is_deleteable = [this](const auto& entry) {
|
||||
static constexpr u64 epochs_to_destroy = 180;
|
||||
return entry.last_epoch + epochs_to_destroy < epoch && !entry.watch.IsUsed();
|
||||
};
|
||||
const std::size_t begin_offset = staging.delete_index;
|
||||
|
||||
@@ -52,6 +52,9 @@ vk::ImageType SurfaceTargetToImage(SurfaceTarget target) {
|
||||
return vk::ImageType::e2D;
|
||||
case SurfaceTarget::Texture3D:
|
||||
return vk::ImageType::e3D;
|
||||
case SurfaceTarget::TextureBuffer:
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
UNREACHABLE_MSG("Unknown texture target={}", static_cast<u32>(target));
|
||||
return {};
|
||||
@@ -273,7 +276,6 @@ void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) {
|
||||
|
||||
for (u32 level = 0; level < params.num_levels; ++level) {
|
||||
vk::BufferImageCopy copy = GetBufferImageCopy(level);
|
||||
const auto& dld = device.GetDispatchLoader();
|
||||
if (image->GetAspectMask() ==
|
||||
(vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil)) {
|
||||
vk::BufferImageCopy depth = copy;
|
||||
@@ -422,7 +424,6 @@ void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface,
|
||||
dst_base_layer, num_layers, copy_params.dest_level, 1, vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eTransferDstOptimal);
|
||||
|
||||
const auto& dld{device.GetDispatchLoader()};
|
||||
const vk::ImageSubresourceLayers src_subresource(
|
||||
src_surface->GetAspectMask(), copy_params.source_level, copy_params.source_z, num_layers);
|
||||
const vk::ImageSubresourceLayers dst_subresource(
|
||||
@@ -458,7 +459,6 @@ void VKTextureCache::ImageBlit(View& src_view, View& dst_view,
|
||||
dst_view->GetImageSubresourceLayers(), {dst_top_left, dst_bot_right});
|
||||
const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear;
|
||||
|
||||
const auto& dld{device.GetDispatchLoader()};
|
||||
scheduler.Record([src_image = src_view->GetImage(), dst_image = dst_view->GetImage(), blit,
|
||||
is_linear](auto cmdbuf, auto& dld) {
|
||||
cmdbuf.blitImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image,
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace VideoCommon::Shader {
|
||||
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::OpCode;
|
||||
using Tegra::Shader::PredCondition;
|
||||
|
||||
u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||
const Instruction instr = {program_code[pc]};
|
||||
@@ -30,7 +31,7 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||
const bool is_signed_b = instr.xmad.sign_b == 1;
|
||||
const bool is_signed_c = is_signed_a;
|
||||
|
||||
auto [is_merge, is_psl, is_high_b, mode, op_b,
|
||||
auto [is_merge, is_psl, is_high_b, mode, op_b_binding,
|
||||
op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> {
|
||||
switch (opcode->get().GetId()) {
|
||||
case OpCode::Id::XMAD_CR:
|
||||
@@ -63,15 +64,19 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||
}
|
||||
}();
|
||||
|
||||
op_a = BitfieldExtract(op_a, instr.xmad.high_a ? 16 : 0, 16);
|
||||
op_a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(op_a),
|
||||
instr.xmad.high_a ? Immediate(16) : Immediate(0), Immediate(16));
|
||||
|
||||
const Node original_b = op_b;
|
||||
op_b = BitfieldExtract(op_b, is_high_b ? 16 : 0, 16);
|
||||
const Node original_b = op_b_binding;
|
||||
const Node op_b =
|
||||
SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b_binding),
|
||||
is_high_b ? Immediate(16) : Immediate(0), Immediate(16));
|
||||
|
||||
// TODO(Rodrigo): Use an appropiate sign for this operation
|
||||
Node product = Operation(OperationCode::IMul, NO_PRECISE, op_a, op_b);
|
||||
// we already check sign_a and sign_b is difference or not before so just use one in here.
|
||||
Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b);
|
||||
if (is_psl) {
|
||||
product = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, product, Immediate(16));
|
||||
product =
|
||||
SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_a, product, Immediate(16));
|
||||
}
|
||||
SetTemporary(bb, 0, product);
|
||||
product = GetTemporary(0);
|
||||
@@ -88,12 +93,40 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||
return BitfieldExtract(original_c, 16, 16);
|
||||
case Tegra::Shader::XmadMode::CBcc: {
|
||||
const Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b,
|
||||
NO_PRECISE, original_b, Immediate(16));
|
||||
return SignedOperation(OperationCode::IAdd, is_signed_c, NO_PRECISE, original_c,
|
||||
shifted_b);
|
||||
original_b, Immediate(16));
|
||||
return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b);
|
||||
}
|
||||
case Tegra::Shader::XmadMode::CSfu: {
|
||||
const Node comp_a = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_a,
|
||||
op_a, Immediate(0));
|
||||
const Node comp_b = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_b,
|
||||
op_b, Immediate(0));
|
||||
const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b);
|
||||
|
||||
const Node comp_minus_a = GetPredicateComparisonInteger(
|
||||
PredCondition::NotEqual, is_signed_a,
|
||||
SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a,
|
||||
Immediate(0x80000000)),
|
||||
Immediate(0));
|
||||
const Node comp_minus_b = GetPredicateComparisonInteger(
|
||||
PredCondition::NotEqual, is_signed_b,
|
||||
SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b,
|
||||
Immediate(0x80000000)),
|
||||
Immediate(0));
|
||||
|
||||
Node new_c = Operation(
|
||||
OperationCode::Select, comp_minus_a,
|
||||
SignedOperation(OperationCode::IAdd, is_signed_c, original_c, Immediate(-65536)),
|
||||
original_c);
|
||||
new_c = Operation(
|
||||
OperationCode::Select, comp_minus_b,
|
||||
SignedOperation(OperationCode::IAdd, is_signed_c, new_c, Immediate(-65536)),
|
||||
std::move(new_c));
|
||||
|
||||
return Operation(OperationCode::Select, comp, original_c, std::move(new_c));
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unhandled XMAD mode: {}", static_cast<u32>(instr.xmad.mode.Value()));
|
||||
UNREACHABLE();
|
||||
return Immediate(0);
|
||||
}
|
||||
}();
|
||||
@@ -102,18 +135,19 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
|
||||
op_c = GetTemporary(1);
|
||||
|
||||
// TODO(Rodrigo): Use an appropiate sign for this operation
|
||||
Node sum = Operation(OperationCode::IAdd, product, op_c);
|
||||
Node sum = SignedOperation(OperationCode::IAdd, is_signed_a, product, std::move(op_c));
|
||||
SetTemporary(bb, 2, sum);
|
||||
sum = GetTemporary(2);
|
||||
if (is_merge) {
|
||||
const Node a = BitfieldExtract(sum, 0, 16);
|
||||
const Node b =
|
||||
Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, original_b, Immediate(16));
|
||||
sum = Operation(OperationCode::IBitwiseOr, NO_PRECISE, a, b);
|
||||
const Node a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(sum),
|
||||
Immediate(0), Immediate(16));
|
||||
const Node b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b, original_b,
|
||||
Immediate(16));
|
||||
sum = SignedOperation(OperationCode::IBitwiseOr, is_signed_a, a, b);
|
||||
}
|
||||
|
||||
SetInternalFlagsFromInteger(bb, sum, instr.generates_cc);
|
||||
SetRegister(bb, instr.gpr0, sum);
|
||||
SetRegister(bb, instr.gpr0, std::move(sum));
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ Node ShaderIR::GetPredicate(bool immediate) {
|
||||
}
|
||||
|
||||
Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
|
||||
MarkAttributeUsage(index, element);
|
||||
used_input_attributes.emplace(index);
|
||||
return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
|
||||
}
|
||||
@@ -106,42 +107,8 @@ Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_addres
|
||||
}
|
||||
|
||||
Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) {
|
||||
if (index == Attribute::Index::LayerViewportPointSize) {
|
||||
switch (element) {
|
||||
case 0:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case 1:
|
||||
uses_layer = true;
|
||||
break;
|
||||
case 2:
|
||||
uses_viewport_index = true;
|
||||
break;
|
||||
case 3:
|
||||
uses_point_size = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == Attribute::Index::TessCoordInstanceIDVertexID) {
|
||||
switch (element) {
|
||||
case 2:
|
||||
uses_instance_id = true;
|
||||
break;
|
||||
case 3:
|
||||
uses_vertex_id = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == Attribute::Index::ClipDistances0123 ||
|
||||
index == Attribute::Index::ClipDistances4567) {
|
||||
const auto clip_index =
|
||||
static_cast<u32>((index == Attribute::Index::ClipDistances4567 ? 1 : 0) + element);
|
||||
used_clip_distances.at(clip_index) = true;
|
||||
}
|
||||
MarkAttributeUsage(index, element);
|
||||
used_output_attributes.insert(index);
|
||||
|
||||
return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
|
||||
}
|
||||
|
||||
@@ -452,6 +419,54 @@ Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) {
|
||||
Immediate(bits));
|
||||
}
|
||||
|
||||
void ShaderIR::MarkAttributeUsage(Attribute::Index index, u64 element) {
|
||||
switch (index) {
|
||||
case Attribute::Index::LayerViewportPointSize:
|
||||
switch (element) {
|
||||
case 0:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case 1:
|
||||
uses_layer = true;
|
||||
break;
|
||||
case 2:
|
||||
uses_viewport_index = true;
|
||||
break;
|
||||
case 3:
|
||||
uses_point_size = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Attribute::Index::TessCoordInstanceIDVertexID:
|
||||
switch (element) {
|
||||
case 2:
|
||||
uses_instance_id = true;
|
||||
break;
|
||||
case 3:
|
||||
uses_vertex_id = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Attribute::Index::ClipDistances0123:
|
||||
case Attribute::Index::ClipDistances4567: {
|
||||
const u64 clip_index = (index == Attribute::Index::ClipDistances4567 ? 4 : 0) + element;
|
||||
used_clip_distances.at(clip_index) = true;
|
||||
break;
|
||||
}
|
||||
case Attribute::Index::FrontColor:
|
||||
case Attribute::Index::FrontSecondaryColor:
|
||||
case Attribute::Index::BackColor:
|
||||
case Attribute::Index::BackSecondaryColor:
|
||||
uses_legacy_varyings = true;
|
||||
break;
|
||||
default:
|
||||
if (index >= Attribute::Index::TexCoord_0 && index <= Attribute::Index::TexCoord_7) {
|
||||
uses_legacy_varyings = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t ShaderIR::DeclareAmend(Node new_amend) {
|
||||
const std::size_t id = amend_code.size();
|
||||
amend_code.push_back(new_amend);
|
||||
|
||||
@@ -137,6 +137,10 @@ public:
|
||||
return uses_vertex_id;
|
||||
}
|
||||
|
||||
bool UsesLegacyVaryings() const {
|
||||
return uses_legacy_varyings;
|
||||
}
|
||||
|
||||
bool UsesWarps() const {
|
||||
return uses_warps;
|
||||
}
|
||||
@@ -343,6 +347,9 @@ private:
|
||||
/// Inserts a sequence of bits from a node
|
||||
Node BitfieldInsert(Node base, Node insert, u32 offset, u32 bits);
|
||||
|
||||
/// Marks the usage of a input or output attribute.
|
||||
void MarkAttributeUsage(Tegra::Shader::Attribute::Index index, u64 element);
|
||||
|
||||
void WriteTexInstructionFloat(NodeBlock& bb, Tegra::Shader::Instruction instr,
|
||||
const Node4& components);
|
||||
|
||||
@@ -443,6 +450,7 @@ private:
|
||||
bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
|
||||
bool uses_instance_id{};
|
||||
bool uses_vertex_id{};
|
||||
bool uses_legacy_varyings{};
|
||||
bool uses_warps{};
|
||||
bool uses_indexed_samplers{};
|
||||
|
||||
|
||||
@@ -539,7 +539,7 @@ void Config::ReadDebuggingValues() {
|
||||
void Config::ReadServiceValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Services"));
|
||||
Settings::values.bcat_backend =
|
||||
ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("boxcat"))
|
||||
ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("null"))
|
||||
.toString()
|
||||
.toStdString();
|
||||
Settings::values.bcat_boxcat_local =
|
||||
@@ -682,6 +682,8 @@ void Config::ReadSystemValues() {
|
||||
|
||||
Settings::values.language_index = ReadSetting(QStringLiteral("language_index"), 1).toInt();
|
||||
|
||||
Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt();
|
||||
|
||||
const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool();
|
||||
if (rng_seed_enabled) {
|
||||
Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong();
|
||||
@@ -698,6 +700,8 @@ void Config::ReadSystemValues() {
|
||||
Settings::values.custom_rtc = std::nullopt;
|
||||
}
|
||||
|
||||
Settings::values.sound_index = ReadSetting(QStringLiteral("sound_index"), 1).toInt();
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
@@ -1114,6 +1118,7 @@ void Config::SaveSystemValues() {
|
||||
WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
|
||||
WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
|
||||
WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1);
|
||||
WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1);
|
||||
|
||||
WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false);
|
||||
WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0);
|
||||
@@ -1125,6 +1130,8 @@ void Config::SaveSystemValues() {
|
||||
Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
|
||||
0);
|
||||
|
||||
WriteSetting(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ void ConfigureSystem::SetConfiguration() {
|
||||
enabled = !Core::System::GetInstance().IsPoweredOn();
|
||||
|
||||
ui->combo_language->setCurrentIndex(Settings::values.language_index);
|
||||
ui->combo_region->setCurrentIndex(Settings::values.region_index);
|
||||
ui->combo_sound->setCurrentIndex(Settings::values.sound_index);
|
||||
|
||||
ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
|
||||
ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value());
|
||||
@@ -81,6 +83,8 @@ void ConfigureSystem::ApplyConfiguration() {
|
||||
}
|
||||
|
||||
Settings::values.language_index = ui->combo_language->currentIndex();
|
||||
Settings::values.region_index = ui->combo_region->currentIndex();
|
||||
Settings::values.sound_index = ui->combo_sound->currentIndex();
|
||||
|
||||
if (ui->rng_seed_checkbox->isChecked()) {
|
||||
Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16);
|
||||
|
||||
@@ -36,5 +36,6 @@ private:
|
||||
bool enabled = false;
|
||||
|
||||
int language_index = 0;
|
||||
int region_index = 0;
|
||||
int sound_index = 0;
|
||||
};
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
<string>System Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_sound">
|
||||
<property name="text">
|
||||
<string>Sound output mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_console_id">
|
||||
<property name="text">
|
||||
<string>Console ID:</string>
|
||||
@@ -128,14 +128,60 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_region">
|
||||
<property name="text">
|
||||
<string>Region:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="combo_region">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Japan</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>USA</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Europe</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Australia</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>China</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Korea</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Taiwan</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="rng_seed_checkbox">
|
||||
<property name="text">
|
||||
<string>RNG Seed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="combo_sound">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -161,7 +207,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="button_regenerate_console_id">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
@@ -177,14 +223,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="custom_rtc_checkbox">
|
||||
<property name="text">
|
||||
<string>Custom RTC</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QDateTimeEdit" name="custom_rtc_edit">
|
||||
<property name="minimumDate">
|
||||
<date>
|
||||
@@ -198,7 +244,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="rng_seed_edit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
|
||||
@@ -1716,11 +1716,6 @@ void GMainWindow::OnStartGame() {
|
||||
}
|
||||
|
||||
void GMainWindow::OnPauseGame() {
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
if (system.GetExitLock() && !ConfirmForceLockedExit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
emu_thread->SetRunning(false);
|
||||
|
||||
ui.action_Start->setEnabled(true);
|
||||
|
||||
@@ -452,7 +452,7 @@ void Config::ReadValues() {
|
||||
Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", "");
|
||||
|
||||
// Services
|
||||
Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "boxcat");
|
||||
Settings::values.bcat_backend = sdl2_config->Get("Services", "bcat_backend", "null");
|
||||
Settings::values.bcat_boxcat_local =
|
||||
sdl2_config->GetBoolean("Services", "bcat_boxcat_local", false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user