Vulkan: Basic geoshader code generation.

This commit is contained in:
Henrik Rydgård 2021-10-26 09:56:14 +02:00 committed by Unknown W. Brackets
parent fbdb278168
commit cdee10fe86
14 changed files with 217 additions and 5 deletions

View File

@ -1562,6 +1562,8 @@ set(GPU_SOURCES
GPU/Common/FragmentShaderGenerator.h
GPU/Common/VertexShaderGenerator.cpp
GPU/Common/VertexShaderGenerator.h
GPU/Common/GeometryShaderGenerator.cpp
GPU/Common/GeometryShaderGenerator.h
GPU/Common/FramebufferManagerCommon.cpp
GPU/Common/FramebufferManagerCommon.h
GPU/Common/GPUDebugInterface.cpp

View File

@ -600,8 +600,6 @@ void VulkanContext::ChooseDevice(int physical_device) {
deviceFeatures_.enabled.samplerAnisotropy = deviceFeatures_.available.samplerAnisotropy;
deviceFeatures_.enabled.shaderClipDistance = deviceFeatures_.available.shaderClipDistance;
deviceFeatures_.enabled.shaderCullDistance = deviceFeatures_.available.shaderCullDistance;
// For easy wireframe mode, someday.
deviceFeatures_.enabled.fillModeNonSolid = deviceFeatures_.available.fillModeNonSolid;
deviceFeatures_.enabled.geometryShader = deviceFeatures_.available.geometryShader;
GetDeviceLayerExtensionList(nullptr, device_extension_properties_);

View File

@ -0,0 +1,79 @@
// Copyright (c) 2012- 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/.
#include <cstdio>
#include <cstdlib>
#include <locale.h>
#include "Common/StringUtils.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/GPU/ShaderWriter.h"
#include "Common/GPU/thin3d.h"
#include "Core/Config.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Common/ShaderId.h"
#include "GPU/Common/ShaderUniforms.h"
#include "GPU/Common/GeometryShaderGenerator.h"
#undef WRITE
#define WRITE(p, ...) p.F(__VA_ARGS__)
bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, std::string *errorString) {
std::vector<const char*> gl_exts;
if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
if (gl_extensions.EXT_gpu_shader4) {
gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable");
}
}
ShaderWriter p(buffer, compat, ShaderStage::Geometry, gl_exts.data(), gl_exts.size());
p.C("layout(triangles) in;\n");
p.C("layout(triangle_strip, max_vertices = 3) out;\n");
std::vector<VaryingDef> varyings, outVaryings;
if (id.Bit(GS_BIT_DO_TEXTURE)) {
varyings.push_back(VaryingDef{ "vec3", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" });
outVaryings.push_back(VaryingDef{ "vec3", "v_texcoordOut", Draw::SEM_TEXCOORD0, 0, "highp" });
}
varyings.push_back(VaryingDef{ "vec4", "v_color0", Draw::SEM_COLOR0, 1, "lowp" });
outVaryings.push_back(VaryingDef{ "vec4", "v_color0Out", Draw::SEM_COLOR0, 1, "lowp" });
if (id.Bit(GS_BIT_LMODE)) {
varyings.push_back(VaryingDef{ "vec3", "v_color1", Draw::SEM_COLOR1, 2, "lowp" });
outVaryings.push_back(VaryingDef{ "vec3", "v_color1Out", Draw::SEM_COLOR1, 2, "lowp" });
}
varyings.push_back(VaryingDef{ "float", "v_fogdepth", Draw::SEM_TEXCOORD1, 3, "highp" });
outVaryings.push_back(VaryingDef{ "float", "v_fogdepthOut", Draw::SEM_TEXCOORD1, 3, "highp" });
p.BeginGSMain(varyings, outVaryings);
p.C(" for (int i = 0; i < gl_in.length(); i++) {\n");
p.C(" gl_Position = gl_in[i].gl_Position;\n"); // copy attributes
for (size_t i = 0; i < varyings.size(); i++) {
VaryingDef &in = varyings[i];
VaryingDef &out = outVaryings[i];
p.F(" %s = %s[i];\n", outVaryings[i].name, varyings[i].name);
}
p.C(" EmitVertex();\n");
p.C(" }\n");
p.EndGSMain();
return true;
}

View File

@ -0,0 +1,5 @@
#pragma once
#include "GPU/Common/ShaderId.h"
bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, std::string *errorString);

View File

@ -340,6 +340,7 @@
<ClInclude Include="..\ext\xbrz\xbrz.h" />
<ClInclude Include="Common\TextureShaderCommon.h" />
<ClInclude Include="Common\Draw2D.h" />
<ClInclude Include="Common\GeometryShaderGenerator.h" />
<ClInclude Include="Common\ReinterpretFramebuffer.h" />
<ClInclude Include="Common\DepalettizeShaderCommon.h" />
<ClInclude Include="Common\DrawEngineCommon.h" />
@ -455,6 +456,7 @@
<ClCompile Include="..\ext\xbrz\xbrz.cpp" />
<ClCompile Include="Common\TextureShaderCommon.cpp" />
<ClCompile Include="Common\Draw2D.cpp" />
<ClCompile Include="Common\GeometryShaderGenerator.cpp" />
<ClCompile Include="Common\ReinterpretFramebuffer.cpp" />
<ClCompile Include="Common\DepalettizeShaderCommon.cpp" />
<ClCompile Include="Common\DrawEngineCommon.cpp" />

View File

@ -261,6 +261,9 @@
<ClInclude Include="Debugger\GECommandTable.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Common\GeometryShaderGenerator.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@ -512,6 +515,9 @@
<ClCompile Include="Debugger\GECommandTable.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Common\GeometryShaderGenerator.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<FxCompile Include="..\assets\shaders\tex_4xbrz.csh">

View File

@ -232,6 +232,14 @@ u32 GPU_Vulkan::CheckGPUFeatures() const {
features |= GPU_SUPPORTS_DEPTH_CLAMP;
}
if (!draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) {
const bool disabled = PSP_CoreParameter().compat.flags().DisableRangeCulling;
// Fall back to geometry shader culling.
if (enabledFeatures.geometryShader && !disabled && (features & GPU_SUPPORTS_VS_RANGE_CULLING) == 0) {
features |= GPU_SUPPORTS_GS_CULLING;
}
}
// These are VULKAN_4444_FORMAT and friends.
uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16);
uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16);

View File

@ -716,7 +716,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID);
VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID);
VulkanGeometryShader *gs = shaderManager->GetGeometryShaderFromID(key.gShaderID);
if (!vs || !fs) {
if (!vs || !fs || (!gs && key.gShaderID.Bit(GS_BIT_ENABLED))) {
failed = true;
ERROR_LOG(G3D, "Failed to find vs or fs in of pipeline %d in cache", (int)i);
continue;

View File

@ -38,6 +38,7 @@
#include "GPU/ge_constants.h"
#include "GPU/Common/FragmentShaderGenerator.h"
#include "GPU/Common/VertexShaderGenerator.h"
#include "GPU/Common/GeometryShaderGenerator.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
#include "GPU/Vulkan/FramebufferManagerVulkan.h"
@ -305,6 +306,11 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
_dbg_assert_(FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE));
_dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE));
if (GSID.Bit(GS_BIT_ENABLED)) {
_dbg_assert_(GSID.Bit(GS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
_dbg_assert_(GSID.Bit(GS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE));
}
// Just update uniforms if this is the same shader as last time.
if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_ && GSID == lastGSID_) {
*vshader = lastVShader_;
@ -345,7 +351,11 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
gs = gsCache_.Get(GSID);
if (!gs) {
// Geometry shader not in cache. Let's compile it.
// TODO
std::string genErrorString;
bool success = GenerateGeometryShader(GSID, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString);
_assert_msg_(success, "GS gen error: %s", genErrorString.c_str());
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
}
} else {
gs = nullptr;
@ -529,7 +539,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
ERROR_LOG(G3D, "Vulkan shader cache truncated");
break;
}
// TODO: Actually generate geometry shaders.
std::string genErrorString;
if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) {
return false;
}
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
gsCache_.Insert(id, gs);
}
NOTICE_LOG(G3D, "Loaded %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders);

View File

@ -385,6 +385,7 @@
<ClInclude Include="..\..\GPU\Common\DrawEngineCommon.h" />
<ClInclude Include="..\..\GPU\Common\FragmentShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\FramebufferManagerCommon.h" />
<ClInclude Include="..\..\GPU\Common\GeometryShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\PresentationCommon.h" />
<ClInclude Include="..\..\GPU\Common\GPUDebugInterface.h" />
<ClInclude Include="..\..\GPU\Common\GPUStateUtils.h" />
@ -446,6 +447,7 @@
<ClCompile Include="..\..\GPU\Common\DrawEngineCommon.cpp" />
<ClCompile Include="..\..\GPU\Common\FragmentShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\FramebufferManagerCommon.cpp" />
<ClCompile Include="..\..\GPU\Common\GeometryShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\PresentationCommon.cpp" />
<ClCompile Include="..\..\GPU\Common\GPUDebugInterface.cpp" />
<ClCompile Include="..\..\GPU\Common\GPUStateUtils.cpp" />

View File

@ -55,6 +55,7 @@
<ClCompile Include="..\..\GPU\Software\RasterizerRectangle.cpp" />
<ClCompile Include="..\..\GPU\Software\RasterizerRegCache.cpp" />
<ClCompile Include="..\..\GPU\Common\FragmentShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\GeometryShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\VertexShaderGenerator.cpp" />
<ClCompile Include="..\..\GPU\Common\ReinterpretFramebuffer.cpp" />
<ClCompile Include="..\..\GPU\Common\Draw2D.cpp" />
@ -116,6 +117,7 @@
<ClInclude Include="..\..\GPU\Software\RasterizerRectangle.h" />
<ClInclude Include="..\..\GPU\Software\RasterizerRegCache.h" />
<ClInclude Include="..\..\GPU\Common\FragmentShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\GeometryShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\VertexShaderGenerator.h" />
<ClInclude Include="..\..\GPU\Common\ReinterpretFramebuffer.h" />
<ClInclude Include="..\..\GPU\Common\Draw2D.h" />

View File

@ -350,6 +350,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/PostShader.cpp \
$(SRC)/GPU/Common/ShaderUniforms.cpp \
$(SRC)/GPU/Common/VertexShaderGenerator.cpp \
$(SRC)/GPU/Common/GeometryShaderGenerator.cpp \
$(SRC)/GPU/Debugger/Breakpoints.cpp \
$(SRC)/GPU/Debugger/Debugger.cpp \
$(SRC)/GPU/Debugger/GECommandTable.cpp \

View File

@ -342,6 +342,7 @@ SOURCES_CXX += \
$(GPUDIR)/Debugger/Stepping.cpp \
$(GPUDIR)/Common/FragmentShaderGenerator.cpp \
$(GPUDIR)/Common/VertexShaderGenerator.cpp \
$(GPUDIR)/Common/GeometryShaderGenerator.cpp \
$(GPUDIR)/Common/TextureCacheCommon.cpp \
$(GPUDIR)/Common/TextureScalerCommon.cpp \
$(GPUDIR)/Common/SoftwareTransformCommon.cpp \

View File

@ -12,6 +12,7 @@
#include "GPU/Common/FragmentShaderGenerator.h"
#include "GPU/Common/VertexShaderGenerator.h"
#include "GPU/Common/GeometryShaderGenerator.h"
#include "GPU/Common/ReinterpretFramebuffer.h"
#include "GPU/Common/StencilCommon.h"
#include "GPU/Common/DepalettizeShaderCommon.h"
@ -91,6 +92,32 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs
}
}
bool GenerateGShader(GShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) {
errorString->clear();
switch (lang) {
case ShaderLanguage::GLSL_VULKAN:
{
ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN);
return GenerateGeometryShader(id, buffer, compat, bugs, errorString);
}
/*
case ShaderLanguage::GLSL_3xx:
{
ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx);
return GenerateGeometryShader(id, buffer, compat, bugs, errorString);
}
case ShaderLanguage::HLSL_D3D11:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11);
return GenerateGeometryShader(id, buffer, compat, bugs, errorString);
}
*/
default:
return false;
}
}
static VkShaderStageFlagBits StageToVulkan(ShaderStage stage) {
switch (stage) {
case ShaderStage::Vertex: return VK_SHADER_STAGE_VERTEX_BIT;
@ -369,6 +396,9 @@ bool TestVertexShaders() {
if (!id.Bit(VS_BIT_USE_HW_TRANSFORM)) {
id.SetBit(VS_BIT_ENABLE_BONES, 0);
}
if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) {
continue;
}
bool generateSuccess[numLanguages]{};
std::string genErrorString[numLanguages];
@ -463,6 +493,63 @@ bool TestFragmentShaders() {
return true;
}
bool TestGeometryShaders() {
char *buffer[numLanguages];
for (int i = 0; i < numLanguages; i++) {
buffer[i] = new char[65536];
}
GMRng rng;
int successes = 0;
int count = 30;
Draw::Bugs bugs;
// Generate a bunch of random fragment shader IDs, try to generate shader source.
// Then compile it and check that it's ok.
for (int i = 0; i < count; i++) {
uint32_t bottom = i << 1;
GShaderID id;
id.d[0] = bottom;
id.d[1] = 0;
id.SetBit(GS_BIT_ENABLED, true);
bool generateSuccess[numLanguages]{};
std::string genErrorString[numLanguages];
for (int j = 0; j < numLanguages; j++) {
generateSuccess[j] = GenerateGShader(id, buffer[j], languages[j], bugs, &genErrorString[j]);
if (!genErrorString[j].empty()) {
printf("%s\n", genErrorString[j].c_str());
}
// We ignore the contents of the error string here, not even gonna try to compile if it errors.
}
// Now that we have the strings ready for easy comparison (buffer,4 in the watch window),
// let's try to compile them.
for (int j = 0; j < numLanguages; j++) {
if (generateSuccess[j]) {
std::string errorMessage;
if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Geometry, &errorMessage)) {
printf("Error compiling geometry shader:\n\n%s\n\n%s\n", LineNumberString(buffer[j]).c_str(), errorMessage.c_str());
return false;
}
successes++;
}
}
}
printf("%d/%d geometry shaders generated (it's normal that it's not all, there are invalid bit combos)\n", successes, count * numLanguages);
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return true;
}
bool TestShaderGenerators() {
#if PPSSPP_PLATFORM(WINDOWS)
LoadD3D11();
@ -476,6 +563,10 @@ bool TestShaderGenerators() {
return false;
}
if (!TestGeometryShaders()) {
return false;
}
if (!TestReinterpretShaders()) {
return false;
}