Merge pull request #12905 from unknownbrackets/postshader

Allow chained post-processing shaders
This commit is contained in:
Henrik Rydgård 2020-05-17 16:09:05 +02:00 committed by GitHub
commit 7a6489ebb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 297 additions and 218 deletions

View File

@ -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") << ": ";

View File

@ -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)

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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_;
};

View File

@ -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) {

View File

@ -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)

View File

@ -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()));

View File

@ -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) {