mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
Merge pull request #12905 from unknownbrackets/postshader
Allow chained post-processing shaders
This commit is contained in:
commit
7a6489ebb4
@ -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.
|
||||
@ -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);
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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") << ": ";
|
||||
|
@ -383,7 +383,7 @@ protected:
|
||||
|
||||
bool useBufferedRendering_ = false;
|
||||
bool postShaderIsUpscalingFilter_ = false;
|
||||
int postShaderSSAAFilterLevel_ = 0;
|
||||
bool postShaderIsSupersampling_ = false;
|
||||
|
||||
std::vector<VirtualFramebuffer *> vfbs_;
|
||||
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
|
||||
|
@ -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:");
|
||||
@ -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, "");
|
||||
@ -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) {
|
||||
@ -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.
|
||||
@ -167,7 +154,7 @@ 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];
|
||||
@ -175,6 +162,30 @@ const ShaderInfo *GetPostShaderInfo(std::string name) {
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
@ -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;
|
||||
@ -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();
|
||||
|
@ -139,17 +139,11 @@ void PresentationCommon::GetCardboardSettings(CardboardSettings *cardboardSettin
|
||||
cardboardSettings->screenHeight = cardboardScreenHeight;
|
||||
}
|
||||
|
||||
void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, bool hasVideo, PostShaderUniforms *uniforms) {
|
||||
void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms) {
|
||||
float u_delta = 1.0f / bufferWidth;
|
||||
float v_delta = 1.0f / bufferHeight;
|
||||
float u_pixel_delta = 1.0f / renderWidth_;
|
||||
float v_pixel_delta = 1.0f / renderHeight_;
|
||||
if (postShaderAtOutputResolution_) {
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
|
||||
u_pixel_delta = 1.0f / w;
|
||||
v_pixel_delta = 1.0f / h;
|
||||
}
|
||||
float u_pixel_delta = 1.0f / targetWidth;
|
||||
float v_pixel_delta = 1.0f / targetHeight;
|
||||
int flipCount = __DisplayGetFlipCount();
|
||||
int vCount = __DisplayGetVCount();
|
||||
float time[4] = { time_now(), (vCount % 60) * 1.0f / 60.0f, (float)vCount, (float)(flipCount % 60) };
|
||||
@ -159,16 +153,16 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer
|
||||
uniforms->pixelDelta[0] = u_pixel_delta;
|
||||
uniforms->pixelDelta[1] = v_pixel_delta;
|
||||
memcpy(uniforms->time, time, 4 * sizeof(float));
|
||||
uniforms->video = hasVideo;
|
||||
uniforms->video = hasVideo_ ? 1.0f : 0.0f;
|
||||
|
||||
// The shader translator tacks this onto our shaders, if we don't set it they render garbage.
|
||||
uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f;
|
||||
uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f;
|
||||
|
||||
uniforms->setting[0] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue1"];;
|
||||
uniforms->setting[1] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue2"];
|
||||
uniforms->setting[2] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue3"];
|
||||
uniforms->setting[3] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue4"];
|
||||
uniforms->setting[0] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue1"];;
|
||||
uniforms->setting[1] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue2"];
|
||||
uniforms->setting[2] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue3"];
|
||||
uniforms->setting[3] = g_Config.mPostShaderSetting[shaderInfo->section + "SettingValue4"];
|
||||
}
|
||||
|
||||
static std::string ReadShaderSrc(const std::string &filename) {
|
||||
@ -184,16 +178,29 @@ static std::string ReadShaderSrc(const std::string &filename) {
|
||||
|
||||
// Note: called on resize and settings changes.
|
||||
bool PresentationCommon::UpdatePostShader() {
|
||||
const ShaderInfo *shaderInfo = nullptr;
|
||||
std::vector<const ShaderInfo *> shaderInfo;
|
||||
if (g_Config.sPostShaderName != "Off") {
|
||||
ReloadAllPostShaderInfo();
|
||||
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
|
||||
shaderInfo = GetPostShaderChain(g_Config.sPostShaderName);
|
||||
}
|
||||
|
||||
DestroyPostShader();
|
||||
if (shaderInfo == nullptr)
|
||||
if (shaderInfo.empty())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < shaderInfo.size(); ++i) {
|
||||
const ShaderInfo *next = i + 1 < shaderInfo.size() ? shaderInfo[i + 1] : nullptr;
|
||||
if (!BuildPostShader(shaderInfo[i], next)) {
|
||||
DestroyPostShader();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
usePostShader_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresentationCommon::BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next) {
|
||||
std::string vsSourceGLSL = ReadShaderSrc(shaderInfo->vertexShaderFile);
|
||||
std::string fsSourceGLSL = ReadShaderSrc(shaderInfo->fragmentShaderFile);
|
||||
if (vsSourceGLSL.empty() || fsSourceGLSL.empty()) {
|
||||
@ -226,15 +233,42 @@ bool PresentationCommon::UpdatePostShader() {
|
||||
if (!pipeline)
|
||||
return false;
|
||||
|
||||
// No depth/stencil for post processing
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ (int)renderWidth_, (int)renderHeight_, 1, 1, false, Draw::FBO_8888 });
|
||||
if (fbo)
|
||||
postShaderFramebuffers_.push_back(fbo);
|
||||
if (!shaderInfo->outputResolution || next) {
|
||||
int nextWidth = renderWidth_;
|
||||
int nextHeight = renderHeight_;
|
||||
|
||||
// When chaining, we use the previous resolution as a base, rather than the render resolution.
|
||||
if (!postShaderFramebuffers_.empty())
|
||||
draw_->GetFramebufferDimensions(postShaderFramebuffers_.back(), &nextWidth, &nextHeight);
|
||||
|
||||
if (next && next->isUpscalingFilter) {
|
||||
// Force 1x for this shader, so the next can upscale.
|
||||
const bool isPortrait = g_Config.IsPortrait();
|
||||
nextWidth = isPortrait ? 272 : 480;
|
||||
nextHeight = isPortrait ? 480 : 272;
|
||||
} else if (next && next->SSAAFilterLevel >= 2) {
|
||||
// Increase the resolution this shader outputs for the next to SSAA.
|
||||
nextWidth *= next->SSAAFilterLevel;
|
||||
nextHeight *= next->SSAAFilterLevel;
|
||||
} else if (shaderInfo->outputResolution) {
|
||||
// If the current shader uses output res (not next), we will use output res for it.
|
||||
float x, y, w, h;
|
||||
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, g_Config.iInternalScreenRotation);
|
||||
nextWidth = (int)w;
|
||||
nextHeight = (int)h;
|
||||
}
|
||||
|
||||
// No depth/stencil for post processing
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ nextWidth, nextHeight, 1, 1, false, Draw::FBO_8888 });
|
||||
if (!fbo) {
|
||||
pipeline->Release();
|
||||
return false;
|
||||
}
|
||||
postShaderFramebuffers_.push_back(fbo);
|
||||
}
|
||||
|
||||
usePostShader_ = true;
|
||||
postShaderPipelines_.push_back(pipeline);
|
||||
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
|
||||
postShaderIsUpscalingFilter_ = shaderInfo->isUpscalingFilter;
|
||||
postShaderInfo_.push_back(*shaderInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -268,10 +302,6 @@ void PresentationCommon::ShowPostShaderError(const std::string &errorString) {
|
||||
}
|
||||
}
|
||||
|
||||
void PresentationCommon::UpdateShaderInfo(const ShaderInfo *shaderInfo) {
|
||||
postShaderAtOutputResolution_ = shaderInfo->outputResolution;
|
||||
}
|
||||
|
||||
void PresentationCommon::DeviceLost() {
|
||||
DestroyDeviceObjects();
|
||||
}
|
||||
@ -324,9 +354,9 @@ void PresentationCommon::CreateDeviceObjects() {
|
||||
using namespace Draw;
|
||||
|
||||
vdata_ = draw_->CreateBuffer(sizeof(Vertex) * 8, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);
|
||||
// TODO: Use 4 and a strip? shorts?
|
||||
idata_ = draw_->CreateBuffer(sizeof(uint16_t) * 6, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA);
|
||||
|
||||
// TODO: Use 4 and a strip?
|
||||
idata_ = draw_->CreateBuffer(sizeof(uint16_t) * 6, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA);
|
||||
uint16_t indexes[] = { 0, 1, 2, 0, 2, 3 };
|
||||
draw_->UpdateBuffer(idata_, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD);
|
||||
|
||||
@ -365,16 +395,17 @@ void PresentationCommon::DestroyDeviceObjects() {
|
||||
DoRelease(srcTexture_);
|
||||
DoRelease(srcFramebuffer_);
|
||||
|
||||
restorePostShader_ = usePostShader_;
|
||||
DestroyPostShader();
|
||||
}
|
||||
|
||||
void PresentationCommon::DestroyPostShader() {
|
||||
restorePostShader_ = usePostShader_;
|
||||
usePostShader_ = false;
|
||||
|
||||
DoReleaseVector(postShaderModules_);
|
||||
DoReleaseVector(postShaderPipelines_);
|
||||
DoReleaseVector(postShaderFramebuffers_);
|
||||
postShaderInfo_.clear();
|
||||
}
|
||||
|
||||
Draw::ShaderModule *PresentationCommon::CompileShaderModule(Draw::ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString) {
|
||||
@ -417,20 +448,24 @@ Draw::ShaderModule *PresentationCommon::CompileShaderModule(Draw::ShaderStage st
|
||||
return shader;
|
||||
}
|
||||
|
||||
void PresentationCommon::SourceTexture(Draw::Texture *texture) {
|
||||
void PresentationCommon::SourceTexture(Draw::Texture *texture, int bufferWidth, int bufferHeight) {
|
||||
DoRelease(srcTexture_);
|
||||
DoRelease(srcFramebuffer_);
|
||||
|
||||
texture->AddRef();
|
||||
srcTexture_ = texture;
|
||||
srcWidth_ = bufferWidth;
|
||||
srcHeight_ = bufferHeight;
|
||||
}
|
||||
|
||||
void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb) {
|
||||
void PresentationCommon::SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight) {
|
||||
DoRelease(srcTexture_);
|
||||
DoRelease(srcFramebuffer_);
|
||||
|
||||
fb->AddRef();
|
||||
srcFramebuffer_ = fb;
|
||||
srcWidth_ = bufferWidth;
|
||||
srcHeight_ = bufferHeight;
|
||||
}
|
||||
|
||||
void PresentationCommon::BindSource() {
|
||||
@ -443,7 +478,11 @@ void PresentationCommon::BindSource() {
|
||||
}
|
||||
}
|
||||
|
||||
void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1, const PostShaderUniforms &uniforms) {
|
||||
void PresentationCommon::UpdateUniforms(bool hasVideo) {
|
||||
hasVideo_ = hasVideo;
|
||||
}
|
||||
|
||||
void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) {
|
||||
// Make sure Direct3D 11 clears state, since we set shaders outside Draw.
|
||||
draw_->BindPipeline(nullptr);
|
||||
|
||||
@ -452,11 +491,11 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
// This should auto-disable usePostShader_ and call ShowPostShaderError().
|
||||
|
||||
bool useNearest = flags & OutputFlags::NEAREST;
|
||||
bool usePostShader = usePostShader_ && !(flags & OutputFlags::RB_SWIZZLE);
|
||||
const bool usePostShader = usePostShader_ && !(flags & OutputFlags::RB_SWIZZLE);
|
||||
const bool isFinalAtOutputResolution = usePostShader && postShaderFramebuffers_.size() < postShaderPipelines_.size();
|
||||
bool usePostShaderOutput = false;
|
||||
|
||||
CardboardSettings cardboardSettings;
|
||||
GetCardboardSettings(&cardboardSettings);
|
||||
int lastWidth = srcWidth_;
|
||||
int lastHeight = srcHeight_;
|
||||
|
||||
// These are the output coordinates.
|
||||
float x, y, w, h;
|
||||
@ -517,7 +556,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
}
|
||||
}
|
||||
|
||||
if (usePostShader && postShaderAtOutputResolution_) {
|
||||
if (isFinalAtOutputResolution) {
|
||||
// In this mode, we ignore the g_display_rot_matrix. Apply manually.
|
||||
if (g_display_rotation != DisplayRotation::ROTATE_0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -530,22 +569,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
}
|
||||
}
|
||||
|
||||
if (usePostShader && postShaderFramebuffers_.size() == 1 && !postShaderAtOutputResolution_) {
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffers_[0], { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
BindSource();
|
||||
|
||||
int fbo_w, fbo_h;
|
||||
draw_->GetFramebufferDimensions(postShaderFramebuffers_[0], &fbo_w, &fbo_h);
|
||||
Draw::Viewport viewport{ 0, 0, (float)fbo_w, (float)fbo_h, 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
draw_->SetScissorRect(0, 0, fbo_w, fbo_h);
|
||||
|
||||
draw_->BindPipeline(postShaderPipelines_.front());
|
||||
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
|
||||
Draw::SamplerState *sampler = useNearest ? samplerNearest_ : samplerLinear_;
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
if (usePostShader) {
|
||||
bool flipped = flags & OutputFlags::POSITION_FLIPPED;
|
||||
float post_v0 = !flipped ? 1.0f : 0.0f;
|
||||
float post_v1 = !flipped ? 0.0f : 1.0f;
|
||||
@ -553,25 +577,54 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
verts[5] = { -1, 1, 0, 0, post_v0, 0xFFFFFFFF }; // BL
|
||||
verts[6] = { 1, 1, 0, 1, post_v0, 0xFFFFFFFF }; // BR
|
||||
verts[7] = { 1, -1, 0, 1, post_v1, 0xFFFFFFFF }; // TR
|
||||
|
||||
draw_->UpdateBuffer(vdata_, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD);
|
||||
|
||||
draw_->BindVertexBuffers(0, 1, &vdata_, &postVertsOffset);
|
||||
draw_->BindIndexBuffer(idata_, 0);
|
||||
draw_->DrawIndexed(6, 0);
|
||||
draw_->BindIndexBuffer(nullptr, 0);
|
||||
for (size_t i = 0; i < postShaderFramebuffers_.size(); ++i) {
|
||||
Draw::Pipeline *postShaderPipeline = postShaderPipelines_[i];
|
||||
const ShaderInfo *shaderInfo = &postShaderInfo_[i];
|
||||
Draw::Framebuffer *postShaderFramebuffer = postShaderFramebuffers_[i];
|
||||
|
||||
usePostShaderOutput = true;
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
if (usePostShaderOutput) {
|
||||
draw_->BindFramebufferAsTexture(postShaderFramebuffers_[i - 1], 0, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
BindSource();
|
||||
}
|
||||
|
||||
int nextWidth, nextHeight;
|
||||
draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight);
|
||||
Draw::Viewport viewport{ 0, 0, (float)nextWidth, (float)nextHeight, 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
draw_->SetScissorRect(0, 0, nextWidth, nextHeight);
|
||||
|
||||
PostShaderUniforms uniforms;
|
||||
CalculatePostShaderUniforms(lastWidth, lastHeight, nextWidth, nextHeight, shaderInfo, &uniforms);
|
||||
|
||||
draw_->BindPipeline(postShaderPipeline);
|
||||
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
|
||||
Draw::SamplerState *sampler = useNearest || shaderInfo->isUpscalingFilter ? samplerNearest_ : samplerLinear_;
|
||||
draw_->BindSamplerStates(0, 1, &sampler);
|
||||
|
||||
draw_->BindVertexBuffers(0, 1, &vdata_, &postVertsOffset);
|
||||
draw_->BindIndexBuffer(idata_, 0);
|
||||
draw_->DrawIndexed(6, 0);
|
||||
draw_->BindIndexBuffer(nullptr, 0);
|
||||
|
||||
usePostShaderOutput = true;
|
||||
lastWidth = nextWidth;
|
||||
lastHeight = nextHeight;
|
||||
}
|
||||
|
||||
if (isFinalAtOutputResolution && postShaderInfo_.back().isUpscalingFilter)
|
||||
useNearest = true;
|
||||
} else {
|
||||
draw_->UpdateBuffer(vdata_, (const uint8_t *)verts, 0, postVertsOffset, Draw::UPDATE_DISCARD);
|
||||
}
|
||||
|
||||
if (postShaderIsUpscalingFilter_)
|
||||
useNearest = true;
|
||||
|
||||
Draw::Pipeline *pipeline = flags & OutputFlags::RB_SWIZZLE ? texColorRBSwizzle_ : texColor_;
|
||||
if (usePostShader && postShaderAtOutputResolution_) {
|
||||
pipeline = postShaderPipelines_.front();
|
||||
if (isFinalAtOutputResolution) {
|
||||
pipeline = postShaderPipelines_.back();
|
||||
}
|
||||
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
|
||||
@ -585,7 +638,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
BindSource();
|
||||
}
|
||||
|
||||
if (usePostShader && postShaderAtOutputResolution_) {
|
||||
if (isFinalAtOutputResolution) {
|
||||
PostShaderUniforms uniforms;
|
||||
CalculatePostShaderUniforms(lastWidth, lastHeight, (int)w, (int)h, &postShaderInfo_.back(), &uniforms);
|
||||
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
|
||||
} else {
|
||||
Draw::VsTexColUB ub{};
|
||||
@ -604,6 +659,8 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
draw_->SetViewports(1, &viewport);
|
||||
};
|
||||
|
||||
CardboardSettings cardboardSettings;
|
||||
GetCardboardSettings(&cardboardSettings);
|
||||
if (cardboardSettings.enabled) {
|
||||
// This is what the left eye sees.
|
||||
setViewport(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
@ -624,3 +681,52 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
||||
|
||||
draw_->BindPipeline(nullptr);
|
||||
}
|
||||
|
||||
void PresentationCommon::CalculateRenderResolution(int *width, int *height, bool *upscaling, bool *ssaa) {
|
||||
// Check if postprocessing shader is doing upscaling as it requires native resolution
|
||||
std::vector<const ShaderInfo *> shaderInfo;
|
||||
if (g_Config.sPostShaderName != "Off") {
|
||||
ReloadAllPostShaderInfo();
|
||||
shaderInfo = GetPostShaderChain(g_Config.sPostShaderName);
|
||||
}
|
||||
|
||||
bool firstIsUpscalingFilter = shaderInfo.empty() ? false : shaderInfo.front()->isUpscalingFilter;
|
||||
int firstSSAAFilterLevel = shaderInfo.empty() ? 0 : shaderInfo.front()->SSAAFilterLevel;
|
||||
|
||||
// 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 || firstSSAAFilterLevel >= 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 (firstSSAAFilterLevel >= 2)
|
||||
zoom *= firstSSAAFilterLevel;
|
||||
}
|
||||
if (zoom <= 1 || firstIsUpscalingFilter)
|
||||
zoom = 1;
|
||||
|
||||
if (upscaling) {
|
||||
*upscaling = firstIsUpscalingFilter;
|
||||
for (auto &info : shaderInfo) {
|
||||
*upscaling = *upscaling || info->isUpscalingFilter;
|
||||
}
|
||||
}
|
||||
if (ssaa) {
|
||||
*ssaa = firstSSAAFilterLevel >= 2;
|
||||
for (auto &info : shaderInfo) {
|
||||
*ssaa = *ssaa || info->SSAAFilterLevel >= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_Config.IsPortrait()) {
|
||||
*width = 272 * zoom;
|
||||
*height = 480 * zoom;
|
||||
} else {
|
||||
*width = 480 * zoom;
|
||||
*height = 272 * zoom;
|
||||
}
|
||||
}
|
||||
|
@ -91,17 +91,16 @@ public:
|
||||
}
|
||||
|
||||
bool UpdatePostShader();
|
||||
void UpdateShaderInfo(const ShaderInfo *shaderInfo);
|
||||
|
||||
void DeviceLost();
|
||||
void DeviceRestore(Draw::DrawContext *draw);
|
||||
|
||||
void GetCardboardSettings(CardboardSettings *cardboardSettings);
|
||||
void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, bool hasVideo, PostShaderUniforms *uniforms);
|
||||
void UpdateUniforms(bool hasVideo);
|
||||
void SourceTexture(Draw::Texture *texture, int bufferWidth, int bufferHeight);
|
||||
void SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight);
|
||||
void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1);
|
||||
|
||||
void SourceTexture(Draw::Texture *texture);
|
||||
void SourceFramebuffer(Draw::Framebuffer *fb);
|
||||
void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1, const PostShaderUniforms &uniforms);
|
||||
void CalculateRenderResolution(int *width, int *height, bool *upscaling, bool *ssaa);
|
||||
|
||||
protected:
|
||||
void CreateDeviceObjects();
|
||||
@ -112,9 +111,13 @@ protected:
|
||||
|
||||
Draw::ShaderModule *CompileShaderModule(Draw::ShaderStage stage, ShaderLanguage lang, const std::string &src, std::string *errorString);
|
||||
Draw::Pipeline *CreatePipeline(std::vector<Draw::ShaderModule *> shaders, bool postShader, const Draw::UniformBufferDesc *uniformDesc);
|
||||
bool BuildPostShader(const ShaderInfo *shaderInfo, const ShaderInfo *next);
|
||||
|
||||
void BindSource();
|
||||
|
||||
void GetCardboardSettings(CardboardSettings *cardboardSettings);
|
||||
void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int targetWidth, int targetHeight, const ShaderInfo *shaderInfo, PostShaderUniforms *uniforms);
|
||||
|
||||
Draw::DrawContext *draw_;
|
||||
Draw::Pipeline *texColor_ = nullptr;
|
||||
Draw::Pipeline *texColorRBSwizzle_ = nullptr;
|
||||
@ -126,9 +129,13 @@ protected:
|
||||
std::vector<Draw::ShaderModule *> postShaderModules_;
|
||||
std::vector<Draw::Pipeline *> postShaderPipelines_;
|
||||
std::vector<Draw::Framebuffer *> postShaderFramebuffers_;
|
||||
std::vector<ShaderInfo> postShaderInfo_;
|
||||
|
||||
Draw::Texture *srcTexture_ = nullptr;
|
||||
Draw::Framebuffer *srcFramebuffer_ = nullptr;
|
||||
int srcWidth_ = 0;
|
||||
int srcHeight_ = 0;
|
||||
bool hasVideo_ = false;
|
||||
|
||||
int pixelWidth_ = 0;
|
||||
int pixelHeight_ = 0;
|
||||
@ -137,7 +144,5 @@ protected:
|
||||
|
||||
bool usePostShader_ = false;
|
||||
bool restorePostShader_ = false;
|
||||
bool postShaderAtOutputResolution_ = false;
|
||||
bool postShaderIsUpscalingFilter_ = false;
|
||||
ShaderLanguage lang_;
|
||||
};
|
||||
|
@ -275,10 +275,8 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
||||
break;
|
||||
}
|
||||
|
||||
PostShaderUniforms uniforms{};
|
||||
presentation_->CalculatePostShaderUniforms(desc.width, desc.height, false, &uniforms);
|
||||
presentation_->SourceTexture(fbTex);
|
||||
presentation_->CopyToOutput(outputFlags, g_Config.iInternalScreenRotation, u0, v0, u1, v1, uniforms);
|
||||
presentation_->SourceTexture(fbTex, desc.width, desc.height);
|
||||
presentation_->CopyToOutput(outputFlags, g_Config.iInternalScreenRotation, u0, v0, u1, v1);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutput(bool reallyDirty) {
|
||||
|
@ -290,22 +290,15 @@ void GameSettingsScreen::CreateViews() {
|
||||
return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
});
|
||||
|
||||
const ShaderInfo *shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
|
||||
if (shaderInfo && !shaderInfo->settingName1.empty()) {
|
||||
auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue1"];
|
||||
graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue1, shaderInfo->maxSettingValue1, shaderInfo->settingName1, shaderInfo->settingStep1, screenManager()));
|
||||
}
|
||||
if (shaderInfo && !shaderInfo->settingName2.empty()) {
|
||||
auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue2"];
|
||||
graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue2, shaderInfo->maxSettingValue2, shaderInfo->settingName2, shaderInfo->settingStep2, screenManager()));
|
||||
}
|
||||
if (shaderInfo && !shaderInfo->settingName3.empty()) {
|
||||
auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue3"];
|
||||
graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue3, shaderInfo->maxSettingValue3, shaderInfo->settingName3, shaderInfo->settingStep3, screenManager()));
|
||||
}
|
||||
if (shaderInfo && !shaderInfo->settingName4.empty()) {
|
||||
auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue4"];
|
||||
graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue4, shaderInfo->maxSettingValue4, shaderInfo->settingName4, shaderInfo->settingStep4, screenManager()));
|
||||
auto shaderChain = GetPostShaderChain(g_Config.sPostShaderName);
|
||||
for (auto shaderInfo : shaderChain) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) {
|
||||
auto &setting = shaderInfo->settings[i];
|
||||
if (!setting.name.empty()) {
|
||||
auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)];
|
||||
graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
|
@ -306,6 +306,8 @@ PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title
|
||||
std::vector<std::string> items;
|
||||
int selected = -1;
|
||||
for (int i = 0; i < (int)shaders_.size(); i++) {
|
||||
if (!shaders_[i].visible)
|
||||
continue;
|
||||
if (shaders_[i].section == g_Config.sPostShaderName)
|
||||
selected = i;
|
||||
items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str()));
|
||||
|
@ -181,6 +181,8 @@ namespace MainWindow {
|
||||
|
||||
availableShaders.clear();
|
||||
for (auto i = info.begin(); i != info.end(); ++i) {
|
||||
if (!i->visible)
|
||||
continue;
|
||||
int checkedStatus = MF_UNCHECKED;
|
||||
availableShaders.push_back(i->section);
|
||||
if (g_Config.sPostShaderName == i->section) {
|
||||
|
Loading…
Reference in New Issue
Block a user