Add generic "PostShader" functionality, replacing FXAA (it's one of them).

Replaces #4018, sorry DanyalZia :)
This commit is contained in:
Henrik Rydgard 2013-10-12 02:05:55 +02:00
parent 1375b725a1
commit e0b19decca
23 changed files with 342 additions and 33 deletions

View File

@ -1001,6 +1001,8 @@ add_library(GPU OBJECT
GPU/Common/IndexGenerator.h
GPU/Common/TextureDecoder.cpp
GPU/Common/TextureDecoder.h
GPU/Common/PostShader.cpp
GPU/Common/PostShader.h
GPU/Common/SplineCommon.h
GPU/GLES/GLES_GPU.cpp
GPU/GLES/GLES_GPU.h

View File

@ -179,7 +179,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename)
graphics->Get("DisableStencilTest", &bDisableStencilTest, false);
graphics->Get("AlwaysDepthWrite", &bAlwaysDepthWrite, false);
graphics->Get("LowQualitySplineBezier", &bLowQualitySplineBezier, false);
graphics->Get("FXAA", &bFXAA, false);
graphics->Get("PostShader", &sPostShaderName, "Off");
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
sound->Get("Enable", &bEnableSound, true);
@ -349,7 +349,7 @@ void Config::Save() {
graphics->Set("DisableStencilTest", bDisableStencilTest);
graphics->Set("AlwaysDepthWrite", bAlwaysDepthWrite);
graphics->Set("LowQualitySplineBezier", bLowQualitySplineBezier);
graphics->Set("FXAA", bFXAA);
graphics->Set("PostShader", sPostShaderName);
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
sound->Set("Enable", bEnableSound);

View File

@ -94,7 +94,7 @@ public:
bool bDisableStencilTest;
bool bAlwaysDepthWrite;
bool bLowQualitySplineBezier;
bool bFXAA;
std::string sPostShaderName; // Off for off.
// Sound
bool bEnableSound;

109
GPU/Common/PostShader.cpp Normal file
View File

@ -0,0 +1,109 @@
// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// Postprocessing shader manager
#include <string>
#include <vector>
#include "base/logging.h"
#include "file/ini_file.h"
#include "file/file_util.h"
#include "file/vfs.h"
#include "GPU/Common/PostShader.h"
static std::vector<ShaderInfo> shaderInfo;
// Scans the directories for shader ini files and collects info about all the shaders found.
// Additionally, scan the VFS assets. (TODO)
void LoadPostShaderInfo(std::vector<std::string> directories) {
shaderInfo.clear();
ShaderInfo off;
off.name = "Off";
off.section = "Off";
shaderInfo.push_back(off);
for (size_t d = 0; d < directories.size(); d++) {
std::vector<FileInfo> fileInfo;
getFilesInDir(directories[d].c_str(), &fileInfo, "ini:");
if (fileInfo.size() == 0) {
// TODO: Really gotta fix the filter, now it's gonna open shaders as ini files..
VFSGetFileListing(directories[d].c_str(), &fileInfo, "ini:");
}
for (size_t f = 0; f < fileInfo.size(); f++) {
IniFile ini;
bool success = false;
std::string name = fileInfo[f].fullName;
std::string path = directories[d];
// Hack around Android VFS path bug. really need to redesign this.
if (name.substr(0, 7) == "assets/")
name = name.substr(7);
if (path.substr(0, 7) == "assets/")
path = path.substr(7);
if (!ini.LoadFromVFS(name)) {
// vsh load. meh.
} else {
success = true;
}
if (!success)
continue;
// Alright, let's loop through the sections and see if any is a shader.
// Ignore the first section (which only consists of the comments before the first real one).
for (size_t i = 1; i < ini.Sections().size(); i++) {
IniFile::Section &section = ini.Sections()[i];
if (section.Exists("Fragment") && section.Exists("Vertex")) {
// Valid shader!
ShaderInfo info;
std::string temp;
info.section = section.name();
section.Get("Name", &info.name, section.name().c_str());
section.Get("Fragment", &temp, "");
info.fragmentShaderFile = path + "/" + temp;
section.Get("Vertex", &temp, "");
info.vertexShaderFile = path + "/" + temp;
shaderInfo.push_back(info);
}
}
}
}
}
// Scans the directories for shader ini files and collects info about all the shaders found.
void LoadAllPostShaderInfo() {
std::vector<std::string> directories;
directories.push_back("assets/shaders");
LoadPostShaderInfo(directories);
}
const ShaderInfo *GetPostShaderInfo(std::string name) {
LoadAllPostShaderInfo();
for (size_t i = 0; i < shaderInfo.size(); i++) {
if (shaderInfo[i].section == name)
return &shaderInfo[i];
}
return 0;
}
const std::vector<ShaderInfo> &GetAllPostShaderInfo() {
LoadAllPostShaderInfo();
return shaderInfo;
}

41
GPU/Common/PostShader.h Normal file
View File

@ -0,0 +1,41 @@
// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// Postprocessing shader manager
// For FXAA, "Natural", bloom, B&W, cross processing and whatnot.
#include <string>
#include <vector>
#include "file/ini_file.h"
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. TODO: Not using yet.
std::string fragmentShaderFile;
std::string vertexShaderFile;
// TODO: Add support for all kinds of fun options like mapping the depth buffer,
// SRGB texture reads, multiple shaders chained, etc.
};
const ShaderInfo *GetPostShaderInfo(std::string name);
const std::vector<ShaderInfo> &GetAllPostShaderInfo();

View File

@ -29,6 +29,7 @@
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Common/PostShader.h"
#include "GPU/GLES/Framebuffer.h"
#include "GPU/GLES/TextureCache.h"
#include "GPU/GLES/ShaderManager.h"
@ -172,23 +173,31 @@ void FramebufferManager::CompileDraw2DProgram() {
glUniform1i(draw2dprogram_->sampler0, 0);
SetNumExtraFBOs(0);
if (g_Config.bFXAA) {
useFXAA_ = true;
fxaaProgram_ = glsl_create("shaders/fxaa.vsh", "shaders/fxaa.fsh");
if (!fxaaProgram_) {
ERROR_LOG(G3D, "Failed to build FXAA program");
useFXAA_ = false;
const ShaderInfo *shaderInfo = 0;
if (g_Config.sPostShaderName != "Off") {
shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName);
}
if (shaderInfo) {
postShaderProgram_ = glsl_create(shaderInfo->vertexShaderFile.c_str(), shaderInfo->fragmentShaderFile.c_str());
if (!postShaderProgram_) {
ERROR_LOG(G3D, "Failed to build post-processing program");
usePostShader_ = false;
} else {
glsl_bind(fxaaProgram_);
glUniform1i(fxaaProgram_->sampler0, 0);
glsl_bind(postShaderProgram_);
glUniform1i(postShaderProgram_->sampler0, 0);
SetNumExtraFBOs(1);
float u_delta = 1.0f / PSP_CoreParameter().renderWidth;
float v_delta = 1.0f / PSP_CoreParameter().renderHeight;
glUniform2f(glsl_uniform_loc(fxaaProgram_, "u_texcoordDelta"), u_delta, v_delta);
int deltaLoc = glsl_uniform_loc(postShaderProgram_, "u_texcoordDelta");
if (deltaLoc != -1)
glUniform2f(deltaLoc, u_delta, v_delta);
usePostShader_ = true;
}
} else {
fxaaProgram_ = 0;
useFXAA_ = false;
postShaderProgram_ = 0;
usePostShader_ = false;
}
glsl_unbind();
@ -200,9 +209,9 @@ void FramebufferManager::DestroyDraw2DProgram() {
glsl_destroy(draw2dprogram_);
draw2dprogram_ = 0;
}
if (fxaaProgram_) {
glsl_destroy(fxaaProgram_);
fxaaProgram_ = 0;
if (postShaderProgram_) {
glsl_destroy(postShaderProgram_);
postShaderProgram_ = 0;
}
}
@ -219,10 +228,10 @@ FramebufferManager::FramebufferManager() :
drawPixelsTexFormat_(GE_FORMAT_INVALID),
convBuf(0),
draw2dprogram_(0),
fxaaProgram_(0),
postShaderProgram_(0),
textureCache_(0),
shaderManager_(0),
useFXAA_(false)
usePostShader_(false)
#ifndef USING_GLES2
,
pixelBufObj_(0),
@ -812,7 +821,7 @@ void FramebufferManager::CopyDisplayToOutput() {
// TODO ES3: Use glInvalidateFramebuffer to discard depth/stencil data at the end of frame.
// and to discard extraFBOs_ after using them.
if (useFXAA_ && extraFBOs_.size() == 1) {
if (usePostShader_ && extraFBOs_.size() == 1) {
glBindTexture(GL_TEXTURE_2D, colorTexture);
// An additional pass, FXAA to the extra FBO.
@ -820,7 +829,7 @@ void FramebufferManager::CopyDisplayToOutput() {
int fbo_w, fbo_h;
fbo_get_dimensions(extraFBOs_[0], &fbo_w, &fbo_h);
glstate.viewport.set(0, 0, fbo_w, fbo_h);
DrawActiveTexture(0, 0, fbo_w, fbo_h, fbo_w, fbo_h, true, 1.0f, 1.0f, fxaaProgram_);
DrawActiveTexture(0, 0, fbo_w, fbo_h, fbo_w, fbo_h, true, 1.0f, 1.0f, postShaderProgram_);
fbo_unbind();

View File

@ -216,11 +216,11 @@ private:
u8 *convBuf;
GLSLProgram *draw2dprogram_;
GLSLProgram *fxaaProgram_;
GLSLProgram *postShaderProgram_;
TextureCache *textureCache_;
ShaderManager *shaderManager_;
bool useFXAA_;
bool usePostShader_;
// Used by antialiasing
std::vector<FBO *> extraFBOs_;

View File

@ -157,6 +157,7 @@
<ClInclude Include="..\ext\xbrz\xbrz.h" />
<ClInclude Include="Common\GPUDebugInterface.h" />
<ClInclude Include="Common\IndexGenerator.h" />
<ClInclude Include="Common\PostShader.h" />
<ClInclude Include="Common\SplineCommon.h" />
<ClInclude Include="Common\VertexDecoderCommon.h" />
<ClInclude Include="Directx9\GPU_DX9.h" />
@ -200,6 +201,7 @@
<ItemGroup>
<ClCompile Include="..\ext\xbrz\xbrz.cpp" />
<ClCompile Include="Common\IndexGenerator.cpp" />
<ClCompile Include="Common\PostShader.cpp" />
<ClCompile Include="Common\VertexDecoderCommon.cpp" />
<ClCompile Include="Directx9\GPU_DX9.cpp" />
<ClCompile Include="Directx9\helper\dx_state.cpp" />

View File

@ -147,6 +147,7 @@
<ClInclude Include="Common\SplineCommon.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\PostShader.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@ -266,6 +267,7 @@
<ClCompile Include="Common\TextureDecoder.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\PostShader.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -138,9 +138,12 @@ void GameSettingsScreen::CreateViews() {
graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gs->T("VSync")));
graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gs->T("FullScreen")));
#endif
graphicsSettings->Add(new ItemHeader(gs->T("Antialiasing")));
graphicsSettings->Add(new ItemHeader(gs->T("Antialiasing and postprocessing")));
graphicsSettings->Add(new Choice(gs->T("Postprocessing shader")))->OnClick.Handle(this, &GameSettingsScreen::OnPostProcShader);
// In case we're going to add few other antialiasing option like MSAA in the future.
graphicsSettings->Add(new CheckBox(&g_Config.bFXAA, gs->T("FXAA")));
// graphicsSettings->Add(new CheckBox(&g_Config.bFXAA, gs->T("FXAA")));
graphicsSettings->Add(new ItemHeader(gs->T("Overlay Information")));
graphicsSettings->Add(new PopupMultiChoice(&g_Config.iShowFPSCounter, gs->T("Show FPS Counter"), fpsChoices, 0, ARRAY_SIZE(fpsChoices), gs, screenManager()));
graphicsSettings->Add(new CheckBox(&g_Config.bShowDebugStats, gs->T("Show Debug Statistics")));
@ -443,6 +446,20 @@ UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnPostProcShader(UI::EventParams &e) {
I18NCategory *g = GetI18NCategory("Graphics");
auto procScreen = new PostProcScreen(g->T("Postprocessing Shader"));
procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange);
screenManager()->push(procScreen);
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) {
if (gpu) {
gpu->Resized();
}
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) {
screenManager()->push(new DeveloperToolsScreen());
return UI::EVENT_DONE;

View File

@ -56,6 +56,8 @@ private:
// Global settings handlers
UI::EventReturn OnLanguage(UI::EventParams &e);
UI::EventReturn OnLanguageChange(UI::EventParams &e);
UI::EventReturn OnPostProcShader(UI::EventParams &e);
UI::EventReturn OnPostProcShaderChange(UI::EventParams &e);
UI::EventReturn OnFactoryReset(UI::EventParams &e);
UI::EventReturn OnDeveloperTools(UI::EventParams &e);
UI::EventReturn OnChangeNickname(UI::EventParams &e);

View File

@ -145,6 +145,24 @@ UI::EventReturn PromptScreen::OnNo(UI::EventParams &e) {
return UI::EVENT_DONE;
}
PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title) {
shaders_ = GetAllPostShaderInfo();
std::vector<std::string> items;
int selected = -1;
for (int i = 0; i < shaders_.size(); i++) {
if (shaders_[i].section == g_Config.sPostShaderName)
selected = i;
items.push_back(shaders_[i].section);
}
adaptor_ = UI::StringVectorListAdaptor(items, selected);
}
void PostProcScreen::OnCompleted(DialogResult result) {
if (result != DR_OK)
return;
g_Config.sPostShaderName = shaders_[listView_->GetSelected()].section;
}
NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen(title) {
// Disable annoying encoding warning
#ifdef _MSC_VER

View File

@ -24,6 +24,7 @@
#include "base/functional.h"
#include "file/file_util.h"
#include "ui/ui_screen.h"
#include "GPU/Common/PostShader.h"
inline void NoOpVoidBool(bool) {}
@ -70,6 +71,16 @@ private:
std::vector<FileInfo> langs_;
};
class PostProcScreen : public ListPopupScreen {
public:
PostProcScreen(const std::string &title);
private:
virtual void OnCompleted(DialogResult result);
virtual bool ShowButtons() const { return true; }
std::vector<ShaderInfo> shaders_;
};
class LogoScreen : public UIScreen {
public:
LogoScreen(const std::string &bootFilename)

View File

@ -1224,11 +1224,13 @@ namespace MainWindow
g_Config.bVSync = !g_Config.bVSync;
break;
/* TODO: Add menus for post processing
case ID_OPTIONS_FXAA:
g_Config.bFXAA = !g_Config.bFXAA;
if (gpu)
gpu->Resized();
break;
*/
case ID_TEXTURESCALING_AUTO: setTexScalingMultiplier(TEXSCALING_AUTO); break;
case ID_TEXTURESCALING_OFF: setTexScalingMultiplier(TEXSCALING_OFF); break;
@ -1618,7 +1620,7 @@ namespace MainWindow
CHECKITEM(ID_OPTIONS_SHOWFPS, g_Config.iShowFPSCounter);
CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != 0);
CHECKITEM(ID_OPTIONS_VSYNC, g_Config.bVSync);
CHECKITEM(ID_OPTIONS_FXAA, g_Config.bFXAA);
// CHECKITEM(ID_OPTIONS_FXAA, g_Config.bFXAA); TODO: Replace with list of loaded post processing shaders
CHECKITEM(ID_OPTIONS_TOPMOST, g_Config.bTopMost);
CHECKITEM(ID_OPTIONS_PAUSE_FOCUS, g_Config.bPauseOnLostFocus);
CHECKITEM(ID_EMULATION_SOUND, g_Config.bEnableSound);

View File

@ -419,7 +419,7 @@ BEGIN
MENUITEM "Stretch to Display", ID_OPTIONS_STRETCHDISPLAY
MENUITEM "Fullscreen", ID_OPTIONS_FULLSCREEN
MENUITEM "VSync", ID_OPTIONS_VSYNC
MENUITEM "FXAA antialiasing", ID_OPTIONS_FXAA
MENUITEM "Postprocessing Shader", ID_OPTIONS_FXAA
POPUP "Rendering Resolution"
BEGIN
MENUITEM "Auto", ID_OPTIONS_SCREENAUTO

View File

@ -196,6 +196,7 @@ LOCAL_SRC_FILES := \
$(SRC)/GPU/Common/IndexGenerator.cpp.arm \
$(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \
$(SRC)/GPU/Common/TextureDecoder.cpp \
$(SRC)/GPU/Common/PostShader.cpp \
$(SRC)/GPU/GLES/Framebuffer.cpp \
$(SRC)/GPU/GLES/GLES_GPU.cpp.arm \
$(SRC)/GPU/GLES/TextureCache.cpp.arm \

View File

@ -1,6 +1,6 @@
APP_STL := gnustl_static
#APP_ABI := armeabi-v7a x86
APP_ABI := armeabi-v7a armeabi x86
#APP_ABI := armeabi-v7a
#APP_ABI := armeabi-v7a armeabi x86
APP_ABI := armeabi-v7a
APP_GNUSTL_CPP_FEATURES :=
NDK_TOOLCHAIN_VERSION := 4.8

View File

@ -0,0 +1,15 @@
# You can have multiple ini files if you want, it doesn't matter.
[FXAA]
Name=FXAA Antialiasing
Author=nVidia
Fragment=fxaa.fsh
Vertex=fxaa.vsh
[Natural]
Name=Natural Look
Fragment=natural.fsh
Vertex=natural.vsh
[Grayscale]
Name=Grayscale
Author=Henrik
Fragment=grayscale.fsh
Vertex=fxaa.vsh

View File

@ -0,0 +1,16 @@
// Simple grayscale shader
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform sampler2D sampler0;
varying vec2 v_texcoord0;
void main() {
vec3 rgb = texture2D(sampler0, v_texcoord0.xy).xyz;
float luma = dot(rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor.rgb = vec3(luma, luma, luma);
gl_FragColor.a = 1.0;
}

View File

@ -0,0 +1,48 @@
// Natural shader, GLSL code adapted from:
// http://forums.ngemu.com/showthread.php?t=76098
uniform sampler2D sampler0;
const mat3 RGBtoYIQ = mat3(0.299, 0.596, 0.212,
0.587,-0.275,-0.523,
0.114,-0.321, 0.311);
const mat3 YIQtoRGB = mat3(1.0, 1.0, 1.0,
0.95568806036115671171,-0.27158179694405859326,-1.1081773266826619523,
0.61985809445637075388,-0.64687381613840131330, 1.7050645599191817149);
const vec3 val00 = vec3( 1.2, 1.2, 1.2);
void main()
{
vec3 c0,c1;
c0 = texture2D(sampler0,gl_TexCoord[0].xy).xyz;
c0+=(texture2D(sampler0,gl_TexCoord[0].zy).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[0].xw).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[0].zw).xyz)*0.125;
c0+= texture2D(sampler0,gl_TexCoord[1].xy).xyz;
c0+=(texture2D(sampler0,gl_TexCoord[1].zy).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[1].xw).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[1].zw).xyz)*0.125;
c0+= texture2D(sampler0,gl_TexCoord[2].xy).xyz;
c0+=(texture2D(sampler0,gl_TexCoord[2].zy).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[2].xw).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[2].zw).xyz)*0.125;
c0+= texture2D(sampler0,gl_TexCoord[3].xy).xyz;
c0+=(texture2D(sampler0,gl_TexCoord[3].zy).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[3].xw).xyz)*0.25;
c0+=(texture2D(sampler0,gl_TexCoord[3].zw).xyz)*0.125;
c0*=0.153846153846;
c1=RGBtoYIQ*c0;
c1=vec3(pow(c1.x,val00.x),c1.yz*val00.yz);
gl_FragColor.xyz=YIQtoRGB*c1;
}

View File

@ -0,0 +1,14 @@
attribute vec4 a_position;
attribute vec2 a_texcoord0;
uniform mat4 u_viewproj;
varying vec2 v_texcoord0;
void main()
{
gl_Position=u_viewproj * a_position;
gl_TexCoord[0]=a_texcoord0.xyxy;
gl_TexCoord[1]=a_texcoord0.xyxy;
gl_TexCoord[2]=a_texcoord0.xyxy;
gl_TexCoord[3]=a_texcoord0.xyxy;
}

2
native

@ -1 +1 @@
Subproject commit b16b67d8b6e2fd5127f9b84ec9f5496d8f782e71
Subproject commit 5a4dec927289eb93fafc7bbd7facaee0c982accc