mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Delete geometry shader culling support. Is mostly replaced, and will be fully replaced with software transform.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user