mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Delete the "Hardware tessellation" feature.
Very hard to maintain and debug, not worth it.
This commit is contained in:
1 parent
dffde6e189
commit
623545bd24
33 files changed
+66
-789
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
@@ -187,7 +187,4 @@ public:
|
||||
FreeAlignedMemory(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool UpdateUseHWTessellation(bool enable) const override { return false; }
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user