Delete the "Hardware tessellation" feature.

Very hard to maintain and debug, not worth it.
This commit is contained in:
Henrik Rydgård committed 2026-06-16 16:17:14 +02:00
1 parent dffde6e189
commit 623545bd24
33 files changed
+66 -789

No files matched your search

+1 -1
View File
@@ -199,7 +199,7 @@ static_assert(sizeof(PackedDescriptor::buffer) == 16, "PackedDescriptor should b
struct VKRPipelineLayout {
~VKRPipelineLayout();
enum { MAX_DESC_SET_BINDINGS = 10 };
enum { MAX_DESC_SET_BINDINGS = 6 };
BindingType bindingTypes[MAX_DESC_SET_BINDINGS];
uint32_t bindingTypesCount = 0;
-1
View File
@@ -774,7 +774,6 @@ static const ConfigSetting graphicsSettings[] = {
// Not really a graphics setting...
ConfigSetting("SplineBezierQuality", SETTING(g_Config, iSplineBezierQuality), 2, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("HardwareTessellation", SETTING(g_Config, bHardwareTessellation), false, CfgFlag::PER_GAME | CfgFlag::REPORT),
ConfigSetting("TextureShader", SETTING(g_Config, sTextureShaderName), "Off", CfgFlag::PER_GAME),
ConfigSetting("ShaderChainRequires60FPS", SETTING(g_Config, bShaderChainRequires60FPS), false, CfgFlag::PER_GAME),
-1
View File
@@ -362,7 +362,6 @@ public:
int iBloomHack; //0 = off, 1 = safe, 2 = balanced, 3 = aggressive
int iSkipGPUReadbackMode; // 0 = off, 1 = skip, 2 = to texture
int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High
bool bHardwareTessellation;
bool bShaderCache; // Hidden ini-only setting, useful for debugging shader compile times.
bool bUberShaderVertex;
int iDefaultTab;
-30
View File
@@ -115,7 +115,6 @@ void DrawEngineCommon::NotifyConfigChanged() {
decoderMap_.Clear();
useHWTransform_ = g_Config.bHardwareTransform;
useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation);
}
void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) {
@@ -979,35 +978,6 @@ bool DrawEngineCommon::CanUseHardwareTransform(int prim) const {
return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && prim > GE_PRIM_LINE_STRIP;
}
bool DrawEngineCommon::CanUseHardwareTessellation(GEPatchPrimType prim) const {
if (useHWTessellation_) {
return CanUseHardwareTransform(PatchPrimToPrim(prim));
}
return false;
}
void TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType) {
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0;
for (int i = 0; i < size; ++i) {
memcpy(pos, points[i]->pos.AsArray(), 3 * sizeof(float));
pos += posStride;
}
if (hasTexCoord) {
for (int i = 0; i < size; ++i) {
memcpy(tex, points[i]->uv, 2 * sizeof(float));
tex += texStride;
}
}
if (hasColor) {
for (int i = 0; i < size; ++i) {
memcpy(col, Vec4f::FromRGBA(points[i]->color_32).AsArray(), 4 * sizeof(float));
col += colStride;
}
}
}
bool DrawEngineCommon::DescribeCodePtr(const u8 *ptr, std::string &name) const {
if (!decJitCache_ || !decJitCache_->IsInSpace(ptr)) {
return false;
-14
View File
@@ -59,13 +59,6 @@ enum FBOTexState {
struct SimpleVertex;
namespace Spline { struct Weight2D; }
class TessellationDataTransfer {
public:
virtual ~TessellationDataTransfer() {}
static void CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType);
virtual void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) = 0;
};
// Culling plane, group of 8.
struct alignas(16) Plane8 {
float x[8], y[8], z[8], w[8];
@@ -129,7 +122,6 @@ public:
static void ClearSplineBezierWeights();
bool CanUseHardwareTransform(int prim) const;
bool CanUseHardwareTessellation(GEPatchPrimType prim) const;
std::vector<std::string> DebugGetVertexLoaderIDs();
std::string DebugGetVertexLoaderString(std::string_view id, DebugShaderStringType stringType);
@@ -164,8 +156,6 @@ public:
void FlushQueuedDepth();
protected:
virtual bool UpdateUseHWTessellation(bool enabled) const { return enabled; }
bool CheckClipFlags(bool useHwTransform) const;
void DecodeVerts(const VertexDecoder *dec, u8 *dest);
@@ -273,7 +263,6 @@ protected:
}
bool useHWTransform_ = false;
bool useHWTessellation_ = false;
// Used to prevent unnecessary flushing in softgpu.
bool flushOnParams_ = true;
@@ -346,9 +335,6 @@ protected:
ComputedPipelineState pipelineState_{};
// Hardware tessellation
TessellationDataTransfer *tessDataTransfer = nullptr;
GPUCommon *gpuCommon_ = nullptr;
// Software depth raster
+4 -4
View File
@@ -68,10 +68,10 @@ enum : uint64_t {
DIRTY_SHADERBLEND = 1ULL << 17, // Used only for in-shader blending.
DIRTY_UVSCALEOFFSET = 1ULL << 18,
// Free bit 19!
// Free uniform bit 19!
DIRTY_VIEWPORT_UNIFORMS = 1ULL << 20,
// Free bit 20!
// Free uniform bit 20!
DIRTY_WORLDMATRIX = 1ULL << 21,
DIRTY_VIEWMATRIX = 1ULL << 22,
@@ -85,9 +85,9 @@ enum : uint64_t {
DIRTY_BONEMATRIX6 = 1ULL << 30,
DIRTY_BONEMATRIX7 = 1ULL << 31,
DIRTY_BEZIERSPLINE = 1ULL << 32,
// Free uniform bit 32!,
DIRTY_TEXCLAMP = 1ULL << 33,
// Free bit 34!
// Free uniform bit 34!
DIRTY_DEPAL = 1ULL << 35,
DIRTY_COLORWRITEMASK = 1ULL << 36,
+1 -19
View File
@@ -55,12 +55,6 @@ std::string VertexShaderDesc(const VShaderID &id) {
if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";
if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";
if (id.Bit(VS_BIT_BEZIER)) desc << "Bezier ";
if (id.Bit(VS_BIT_SPLINE)) desc << "Spline ";
if (id.Bit(VS_BIT_HAS_COLOR_TESS)) desc << "TessC ";
if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT ";
if (id.Bit(VS_BIT_HAS_NORMAL_TESS)) desc << "TessN ";
if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN ";
if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "RangeCull ";
if (id.Bit(VS_BIT_SIMPLE_STEREO)) desc << "SimpleStereo ";
@@ -70,7 +64,7 @@ std::string VertexShaderDesc(const VShaderID &id) {
return desc.str();
}
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
const bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
const bool isSoftwareFallback = !isModeThrough && !useHWTransform && g_Config.bHardwareTransform;
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
@@ -151,18 +145,6 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
id.SetBit(VS_BIT_HAS_TEXCOORD, vtypeHasTexcoord);
if (useHWTessellation) {
id.SetBit(VS_BIT_BEZIER, doBezier);
id.SetBit(VS_BIT_SPLINE, doSpline);
if (doBezier || doSpline) {
// These are the original vertType's values (normalized will always have colors, etc.)
id.SetBit(VS_BIT_HAS_COLOR_TESS, (gstate.vertType & GE_VTYPE_COL_MASK) != 0);
id.SetBit(VS_BIT_HAS_TEXCOORD_TESS, (gstate.vertType & GE_VTYPE_TC_MASK) != 0);
id.SetBit(VS_BIT_HAS_NORMAL_TESS, (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 || gstate.isLightingEnabled());
}
id.SetBit(VS_BIT_NORM_REVERSE_TESS, gstate.isPatchNormalsReversed());
}
}
if (clipInfoFlags & ClipInfoFlags::DepthClampFragment) {
+4 -8
View File
@@ -36,10 +36,7 @@ enum VShaderBit : uint8_t {
VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform
VS_BIT_NORM_REVERSE = 10,
VS_BIT_HAS_TEXCOORD = 11,
VS_BIT_HAS_COLOR_TESS = 12, // 1 bit
VS_BIT_HAS_TEXCOORD_TESS = 13, // 1 bit
VS_BIT_NORM_REVERSE_TESS = 14, // 1 bit
VS_BIT_HAS_NORMAL_TESS = 15, // 1 bit
// 4 bits free: 12-15
VS_BIT_UVGEN_MODE = 16,
VS_BIT_UVPROJ_MODE = 18, // 2, can overlap with LS0
VS_BIT_LS0 = 18, // 2
@@ -61,7 +58,7 @@ enum VShaderBit : uint8_t {
VS_BIT_LIGHT3_COMP = 44, // 2 bits
VS_BIT_LIGHT3_TYPE = 46, // 2 bits
VS_BIT_MATERIAL_UPDATE = 48, // 3 bits
VS_BIT_SPLINE = 51, // 1 bit
// Bit 51 is free.
VS_BIT_LIGHT0_ENABLE = 52,
VS_BIT_LIGHT1_ENABLE = 53,
VS_BIT_LIGHT2_ENABLE = 54,
@@ -72,8 +69,7 @@ enum VShaderBit : uint8_t {
VS_BIT_FS_MINMAX_DISCARD = 59, // Do min/max and/or depth clamp in the fragment shader. It just means we need to forward Z and W to the fragment shader.
VS_BIT_FS_DEPTH_CLAMP = 60, // Do depth clamp in the fragment shader.
VS_BIT_FLATSHADE = 62, // 1 bit
VS_BIT_BEZIER = 63, // 1 bit
// No more free
// Bit 63 is free.
};
static inline VShaderBit operator +(VShaderBit bit, int i) {
@@ -259,7 +255,7 @@ namespace Draw {
class Bugs;
}
void ComputeVertexShaderID(VShaderID *id, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void ComputeVertexShaderID(VShaderID *id, u32 vertType, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string VertexShaderDesc(const VShaderID &id);
-4
View File
@@ -148,10 +148,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool useBuffe
UpdateUVScaleOff(gstate, ub->uvScaleOffset);
}
if (dirtyUniforms & DIRTY_BEZIERSPLINE) {
ub->spline_counts = gstate_c.spline_num_points_u;
}
if (dirtyUniforms & DIRTY_DEPAL) {
ub->depal_mask_shift_off_fmt = PackDepalBits();
}
+2 -2
View File
@@ -13,7 +13,7 @@ enum : uint64_t {
DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF |
DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_TEX_ALPHA_MUL | DIRTY_STENCILREPLACEVALUE |
DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_COLORWRITEMASK | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_MATAMBIENTALPHA |
DIRTY_BEZIERSPLINE | DIRTY_DEPAL | DIRTY_VIEWPORT_UNIFORMS | DIRTY_RASTER_OFFSET,
DIRTY_DEPAL | DIRTY_VIEWPORT_UNIFORMS | DIRTY_RASTER_OFFSET,
DIRTY_LIGHT_UNIFORMS =
DIRTY_LIGHT_CONTROL | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 |
DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT,
@@ -32,7 +32,7 @@ struct alignas(16) UB_VS_FS_Base {
float rasterOffset[2]; float minZmaxZ[2];
float uvScaleOffset[4];
float matAmbient[4];
uint32_t spline_counts; uint32_t depal_mask_shift_off_fmt; // 4 params packed into one.
uint32_t padding3; uint32_t depal_mask_shift_off_fmt; // 4 params packed into one.
uint32_t colorWriteMask; float mipBias;
// Fragment data
float texNoAlpha; float texMul; float padding4[2]; // this vec4 will hold ubershader stuff. We won't use integer flags in the fragment shader.
+5 -48
View File
@@ -435,45 +435,6 @@ void SoftwareTessellation(OutputBuffers &output, const Surface &surface, u32 ori
template void SoftwareTessellation<BezierSurface>(OutputBuffers &output, const BezierSurface &surface, u32 origVertType, const ControlPoints &points);
template void SoftwareTessellation<SplineSurface>(OutputBuffers &output, const SplineSurface &surface, u32 origVertType, const ControlPoints &points);
template<class Surface>
static void HardwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType,
const SimpleVertex *const *points, TessellationDataTransfer *tessDataTransfer) {
using WeightType = typename Surface::WeightType;
u32 key_u = WeightType::ToKey(surface.tess_u, surface.num_points_u, surface.type_u);
u32 key_v = WeightType::ToKey(surface.tess_v, surface.num_points_v, surface.type_v);
Weight2D weights(WeightType::weightsCache, key_u, key_v);
weights.size_u = WeightType::CalcSize(surface.tess_u, surface.num_points_u);
weights.size_v = WeightType::CalcSize(surface.tess_v, surface.num_points_v);
tessDataTransfer->SendDataToShader(points, surface.num_points_u, surface.num_points_v, origVertType, weights);
// Generating simple input vertices for the spline-computing vertex shader.
float inv_u = 1.0f / (float)surface.tess_u;
float inv_v = 1.0f / (float)surface.tess_v;
for (int patch_u = 0; patch_u < surface.num_patches_u; ++patch_u) {
const int start_u = surface.GetTessStart(patch_u);
for (int patch_v = 0; patch_v < surface.num_patches_v; ++patch_v) {
const int start_v = surface.GetTessStart(patch_v);
for (int tile_u = start_u; tile_u <= surface.tess_u; ++tile_u) {
const int index_u = surface.GetIndexU(patch_u, tile_u);
for (int tile_v = start_v; tile_v <= surface.tess_v; ++tile_v) {
const int index_v = surface.GetIndexV(patch_v, tile_v);
SimpleVertex &vert = output.vertices[surface.GetIndex(index_u, index_v, patch_u, patch_v)];
// Index for the weights
vert.pos.x = index_u;
vert.pos.y = index_v;
// For texcoord generation
vert.nrm.x = patch_u + (float)tile_u * inv_u;
vert.nrm.y = patch_v + (float)tile_v * inv_v;
// Patch position
vert.pos.z = patch_u;
vert.nrm.z = patch_v;
}
}
}
}
surface.BuildIndex(output.indices, output.count);
}
} // namespace Spline
using namespace Spline;
@@ -551,15 +512,11 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
surface.Init(maxVerts);
if (CanUseHardwareTessellation(surface.primType)) {
HardwareTessellation(output, surface, origVertType, points, tessDataTransfer);
} else {
ControlPoints cpoints(points, num_points, managedBuf);
if (cpoints.IsValid())
SoftwareTessellation(output, surface, origVertType, cpoints);
else
ERROR_LOG(Log::G3D, "Failed to allocate space for control point values, skipping curve draw");
}
ControlPoints cpoints(points, num_points, managedBuf);
if (cpoints.IsValid())
SoftwareTessellation(output, surface, origVertType, cpoints);
else
ERROR_LOG(Log::G3D, "Failed to allocate space for control point values, skipping curve draw");
u32 vertTypeWithIndex16 = (vertType & ~GE_VTYPE_IDX_MASK) | GE_VTYPE_IDX_16BIT;
+19 -238
View File
@@ -202,25 +202,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
return false;
}
// Apparently we don't support bezier/spline together with bones.
bool doBezier = id.Bit(VS_BIT_BEZIER) && !enableBones && useHWTransform;
bool doSpline = id.Bit(VS_BIT_SPLINE) && !enableBones && useHWTransform;
if (doBezier || doSpline) {
if (!hasNormal) {
// Bad usage.
*errorString = "Invalid flags - tess requires normal.";
return false;
}
if (compat.texelFetch == nullptr) {
*errorString = "Tess not supported on this shader language version";
return false;
}
}
bool hasColorTess = id.Bit(VS_BIT_HAS_COLOR_TESS);
bool hasTexcoordTess = id.Bit(VS_BIT_HAS_TEXCOORD_TESS);
bool hasNormalTess = id.Bit(VS_BIT_HAS_NORMAL_TESS);
bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS);
// Should we do the min/max discard in the shader and/or or use depth clamping?
// In both cases we need to just forward
const bool fsMinmaxDiscard = id.Bit(VS_BIT_FS_MINMAX_DISCARD);
@@ -316,9 +297,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
// And the "varyings".
if (useHWTransform) {
WRITE(p, "struct VS_IN { \n");
if ((doSpline || doBezier) && compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " uint instanceId : SV_InstanceID;\n");
}
if (enableBones) {
WRITE(p, " %s", boneWeightAttrDeclHLSL[numBoneWeights]);
}
@@ -538,163 +516,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
}
// Hardware tessellation
if (doBezier || doSpline) {
*uniformMask |= DIRTY_BEZIERSPLINE;
if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, "struct TessData {\n");
WRITE(p, " vec4 pos;\n");
WRITE(p, " vec4 tex;\n");
WRITE(p, " vec4 col;\n");
WRITE(p, "};\n");
WRITE(p, "layout (std430, set = 0, binding = %d) readonly buffer s_tess_data {\n", DRAW_BINDING_TESS_STORAGE_BUF);
WRITE(p, " TessData tess_data[];\n");
WRITE(p, "};\n");
WRITE(p, "struct TessWeight {\n");
WRITE(p, " vec4 basis;\n");
WRITE(p, " vec4 deriv;\n");
WRITE(p, "};\n");
WRITE(p, "layout (std430, set = 0, binding = %d) readonly buffer s_tess_weights_u {\n", DRAW_BINDING_TESS_STORAGE_BUF_WU);
WRITE(p, " TessWeight tess_weights_u[];\n");
WRITE(p, "};\n");
WRITE(p, "layout (std430, set = 0, binding = %d) readonly buffer s_tess_weights_v {\n", DRAW_BINDING_TESS_STORAGE_BUF_WV);
WRITE(p, " TessWeight tess_weights_v[];\n");
WRITE(p, "};\n");
} else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
WRITE(p, "uniform sampler2D u_tess_points;\n"); // Control Points
WRITE(p, "uniform sampler2D u_tess_weights_u;\n");
WRITE(p, "uniform sampler2D u_tess_weights_v;\n");
WRITE(p, "uniform int u_spline_counts;\n");
} else if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "struct TessData {\n");
WRITE(p, " vec3 pos; float pad1;\n");
WRITE(p, " vec2 tex; vec2 pad2;\n");
WRITE(p, " vec4 col;\n");
WRITE(p, "};\n");
WRITE(p, "StructuredBuffer<TessData> tess_data : register(t0);\n");
WRITE(p, "struct TessWeight {\n");
WRITE(p, " vec4 basis;\n");
WRITE(p, " vec4 deriv;\n");
WRITE(p, "};\n");
WRITE(p, "StructuredBuffer<TessWeight> tess_weights_u : register(t1);\n");
WRITE(p, "StructuredBuffer<TessWeight> tess_weights_v : register(t2);\n");
}
const char *init[3] = { "0.0, 0.0", "0.0, 0.0, 0.0", "0.0, 0.0, 0.0, 0.0" };
for (int i = 2; i <= 4; i++) {
// Define 3 types vec2, vec3, vec4
WRITE(p, "vec%d tess_sample(in vec%d points[16], mat4 weights) {\n", i, i);
WRITE(p, " vec%d pos = vec%d(%s);\n", i, i, init[i - 2]);
for (int v = 0; v < 4; ++v) {
for (int u = 0; u < 4; ++u) {
WRITE(p, " pos += weights[%i][%i] * points[%i];\n", v, u, v * 4 + u);
}
}
WRITE(p, " return pos;\n");
WRITE(p, "}\n");
}
if (ShaderLanguageIsOpenGL(compat.shaderLanguage) && compat.glslVersionNumber < 130) { // For glsl version 1.10
WRITE(p, "mat4 outerProduct(vec4 u, vec4 v) {\n");
WRITE(p, " return mat4(u * v[0], u * v[1], u * v[2], u * v[3]);\n");
WRITE(p, "}\n");
} else if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "mat4 outerProduct(vec4 u, vec4 v) {\n");
WRITE(p, " return mul((float4x1)v, (float1x4)u);\n");
WRITE(p, "}\n");
}
WRITE(p, "struct Tess {\n");
WRITE(p, " vec3 pos;\n");
WRITE(p, " vec2 tex;\n");
WRITE(p, " vec4 col;\n");
if (hasNormalTess)
WRITE(p, " vec3 nrm;\n");
WRITE(p, "};\n");
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "void tessellate(in VS_IN In, out Tess tess) {\n");
WRITE(p, " vec3 position = In.position;\n");
WRITE(p, " vec3 normal = In.normal;\n");
} else {
WRITE(p, "void tessellate(out Tess tess) {\n");
}
WRITE(p, " ivec2 point_pos = ivec2(position.z, normal.z)%s;\n", doBezier ? " * 3" : "");
WRITE(p, " ivec2 weight_idx = ivec2(position.xy);\n");
// Load 4x4 control points
WRITE(p, " vec3 _pos[16];\n");
WRITE(p, " vec2 _tex[16];\n");
WRITE(p, " vec4 _col[16];\n");
if (compat.coefsFromBuffers) {
WRITE(p, " int index;\n");
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
WRITE(p, " index = (%i + point_pos.y) * int(u_spline_counts) + (%i + point_pos.x);\n", i, j);
WRITE(p, " _pos[%i] = tess_data[index].pos.xyz;\n", i * 4 + j);
if (hasTexcoordTess)
WRITE(p, " _tex[%i] = tess_data[index].tex.xy;\n", i * 4 + j);
if (hasColorTess)
WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j);
}
}
// Basis polynomials as weight coefficients
WRITE(p, " vec4 basis_u = tess_weights_u[weight_idx.x].basis;\n");
WRITE(p, " vec4 basis_v = tess_weights_v[weight_idx.y].basis;\n");
WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n");
} else {
WRITE(p, " int index_u, index_v;\n");
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
WRITE(p, " index_u = (%i + point_pos.x);\n", j);
WRITE(p, " index_v = (%i + point_pos.y);\n", i);
WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, compat.texelFetch);
if (hasTexcoordTess)
WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, compat.texelFetch);
if (hasColorTess)
WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, compat.texelFetch);
}
}
// Basis polynomials as weight coefficients
WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.x * 2, 0)");
WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.y * 2, 0)");
WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n");
}
// Tessellate
WRITE(p, " tess.pos = tess_sample(_pos, basis);\n");
if (hasTexcoordTess)
WRITE(p, " tess.tex = tess_sample(_tex, basis);\n");
else
WRITE(p, " tess.tex = normal.xy;\n");
if (hasColorTess)
WRITE(p, " tess.col = tess_sample(_col, basis);\n");
else
WRITE(p, " tess.col = u_matambientalpha;\n");
if (hasNormalTess) {
if (compat.coefsFromBuffers) {
// Derivatives as weight coefficients
WRITE(p, " vec4 deriv_u = tess_weights_u[weight_idx.x].deriv;\n");
WRITE(p, " vec4 deriv_v = tess_weights_v[weight_idx.y].deriv;\n");
} else {
// Derivatives as weight coefficients
WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.x * 2 + 1, 0)");
WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.y * 2 + 1, 0)");
}
WRITE(p, " vec3 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n");
WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n");
WRITE(p, " tess.nrm = normalize(cross(du, dv));\n");
}
WRITE(p, "}\n");
}
if (useHWTransform) {
WRITE(p, "vec3 normalizeOr001(vec3 v) {\n");
WRITE(p, " return length(v) == 0.0 ? vec3(0.0, 0.0, 1.0) : normalize(v);\n");
@@ -766,28 +587,13 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
} else {
// Step 1: World Transform / Skinning
if (!enableBones) {
if (doBezier || doSpline) {
// Hardware tessellation
WRITE(p, " Tess tess;\n");
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " tessellate(In, tess);\n");
} else {
WRITE(p, " tessellate(tess);\n");
}
WRITE(p, " vec3 worldpos = mul(vec4(tess.pos.xyz, 1.0), u_world).xyz;\n");
if (hasNormalTess) {
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%stess.nrm, 0.0), u_world).xyz);\n", flipNormalTess ? "-" : "");
} else {
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormalTess ? "-" : "");
}
// No skinning, just standard T&L.
WRITE(p, " vec3 worldpos = mul(vec4(position, 1.0), u_world).xyz;\n");
if (hasNormal) {
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%snormal, 0.0), u_world).xyz);\n", flipNormal ? "-" : "");
} else {
// No skinning, just standard T&L.
WRITE(p, " vec3 worldpos = mul(vec4(position, 1.0), u_world).xyz;\n");
if (hasNormal)
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(%snormal, 0.0), u_world).xyz);\n", flipNormal ? "-" : "");
else
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormal ? "-" : "");
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormal ? "-" : "");
}
} else {
static const char * const rescale[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f};
@@ -878,11 +684,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
// TODO: Declare variables for dots for shade mapping if needed.
const char *srcCol = "color0";
if (doBezier || doSpline) {
// TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background.
srcCol = "tess.col";
}
if (lightUberShader && hasColor) {
p.F(" vec4 ambientColor = ((u_lightControl & (1u << 0x14u)) != 0x0u) ? %s : u_matambientalpha;\n", srcCol);
if (enableLighting) {
@@ -1115,10 +916,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
} else {
// Lighting doesn't affect color.
if (hasColor) {
if (doBezier || doSpline)
WRITE(p, " %sv_color0 = tess.col;\n", compat.vsOutPrefix);
else
WRITE(p, " %sv_color0 = color0;\n", compat.vsOutPrefix);
WRITE(p, " %sv_color0 = color0;\n", compat.vsOutPrefix);
} else {
WRITE(p, " %sv_color0 = u_matambientalpha;\n", compat.vsOutPrefix);
if (bugs.Has(Draw::Bugs::MALI_CONSTANT_LOAD_BUG) && g_Config.bVendorBugChecksEnabled) {
@@ -1139,19 +937,13 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
case GE_TEXMAP_UNKNOWN: // Not sure what this is, but Riviera uses it. Treating as coords works.
if (scaleUV) {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " %sv_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix);
else
WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n", compat.vsOutPrefix);
WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n", compat.vsOutPrefix);
} else {
WRITE(p, " %sv_texcoord = splat3(0.0);\n", compat.vsOutPrefix);
}
} else {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " %sv_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix);
else
WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix);
WRITE(p, " %sv_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix);
} else {
WRITE(p, " %sv_texcoord = vec3(u_uvscaleoffset.zw, 0.0);\n", compat.vsOutPrefix);
}
@@ -1163,39 +955,28 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
std::string temp_tc;
switch (uvProjMode) {
case GE_PROJMAP_POSITION: // Use model space XYZ as source
if (doBezier || doSpline)
temp_tc = "vec4(tess.pos, 1.0)";
else
temp_tc = "vec4(position, 1.0)";
temp_tc = "vec4(position, 1.0)";
break;
case GE_PROJMAP_UV: // Use unscaled UV as source
{
// prescale is false here.
if (hasTexcoord) {
if (doBezier || doSpline)
temp_tc = "vec4(tess.tex.xy, 0.0, 1.0)";
else
temp_tc = "vec4(texcoord.xy, 0.0, 1.0)";
} else {
temp_tc = "vec4(0.0, 0.0, 0.0, 1.0)";
}
if (hasTexcoord) {
temp_tc = "vec4(texcoord.xy, 0.0, 1.0)";
} else {
temp_tc = "vec4(0.0, 0.0, 0.0, 1.0)";
}
break;
case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized transformed normal as source
if ((doBezier || doSpline) && hasNormalTess)
temp_tc = StringFromFormat("length(tess.nrm) == 0.0 ? vec4(0.0, 0.0, 0.0, 1.0) : vec4(normalize(%stess.nrm), 1.0)", flipNormalTess ? "-" : "");
else if (hasNormal)
if (hasNormal) {
temp_tc = StringFromFormat("length(normal) == 0.0 ? vec4(0.0, 0.0, 0.0, 1.0) : vec4(normalize(%snormal), 1.0)", flipNormal ? "-" : "");
else
} else {
temp_tc = "vec4(0.0, 0.0, 1.0, 1.0)";
}
break;
case GE_PROJMAP_NORMAL: // Use non-normalized transformed normal as source
if ((doBezier || doSpline) && hasNormalTess)
temp_tc = flipNormalTess ? "vec4(-tess.nrm, 1.0)" : "vec4(tess.nrm, 1.0)";
else if (hasNormal)
if (hasNormal) {
temp_tc = flipNormal ? "vec4(-normal, 1.0)" : "vec4(normal, 1.0)";
else
} else {
temp_tc = "vec4(0.0, 0.0, 1.0, 1.0)";
}
break;
}
// Transform by texture matrix. XYZ as we are doing projection mapping.
+2 -100
View File
@@ -85,9 +85,6 @@ void DrawEngineD3D11::InitDeviceObjects() {
pushVerts_ = new PushBufferD3D11(device_, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER);
pushInds_ = new PushBufferD3D11(device_, INDEX_PUSH_SIZE, D3D11_BIND_INDEX_BUFFER);
tessDataTransferD3D11 = new TessellationDataTransferD3D11(context_, device_);
tessDataTransfer = tessDataTransferD3D11;
draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1));
}
@@ -97,9 +94,6 @@ void DrawEngineD3D11::DestroyDeviceObjects() {
}
ClearInputLayoutMap();
delete tessDataTransferD3D11;
tessDataTransferD3D11 = nullptr;
tessDataTransfer = nullptr;
delete pushVerts_;
delete pushInds_;
pushVerts_ = nullptr;
@@ -347,7 +341,7 @@ void DrawEngineD3D11::Flush() {
D3D11VertexShader *vshader;
D3D11FragmentShader *fshader;
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, useHWTransform, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
ID3D11InputLayout *inputLayout;
SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType(), &inputLayout);
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
@@ -459,7 +453,7 @@ void DrawEngineD3D11::Flush() {
if (action == SW_DRAW_INDEXED) {
D3D11VertexShader *vshader;
D3D11FragmentShader *fshader;
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
@@ -519,95 +513,3 @@ void DrawEngineD3D11::Flush() {
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
gpuCommon_->NotifyFlush();
}
TessellationDataTransferD3D11::TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device)
: context_(context), device_(device) {
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
}
TessellationDataTransferD3D11::~TessellationDataTransferD3D11() {
}
void TessellationDataTransferD3D11::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {
struct TessData {
float pos[3]; float pad1;
float uv[2]; float pad2[2];
float color[4];
};
int size = size_u * size_v;
if (prevSize < size || !buf[0]) {
prevSize = size;
buf[0].Reset();
view[0].Reset();
desc.ByteWidth = size * sizeof(TessData);
desc.StructureByteStride = sizeof(TessData);
device_->CreateBuffer(&desc, nullptr, &buf[0]);
if (buf[0])
device_->CreateShaderResourceView(buf[0].Get(), nullptr, &view[0]);
if (!buf[0] || !view[0])
return;
context_->VSSetShaderResources(0, 1, view[0].GetAddressOf());
}
D3D11_MAPPED_SUBRESOURCE map{};
HRESULT hr = context_->Map(buf[0].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr))
return;
uint8_t *data = (uint8_t *)map.pData;
float *pos = (float *)(data);
float *tex = (float *)(data + offsetof(TessData, uv));
float *col = (float *)(data + offsetof(TessData, color));
int stride = sizeof(TessData) / sizeof(float);
CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType);
context_->Unmap(buf[0].Get(), 0);
using Spline::Weight;
// Weights U
if (prevSizeWU < weights.size_u || !buf[1]) {
prevSizeWU = weights.size_u;
buf[1].Reset();
view[1].Reset();
desc.ByteWidth = weights.size_u * sizeof(Weight);
desc.StructureByteStride = sizeof(Weight);
device_->CreateBuffer(&desc, nullptr, &buf[1]);
if (buf[1])
device_->CreateShaderResourceView(buf[1].Get(), nullptr, &view[1]);
if (!buf[1] || !view[1])
return;
context_->VSSetShaderResources(1, 1, view[1].GetAddressOf());
}
hr = context_->Map(buf[1].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr))
memcpy(map.pData, weights.u, weights.size_u * sizeof(Weight));
context_->Unmap(buf[1].Get(), 0);
// Weights V
if (prevSizeWV < weights.size_v) {
prevSizeWV = weights.size_v;
buf[2].Reset();
view[2].Reset();
desc.ByteWidth = weights.size_v * sizeof(Weight);
desc.StructureByteStride = sizeof(Weight);
device_->CreateBuffer(&desc, nullptr, &buf[2]);
if (buf[2])
device_->CreateShaderResourceView(buf[2].Get(), nullptr, &view[2]);
if (!buf[2] || !view[2])
return;
context_->VSSetShaderResources(2, 1, view[2].GetAddressOf());
}
hr = context_->Map(buf[2].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr))
memcpy(map.pData, weights.v, weights.size_v * sizeof(Weight));
context_->Unmap(buf[2].Get(), 0);
}
-19
View File
@@ -37,22 +37,6 @@ class ShaderManagerD3D11;
class TextureCacheD3D11;
class FramebufferManagerD3D11;
class TessellationDataTransferD3D11 : public TessellationDataTransfer {
private:
ID3D11DeviceContext *context_;
ID3D11Device *device_;
Microsoft::WRL::ComPtr<ID3D11Buffer> buf[3]{};
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> view[3]{};
D3D11_BUFFER_DESC desc{};
int prevSize = 0;
int prevSizeWU = 0, prevSizeWV = 0;
public:
TessellationDataTransferD3D11(ID3D11DeviceContext *context, ID3D11Device *device);
~TessellationDataTransferD3D11();
// Send spline/bezier's control points and weights to vertex shader through structured shader buffer.
void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override;
};
// Handles transform, lighting and drawing.
class DrawEngineD3D11 : public DrawEngineCommon {
public:
@@ -140,8 +124,5 @@ private:
D3D11StateKeys keys_{};
D3D11DynamicState dynState_{};
// Hardware tessellation
TessellationDataTransferD3D11 *tessDataTransferD3D11 = nullptr;
int lastRenderStepId_ = -1;
};
-1
View File
@@ -83,7 +83,6 @@ u32 GPU_D3D11::CheckGPUFeatures() const {
u32 features = GPUCommonHW::CheckGPUFeatures();
features |= GPU_USE_TEXTURE_FLOAT;
features |= GPU_USE_INSTANCE_RENDERING;
features |= GPU_USE_TEXTURE_LOD_CONTROL;
uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16);
+2 -2
View File
@@ -186,13 +186,13 @@ void ShaderManagerD3D11::BindUniforms() {
context_->PSSetConstantBuffers(0, 1, ps_cbs);
}
void ShaderManagerD3D11::GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
void ShaderManagerD3D11::GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
VShaderID VSID;
FShaderID FSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode, clipInfoFlags);
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, weightsAsFloat, useSkinInDecode, clipInfoFlags);
} else {
VSID = lastVSID_;
}
+1 -1
View File
@@ -88,7 +88,7 @@ public:
ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel);
~ShaderManagerD3D11();
void GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void ClearShaders() override;
void DirtyLastShader() override;
+1 -84
View File
@@ -57,15 +57,10 @@ DrawEngineGLES::DrawEngineGLES(Draw::DrawContext *draw) : inputLayoutMap_(16), d
decOptions_.expand8BitNormalsToFloat = false;
InitDeviceObjects();
tessDataTransferGLES = new TessellationDataTransferGLES(render_);
tessDataTransfer = tessDataTransferGLES;
}
DrawEngineGLES::~DrawEngineGLES() {
DestroyDeviceObjects();
delete tessDataTransferGLES;
}
void DrawEngineGLES::DeviceLost() {
@@ -147,7 +142,6 @@ void DrawEngineGLES::EndFrame() {
FrameData &frameData = frameData_[render_->GetCurFrame()];
frameData.pushIndex->End();
frameData.pushVertex->End();
tessDataTransferGLES->EndFrame();
}
struct GlTypeInfo {
@@ -275,7 +269,7 @@ void DrawEngineGLES::Flush() {
lastUseHwTransform_ = useHWTransform;
}
Shader *vshader = shaderManager_->ApplyVertexShader(useHWTransform, useHWTessellation_, dec_->VertexType(), decOptions_.expandAllWeightsToFloat, applySkinInDecode_ || !useHWTransform, clipInfoFlags_, &vsid);
Shader *vshader = shaderManager_->ApplyVertexShader(useHWTransform, dec_->VertexType(), decOptions_.expandAllWeightsToFloat, applySkinInDecode_ || !useHWTransform, clipInfoFlags_, &vsid);
useHWTransform = vshader->UseHWTransform(); // In case shader compilation failed and it fell back. However, this can no longer really happen... Need to fix this.
@@ -458,80 +452,3 @@ bail:
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
gpuCommon_->NotifyFlush();
}
// TODO: Refactor this to a single USE flag.
bool DrawEngineGLES::SupportsHWTessellation() {
bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4;
return hasTexelFetch && gstate_c.UseAll(GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_INSTANCE_RENDERING);
}
bool DrawEngineGLES::UpdateUseHWTessellation(bool enable) const {
return enable && SupportsHWTessellation();
}
void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0;
int size = size_u * size_v;
float *pos = new float[size * 4];
float *tex = hasTexCoord ? new float[size * 4] : nullptr;
float *col = hasColor ? new float[size * 4] : nullptr;
int stride = 4;
CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType);
// Removed the 1D texture support, it's unlikely to be relevant for performance.
// Control Points
if (prevSizeU < size_u || prevSizeV < size_v) {
prevSizeU = size_u;
prevSizeV = size_v;
if (data_tex[0])
renderManager_->DeleteTexture(data_tex[0]);
data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D, size_u * 3, size_v, 1, 1);
renderManager_->TextureImage(data_tex[0], 0, size_u * 3, size_v, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);
renderManager_->FinalizeTexture(data_tex[0], 0, false);
}
renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]);
// Position
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, 0, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)pos, GLRAllocType::NEW);
// Texcoord
if (hasTexCoord)
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)tex, GLRAllocType::NEW);
// Color
if (hasColor)
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u * 2, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)col, GLRAllocType::NEW);
// Weight U
if (prevSizeWU < weights.size_u) {
prevSizeWU = weights.size_u;
if (data_tex[1])
renderManager_->DeleteTexture(data_tex[1]);
data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_u * 2, 1, 1, 1);
renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);
renderManager_->FinalizeTexture(data_tex[1], 0, false);
}
renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1]);
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1], 0, 0, 0, weights.size_u * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.u, GLRAllocType::NONE);
// Weight V
if (prevSizeWV < weights.size_v) {
prevSizeWV = weights.size_v;
if (data_tex[2])
renderManager_->DeleteTexture(data_tex[2]);
data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_v * 2, 1, 1, 1);
renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);
renderManager_->FinalizeTexture(data_tex[2], 0, false);
}
renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]);
renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2], 0, 0, 0, weights.size_v * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.v, GLRAllocType::NONE);
}
void TessellationDataTransferGLES::EndFrame() {
for (int i = 0; i < 3; i++) {
if (data_tex[i]) {
renderManager_->DeleteTexture(data_tex[i]);
data_tex[i] = nullptr;
}
}
prevSizeU = prevSizeV = prevSizeWU = prevSizeWV = 0;
}
-25
View File
@@ -40,23 +40,6 @@ struct TransformedVertex;
struct DecVtxFormat;
class TessellationDataTransferGLES : public TessellationDataTransfer {
private:
GLRTexture *data_tex[3]{};
int prevSizeU = 0, prevSizeV = 0;
int prevSizeWU = 0, prevSizeWV = 0;
GLRenderManager *renderManager_;
public:
TessellationDataTransferGLES(GLRenderManager *renderManager)
: renderManager_(renderManager) { }
~TessellationDataTransferGLES() {
EndFrame();
}
// Send spline/bezier's control points and weights to vertex shader through floating point texture.
void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override;
void EndFrame(); // Queues textures for deletion.
};
// Handles transform, lighting and drawing.
class DrawEngineGLES : public DrawEngineCommon {
public:
@@ -90,11 +73,6 @@ public:
void ClearInputLayoutMap();
static bool SupportsHWTessellation() ;
protected:
bool UpdateUseHWTessellation(bool enable) const override;
private:
void Invalidate(InvalidationCallbackFlags flags);
@@ -131,7 +109,4 @@ private:
int bufferDecimationCounter_ = 0;
int lastRenderStepId_ = -1;
// Hardware tessellation
TessellationDataTransferGLES *tessDataTransferGLES;
};
-17
View File
@@ -107,13 +107,6 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
INFO_LOG(Log::G3D, "Shader cache disabled. Not loading.");
}
}
if (g_Config.bHardwareTessellation) {
// Log information that we disable hardware tessellation if device is unsupported.
if (!drawEngine_.SupportsHWTessellation()) {
ERROR_LOG(Log::G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
}
}
}
GPU_GLES::~GPU_GLES() {
@@ -141,16 +134,6 @@ u32 GPU_GLES::CheckGPUFeatures() const {
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
features |= GPU_USE_TEXTURE_LOD_CONTROL;
bool canUseInstanceID = gl_extensions.EXT_draw_instanced || gl_extensions.ARB_draw_instanced;
bool canDefInstanceID = gl_extensions.IsGLES || gl_extensions.EXT_gpu_shader4 || gl_extensions.VersionGEThan(3, 1);
bool instanceRendering = gl_extensions.GLES3 || (canUseInstanceID && canDefInstanceID);
if (instanceRendering)
features |= GPU_USE_INSTANCE_RENDERING;
int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits;
if (maxVertexTextureImageUnits >= 3) // At least 3 for hardware tessellation
features |= GPU_USE_VERTEX_TEXTURE_FETCH;
if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float)
features |= GPU_USE_TEXTURE_FLOAT;
+3 -9
View File
@@ -607,12 +607,6 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, const ShaderLanguageDesc
if (u_lightspecular[i] != -1) SetColorUniform3(render_, &u_lightspecular[i], gstate.lcolor[i * 3 + 2]);
}
}
if (dirty & DIRTY_BEZIERSPLINE) {
if (u_spline_counts != -1) {
render_->SetUniformI1(&u_spline_counts, gstate_c.spline_num_points_u);
}
}
}
static constexpr size_t CODE_BUFFER_SIZE = 32768;
@@ -707,10 +701,10 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
return new Shader(render_, codeBuffer_, desc, params);
}
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertexType, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags, VShaderID *VSID) {
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, u32 vertexType, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags, VShaderID *VSID) {
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode, clipInfoFlags);
ComputeVertexShaderID(VSID, vertexType, useHWTransform, weightsAsFloat, useSkinInDecode, clipInfoFlags);
} else {
*VSID = lastVSID_;
}
@@ -743,7 +737,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
// Can still work with software transform.
VShaderID vsidTemp;
ComputeVertexShaderID(&vsidTemp, vertexType, false, false, weightsAsFloat, true, clipInfoFlags);
ComputeVertexShaderID(&vsidTemp, vertexType, false, weightsAsFloat, true, clipInfoFlags);
vs = CompileVertexShader(vsidTemp);
}
+1 -1
View File
@@ -172,7 +172,7 @@ public:
// This is the old ApplyShader split into two parts, because of annoying information dependencies.
// If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards.
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertexType, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags, VShaderID *VSID);
Shader *ApplyVertexShader(bool useHWTransform, u32 vertexType, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags, VShaderID *VSID);
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, ClipInfoFlags clipInfoFlags);
void DeviceLost() override;
+2 -18
View File
@@ -1328,15 +1328,7 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) {
// 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_UVSCALEOFFSET);
if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
gstate_c.submitType = SubmitType::HW_BEZIER;
if (gstate_c.spline_num_points_u != surface.num_points_u) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_num_points_u = surface.num_points_u;
}
} else {
gstate_c.submitType = SubmitType::BEZIER;
}
gstate_c.submitType = SubmitType::BEZIER;
int bytesRead = 0;
gstate_c.UpdateUVScaleOffset();
@@ -1408,15 +1400,7 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) {
// 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_UVSCALEOFFSET);
if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
gstate_c.submitType = SubmitType::HW_SPLINE;
if (gstate_c.spline_num_points_u != surface.num_points_u) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_num_points_u = surface.num_points_u;
}
} else {
gstate_c.submitType = SubmitType::SPLINE;
}
gstate_c.submitType = SubmitType::SPLINE;
int bytesRead = 0;
gstate_c.UpdateUVScaleOffset();
+10 -10
View File
@@ -375,29 +375,29 @@ static constexpr const char * g_gpuUseFlagNames[32] = {
"GPU_USE_VS_RANGE_CULLING",
"GPU_USE_BLEND_MINMAX",
"GPU_USE_LOGIC_OP",
"GPU_USE_FRAGMENT_UBERSHADER",
"GPU_USE_TEXTURE_NPOT",
"N/A",
"N/A",
"GPU_USE_ANISOTROPY",
"GPU_USE_CLEAR_RAM_HACK",
"GPU_USE_INSTANCE_RENDERING",
"GPU_USE_VERTEX_TEXTURE_FETCH",
"N/A",
"N/A",
"GPU_USE_TEXTURE_FLOAT",
"GPU_USE_16BIT_FORMATS",
"GPU_USE_DEPTH_CLAMP",
"GPU_USE_TEXTURE_LOD_CONTROL",
"GPU_USE_DEPTH_TEXTURE",
"GPU_USE_ACCURATE_DEPTH",
"GPU_USE_GS_CULLING",
"N/A",
"N/A",
"GPU_USE_FRAMEBUFFER_ARRAYS",
"GPU_USE_FRAMEBUFFER_FETCH",
"GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT",
"N/A",
"GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT",
"GPU_ROUND_DEPTH_TO_16BIT",
"GPU_USE_CLIP_DISTANCE",
"GPU_USE_CULL_DISTANCE",
"N/A", // bit 26
"N/A", // bit 27
"N/A", // bit 28
"GPU_USE_SHADER_BLENDING", // bit 26
"GPU_USE_NONBUFFERED_FLIP", // bit 27
"GPU_USE_PRE_ROTATION", // bit 28
"GPU_USE_VIRTUAL_REALITY",
"GPU_USE_SINGLE_PASS_STEREO",
"GPU_USE_SIMPLE_STEREO_PERSPECTIVE",
+2 -2
View File
@@ -475,8 +475,8 @@ enum : u32 {
// Free bits: 6-7
GPU_USE_ANISOTROPY = FLAG_BIT(8),
GPU_USE_CLEAR_RAM_HACK = FLAG_BIT(9),
GPU_USE_INSTANCE_RENDERING = FLAG_BIT(10),
GPU_USE_VERTEX_TEXTURE_FETCH = FLAG_BIT(11),
// Free bit: 10
// Free bit: 11
GPU_USE_TEXTURE_FLOAT = FLAG_BIT(12),
GPU_USE_16BIT_FORMATS = FLAG_BIT(13),
GPU_USE_DEPTH_CLAMP = FLAG_BIT(14),
-3
View File
@@ -187,7 +187,4 @@ public:
FreeAlignedMemory(p);
}
#endif
protected:
bool UpdateUseHWTessellation(bool enable) const override { return false; }
};
+3 -59
View File
@@ -64,9 +64,6 @@ void DrawEngineVulkan::InitDeviceObjects() {
BindingType::UNIFORM_BUFFER_DYNAMIC_ALL, // uniforms
BindingType::UNIFORM_BUFFER_DYNAMIC_VERTEX, // lights
BindingType::UNIFORM_BUFFER_DYNAMIC_VERTEX, // bones
BindingType::STORAGE_BUFFER_VERTEX, // tess
BindingType::STORAGE_BUFFER_VERTEX,
BindingType::STORAGE_BUFFER_VERTEX,
};
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
@@ -94,9 +91,6 @@ void DrawEngineVulkan::InitDeviceObjects() {
res = vkCreateSampler(device, &samp, nullptr, &nullSampler_);
_dbg_assert_(VK_SUCCESS == res);
tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan);
tessDataTransfer = tessDataTransferVulkan;
draw_->SetInvalidationCallback(std::bind(&DrawEngineVulkan::Invalidate, this, std::placeholders::_1));
}
@@ -115,10 +109,6 @@ void DrawEngineVulkan::DestroyDeviceObjects() {
draw_->SetInvalidationCallback(InvalidationCallback());
delete tessDataTransferVulkan;
tessDataTransfer = nullptr;
tessDataTransferVulkan = nullptr;
pushUBO_ = nullptr;
if (pushVertex_) {
@@ -166,8 +156,6 @@ void DrawEngineVulkan::BeginFrame() {
pushVertex_->BeginFrame();
pushIndex_->BeginFrame();
tessDataTransferVulkan->SetPushPool(pushUBO_);
DirtyAllUBOs();
AssertEmpty();
@@ -318,7 +306,7 @@ void DrawEngineVulkan::Flush() {
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, true, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
_dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, true, 0, framebufferManager_->GetMSAALevel(), false);
if (!pipeline || !pipeline->pipeline) {
@@ -351,8 +339,6 @@ void DrawEngineVulkan::Flush() {
UpdateUBOs();
int descCount = 6;
if (tess)
descCount = 9;
int descSetIndex;
PackedDescriptor *descriptors = renderManager->PushDescriptorSet(descCount, &descSetIndex);
descriptors[0].image.view = imageView;
@@ -375,14 +361,7 @@ void DrawEngineVulkan::Flush() {
descriptors[5].buffer.buffer = boneBuf;
descriptors[5].buffer.range = sizeof(UB_VS_Bones);
descriptors[5].buffer.offset = 0;
if (tess) {
const VkDescriptorBufferInfo *bufInfo = tessDataTransferVulkan->GetBufferInfo();
for (int j = 0; j < 3; j++) {
descriptors[j + 6].buffer.buffer = bufInfo[j].buffer;
descriptors[j + 6].buffer.range = bufInfo[j].range;
descriptors[j + 6].buffer.offset = bufInfo[j].offset;
}
}
// TODO: Can we avoid binding all three when not needed? Same below for hardware transform.
// Think this will require different descriptor set layouts.
const uint32_t dynamicUBOOffsets[3] = {
@@ -485,7 +464,7 @@ void DrawEngineVulkan::Flush() {
VulkanVertexShader *vshader = nullptr;
VulkanFragmentShader *fshader = nullptr;
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
_dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &swDec->decFmt, vshader, fshader, false, 0, framebufferManager_->GetMSAALevel(), false);
if (!pipeline || !pipeline->pipeline) {
@@ -605,38 +584,3 @@ void DrawEngineVulkan::UpdateUBOs() {
dirtyUniforms_ &= ~DIRTY_BONE_UNIFORMS;
}
}
void TessellationDataTransferVulkan::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {
// SSBOs that are not simply float1 or float2 need to be padded up to a float4 size. vec3 members
// also need to be 16-byte aligned, hence the padding.
struct TessData {
float pos[3]; float pad1;
float uv[2]; float pad2[2];
float color[4];
};
int size = size_u * size_v;
int ssboAlignment = vulkan_->GetPhysicalDeviceProperties().properties.limits.minStorageBufferOffsetAlignment;
uint8_t *data = (uint8_t *)push_->Allocate(size * sizeof(TessData), ssboAlignment, &bufInfo_[0].buffer, (uint32_t *)&bufInfo_[0].offset);
bufInfo_[0].range = size * sizeof(TessData);
float *pos = (float *)(data);
float *tex = (float *)(data + offsetof(TessData, uv));
float *col = (float *)(data + offsetof(TessData, color));
int stride = sizeof(TessData) / sizeof(float);
CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType);
using Spline::Weight;
// Weights U
data = (uint8_t *)push_->Allocate(weights.size_u * sizeof(Weight), ssboAlignment, &bufInfo_[1].buffer, (uint32_t *)&bufInfo_[1].offset);
memcpy(data, weights.u, weights.size_u * sizeof(Weight));
bufInfo_[1].range = weights.size_u * sizeof(Weight);
// Weights V
data = (uint8_t *)push_->Allocate(weights.size_v * sizeof(Weight), ssboAlignment, &bufInfo_[2].buffer, (uint32_t *)&bufInfo_[2].offset);
memcpy(data, weights.v, weights.size_v * sizeof(Weight));
bufInfo_[2].range = weights.size_v * sizeof(Weight);
}
-17
View File
@@ -64,20 +64,6 @@ struct DrawEngineVulkanStats {
class VulkanRenderManager;
class TessellationDataTransferVulkan : public TessellationDataTransfer {
public:
TessellationDataTransferVulkan(VulkanContext *vulkan) : vulkan_(vulkan) {}
void SetPushPool(VulkanPushPool *push) { push_ = push; }
// Send spline/bezier's control points and weights to vertex shader through structured shader buffer.
void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override;
const VkDescriptorBufferInfo *GetBufferInfo() { return bufInfo_; }
private:
VulkanContext *vulkan_;
VulkanPushPool *push_; // Updated each frame.
VkDescriptorBufferInfo bufInfo_[3]{};
};
enum {
DRAW_BINDING_TEXTURE = 0,
DRAW_BINDING_2ND_TEXTURE = 1,
@@ -227,7 +213,4 @@ private:
int tessOffset_ = 0;
FBOTexState fboTexBindState_ = FBO_TEX_NONE;
// Hardware tessellation
TessellationDataTransferVulkan *tessDataTransferVulkan = nullptr;
};
-2
View File
@@ -214,8 +214,6 @@ u32 GPU_Vulkan::CheckGPUFeatures() const {
// Mandatory features on Vulkan, which may be checked in "centralized" code
features |= GPU_USE_TEXTURE_LOD_CONTROL;
features |= GPU_USE_INSTANCE_RENDERING;
features |= GPU_USE_VERTEX_TEXTURE_FETCH;
features |= GPU_USE_TEXTURE_FLOAT;
if (!draw_->GetBugs().Has(Draw::Bugs::PVR_BAD_16BIT_TEXFORMATS)) {
+2 -2
View File
@@ -244,7 +244,7 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
return dirty;
}
void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags) {
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
VShaderID VSID;
@@ -254,7 +254,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShade
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
recomputedVS = true;
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode, clipInfoFlags);
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, weightsAsFloat, useSkinInDecode, clipInfoFlags);
if (VSID == lastVSID_) {
_dbg_assert_(lastVShader_ != nullptr);
vs = lastVShader_;
+1 -1
View File
@@ -102,7 +102,7 @@ public:
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
void GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
void ClearShaders() override;
void DirtyLastShader() override;
-37
View File
@@ -159,35 +159,6 @@ void GameSettingsScreen::PreCreateViews() {
ReloadAllThemeInfo();
}
// This needs before run CheckGPUFeatures()
// TODO: Remove this if fix the issue
static bool CheckSupportShaderTessellationGLES() {
#if PPSSPP_PLATFORM(UWP)
return true;
#else
// TODO: Make work with non-GL backends
int maxVertexTextureImageUnits = gl_extensions.maxVertexTextureUnits;
bool vertexTexture = maxVertexTextureImageUnits >= 3; // At least 3 for hardware tessellation
bool textureFloat = gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float;
bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4;
return vertexTexture && textureFloat && hasTexelFetch;
#endif
}
static bool DoesBackendSupportHWTess() {
switch (GetGPUBackend()) {
case GPUBackend::OPENGL:
return CheckSupportShaderTessellationGLES();
case GPUBackend::VULKAN:
case GPUBackend::DIRECT3D11:
return true;
default:
return false;
}
}
static bool UsingHardwareTextureScaling() {
// For now, Vulkan only.
return g_Config.bTexHardwareScaling && GetGPUBackend() == GPUBackend::VULKAN && !g_Config.bSoftwareRendering;
@@ -563,14 +534,6 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
swSkin->SetDisabledPtr(&g_Config.bSoftwareRendering);
graphicsSettings->Add(new SettingHint(gr->T("SoftwareSkinning Tip", "Combine skinned model draws on the CPU, faster in most games"), swSkin));
if (DoesBackendSupportHWTess()) {
CheckBox *tessellationHW = graphicsSettings->Add(new CheckBox(&g_Config.bHardwareTessellation, gr->T("Hardware Tessellation")));
tessellationHW->SetEnabledFunc([]() {
return !g_Config.bSoftwareRendering && g_Config.bHardwareTransform;
});
graphicsSettings->Add(new SettingHint(gr->T("HardwareTessellation Tip", "Uses hardware to make curves"), tessellationHW));
}
graphicsSettings->Add(new ItemHeader(gr->T("Texture upscaling")));
if (GetGPUBackend() == GPUBackend::VULKAN) {
-9
View File
@@ -818,15 +818,6 @@ static void check_variables(CoreParameter &coreParam)
g_Config.bSoftwareSkinning = true;
}
var.key = "ppsspp_hardware_tesselation";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (!strcmp(var.value, "disabled"))
g_Config.bHardwareTessellation = false;
else
g_Config.bHardwareTessellation = true;
}
var.key = "ppsspp_lower_resolution_for_effects";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{