Compare commits

..

2 Commits

Author SHA1 Message Date
GPUCode
208e1a0aaf rasterizer_cache: Clear null surface to transparent 2024-01-21 13:22:35 +02:00
GPUCode
1247bff174 glsl_shader_gen: Remove invariant qualifier
* Causes visual regressions in Pokemon with RADV
2024-01-21 11:57:56 +02:00
3 changed files with 91 additions and 108 deletions

View File

@@ -10,6 +10,7 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/camera/factory.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/process.h"
@@ -76,10 +77,10 @@ constexpr std::array<int, 13> LATENCY_BY_FRAME_RATE{{
33, // Rate_30_To_10
}};
constexpr Result ResultInvalidEnumValue(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
constexpr Result ResultOutOfRange(ErrorDescription::OutOfRange, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
const Result ERROR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
const Result ERROR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::CAM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
void Module::PortConfig::Clear() {
completion_event->Clear();
@@ -260,32 +261,27 @@ void Module::Interface::StartCapture(Kernel::HLERequestContext& ctx) {
if (port_select.IsValid()) {
for (int i : port_select) {
auto& port = cam->ports[i];
if (port.is_busy) {
if (!cam->ports[i].is_busy) {
if (!cam->ports[i].is_active) {
// This doesn't return an error, but seems to put the camera in an undefined
// state
LOG_ERROR(Service_CAM, "port {} hasn't been activated", i);
} else {
cam->cameras[cam->ports[i].camera_id].impl->StartCapture();
cam->ports[i].is_busy = true;
if (cam->ports[i].is_pending_receiving) {
cam->ports[i].is_pending_receiving = false;
cam->StartReceiving(i);
}
}
} else {
LOG_WARNING(Service_CAM, "port {} already started", i);
continue;
}
if (!port.is_active) {
// This doesn't return an error, but seems to put the camera in an undefined
// state
LOG_ERROR(Service_CAM, "port {} hasn't been activated", i);
continue;
}
auto& camera = cam->cameras[port.camera_id];
if (!camera.impl) {
cam->LoadCameraImplementation(camera, port.camera_id);
}
camera.impl->StartCapture();
port.is_busy = true;
if (port.is_pending_receiving) {
port.is_pending_receiving = false;
cam->StartReceiving(i);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, port_select={}", port_select.m_val);
@@ -310,7 +306,7 @@ void Module::Interface::StopCapture(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, port_select={}", port_select.m_val);
@@ -332,7 +328,7 @@ void Module::Interface::IsBusy(Kernel::HLERequestContext& ctx) {
rb.Push(is_busy);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
}
@@ -360,7 +356,7 @@ void Module::Interface::GetVsyncInterruptEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(cam->ports[port].vsync_interrupt_event);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.PushCopyObjects<Kernel::Object>(nullptr);
}
@@ -378,7 +374,7 @@ void Module::Interface::GetBufferErrorInterruptEvent(Kernel::HLERequestContext&
rb.PushCopyObjects(cam->ports[port].buffer_error_interrupt_event);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.PushCopyObjects<Kernel::Object>(nullptr);
}
@@ -413,7 +409,7 @@ void Module::Interface::SetReceiving(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(port.completion_event);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.PushCopyObjects<Kernel::Object>(nullptr);
}
@@ -433,7 +429,7 @@ void Module::Interface::IsFinishedReceiving(Kernel::HLERequestContext& ctx) {
rb.Push(!is_busy);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
}
@@ -455,7 +451,7 @@ void Module::Interface::SetTransferLines(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_WARNING(Service_CAM, "(STUBBED) called, port_select={}, lines={}, width={}, height={}",
@@ -473,7 +469,7 @@ void Module::Interface::GetMaxLines(Kernel::HLERequestContext& ctx) {
constexpr u32 MIN_TRANSFER_UNIT = 256;
constexpr u32 MAX_BUFFER_SIZE = 2560;
if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
rb.Push(ResultOutOfRange);
rb.Push(ERROR_OUT_OF_RANGE);
rb.Skip(1, false);
} else {
u32 lines = MAX_BUFFER_SIZE / width;
@@ -484,7 +480,7 @@ void Module::Interface::GetMaxLines(Kernel::HLERequestContext& ctx) {
while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) {
--lines;
if (lines == 0) {
result = ResultOutOfRange;
result = ERROR_OUT_OF_RANGE;
break;
}
}
@@ -510,7 +506,7 @@ void Module::Interface::SetTransferBytes(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_WARNING(Service_CAM, "(STUBBED)called, port_select={}, bytes={}, width={}, height={}",
@@ -528,7 +524,7 @@ void Module::Interface::GetTransferBytes(Kernel::HLERequestContext& ctx) {
rb.Push(cam->ports[port].transfer_bytes);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
}
@@ -546,7 +542,7 @@ void Module::Interface::GetMaxBytes(Kernel::HLERequestContext& ctx) {
constexpr u32 MIN_TRANSFER_UNIT = 256;
constexpr u32 MAX_BUFFER_SIZE = 2560;
if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
rb.Push(ResultOutOfRange);
rb.Push(ERROR_OUT_OF_RANGE);
rb.Skip(1, false);
} else {
u32 bytes = MAX_BUFFER_SIZE;
@@ -575,7 +571,7 @@ void Module::Interface::SetTrimming(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, port_select={}, trim={}", port_select.m_val, trim);
@@ -592,7 +588,7 @@ void Module::Interface::IsTrimming(Kernel::HLERequestContext& ctx) {
rb.Push(cam->ports[port].is_trimming);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(1, false);
}
@@ -618,7 +614,7 @@ void Module::Interface::SetTrimmingParams(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, port_select={}, x0={}, y0={}, x1={}, y1={}", port_select.m_val,
@@ -639,7 +635,7 @@ void Module::Interface::GetTrimmingParams(Kernel::HLERequestContext& ctx) {
rb.Push(cam->ports[port].y1);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
rb.Skip(4, false);
}
@@ -665,7 +661,7 @@ void Module::Interface::SetTrimmingParamsCenter(Kernel::HLERequestContext& ctx)
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid port_select={}", port_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, port_select={}, trim_w={}, trim_h={}, cam_w={}, cam_h={}",
@@ -691,7 +687,7 @@ void Module::Interface::Activate(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
} else if (camera_select[0] && camera_select[1]) {
LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated");
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
} else {
if (camera_select[0]) {
cam->ActivatePort(0, 0);
@@ -706,7 +702,7 @@ void Module::Interface::Activate(Kernel::HLERequestContext& ctx) {
}
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}", camera_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}", camera_select.m_val);
@@ -732,7 +728,7 @@ void Module::Interface::SwitchContext(Kernel::HLERequestContext& ctx) {
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, context_select={}", camera_select.m_val,
@@ -742,29 +738,24 @@ void Module::Interface::SwitchContext(Kernel::HLERequestContext& ctx) {
void Module::Interface::FlipImage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const Flip flip = rp.PopEnum<Flip>();
const Flip flip = static_cast<Flip>(rp.Pop<u8>());
const ContextSet context_select(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int camera : camera_select) {
for (int context : context_select) {
camera.contexts[context].flip = flip;
if (camera.current_context != context) {
continue;
cam->cameras[camera].contexts[context].flip = flip;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetFlip(flip);
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetFlip(flip);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, flip={}, context_select={}",
@@ -785,24 +776,19 @@ void Module::Interface::SetDetailSize(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int camera : camera_select) {
for (int context : context_select) {
camera.contexts[context].resolution = resolution;
if (camera.current_context != context) {
continue;
cam->cameras[camera].contexts[context].resolution = resolution;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetResolution(resolution);
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetResolution(resolution);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM,
@@ -820,24 +806,19 @@ void Module::Interface::SetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int camera : camera_select) {
for (int context : context_select) {
camera.contexts[context].resolution = PRESET_RESOLUTION[size];
if (camera.current_context != context) {
continue;
cam->cameras[camera].contexts[context].resolution = PRESET_RESOLUTION[size];
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetResolution(PRESET_RESOLUTION[size]);
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetResolution(PRESET_RESOLUTION[size]);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, size={}, context_select={}",
@@ -847,22 +828,18 @@ void Module::Interface::SetSize(Kernel::HLERequestContext& ctx) {
void Module::Interface::SetFrameRate(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const FrameRate frame_rate = rp.PopEnum<FrameRate>();
const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid()) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
camera.frame_rate = frame_rate;
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetFrameRate(frame_rate);
for (int camera : camera_select) {
cam->cameras[camera].frame_rate = frame_rate;
cam->cameras[camera].impl->SetFrameRate(frame_rate);
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}", camera_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select={}, frame_rate={}",
@@ -872,29 +849,24 @@ void Module::Interface::SetFrameRate(Kernel::HLERequestContext& ctx) {
void Module::Interface::SetEffect(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const Effect effect = rp.PopEnum<Effect>();
const Effect effect = static_cast<Effect>(rp.Pop<u8>());
const ContextSet context_select(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int camera : camera_select) {
for (int context : context_select) {
camera.contexts[context].effect = effect;
if (camera.current_context != context) {
continue;
cam->cameras[camera].contexts[context].effect = effect;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetEffect(effect);
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetEffect(effect);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, effect={}, context_select={}",
@@ -904,29 +876,24 @@ void Module::Interface::SetEffect(Kernel::HLERequestContext& ctx) {
void Module::Interface::SetOutputFormat(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const CameraSet camera_select(rp.Pop<u8>());
const OutputFormat format = rp.PopEnum<OutputFormat>();
const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
const ContextSet context_select(rp.Pop<u8>());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
if (camera_select.IsValid() && context_select.IsValid()) {
for (int index : camera_select) {
auto& camera = cam->cameras[index];
for (int camera : camera_select) {
for (int context : context_select) {
camera.contexts[context].format = format;
if (camera.current_context != context) {
continue;
cam->cameras[camera].contexts[context].format = format;
if (cam->cameras[camera].current_context == context) {
cam->cameras[camera].impl->SetFormat(format);
}
if (!camera.impl) {
cam->LoadCameraImplementation(camera, index);
}
camera.impl->SetFormat(format);
}
}
rb.Push(ResultSuccess);
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", camera_select.m_val,
context_select.m_val);
rb.Push(ResultInvalidEnumValue);
rb.Push(ERROR_INVALID_ENUM_VALUE);
}
LOG_DEBUG(Service_CAM, "called, camera_select={}, format={}, context_select={}",
@@ -952,7 +919,7 @@ void Module::Interface::GetLatestVsyncTiming(Kernel::HLERequestContext& ctx) {
if (!port_select.IsSingle() || count > MaxVsyncTimings) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(ResultOutOfRange);
rb.Push(ERROR_OUT_OF_RANGE);
rb.PushStaticBuffer({}, 0);
return;
}
@@ -1036,7 +1003,7 @@ Result Module::SetPackageParameter(const PackageParameterType& package) {
} else {
LOG_ERROR(Service_CAM, "invalid camera_select={}, context_select={}", package.camera_select,
package.context_select);
return ResultInvalidEnumValue;
return ERROR_INVALID_ENUM_VALUE;
}
}

View File

@@ -67,6 +67,16 @@ RasterizerCache<T>::RasterizerCache(Memory::MemorySystem& memory_,
.wrap_s = TextureConfig::WrapMode::ClampToBorder,
.wrap_t = TextureConfig::WrapMode::ClampToBorder,
}));
auto& null_surface = slot_surfaces[NULL_SURFACE_ID];
runtime.ClearTexture(null_surface, {
.texture_level = 0,
.texture_rect = null_surface.GetScaledRect(),
.value =
{
.color = {0.f, 0.f, 0.f, 0.f},
},
});
}
template <class T>

View File

@@ -63,7 +63,13 @@ static std::string GetVertexInterfaceDeclaration(bool is_output, bool use_clip_p
if (is_output && separable_shader) {
// gl_PerVertex redeclaration is required for separate shader object
out += "out gl_PerVertex {\n";
// Apple Silicon GPU drivers optimize more aggressively, which can create
// too much variance and cause visual artifacting in games like Pokemon.
#ifdef __APPLE__
out += " invariant vec4 gl_Position;\n";
#else
out += " vec4 gl_Position;\n";
#endif
if (use_clip_planes) {
out += " float gl_ClipDistance[2];\n";
}