Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow chained post-processing shaders #12905

Merged
merged 11 commits into from
May 17, 2020
54 changes: 12 additions & 42 deletions GPU/Common/FramebufferCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,10 +791,9 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
flags |= OutputFlags::POSITION_FLIPPED;
}

PostShaderUniforms uniforms{};
presentation_->CalculatePostShaderUniforms(512, 272, textureCache_->VideoIsPlaying(), &uniforms);
presentation_->SourceTexture(pixelsTex);
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1, uniforms);
presentation_->UpdateUniforms(textureCache_->VideoIsPlaying());
presentation_->SourceTexture(pixelsTex, 512, 272);
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1);
pixelsTex->Release();

// PresentationCommon sets all kinds of state, we can't rely on anything.
Expand Down Expand Up @@ -954,12 +953,11 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
flags |= OutputFlags::POSITION_FLIPPED;
}

PostShaderUniforms uniforms{};
int actualWidth = (vfb->bufferWidth * vfb->renderWidth) / vfb->width;
int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
presentation_->CalculatePostShaderUniforms(actualWidth, actualHeight, textureCache_->VideoIsPlaying(), &uniforms);
presentation_->SourceFramebuffer(vfb->fbo);
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1, uniforms);
presentation_->UpdateUniforms(textureCache_->VideoIsPlaying());
presentation_->SourceFramebuffer(vfb->fbo, actualWidth, actualHeight);
presentation_->CopyToOutput(flags, uvRotation, u0, v0, u1, v1);
} else if (useBufferedRendering_) {
WARN_LOG(FRAMEBUF, "Current VFB lacks an FBO: %08x", vfb->fb_address);
}
Expand Down Expand Up @@ -1671,41 +1669,13 @@ void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) {
}

void FramebufferManagerCommon::Resized() {
// Check if postprocessing shader is doing upscaling as it requires native resolution
const ShaderInfo *shaderInfo = nullptr;
if (g_Config.sPostShaderName != "Off") {
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
}

postShaderIsUpscalingFilter_ = shaderInfo ? shaderInfo->isUpscalingFilter : false;
postShaderSSAAFilterLevel_ = shaderInfo ? shaderInfo->SSAAFilterLevel : 0;

// Actually, auto mode should be more granular...
// Round up to a zoom factor for the render size.
int zoom = g_Config.iInternalResolution;
if (zoom == 0 || postShaderSSAAFilterLevel_ >= 2) {
// auto mode, use the longest dimension
if (!g_Config.IsPortrait()) {
zoom = (PSP_CoreParameter().pixelWidth + 479) / 480;
} else {
zoom = (PSP_CoreParameter().pixelHeight + 479) / 480;
}
if (postShaderSSAAFilterLevel_ >= 2)
zoom *= postShaderSSAAFilterLevel_;
}
if (zoom <= 1 || postShaderIsUpscalingFilter_)
zoom = 1;

if (g_Config.IsPortrait()) {
PSP_CoreParameter().renderWidth = 272 * zoom;
PSP_CoreParameter().renderHeight = 480 * zoom;
} else {
PSP_CoreParameter().renderWidth = 480 * zoom;
PSP_CoreParameter().renderHeight = 272 * zoom;
}

gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB;

int w, h;
presentation_->CalculateRenderResolution(&w, &h, &postShaderIsUpscalingFilter_, &postShaderIsSupersampling_);
PSP_CoreParameter().renderWidth = w;
PSP_CoreParameter().renderHeight = h;

if (UpdateSize()) {
DestroyAllFBOs();
}
Expand Down Expand Up @@ -1787,7 +1757,7 @@ void FramebufferManagerCommon::ShowScreenResolution() {
messageStream << PSP_CoreParameter().renderWidth << "x" << PSP_CoreParameter().renderHeight << " ";
if (postShaderIsUpscalingFilter_) {
messageStream << gr->T("(upscaling)") << " ";
} else if (postShaderSSAAFilterLevel_ >= 2) {
} else if (postShaderIsSupersampling_) {
messageStream << gr->T("(supersampling)") << " ";
}
messageStream << gr->T("Window Size") << ": ";
Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/FramebufferCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ class FramebufferManagerCommon {

bool useBufferedRendering_ = false;
bool postShaderIsUpscalingFilter_ = false;
int postShaderSSAAFilterLevel_ = 0;
bool postShaderIsSupersampling_ = false;

std::vector<VirtualFramebuffer *> vfbs_;
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
Expand Down
129 changes: 70 additions & 59 deletions GPU/Common/PostShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,36 +36,30 @@ static std::vector<ShaderInfo> shaderInfo;
// Additionally, scan the VFS assets. (TODO)

void LoadPostShaderInfo(std::vector<std::string> directories) {
std::vector<ShaderInfo> notVisible;

shaderInfo.clear();
ShaderInfo off;
ShaderInfo off{};
off.visible = true;
off.name = "Off";
off.section = "Off";
off.outputResolution = false;
off.isUpscalingFilter = false;
off.SSAAFilterLevel = 0;
off.requires60fps = false;
off.settingName1 = "";
off.settingValue1 = 0.0f;
off.minSettingValue1 = -1.0f;
off.maxSettingValue1 = 1.0f;
off.settingStep1 = 0.01f;
off.settingName2 = "";
off.settingValue2 = 0.0f;
off.minSettingValue2 = -1.0f;
off.maxSettingValue2 = 1.0f;
off.settingStep2 = 0.01f;
off.settingName3 = "";
off.settingValue3 = 0.0f;
off.minSettingValue3 = -1.0f;
off.maxSettingValue3 = 1.0f;
off.settingStep3 = 0.01f;
off.settingName4 = "";
off.settingValue4 = 0.0f;
off.minSettingValue4 = -1.0f;
off.maxSettingValue4 = 1.0f;
off.settingStep4 = 0.01f;
for (size_t i = 0; i < ARRAY_SIZE(off.settings); ++i) {
off.settings[i].name = "";
off.settings[i].value = 0.0f;
off.settings[i].minValue = -1.0f;
off.settings[i].maxValue = 1.0f;
off.settings[i].step = 0.01f;
}
shaderInfo.push_back(off);

auto appendShader = [&](const ShaderInfo &info) {
auto beginErase = std::remove(shaderInfo.begin(), shaderInfo.end(), info.name);
if (beginErase != shaderInfo.end()) {
shaderInfo.erase(beginErase, shaderInfo.end());
}
shaderInfo.push_back(info);
};

for (size_t d = 0; d < directories.size(); d++) {
std::vector<FileInfo> fileInfo;
getFilesInDir(directories[d].c_str(), &fileInfo, "ini:");
Expand Down Expand Up @@ -102,6 +96,8 @@ void LoadPostShaderInfo(std::vector<std::string> directories) {
std::string temp;
info.section = section.name();
section.Get("Name", &info.name, section.name().c_str());
section.Get("Parent", &info.parent, "");
section.Get("Visible", &info.visible, true);
section.Get("Fragment", &temp, "");
info.fragmentShaderFile = path + "/" + temp;
section.Get("Vertex", &temp, "");
Expand All @@ -110,35 +106,21 @@ void LoadPostShaderInfo(std::vector<std::string> directories) {
section.Get("Upscaling", &info.isUpscalingFilter, false);
section.Get("SSAA", &info.SSAAFilterLevel, 0);
section.Get("60fps", &info.requires60fps, false);
section.Get("SettingName1", &info.settingName1, "");
section.Get("SettingDefaultValue1", &info.settingValue1, 0.0f);
section.Get("SettingMinValue1", &info.minSettingValue1, -1.0f);
section.Get("SettingMaxValue1", &info.maxSettingValue1, 1.0f);
section.Get("SettingStep1", &info.settingStep1, 0.01f);
section.Get("SettingName2", &info.settingName2, "");
section.Get("SettingDefaultValue2", &info.settingValue2, 0.0f);
section.Get("SettingMinValue2", &info.minSettingValue2, -1.0f);
section.Get("SettingMaxValue2", &info.maxSettingValue2, 1.0f);
section.Get("SettingStep2", &info.settingStep2, 0.01f);
section.Get("SettingName3", &info.settingName3, "");
section.Get("SettingDefaultValue3", &info.settingValue3, 0.0f);
section.Get("SettingMinValue3", &info.minSettingValue3, -1.0f);
section.Get("SettingMaxValue3", &info.maxSettingValue3, 1.0f);
section.Get("SettingStep3", &info.settingStep3, 0.01f);
section.Get("SettingName4", &info.settingName4, "");
section.Get("SettingDefaultValue4", &info.settingValue4, 0.0f);
section.Get("SettingMinValue4", &info.minSettingValue4, -1.0f);
section.Get("SettingMaxValue4", &info.maxSettingValue4, 1.0f);
section.Get("SettingStep4", &info.settingStep4, 0.01f);

if (g_Config.mPostShaderSetting.find(info.section + "SettingValue1") == g_Config.mPostShaderSetting.end())
g_Config.mPostShaderSetting.insert(std::pair<std::string, float>(info.section + "SettingValue1", info.settingValue1));
if (g_Config.mPostShaderSetting.find(info.section + "SettingValue2") == g_Config.mPostShaderSetting.end())
g_Config.mPostShaderSetting.insert(std::pair<std::string, float>(info.section + "SettingValue2", info.settingValue2));
if (g_Config.mPostShaderSetting.find(info.section + "SettingValue3") == g_Config.mPostShaderSetting.end())
g_Config.mPostShaderSetting.insert(std::pair<std::string, float>(info.section + "SettingValue3", info.settingValue3));
if (g_Config.mPostShaderSetting.find(info.section + "SettingValue4") == g_Config.mPostShaderSetting.end())
g_Config.mPostShaderSetting.insert(std::pair<std::string, float>(info.section + "SettingValue4", info.settingValue4));

for (size_t i = 0; i < ARRAY_SIZE(info.settings); ++i) {
auto &setting = info.settings[i];
section.Get(StringFromFormat("SettingName%d", i + 1).c_str(), &setting.name, "");
section.Get(StringFromFormat("SettingDefaultValue%d", i + 1).c_str(), &setting.value, 0.0f);
section.Get(StringFromFormat("SettingMinValue%d", i + 1).c_str(), &setting.minValue, -1.0f);
section.Get(StringFromFormat("SettingMaxValue%d", i + 1).c_str(), &setting.maxValue, 1.0f);
section.Get(StringFromFormat("SettingStep%d", i + 1).c_str(), &setting.step, 0.01f);

// Populate the default setting value.
std::string section = StringFromFormat("%sSettingValue%d", info.section.c_str(), i + 1);
if (!setting.name.empty() && g_Config.mPostShaderSetting.find(section) == g_Config.mPostShaderSetting.end()) {
g_Config.mPostShaderSetting.insert(std::pair<std::string, float>(section, setting.value));
}
}

// Let's ignore shaders we can't support. TODO: Not a very good check
if (gl_extensions.IsGLES && !gl_extensions.GLES3) {
Expand All @@ -148,15 +130,20 @@ void LoadPostShaderInfo(std::vector<std::string> directories) {
continue;
}

auto beginErase = std::find(shaderInfo.begin(), shaderInfo.end(), info.name);
if (beginErase != shaderInfo.end()) {
shaderInfo.erase(beginErase, shaderInfo.end());
if (info.visible) {
appendShader(info);
} else {
notVisible.push_back(info);
}
shaderInfo.push_back(info);
}
}
}
}

// We always want the not visible ones at the end. Makes menus easier.
for (const auto &info : notVisible) {
appendShader(info);
}
}

// Scans the directories for shader ini files and collects info about all the shaders found.
Expand All @@ -167,14 +154,38 @@ void ReloadAllPostShaderInfo() {
LoadPostShaderInfo(directories);
}

const ShaderInfo *GetPostShaderInfo(std::string name) {
const ShaderInfo *GetPostShaderInfo(const std::string &name) {
for (size_t i = 0; i < shaderInfo.size(); i++) {
if (shaderInfo[i].section == name)
return &shaderInfo[i];
}
return nullptr;
}

std::vector<const ShaderInfo *> GetPostShaderChain(const std::string &name) {
std::vector<const ShaderInfo *> backwards;
const ShaderInfo *shaderInfo = GetPostShaderInfo(name);
while (shaderInfo) {
backwards.push_back(shaderInfo);

if (!shaderInfo->parent.empty() && shaderInfo->parent != "Off") {
shaderInfo = GetPostShaderInfo(shaderInfo->parent);
} else {
shaderInfo = nullptr;
}
auto dup = std::find(backwards.begin(), backwards.end(), shaderInfo);
if (dup != backwards.end()) {
// Don't loop forever.
break;
}
}

if (!backwards.empty())
std::reverse(backwards.begin(), backwards.end());
// Not backwards anymore.
return backwards;
}

const std::vector<ShaderInfo> &GetAllPostShaderInfo() {
return shaderInfo;
}
36 changes: 14 additions & 22 deletions GPU/Common/PostShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ struct ShaderInfo {
std::string iniFile; // which ini file was this definition in? So we can write settings back later
std::string section; // ini file section. This is saved.
std::string name; // Fancy display name.
std::string parent; // Parent shader ini section name.

std::string fragmentShaderFile;
std::string vertexShaderFile;

// Show this shader in lists (i.e. not just for chaining.)
bool visible;
// Run at output instead of input resolution
bool outputResolution;
// Use x1 rendering res + nearest screen scaling filter
Expand All @@ -41,29 +44,17 @@ struct ShaderInfo {
// Force constant/max refresh for animated filters
bool requires60fps;

std::string settingName1;
float settingValue1;
float maxSettingValue1;
float minSettingValue1;
float settingStep1;
std::string settingName2;
float settingValue2;
float maxSettingValue2;
float minSettingValue2;
float settingStep2;
std::string settingName3;
float settingValue3;
float maxSettingValue3;
float minSettingValue3;
float settingStep3;
std::string settingName4;
float settingValue4;
float maxSettingValue4;
float minSettingValue4;
float settingStep4;
struct Setting {
std::string name;
float value;
float maxValue;
float minValue;
float step;
};
Setting settings[4];

// TODO: Add support for all kinds of fun options like mapping the depth buffer,
// SRGB texture reads, multiple shaders chained, etc.
// SRGB texture reads, etc.

bool operator == (const std::string &other) {
return name == other;
Expand All @@ -75,5 +66,6 @@ struct ShaderInfo {

void ReloadAllPostShaderInfo();

const ShaderInfo *GetPostShaderInfo(std::string name);
const ShaderInfo *GetPostShaderInfo(const std::string &name);
std::vector<const ShaderInfo *> GetPostShaderChain(const std::string &name);
const std::vector<ShaderInfo> &GetAllPostShaderInfo();
Loading