Delete geometry shader culling support. Is mostly replaced, and will be fully replaced with software transform.

This commit is contained in:
Henrik Rydgård
2026-05-28 10:51:59 +02:00
parent d849db6be5
commit 0b47955c64
22 changed files with 43 additions and 769 deletions
-2
View File
@@ -2013,8 +2013,6 @@ 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
-315
View File
@@ -1,315 +0,0 @@
// 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__)
// TODO: Could support VK_NV_geometry_shader_passthrough, though the hardware that supports
// it is already pretty fast at geometry shaders..
bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, std::string *errorString) {
std::vector<const char*> extensions;
if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
if (gl_extensions.EXT_gpu_shader4) {
extensions.push_back("#extension GL_EXT_gpu_shader4 : enable");
}
}
bool vertexRangeCulling = !id.Bit(GS_BIT_CURVE);
bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP);
ShaderWriter p(buffer, compat, ShaderStage::Geometry, extensions);
p.F("// %s\n", GeometryShaderDesc(id).c_str());
p.C("layout(triangles) in;\n");
if (clipClampedDepth && vertexRangeCulling && !gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
p.C("layout(triangle_strip, max_vertices = 12) out;\n");
} else {
p.C("layout(triangle_strip, max_vertices = 6) out;\n");
}
if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, "\n");
WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr);
} else if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr);
}
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);
// Apply culling.
if (vertexRangeCulling) {
p.C(" bool anyInside = false;\n");
}
// And apply manual clipping if necessary.
if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
p.C(" float clip0[3];\n");
if (clipClampedDepth) {
p.C(" float clip1[3];\n");
}
}
p.C(" for (int i = 0; i < 3; i++) {\n"); // TODO: 3 or gl_in.length()? which will be faster?
p.C(" vec4 outPos = gl_in[i].gl_Position;\n");
p.C(" vec3 projPos = outPos.xyz / outPos.w;\n");
if (vertexRangeCulling) {
p.C(" float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
// Vertex range culling doesn't happen when Z clips, note sign of w is important.
p.C(" if (u_cullRangeMin.w <= 0.0 || projZ * outPos.w > -outPos.w) {\n");
const char *outMin = "projPos.x < u_cullRangeMin.x || projPos.y < u_cullRangeMin.y";
const char *outMax = "projPos.x > u_cullRangeMax.x || projPos.y > u_cullRangeMax.y";
p.F(" if ((%s) || (%s)) {\n", outMin, outMax);
p.C(" return;\n"); // Cull!
p.C(" }\n");
p.C(" }\n");
p.C(" if (u_cullRangeMin.w <= 0.0) {\n");
p.C(" if (projPos.z < u_cullRangeMin.z || projPos.z > u_cullRangeMax.z) {\n");
// When not clamping depth, cull the triangle of Z is outside the valid range (not based on clip Z.)
p.C(" return;\n");
p.C(" }\n");
p.C(" } else {\n");
p.C(" if (projPos.z >= u_cullRangeMin.z) { anyInside = true; }\n");
p.C(" if (projPos.z <= u_cullRangeMax.z) { anyInside = true; }\n");
p.C(" }\n");
}
if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
// This is basically the same value as gl_ClipDistance would take, z + w.
if (vertexRangeCulling) {
// We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.)
p.F(" clip0[i] = projZ * outPos.w + outPos.w + %f;\n", 0.0625 / 65536.0);
} else {
// Let's not complicate the code overly for this case. We'll clipClampedDepth.
p.C(" clip0[i] = 0.0;\n");
}
// This one does happen for rectangles.
if (clipClampedDepth) {
if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
// On OpenGL/GLES, these values account for the -1 -> 1 range.
p.C(" if (u_depthRange.y - u_depthRange.x >= 1.0) {\n");
p.C(" clip1[i] = outPos.w + outPos.z;\n");
} else {
// Everywhere else, it's 0 -> 1, simpler.
p.C(" if (u_depthRange.y >= 1.0) {\n");
p.C(" clip1[i] = outPos.z;\n");
}
// This is similar, but for maxz when it's below 65535.0. -1/0 don't matter here.
p.C(" } else if (u_depthRange.x + u_depthRange.y <= 65534.0) {\n");
p.C(" clip1[i] = outPos.w - outPos.z;\n");
p.C(" } else {\n");
p.C(" clip1[i] = 0.0;\n");
p.C(" }\n");
}
}
p.C(" } // for\n");
// Cull any triangle fully outside in the same direction when depth clamp enabled.
// Basically simulate cull distances.
if (vertexRangeCulling) {
p.C(" if (u_cullRangeMin.w > 0.0 && !anyInside) {\n");
p.C(" return;\n");
p.C(" }\n");
}
if (!gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
// Clipping against one half-space cuts a triangle (17/27), culls (7/27), or creates two triangles (3/27).
// We clip against two, so we can generate up to 4 triangles, a polygon with 6 points.
p.C(" int indices[6];\n");
p.C(" float factors[6];\n");
p.C(" int ind = 0;\n");
// Pass 1 - clip against first half-space.
p.C(" for (int i = 0; i < 3; i++) {\n");
// First, use this vertex if it doesn't need clipping.
p.C(" if (clip0[i] >= 0.0) {\n");
p.C(" indices[ind] = i;\n");
p.C(" factors[ind] = 0.0;\n");
p.C(" ind++;\n");
p.C(" }\n");
// Next, we generate an interpolated vertex if signs differ.
p.C(" int inext = i == 2 ? 0 : i + 1;\n");
p.C(" if (clip0[i] * clip0[inext] < 0.0) {\n");
p.C(" float t = clip0[i] < 0.0 ? clip0[i] / (clip0[i] - clip0[inext]) : 1.0 - (clip0[inext] / (clip0[inext] - clip0[i]));\n");
p.C(" indices[ind] = i;\n");
p.C(" factors[ind] = t;\n");
p.C(" ind++;\n");
p.C(" }\n");
p.C(" }\n");
// Pass 2 - further clip against clamped Z.
if (clipClampedDepth) {
p.C(" int count0 = ind;\n");
p.C(" int indices1[6];\n");
p.C(" float factors1[6];\n");
p.C(" ind = 0;\n");
// Let's start by interpolating the clip values.
p.C(" float clip1after[4];\n");
p.C(" for (int i = 0; i < count0; i++) {\n");
p.C(" int idx = indices[i];\n");
p.C(" float factor = factors[i];\n");
p.C(" int next = idx == 2 ? 0 : idx + 1;\n");
p.C(" clip1after[i] = mix(clip1[idx], clip1[next], factor);\n");
p.C(" }\n");
// Alright, now time to clip, again.
p.C(" for (int i = 0; i < count0; i++) {\n");
// First, use this vertex if it doesn't need clipping.
p.C(" if (clip1after[i] >= 0.0) {\n");
p.C(" indices1[ind] = i;\n");
p.C(" factors1[ind] = 0.0;\n");
p.C(" ind++;\n");
p.C(" }\n");
// Next, we generate an interpolated vertex if signs differ.
p.C(" int inext = i == count0 - 1 ? 0 : i + 1;\n");
p.C(" if (clip1after[i] * clip1after[inext] < 0.0) {\n");
p.C(" float t = clip1after[i] < 0.0 ? clip1after[i] / (clip1after[i] - clip1after[inext]) : 1.0 - (clip1after[inext] / (clip1after[inext] - clip1after[i]));\n");
p.C(" indices1[ind] = i;\n");
p.C(" factors1[ind] = t;\n");
p.C(" ind++;\n");
p.C(" }\n");
p.C(" }\n");
}
p.C(" if (ind < 3) {\n");
p.C(" return;\n");
p.C(" }\n");
p.C(" int idx;\n");
p.C(" int next;\n");
p.C(" float factor;\n");
auto emitIndex = [&](const char *which) {
if (clipClampedDepth) {
// We have to interpolate between four vertices.
p.F(" idx = indices1[%s];\n", which);
p.F(" factor = factors1[%s];\n", which);
p.C(" next = idx == count0 - 1 ? 0 : idx + 1;\n");
p.C(" gl_Position = mix(mix(gl_in[indices[idx]].gl_Position, gl_in[(indices[idx] + 1) % 3].gl_Position, factors[idx]), mix(gl_in[indices[next]].gl_Position, gl_in[(indices[next] + 1) % 3].gl_Position, factors[next]), factor);\n");
for (size_t i = 0; i < varyings.size(); i++) {
const VaryingDef &in = varyings[i];
const VaryingDef &out = outVaryings[i];
p.F(" %s = mix(mix(%s[indices[idx]], %s[(indices[idx] + 1) % 3], factors[idx]), mix(%s[indices[next]], %s[(indices[next] + 1) % 3], factors[next]), factor);\n", out.name, in.name, in.name, in.name, in.name);
}
} else {
p.F(" idx = indices[%s];\n", which);
p.F(" factor = factors[%s];\n", which);
p.C(" next = idx == 2 ? 0 : idx + 1;\n");
p.C(" gl_Position = mix(gl_in[idx].gl_Position, gl_in[next].gl_Position, factor);\n");
for (size_t i = 0; i < varyings.size(); i++) {
const VaryingDef &in = varyings[i];
const VaryingDef &out = outVaryings[i];
p.F(" %s = mix(%s[idx], %s[next], factor);\n", out.name, in.name, in.name);
}
}
p.C(" EmitVertex();\n");
};
// Alright, time to actually emit the first triangle.
p.C(" for (int i = 0; i < 3; i++) {\n");
emitIndex("i");
p.C(" }\n");
// Did we end up with additional triangles? We'll do three points each for the rest.
p.C(" for (int i = 3; i < ind; i++) {\n");
p.C(" EndPrimitive();\n");
// Point one, always index zero.
emitIndex("0");
// After that, one less than i (basically a triangle fan.)
emitIndex("(i - 1)");
// And the new vertex itself.
emitIndex("i");
p.C(" }\n");
} else {
const char *clipSuffix0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]";
const char *clipSuffix1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]";
p.C(" for (int i = 0; i < 3; i++) {\n"); // TODO: 3 or gl_in.length()? which will be faster?
p.C(" vec4 outPos = gl_in[i].gl_Position;\n");
p.C(" vec3 projPos = outPos.xyz / outPos.w;\n");
p.C(" float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
if (clipClampedDepth) {
// Copy the clip distance from the vertex shader.
p.F(" gl_ClipDistance%s = gl_in[i].gl_ClipDistance%s;\n", clipSuffix0, clipSuffix0);
p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", clipSuffix1);
} else {
// We shouldn't need to worry about rectangles-as-triangles here, since we don't use geometry shaders for that.
// We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.)
p.F(" gl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", clipSuffix0, 0.0625 / 65536.0);
}
p.C(" gl_Position = outPos;\n");
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
}
for (size_t i = 0; i < varyings.size(); i++) {
const VaryingDef &in = varyings[i];
const VaryingDef &out = outVaryings[i];
p.F(" %s = %s[i];\n", out.name, in.name);
}
// Debug - null the red channel
//p.C(" if (i == 0) v_color0Out.x = 0.0;\n");
p.C(" EmitVertex();\n");
p.C(" }\n");
}
p.EndGSMain();
return true;
}
-5
View File
@@ -1,5 +0,0 @@
#pragma once
#include "GPU/Common/ShaderId.h"
bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, std::string *errorString);
+2 -2
View File
@@ -119,13 +119,13 @@ enum : uint64_t {
DIRTY_VIEWPORTSCISSOR_STATE = 1ULL << 50,
DIRTY_VERTEXSHADER_STATE = 1ULL << 51,
DIRTY_FRAGMENTSHADER_STATE = 1ULL << 52,
DIRTY_GEOMETRYSHADER_STATE = 1ULL << 53,
// Free bit 53,
// Note that the top 8 bits (54-63) cannot be dirtied through the commonCommandTable due to packing of other flags.
// Everything that's not uniforms. Use this after using thin3d.
// TODO: Should we also add DIRTY_FRAMEBUF here? It kinda generally takes care of itself.
DIRTY_ALL_RENDER_STATE = DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS,
DIRTY_ALL_RENDER_STATE = DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS,
DIRTY_ALL = 0xFFFFFFFFFFFFFFFF
};
-48
View File
@@ -423,51 +423,3 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
*id_out = id;
}
std::string GeometryShaderDesc(const GShaderID &id) {
std::stringstream desc;
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(GS_BIT_ENABLED)) desc << "ENABLED ";
if (id.Bit(GS_BIT_DO_TEXTURE)) desc << "TEX ";
if (id.Bit(GS_BIT_LMODE)) desc << "LM ";
return desc.str();
}
void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim) {
GShaderID id;
// Early out.
if (!gstate_c.Use(GPU_USE_GS_CULLING)) {
*id_out = id;
return;
}
bool isModeThrough = gstate.isModeThrough();
bool isCurve = gstate_c.submitType != SubmitType::DRAW;
bool isTriangle = prim == GE_PRIM_TRIANGLES || prim == GE_PRIM_TRIANGLE_FAN || prim == GE_PRIM_TRIANGLE_STRIP;
bool vertexRangeCulling = !isCurve;
bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !gstate_c.Use(GPU_USE_CLIP_DISTANCE);
// Only use this for triangle primitives, and if we actually need it.
if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle) {
*id_out = id;
return;
}
id.SetBit(GS_BIT_ENABLED, true);
// Vertex range culling doesn't seem tno happen for spline/bezier, see #11692.
id.SetBit(GS_BIT_CURVE, isCurve);
if (gstate.isModeClear()) {
// No attribute bits.
} else {
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
id.SetBit(GS_BIT_LMODE, lmode);
if (gstate.isTextureMapEnabled()) {
id.SetBit(GS_BIT_DO_TEXTURE);
}
}
*id_out = id;
}
-40
View File
@@ -109,18 +109,6 @@ static inline FShaderBit operator +(FShaderBit bit, int i) {
return FShaderBit((int)bit + i);
}
// Some of these bits are straight from FShaderBit, since they essentially enable attributes directly.
enum GShaderBit : uint8_t {
GS_BIT_ENABLED = 0, // If not set, we don't use a geo shader.
GS_BIT_DO_TEXTURE = 1, // presence of texcoords
GS_BIT_LMODE = 2,
GS_BIT_CURVE = 3, // curve, which means don't do range culling.
};
static inline GShaderBit operator +(GShaderBit bit, int i) {
return GShaderBit((int)bit + i);
}
struct ShaderID {
ShaderID() {
clear();
@@ -251,31 +239,6 @@ struct FShaderID : ShaderID {
}
};
struct GShaderID : ShaderID {
GShaderID() : ShaderID() {
}
explicit GShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(GShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(GShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(GShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(GShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
namespace Draw {
class Bugs;
}
@@ -289,8 +252,5 @@ struct ComputedPipelineState;
void ComputeFragmentShaderID(FShaderID *id, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs);
std::string FragmentShaderDesc(const FShaderID &id);
void ComputeGeometryShaderID(GShaderID *id, const Draw::Bugs &bugs, int prim);
std::string GeometryShaderDesc(const GShaderID &id);
// For sanity checking.
bool FragmentIdNeedsFramebufferRead(const FShaderID &id);
-2
View File
@@ -260,7 +260,6 @@
<ClInclude Include="Common\TextureReplacer.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" />
@@ -365,7 +364,6 @@
<ClCompile Include="Common\TextureReplacer.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" />
-6
View File
@@ -243,9 +243,6 @@
<ClInclude Include="Debugger\GECommandTable.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Common\GeometryShaderGenerator.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="GPUCommonHW.h">
<Filter>Common</Filter>
</ClInclude>
@@ -497,9 +494,6 @@
<ClCompile Include="Debugger\GECommandTable.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Common\GeometryShaderGenerator.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\DepthBufferCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
+2 -2
View File
@@ -280,14 +280,14 @@ protected:
void SetDrawType(DrawType type, GEPrimitiveType prim) {
if (type != lastDraw_) {
// We always flush when drawing splines/beziers so no need to do so here
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE);
lastDraw_ = type;
}
// Prim == RECTANGLES can cause CanUseHardwareTransform to flip, so we need to dirty.
// Also, culling may be affected so dirty the raster state.
if (IsTrianglePrim(prim) != IsTrianglePrim(lastPrim_)) {
Flush();
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE);
lastPrim_ = prim;
}
}
+10 -10
View File
@@ -75,8 +75,8 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEF },
// These affect the fragment shader so need flushing.
{ GE_CMD_CLEARMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
{ GE_CMD_TEXTUREMAPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
{ GE_CMD_CLEARMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_TEXTUREMAPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_TEXMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_TEXSHADELS, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
@@ -90,7 +90,7 @@ const CommonCommandTableEntry commonCommandTable[] = {
// These change the vertex shader so need flushing.
{ GE_CMD_REVERSENORMAL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
{ GE_CMD_LIGHTINGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
{ GE_CMD_LIGHTINGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_LIGHTENABLE0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
{ GE_CMD_LIGHTENABLE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
{ GE_CMD_LIGHTENABLE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
@@ -102,7 +102,7 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
// These change all shaders so need flushing.
{ GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
{ GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_TEXFILTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXWRAP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
@@ -852,7 +852,7 @@ void GPUCommonHW::Execute_VertexType(u32 op, u32 diff) {
if (diff & GE_VTYPE_THROUGH_MASK) {
// Switching between through and non-through, we need to invalidate a bunch of stuff.
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
}
}
@@ -873,7 +873,7 @@ void GPUCommonHW::Execute_VertexTypeSkinning(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
@@ -1338,7 +1338,7 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) {
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(surface.primType));
// We need to dirty UVSCALEOFFSET here because we look at the submit type when setting that uniform.
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_UVSCALEOFFSET);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_UVSCALEOFFSET);
if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
gstate_c.submitType = SubmitType::HW_BEZIER;
if (gstate_c.spline_num_points_u != surface.num_points_u) {
@@ -1353,7 +1353,7 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) {
gstate_c.UpdateUVScaleOffset();
drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier");
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_UVSCALEOFFSET);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_UVSCALEOFFSET);
gstate_c.submitType = SubmitType::DRAW;
// After drawing, we advance pointers - see SubmitPrim which does the same.
@@ -1418,7 +1418,7 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) {
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(surface.primType));
// We need to dirty UVSCALEOFFSET here because we look at the submit type when setting that uniform.
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_UVSCALEOFFSET);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_UVSCALEOFFSET);
if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
gstate_c.submitType = SubmitType::HW_SPLINE;
if (gstate_c.spline_num_points_u != surface.num_points_u) {
@@ -1433,7 +1433,7 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) {
gstate_c.UpdateUVScaleOffset();
drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline");
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_UVSCALEOFFSET);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_UVSCALEOFFSET);
gstate_c.submitType = SubmitType::DRAW;
// After drawing, we advance pointers - see SubmitPrim which does the same.
+1 -1
View File
@@ -484,7 +484,7 @@ enum : u32 {
GPU_USE_TEXTURE_LOD_CONTROL = FLAG_BIT(15),
GPU_USE_DEPTH_TEXTURE = FLAG_BIT(16),
// Free bit: 17
GPU_USE_GS_CULLING = FLAG_BIT(18), // Geometry shader
// Free bit: 18
GPU_USE_FRAMEBUFFER_ARRAYS = FLAG_BIT(19),
GPU_USE_FRAMEBUFFER_FETCH = FLAG_BIT(20),
// Free bit: 21,
+6 -8
View File
@@ -304,18 +304,17 @@ void DrawEngineVulkan::Flush() {
sampler = nullSampler_;
}
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE) || prim != lastPrim_) {
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_);
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_);
_dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, true, 0, framebufferManager_->GetMSAALevel(), false);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, true, 0, framebufferManager_->GetMSAALevel(), false);
if (!pipeline || !pipeline->pipeline) {
// Already logged, let's bail out.
ResetAfterSkippedDraw();
@@ -473,18 +472,17 @@ void DrawEngineVulkan::Flush() {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
}
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE) || prim != lastPrim_) {
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
_dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &swDec->decFmt, vshader, fshader, gshader, false, 0, framebufferManager_->GetMSAALevel(), false);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &swDec->decFmt, vshader, fshader, false, 0, framebufferManager_->GetMSAALevel(), false);
if (!pipeline || !pipeline->pipeline) {
// Already logged, let's bail out.
ResetAfterSkippedDraw();
-18
View File
@@ -218,18 +218,6 @@ u32 GPU_Vulkan::CheckGPUFeatures() const {
features |= GPU_USE_VERTEX_TEXTURE_FETCH;
features |= GPU_USE_TEXTURE_FLOAT;
// Fall back to geometry shader culling if we can't do vertex range culling.
// Checking accurate depth here because the old depth path is uncommon and not well tested for this.
if (draw_->GetDeviceCaps().geometryShaderSupported) {
const bool useGeometry = g_Config.bUseGeometryShader && !draw_->GetBugs().Has(Draw::Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN);
const bool vertexSupported = draw_->GetDeviceCaps().maxClipDistances >= 2 && draw_->GetDeviceCaps().maxCullDistances >= 1;
if (useGeometry && (!vertexSupported || (features & GPU_USE_VS_RANGE_CULLING) == 0)) {
// Switch to culling via the geometry shader if not fully supported in vertex.
features |= GPU_USE_GS_CULLING;
features &= ~GPU_USE_VS_RANGE_CULLING;
}
}
if (!draw_->GetBugs().Has(Draw::Bugs::PVR_BAD_16BIT_TEXFORMATS)) {
// These are VULKAN_4444_FORMAT and friends.
// Note that we are now using the correct set of formats - the only cases where some may be missing
@@ -247,12 +235,6 @@ u32 GPU_Vulkan::CheckGPUFeatures() const {
if (g_Config.bStereoRendering && draw_->GetDeviceCaps().multiViewSupported) {
features |= GPU_USE_SINGLE_PASS_STEREO;
features |= GPU_USE_SIMPLE_STEREO_PERSPECTIVE;
if (features & GPU_USE_GS_CULLING) {
// Many devices that support stereo and GS don't support GS during stereo.
features &= ~GPU_USE_GS_CULLING;
features |= GPU_USE_VS_RANGE_CULLING;
}
}
// Attempt to workaround #17386
+8 -36
View File
@@ -186,7 +186,7 @@ static std::string CutFromMain(const std::string &str) {
static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache,
VKRPipelineLayout *layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key,
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, bool cacheLoad) {
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask, bool cacheLoad) {
_assert_(fs && vs);
if (!fs || !fs->GetModule()) {
@@ -197,10 +197,6 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
ERROR_LOG(Log::G3D, "Vertex shader missing in CreateVulkanPipeline");
return nullptr;
}
if (gs && !gs->GetModule()) {
ERROR_LOG(Log::G3D, "Geometry shader missing in CreateVulkanPipeline");
return nullptr;
}
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
vulkanPipeline->desc = new VKRGraphicsPipelineDesc();
@@ -209,7 +205,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
desc->fragmentShader = fs->GetModule();
desc->vertexShader = vs->GetModule();
desc->geometryShader = gs ? gs->GetModule() : nullptr;
desc->geometryShader = nullptr;
PROFILE_THIS_SCOPE("pipelinebuild");
bool useBlendConstant = false;
@@ -290,9 +286,6 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE);
desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE);
if (gs) {
desc->geometryShaderSource = gs->GetShaderString(SHADER_STRING_SOURCE_CODE);
}
_dbg_assert_(key.topology != VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
_dbg_assert_(key.topology != VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
@@ -344,9 +337,6 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
if (useBlendConstant) {
pipelineFlags |= PipelineFlags::USES_BLEND_CONSTANT;
}
if (gs) {
pipelineFlags |= PipelineFlags::USES_GEOMETRY_SHADER;
}
if (dss.depthTestEnable || dss.stencilTestEnable) {
pipelineFlags |= PipelineFlags::USES_DEPTH_STENCIL;
}
@@ -354,7 +344,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
return vulkanPipeline;
}
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel, bool cacheLoad) {
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask, int multiSampleLevel, bool cacheLoad) {
if (!pipelineCache_) {
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
@@ -367,7 +357,6 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
key.useHWTransform = useHwTransform;
key.vShader = vs->GetModule();
key.fShader = fs->GetModule();
key.gShader = gs ? gs->GetModule() : VK_NULL_HANDLE;
key.vtxFmtId = useHwTransform ? decFmt->id : 0;
VulkanPipeline *pipeline;
@@ -390,7 +379,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
pipeline = CreateVulkanPipeline(
renderManager, pipelineCache_, layout, pipelineFlags, sampleCount,
rasterKey, decFmt, vs, fs, gs, useHwTransform, variantBitmask, cacheLoad);
rasterKey, decFmt, vs, fs, useHwTransform, variantBitmask, cacheLoad);
// If the above failed, we got a null pipeline. We still insert it to keep track.
pipelines_.Insert(key, pipeline);
@@ -592,14 +581,10 @@ std::string VulkanPipelineKey::GetDescription(DebugShaderStringType stringType,
// More detailed description of all the parts of the pipeline.
VkShaderModule fsModule = this->fShader->BlockUntilReady();
VkShaderModule vsModule = this->vShader->BlockUntilReady();
VkShaderModule gsModule = this->gShader ? this->gShader->BlockUntilReady() : VK_NULL_HANDLE;
std::stringstream str;
str << "VS: " << VertexShaderDesc(shaderManager->GetVertexShaderFromModule(vsModule)->GetID()) << std::endl;
str << "FS: " << FragmentShaderDesc(shaderManager->GetFragmentShaderFromModule(fsModule)->GetID()) << std::endl;
if (gsModule) {
str << "GS: " << GeometryShaderDesc(shaderManager->GetGeometryShaderFromModule(gsModule)->GetID()) << std::endl;
}
str << GetRasterStateDesc(true);
return str.str();
}
@@ -622,7 +607,7 @@ struct StoredVulkanPipelineKey {
VulkanPipelineRasterStateKey raster;
VShaderID vShaderID;
FShaderID fShaderID;
GShaderID gShaderID;
FShaderID gShaderID; // keep the file format compatible
uint32_t vtxFmtId;
uint32_t variants;
bool useHWTransform; // TODO: Still needed?
@@ -673,13 +658,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa
return;
VulkanVertexShader *vshader = shaderManager->GetVertexShaderFromModule(pkey.vShader->BlockUntilReady());
VulkanFragmentShader *fshader = shaderManager->GetFragmentShaderFromModule(pkey.fShader->BlockUntilReady());
VulkanGeometryShader *gshader = nullptr;
if (pkey.gShader) {
gshader = shaderManager->GetGeometryShaderFromModule(pkey.gShader->BlockUntilReady());
if (!gshader)
failed = true;
}
if (!vshader || !fshader || failed) {
if (!vshader || !fshader) {
failed = true;
return;
}
@@ -689,7 +668,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa
key.useHWTransform = pkey.useHWTransform;
key.fShaderID = fshader->GetID();
key.vShaderID = vshader->GetID();
key.gShaderID = gshader ? gshader->GetID() : GShaderID();
key.gShaderID = {};
key.variants = value->GetVariantsBitmask();
if (key.useHWTransform) {
// NOTE: This is not a vtype, but a decoded vertex format.
@@ -804,13 +783,6 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa
VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID);
VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID);
VulkanGeometryShader *gs = shaderManager->GetGeometryShaderFromID(key.gShaderID);
if (!vs || !fs || (!gs && key.gShaderID.Bit(GS_BIT_ENABLED))) {
// We just ignore this one, it'll get created later if needed.
// Probably some useFlags mismatch.
WARN_LOG(Log::G3D, "Failed to find vs or fs in pipeline %d in cache, skipping pipeline", (int)i);
continue;
}
// Avoid creating multisampled shaders if it's not enabled, as that results in an invalid combination.
// Note that variantsToBuild is NOT directly a RenderPassType! instead, it's a collection of (1 << RenderPassType).
@@ -826,7 +798,7 @@ bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCa
DecVtxFormat fmt;
fmt.InitializeFromID(key.vtxFmtId);
VulkanPipeline *pipeline = GetOrCreatePipeline(
rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, variantsToBuild, multiSampleLevel, true);
rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, key.useHWTransform, variantsToBuild, multiSampleLevel, true);
if (!pipeline) {
pipelineCreateFailCount += 1;
}
+2 -3
View File
@@ -46,7 +46,6 @@ struct VulkanPipelineKey {
VKRRenderPass *renderPass;
Promise<VkShaderModule> *vShader;
Promise<VkShaderModule> *fShader;
Promise<VkShaderModule> *gShader;
uint32_t vtxFmtId;
bool useHWTransform;
@@ -88,7 +87,8 @@ public:
~PipelineManagerVulkan();
// variantMask is only used when loading pipelines from cache.
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantMask, int multiSampleLevel, bool cacheLoad);
VulkanPipeline *GetOrCreatePipeline(VulkanRenderManager *renderManager, VKRPipelineLayout *layout, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt,
VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantMask, int multiSampleLevel, bool cacheLoad);
int GetNumPipelines() const { return (int)pipelines_.size(); }
void Clear();
@@ -97,7 +97,6 @@ public:
void DeviceRestore(VulkanContext *vulkan);
void InvalidateMSAAPipelines();
void BlockUntilReady();
std::string DebugGetObjectString(const std::string &id, DebugShaderType type, DebugShaderStringType stringType, ShaderManagerVulkan *shaderManager);
std::vector<std::string> DebugGetObjectIDs(DebugShaderType type) const;
+9 -130
View File
@@ -33,7 +33,6 @@
#include "GPU/GPUState.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"
@@ -167,42 +166,10 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons
}
}
VulkanGeometryShader::VulkanGeometryShader(VulkanContext *vulkan, GShaderID id, const char *code)
: vulkan_(vulkan), id_(id) {
_assert_(!id.is_invalid());
source_ = code;
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_GEOMETRY_BIT, source_.c_str(), new std::string(GeometryShaderDesc(id).c_str()));
VERBOSE_LOG(Log::G3D, "Compiled geometry shader:\n%s\n", (const char *)code);
}
VulkanGeometryShader::~VulkanGeometryShader() {
if (module_) {
VkShaderModule shaderModule = module_->BlockUntilReady();
if (shaderModule) {
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
}
vulkan_->Delete().QueueCallback([](VulkanContext *vulkan, void *m) {
auto module = (Promise<VkShaderModule> *)m;
delete module;
}, module_);
}
}
std::string VulkanGeometryShader::GetShaderString(DebugShaderStringType type) const {
switch (type) {
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return GeometryShaderDesc(id_);
default:
return "N/A";
}
}
static constexpr size_t CODE_BUFFER_SIZE = 32768;
ShaderManagerVulkan::ShaderManagerVulkan(Draw::DrawContext *draw)
: ShaderManagerCommon(draw), compat_(GLSL_VULKAN), fsCache_(16), vsCache_(16), gsCache_(16) {
: ShaderManagerCommon(draw), compat_(GLSL_VULKAN), fsCache_(16), vsCache_(16) {
codeBuffer_ = new char[CODE_BUFFER_SIZE];
VulkanContext *vulkan = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
uboAlignment_ = vulkan->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment;
@@ -239,36 +206,28 @@ void ShaderManagerVulkan::Clear() {
vsCache_.Iterate([&](const VShaderID &key, VulkanVertexShader *shader) {
delete shader;
});
gsCache_.Iterate([&](const GShaderID &key, VulkanGeometryShader *shader) {
delete shader;
});
fsCache_.Clear();
vsCache_.Clear();
gsCache_.Clear();
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastGSID_.set_invalid();
lastVShader_ = nullptr;
lastFShader_ = nullptr;
lastGShader_ = nullptr;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void ShaderManagerVulkan::ClearShaders() {
Clear();
DirtyLastShader();
gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void ShaderManagerVulkan::DirtyLastShader() {
// Forget the last shader ID
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastGSID_.set_invalid();
lastVShader_ = nullptr;
lastFShader_ = nullptr;
lastGShader_ = nullptr;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
@@ -285,7 +244,7 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
return dirty;
}
void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
VShaderID VSID;
@@ -346,41 +305,8 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShade
}
*fshader = fs;
GShaderID GSID;
VulkanGeometryShader *gs = nullptr;
if (gstate_c.IsDirty(DIRTY_GEOMETRYSHADER_STATE)) {
gstate_c.Clean(DIRTY_GEOMETRYSHADER_STATE);
ComputeGeometryShaderID(&GSID, draw_->GetBugs(), prim);
if (GSID == lastGSID_) {
// it's ok for this to be null.
gs = lastGShader_;
} else if (GSID.Bit(GS_BIT_ENABLED)) {
if (!gsCache_.Get(GSID, &gs)) {
// Geometry shader not in cache. Let's compile it.
std::string genErrorString;
bool success = GenerateGeometryShader(GSID, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString);
_assert_msg_(success, "GS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
}
} else {
gs = nullptr;
}
lastGShader_ = gs;
lastGSID_ = GSID;
} else {
GSID = lastGSID_;
gs = lastGShader_;
}
*gshader = gs;
_dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE));
_dbg_assert_(FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
if (GSID.Bit(GS_BIT_ENABLED)) {
_dbg_assert_(GSID.Bit(GS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
}
_dbg_assert_msg_((*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed");
}
@@ -403,12 +329,7 @@ std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType
});
break;
case SHADER_TYPE_GEOMETRY:
gsCache_.Iterate([&](const GShaderID &id, VulkanGeometryShader *shader) {
std::string idstr;
id.ToString(&idstr);
ids.push_back(idstr);
});
break;
return ids;
default:
break;
}
@@ -439,12 +360,7 @@ std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShade
}
case SHADER_TYPE_GEOMETRY:
{
VulkanGeometryShader *gs;
if (gsCache_.Get(GShaderID(shaderId), &gs)) {
return gs ? gs->GetShaderString(stringType) : "null (bad)";
} else {
return "";
}
return "";
}
default:
return "N/A";
@@ -473,17 +389,6 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM
return fs;
}
VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderModule module) {
VulkanGeometryShader *gs = nullptr;
gsCache_.Iterate([&](const GShaderID &id, VulkanGeometryShader *shader) {
Promise<VkShaderModule> *p = shader->GetModule();
VkShaderModule m = p->BlockUntilReady();
if (m == module)
gs = shader;
});
return gs;
}
// Shader cache.
//
// We simply store the IDs of the shaders used during gameplay. On next startup of
@@ -497,7 +402,7 @@ enum class VulkanCacheDetectFlags {
};
#define CACHE_HEADER_MAGIC 0xff51f420
#define CACHE_VERSION 53
#define CACHE_VERSION 54
struct VulkanCacheHeader {
uint32_t magic;
@@ -592,29 +497,6 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
}
}
// If it's not enabled, don't create shaders cached from earlier runs - creation will likely fail.
if (gstate_c.Use(GPU_USE_GS_CULLING)) {
for (int i = 0; i < header.numGeometryShaders; i++) {
GShaderID id;
if (fread(&id, sizeof(id), 1, f) != 1) {
ERROR_LOG(Log::G3D, "Vulkan shader cache truncated (in GeometryShaders)");
return false;
}
std::string genErrorString;
if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) {
ERROR_LOG(Log::G3D, "Failed to generate geometry shader during cache load");
// We just ignore this one and carry on.
failCount++;
continue;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
if (!gsCache_.ContainsKey(id)) {
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
gsCache_.Insert(id, gs);
}
}
}
NOTICE_LOG(Log::G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders (failed %d)", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders, failCount);
return true;
}
@@ -627,7 +509,7 @@ void ShaderManagerVulkan::SaveCache(FILE *f, DrawEngineVulkan *drawEngine) {
header.detectFlags = 0;
header.numVertexShaders = (int)vsCache_.size();
header.numFragmentShaders = (int)fsCache_.size();
header.numGeometryShaders = (int)gsCache_.size();
header.numGeometryShaders = 0;
bool writeFailed = fwrite(&header, sizeof(header), 1, f) != 1;
vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *vs) {
writeFailed = writeFailed || fwrite(&id, sizeof(id), 1, f) != 1;
@@ -635,9 +517,6 @@ void ShaderManagerVulkan::SaveCache(FILE *f, DrawEngineVulkan *drawEngine) {
fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *fs) {
writeFailed = writeFailed || fwrite(&id, sizeof(id), 1, f) != 1;
});
gsCache_.Iterate([&](const GShaderID &id, VulkanGeometryShader *gs) {
writeFailed = writeFailed || fwrite(&id, sizeof(id), 1, f) != 1;
});
if (writeFailed) {
ERROR_LOG(Log::G3D, "Failed to write Vulkan shader cache, disk full?");
} else {
+1 -29
View File
@@ -85,26 +85,6 @@ protected:
VertexShaderFlags flags_;
};
class VulkanGeometryShader {
public:
VulkanGeometryShader(VulkanContext *vulkan, GShaderID id, const char *code);
~VulkanGeometryShader();
const std::string &source() const { return source_; }
std::string GetShaderString(DebugShaderStringType type) const;
Promise<VkShaderModule> *GetModule() const { return module_; }
const GShaderID &GetID() { return id_; }
protected:
Promise<VkShaderModule> *module_ = nullptr;
VulkanContext *vulkan_;
std::string source_;
GShaderID id_;
};
struct Uniforms {
// Uniform block scratchpad. These (the relevant ones) are copied to the current pushbuffer at draw time.
UB_VS_FS_Base ub_base{};
@@ -120,22 +100,19 @@ public:
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
void GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void ClearShaders() override;
void DirtyLastShader() override;
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
int GetNumGeometryShaders() const { return (int)gsCache_.size(); }
// Used for saving/loading the cache. Don't need to be particularly fast.
VulkanVertexShader *GetVertexShaderFromID(VShaderID id) { return vsCache_.GetOrNull(id); }
VulkanFragmentShader *GetFragmentShaderFromID(FShaderID id) { return fsCache_.GetOrNull(id); }
VulkanGeometryShader *GetGeometryShaderFromID(GShaderID id) { return gsCache_.GetOrNull(id); }
VulkanVertexShader *GetVertexShaderFromModule(VkShaderModule module);
VulkanFragmentShader *GetFragmentShaderFromModule(VkShaderModule module);
VulkanGeometryShader *GetGeometryShaderFromModule(VkShaderModule module);
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type) override;
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
@@ -174,9 +151,6 @@ private:
typedef DenseHashMap<VShaderID, VulkanVertexShader *> VSCache;
VSCache vsCache_;
typedef DenseHashMap<GShaderID, VulkanGeometryShader *> GSCache;
GSCache gsCache_;
char *codeBuffer_;
uint64_t uboAlignment_;
@@ -185,9 +159,7 @@ private:
VulkanFragmentShader *lastFShader_ = nullptr;
VulkanVertexShader *lastVShader_ = nullptr;
VulkanGeometryShader *lastGShader_ = nullptr;
FShaderID lastFSID_;
VShaderID lastVSID_;
GShaderID lastGSID_;
};
+1 -3
View File
@@ -94,7 +94,6 @@
<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" />
@@ -163,7 +162,6 @@
<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" />
@@ -239,4 +237,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+1 -3
View File
@@ -50,7 +50,6 @@
<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" />
@@ -132,7 +131,6 @@
<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" />
@@ -171,4 +169,4 @@
<UniqueIdentifier>{49bcf7f6-518a-4ecd-af55-bda3a344efe7}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>
-1
View File
@@ -560,7 +560,6 @@ 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/Common/TextureReplacer.cpp \
$(SRC)/GPU/Common/ReplacedTexture.cpp \
$(SRC)/GPU/Debugger/Breakpoints.cpp \
-1
View File
@@ -591,7 +591,6 @@ 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 \
-104
View File
@@ -12,7 +12,6 @@
#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"
@@ -90,34 +89,6 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs
}
}
bool GenerateGShader(GShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) {
buffer[0] = '\0';
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;
@@ -521,77 +492,6 @@ 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++) {
buffer[j][0] = 0;
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.
}
for (int j = 0; j < numLanguages; j++) {
if (strlen(buffer[j]) >= CODE_BUFFER_SIZE) {
printf("Geometry shader exceeded buffer:\n\n%s\n", LineNumberString(buffer[j]).c_str());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
return false;
}
}
// 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());
for (int i = 0; i < numLanguages; i++) {
delete[] buffer[i];
}
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();
@@ -604,10 +504,6 @@ bool TestShaderGenerators() {
return false;
}
if (!TestGeometryShaders()) {
return false;
}
if (!TestReinterpretShaders()) {
return false;
}