summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/gdbstub/gdbstub.cpp9
-rw-r--r--src/core/gdbstub/gdbstub.h7
-rw-r--r--src/core/hle/service/am/am.cpp42
-rw-r--r--src/core/hle/service/am/am.h3
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp6
-rw-r--r--src/core/hle/service/hid/hid.cpp9
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/sm/controller.cpp2
-rw-r--r--src/video_core/engines/const_buffer_engine_interface.h14
-rw-r--r--src/video_core/engines/maxwell_3d.cpp25
-rw-r--r--src/video_core/engines/maxwell_3d.h23
-rw-r--r--src/video_core/engines/shader_bytecode.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp67
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp20
-rw-r--r--src/video_core/shader/decode/xmad.cpp9
-rw-r--r--src/video_core/shader/shader_ir.cpp85
-rw-r--r--src/video_core/shader/shader_ir.h8
-rw-r--r--src/yuzu/main.cpp15
20 files changed, 285 insertions, 78 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 218508126..d1bc9340d 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -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()) {
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index e8d8871a7..6d15aeed9 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -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) {
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index 5a36524b2..8fe3c320b 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -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();
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d1bf13c89..557608e76 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -52,6 +52,11 @@ enum class LaunchParameterKind : u32 {
AccountPreselectedUser = 2,
};
+enum class VrMode : u8 {
+ Disabled = 0,
+ Enabled = 1,
+};
+
constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA;
struct LaunchParameterAccountPreselectedUser {
@@ -605,11 +610,11 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system,
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, nullptr, "GetReaderLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"},
- {50, nullptr, "IsVrModeEnabled"},
- {51, nullptr, "SetVrModeEnabled"},
+ {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
+ {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
{52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
{53, nullptr, "BeginVrModeEx"},
- {54, nullptr, "EndVrModeEx"},
+ {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
@@ -672,6 +677,30 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u8>(FocusState::InFocus));
}
+void ICommonStateGetter::IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushEnum(VrMode::Disabled);
+}
+
+void ICommonStateGetter::SetVrModeEnabled(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto is_vr_mode_enabled = rp.Pop<bool>();
+
+ LOG_WARNING(Service_AM, "(STUBBED) called. is_vr_mode_enabled={}", is_vr_mode_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ if (!is_vr_mode_enabled) {
+ rb.Push(RESULT_SUCCESS);
+ } else {
+ // TODO: Find better error code for this
+ UNIMPLEMENTED_MSG("is_vr_mode_enabled={}", is_vr_mode_enabled);
+ rb.Push(RESULT_UNKNOWN);
+ }
+}
+
void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
@@ -683,6 +712,13 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx
rb.Push(RESULT_SUCCESS);
}
+void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0843de781..53cfce10f 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -182,7 +182,10 @@ private:
void GetOperationMode(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
void GetBootMode(Kernel::HLERequestContext& ctx);
+ void IsVrModeEnabled(Kernel::HLERequestContext& ctx);
+ void SetVrModeEnabled(Kernel::HLERequestContext& ctx);
void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx);
+ void EndVrModeEx(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 12443c910..9f30e167d 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -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;
}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e6b56a9f9..d6ed5f304 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -235,7 +235,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{303, nullptr, "ActivateSevenSixAxisSensor"},
{304, nullptr, "StartSevenSixAxisSensor"},
{305, nullptr, "StopSevenSixAxisSensor"},
- {306, nullptr, "InitializeSevenSixAxisSensor"},
+ {306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
{307, nullptr, "FinalizeSevenSixAxisSensor"},
{308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
{309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
@@ -853,6 +853,13 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
}
+void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
class HidDbg final : public ServiceFramework<HidDbg> {
public:
explicit HidDbg() : ServiceFramework{"hid:dbg"} {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index ad20f147c..039c38b58 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -128,6 +128,7 @@ private:
void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
+ void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
std::shared_ptr<IAppletResource> applet_resource;
Core::System& system;
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index c45b285f8..9cca84b31 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -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") {
diff --git a/src/video_core/engines/const_buffer_engine_interface.h b/src/video_core/engines/const_buffer_engine_interface.h
index 724ee0fd6..ebe139504 100644
--- a/src/video_core/engines/const_buffer_engine_interface.h
+++ b/src/video_core/engines/const_buffer_engine_interface.h
@@ -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:
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index ce536e29b..ba63b44b4 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -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();
}
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 8a9e9992e..d24c9f657 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -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);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index eba42deb4..49dc5abe0 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -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,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 063f41327..826eee7df 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -933,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);
}
}
}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 2c38f57fd..8aa4a7ac9 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -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);
@@ -498,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");
@@ -561,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);
}
@@ -617,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;
@@ -1128,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:
@@ -1168,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));
@@ -1206,11 +1235,12 @@ 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 {};
@@ -1228,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 {};
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index f93447610..7480cb7c3 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -401,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) {
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp
index fbd7e9a17..6191ffba1 100644
--- a/src/video_core/shader/decode/xmad.cpp
+++ b/src/video_core/shader/decode/xmad.cpp
@@ -31,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:
@@ -67,9 +67,10 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
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 = SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b),
- is_high_b ? Immediate(16) : Immediate(0), Immediate(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));
// 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);
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index 425927777..baf7188d2 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -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);
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index dde036b40..80fc9b82c 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -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{};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 47615adfe..d7e59d0cd 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1034,6 +1034,14 @@ void GMainWindow::BootGame(const QString& filename) {
}
void GMainWindow::ShutdownGame() {
+ if (!emulation_running) {
+ return;
+ }
+
+ if (ui.action_Fullscreen->isChecked()) {
+ HideFullscreen();
+ }
+
AllowOSSleep();
discord_rpc->Pause();
@@ -1716,11 +1724,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);
@@ -1803,7 +1806,7 @@ void GMainWindow::ToggleWindowMode() {
// Render in the main window...
render_window->BackupGeometry();
ui.horizontalLayout->addWidget(render_window);
- render_window->setFocusPolicy(Qt::ClickFocus);
+ render_window->setFocusPolicy(Qt::StrongFocus);
if (emulation_running) {
render_window->setVisible(true);
render_window->setFocus();