Write rough framework for GPU discard test screen

This commit is contained in:
Henrik Rydgård 2018-12-16 21:48:35 +01:00
parent 8686960180
commit df98721e73
15 changed files with 271 additions and 17 deletions

View File

@ -127,8 +127,6 @@ UI::EventReturn DevMenu::OnShaderView(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn DevMenu::OnFreezeFrame(UI::EventParams &e) {
if (PSP_CoreParameter().frozen) {
PSP_CoreParameter().frozen = false;

178
UI/GPUDriverTestScreen.cpp Normal file
View File

@ -0,0 +1,178 @@
#include "GPUDriverTestScreen.h"
#include "i18n/i18n.h"
#include "ui/view.h"
static const std::vector<Draw::ShaderSource> fsDiscard = {
{Draw::ShaderLanguage::GLSL_ES_200,
R"(varying vec4 oColor0;
varying vec2 oTexCoord0;
uniform sampler2D Sampler0;
void main() {
vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
gl_FragColor = color;
})"
},
{Draw::ShaderLanguage::GLSL_VULKAN,
R"(layout(location = 0) in vec4 oColor0;
layout(location = 1) in vec2 oTexCoord0;
layout(location = 0) out vec4 fragColor0;
layout(set = 0, binding = 1) uniform sampler2D Sampler0;
void main() {
vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
fragColor0 = color;
})"
},
};
GPUDriverTestScreen::GPUDriverTestScreen() {
using namespace Draw;
}
GPUDriverTestScreen::~GPUDriverTestScreen() {
if (discardWriteStencil_)
discardWriteStencil_->Release();
if (drawTestStencil_)
drawTestStencil_->Release();
if (drawTestDepth_)
drawTestDepth_->Release();
if (discard_)
discard_->Release();
if (samplerNearest_)
samplerNearest_->Release();
}
void GPUDriverTestScreen::CreateViews() {
// Don't bother with views for now.
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *cr = GetI18NCategory("PSPCredits");
auto tabs = new TabHolder(UI::ORIENT_HORIZONTAL, 30.0f);
root_ = tabs;
tabs->AddTab("Discard", new LinearLayout(UI::ORIENT_VERTICAL));
}
void GPUDriverTestScreen::render() {
using namespace Draw;
UIScreen::render();
if (!discardWriteStencil_) {
DrawContext *draw = screenManager()->getDrawContext();
// Create the special shader module.
discard_ = CreateShader(draw, Draw::ShaderStage::FRAGMENT, fsDiscard);
InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw);
BlendState *blendOff = draw->CreateBlendState({false, 0xF});
// Write depth, write stencil.
DepthStencilStateDesc dsDesc{};
dsDesc.depthTestEnabled = true;
dsDesc.depthWriteEnabled = true;
dsDesc.depthCompare = Comparison::ALWAYS;
dsDesc.stencilEnabled = true;
dsDesc.front.compareMask = 0xFF;
dsDesc.front.compareOp = Comparison::ALWAYS;
dsDesc.front.passOp = StencilOp::REPLACE;
dsDesc.front.failOp = StencilOp::ZERO;
dsDesc.front.depthFailOp = StencilOp::ZERO;
dsDesc.front.reference = 0xFF;
dsDesc.front.writeMask = 0xFF;
dsDesc.back = dsDesc.front;
DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc);
dsDesc.depthCompare = Comparison::ALWAYS;
dsDesc.front.compareOp = Comparison::EQUAL;
DepthStencilState *stencilTestEqual = draw->CreateDepthStencilState(dsDesc);
dsDesc.depthCompare = Comparison::LESS_EQUAL;
dsDesc.front.compareOp = Comparison::ALWAYS;
DepthStencilState *depthTestEqual = draw->CreateDepthStencilState(dsDesc);
RasterState *rasterNoCull = draw->CreateRasterState({});
PipelineDesc discardDesc{
Primitive::TRIANGLE_LIST,
{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discard_ },
inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc,
};
discardWriteStencil_ = draw->CreateGraphicsPipeline(discardDesc);
PipelineDesc testStencilDesc{
Primitive::TRIANGLE_LIST,
{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc,
};
drawTestStencil_ = draw->CreateGraphicsPipeline(testStencilDesc);
PipelineDesc testDepthDesc{
Primitive::TRIANGLE_LIST,
{draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D)},
inputLayout, stencilTestEqual, blendOff, rasterNoCull, &vsColBufDesc,
};
drawTestDepth_ = draw->CreateGraphicsPipeline(testDepthDesc);
inputLayout->Release();
blendOff->Release();
depthStencilWrite->Release();
stencilTestEqual->Release();
depthTestEqual->Release();
rasterNoCull->Release();
SamplerStateDesc nearestDesc{};
samplerNearest_ = draw->CreateSamplerState(nearestDesc);
}
UIContext &dc = *screenManager()->getUIContext();
const Bounds &bounds = dc.GetBounds();
const char *testNames[] = {"Normal", "Z test", "Stencil test"};
const int numTests = ARRAY_SIZE(testNames);
uint32_t textColorOK = 0xFF30FF30;
uint32_t textColorBAD = 0xFF3030FF;
uint32_t bgColorOK = 0xFF106010;
uint32_t bgColorBAD = 0xFF101060;
// Don't want any fancy font texture stuff going on here, so use FLAG_DYNAMIC_ASCII everywhere!
float testW = 200.f;
float padding = 20.0f;
UI::Style style = dc.theme->itemStyle;
float y = 100;
float x = dc.GetBounds().centerX() - ((float)numTests * testW + (float)(numTests - 1) * padding) / 2.0f;
for (int i = 0; i < 3; i++) {
dc.Begin();
dc.SetFontScale(1.0f, 1.0f);
Bounds bounds = {x - testW / 2, y + 40, testW, 70};
dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII);
dc.FillRect(UI::Drawable(bgColorOK), bounds);
// test bounds
dc.Flush();
dc.BeginPipeline(discardWriteStencil_, samplerNearest_);
dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER);
dc.Flush();
dc.BeginPipeline(drawTestStencil_, samplerNearest_);
dc.FillRect(UI::Drawable(textColorOK), bounds);
dc.Flush();
// Methodology:
// 1. Draw text in red, writing to stencil.
// 2. Use stencil test equality to make it green.
x += testW + padding;
}
dc.SetFontScale(1.0f, 1.0f);
dc.Flush();
}

29
UI/GPUDriverTestScreen.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <algorithm>
#include "base/display.h"
#include "ui/ui_context.h"
#include "ui/view.h"
#include "ui/viewgroup.h"
#include "ui/ui.h"
#include "Common/LogManager.h"
#include "UI/MiscScreens.h"
#include "thin3d/thin3d.h"
class GPUDriverTestScreen : public UIDialogScreenWithBackground {
public:
GPUDriverTestScreen();
~GPUDriverTestScreen();
void CreateViews() override;
void render() override;
private:
Draw::ShaderModule *discard_ = nullptr;
Draw::Pipeline *discardWriteStencil_ = nullptr;
Draw::Pipeline *drawTestStencil_ = nullptr;
Draw::Pipeline *drawTestDepth_ = nullptr;
Draw::SamplerState *samplerNearest_ = nullptr;
};

View File

@ -44,6 +44,7 @@
#include "UI/TiltAnalogSettingsScreen.h"
#include "UI/TiltEventProcessor.h"
#include "UI/ComboKeyMappingScreen.h"
#include "UI/GPUDriverTestScreen.h"
#include "Common/KeyMap.h"
#include "Common/FileUtil.h"
@ -1211,8 +1212,8 @@ UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) {
screenManager()->push(new DeveloperToolsScreen());
return UI::EVENT_DONE;
screenManager()->push(new DeveloperToolsScreen());
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) {
@ -1232,12 +1233,12 @@ UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) {
//when the tilt event type is modified, we need to reset all tilt settings.
//refer to the ResetTiltEvents() function for a detailed explanation.
UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e){
UI::EventReturn GameSettingsScreen::OnTiltTypeChange(UI::EventParams &e) {
TiltEventProcessor::ResetTiltEvents();
return UI::EVENT_DONE;
};
UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e){
UI::EventReturn GameSettingsScreen::OnTiltCustomize(UI::EventParams &e) {
screenManager()->push(new TiltAnalogSettingsScreen());
return UI::EVENT_DONE;
};
@ -1276,7 +1277,7 @@ void DeveloperToolsScreen::CreateViews() {
// iOS can now use JIT on all modes, apparently.
// The bool may come in handy for future non-jit platforms though (UWP XB1?)
static const char *cpuCores[] = { "Interpreter", "Dynarec (JIT)", "IR Interpreter" };
static const char *cpuCores[] = {"Interpreter", "Dynarec (JIT)", "IR Interpreter"};
PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, gr->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), sy->GetName(), screenManager()));
core->OnChoice.Handle(this, &DeveloperToolsScreen::OnJitAffectingSetting);
if (!canUseJit) {
@ -1308,6 +1309,14 @@ void DeveloperToolsScreen::CreateViews() {
list->Add(new ItemHeader(dev->T("Texture Replacement")));
list->Add(new CheckBox(&g_Config.bSaveNewTextures, dev->T("Save new textures")));
list->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures")));
// For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply
// because the D3D drivers are generally solid enough to not need this type of investigation.
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN || g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
list->Add(new ItemHeader(dev->T("Hardware Tests")));
list->Add(new Choice(dev->T("GPU Driver Test")))->OnClick.Handle(this, &DeveloperToolsScreen::OnGPUDriverTest);
}
#if !defined(MOBILE_DEVICE)
Choice *createTextureIni = list->Add(new Choice(dev->T("Create/Open textures.ini file for current game")));
createTextureIni->OnClick.Handle(this, &DeveloperToolsScreen::OnOpenTexturesIniFile);
@ -1382,6 +1391,11 @@ UI::EventReturn DeveloperToolsScreen::OnLogConfig(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn DeveloperToolsScreen::OnGPUDriverTest(UI::EventParams &e) {
screenManager()->push(new GPUDriverTestScreen());
return UI::EVENT_DONE;
}
UI::EventReturn DeveloperToolsScreen::OnJitAffectingSetting(UI::EventParams &e) {
NativeMessageReceived("clear jit", "");
return UI::EVENT_DONE;

View File

@ -158,6 +158,7 @@ private:
UI::EventReturn OnLogConfig(UI::EventParams &e);
UI::EventReturn OnJitAffectingSetting(UI::EventParams &e);
UI::EventReturn OnRemoteDebugger(UI::EventParams &e);
UI::EventReturn OnGPUDriverTest(UI::EventParams &e);
bool allowDebugger_ = false;
bool canAllowDebugger_ = true;

View File

@ -96,6 +96,7 @@
#include "UI/BackgroundAudio.h"
#include "UI/TextureUtil.h"
#include "UI/DiscordIntegration.h"
#include "UI/GPUDriverTestScreen.h"
#if !defined(MOBILE_DEVICE)
#include "Common/KeyMap.h"

View File

@ -32,6 +32,7 @@
<ClCompile Include="GamepadEmu.cpp" />
<ClCompile Include="GameScreen.cpp" />
<ClCompile Include="GameSettingsScreen.cpp" />
<ClCompile Include="GPUDriverTestScreen.cpp" />
<ClCompile Include="MainScreen.cpp" />
<ClCompile Include="MiscScreens.cpp" />
<ClCompile Include="NativeApp.cpp" />
@ -64,6 +65,7 @@
<ClInclude Include="GameScreen.h" />
<ClInclude Include="GameSettingsScreen.h" />
<ClInclude Include="CwCheatScreen.h" />
<ClInclude Include="GPUDriverTestScreen.h" />
<ClInclude Include="HostTypes.h" />
<ClInclude Include="MainScreen.h" />
<ClInclude Include="MiscScreens.h" />

View File

@ -71,6 +71,9 @@
</ClCompile>
<ClCompile Include="TextureUtil.cpp" />
<ClCompile Include="DiscordIntegration.cpp" />
<ClCompile Include="GPUDriverTestScreen.cpp">
<Filter>Screens</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GameInfoCache.h" />
@ -143,6 +146,9 @@
</ClInclude>
<ClInclude Include="TextureUtil.h" />
<ClInclude Include="DiscordIntegration.h" />
<ClInclude Include="GPUDriverTestScreen.h">
<Filter>Screens</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Screens">

View File

@ -78,6 +78,7 @@ void DrawBuffer::Shutdown() {
void DrawBuffer::Begin(Draw::Pipeline *program) {
pipeline_ = program;
count_ = 0;
curZ_ = 0.0f;
}
void DrawBuffer::Flush(bool set_blend_state) {

View File

@ -97,7 +97,7 @@ public:
void V(float x, float y, float z, uint32_t color, float u, float v);
void V(float x, float y, uint32_t color, float u, float v) {
V(x, y, 0.0f, color, u, v);
V(x, y, curZ_, color, u, v);
}
void Circle(float x, float y, float radius, float thickness, int segments, float startAngle, uint32_t color, float u_mul);
@ -166,6 +166,10 @@ public:
alphaStack_.pop_back();
}
void SetCurZ(float curZ) {
curZ_ = curZ;
}
private:
struct Vertex {
float x, y, z;
@ -191,5 +195,7 @@ private:
bool inited_;
float fontscalex;
float fontscaley;
float curZ_ = 0.0f;
};

View File

@ -101,11 +101,6 @@ bool RefCountedObject::ReleaseAssertLast() {
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
struct ShaderSource {
ShaderLanguage lang;
const char *src;
};
static const std::vector<ShaderSource> fsTexCol = {
{ShaderLanguage::GLSL_ES_200,
"#ifdef GL_ES\n"
@ -196,6 +191,7 @@ static const std::vector<ShaderSource> vsCol = {
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"varying vec4 oColor0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
@ -317,7 +313,7 @@ const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 }
} };
static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {
uint32_t supported = draw->GetSupportedShaderLanguages();
for (auto iter : sources) {
if ((uint32_t)iter.lang & supported) {

View File

@ -662,4 +662,13 @@ struct VsColUB {
};
extern const UniformBufferDesc vsColBufDesc;
// Useful utility for specifying a shader in multiple languages.
struct ShaderSource {
ShaderLanguage lang;
const char *src;
};
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources);
} // namespace Draw

View File

@ -15,9 +15,9 @@
DrawBuffer ui_draw2d;
DrawBuffer ui_draw2d_front;
void UIBegin(Draw::Pipeline *shaderSet) {
ui_draw2d.Begin(shaderSet);
ui_draw2d_front.Begin(shaderSet);
void UIBegin(Draw::Pipeline *pipeline) {
ui_draw2d.Begin(pipeline);
ui_draw2d_front.Begin(pipeline);
}
void UIFlush() {

View File

@ -52,6 +52,12 @@ void UIContext::BeginNoTex() {
UIBegin(ui_pipeline_notex_);
}
void UIContext::BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState) {
draw_->BindSamplerStates(0, 1, &sampler_);
draw_->BindTexture(0, uitexture_->GetTexture());
UIBegin(pipeline);
}
void UIContext::RebindTexture() const {
draw_->BindTexture(0, uitexture_->GetTexture());
}
@ -65,6 +71,11 @@ void UIContext::Flush() {
}
}
void UIContext::SetCurZ(float curZ) {
ui_draw2d.SetCurZ(curZ);
ui_draw2d_front.SetCurZ(curZ);
}
// TODO: Support transformed bounds using stencil instead.
void UIContext::PushScissor(const Bounds &bounds) {
Flush();

View File

@ -51,6 +51,7 @@ public:
void Begin();
void BeginNoTex();
void BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState);
void Flush();
void RebindTexture() const;
@ -85,6 +86,7 @@ public:
void SetBounds(const Bounds &b) { bounds_ = b; }
const Bounds &GetBounds() const { return bounds_; }
Draw::DrawContext *GetDrawContext() { return draw_; }
void SetCurZ(float curZ);
void PushTransform(const UITransform &transform);
void PopTransform();