mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Determine the clip flags directly when culling, simplifying the code.
This commit is contained in:
@@ -157,7 +157,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex
|
||||
|
||||
bool clockwise = !gstate.isCullEnabled() || gstate.getCullMode() == cullMode;
|
||||
VertexDecoder *dec = GetVertexDecoder(vertTypeID);
|
||||
SubmitPrim(&temp[0], nullptr, prim, vertexCount, dec, vertTypeID, clockwise, &bytesRead, BoundingDepths());
|
||||
SubmitPrim(&temp[0], nullptr, prim, vertexCount, dec, vertTypeID, clockwise, &bytesRead, clipInfoFlags_);
|
||||
Flush();
|
||||
|
||||
if (!prevThrough) {
|
||||
@@ -330,20 +330,19 @@ bool DrawEngineCommon::TestBoundingBox(const void *vdata, const void *inds, int
|
||||
}
|
||||
|
||||
// This optionally culls collections of points against the four side planes, and always computes the min and max of Z and W.
|
||||
// The result of that can be used to determine if we need to drop down to software transform+clip or we can hand
|
||||
//
|
||||
// The result of that is then used to determine if we need to drop down to software transform+clip or we can hand
|
||||
// off to hardware, with whatever capabilities are available.
|
||||
//
|
||||
// NOTE: This doesn't handle through-mode or indexing (morph or skinning can be handled if they're implemented in software during decode).
|
||||
template<u32 posFmt>
|
||||
static bool TestBoundingBoxFast(const float *worldViewProj, const void *vdata, int vertexCount, const VertexDecoder *dec, u8 *decoded, BoundingDepths *depths) {
|
||||
static bool TestBoundingBoxFast(const float *worldViewProj, const void *vdata, int vertexCount, const VertexDecoder *dec, u8 *decoded, ClipInfoFlags *clipInfoFlags) {
|
||||
Mat4F32 worldViewProjMat(worldViewProj);
|
||||
alignas(16) static const float planesXYData[4] = { 1, -1, 1, -1 };
|
||||
Vec4F32 planesXY = Vec4F32::LoadAligned(planesXYData);
|
||||
Vec4S32 insideMaskXY = Vec4S32::Zero();
|
||||
Vec4S32 insideMaskZ = Vec4S32::Zero(); // Note: This does some duplicate computation. We could avoid it on ARM32 using Vec2S32 but not really worth it.
|
||||
Vec4S32 anyOutsideMaskZ = Vec4S32::Zero();
|
||||
float minProjZ = FLT_MAX;
|
||||
float maxProjZ = -FLT_MAX;
|
||||
|
||||
// Used to reduce the Z precision. This effectively implements the small offsets where Z can be very slightly outside -1..1.
|
||||
// In reality we should probably affect X and Y too, but meh.
|
||||
@@ -353,9 +352,11 @@ static bool TestBoundingBoxFast(const float *worldViewProj, const void *vdata, i
|
||||
const int offset = dec->posoff;
|
||||
const s8 *data = (const s8 *)vdata + offset;
|
||||
|
||||
const float vpZOffset = gstate.getViewportZCenter();
|
||||
const float vpZScale = gstate.getViewportZScale();
|
||||
|
||||
float minProjZ = FLT_MAX;
|
||||
float maxProjZ = -FLT_MAX;
|
||||
|
||||
for (int i = 0; i < vertexCount; i++, data += stride) {
|
||||
Vec4F32 objPos;
|
||||
switch (posFmt) {
|
||||
@@ -392,23 +393,47 @@ static bool TestBoundingBoxFast(const float *worldViewProj, const void *vdata, i
|
||||
return false;
|
||||
}
|
||||
|
||||
depths->valid = true;
|
||||
depths->hitClipSpaceZW = AnyCompareBitsSet(anyOutsideMaskZ);
|
||||
const float vpZOffset = gstate.getViewportZCenter();
|
||||
minProjZ += vpZOffset;
|
||||
maxProjZ += vpZOffset;
|
||||
|
||||
ClipInfoFlags flags = ClipInfoFlags::Valid;
|
||||
|
||||
// If the W=-Z plane was intersected, here we can go through the vertices again, and check for X/Y bounds for range culling.
|
||||
// However! We need to find a valid way to do so by "backprojecting" the range culling into clip space, which may be a little tricky.
|
||||
//
|
||||
// If nothing is outside the box, the "inversion" cases (vertices hit the boundary after clipping like Flatout, Sengoku Cannon)
|
||||
// cannot happen, and soft clipping is only needed if the viewport is smaller than the valid Z range.
|
||||
//
|
||||
// Alternatively, we just do a compat flag for the affected games until we can solve this.
|
||||
|
||||
// Before checking later, we apply a viewport to the projZ, so we can later compare against minZ/maxZ or the outer bounds.
|
||||
// But to save operations we don't do it here.
|
||||
depths->minProjZ = minProjZ + vpZOffset;
|
||||
depths->maxProjZ = maxProjZ + vpZOffset;
|
||||
if (needFragmentMinMaxClipping() && (minProjZ < gstate.getDepthRangeMin() || maxProjZ > gstate.getDepthRangeMax())) {
|
||||
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
|
||||
flags |= ClipInfoFlags::MinMaxZDiscard;
|
||||
} else {
|
||||
flags |= ClipInfoFlags::MinMaxZClip;
|
||||
}
|
||||
}
|
||||
|
||||
if (AnyCompareBitsSet(anyOutsideMaskZ) || !gstate_c.Use(GPU_USE_CULL_DISTANCE)) {
|
||||
// Some vertices were outside the Z clipping planes. Clip againt Z=-W in software (and do culling, too).
|
||||
// TODO: With a compat flag for Flatout/Sengoku, we'll be able to avoid this in many cases.
|
||||
flags |= ClipInfoFlags::SoftClipCull;
|
||||
}
|
||||
|
||||
if (needFragmentDepthClamp() && (minProjZ < 0 || maxProjZ > 65535)) {
|
||||
if (gstate_c.Use(GPU_USE_DEPTH_CLAMP)) {
|
||||
flags |= ClipInfoFlags::DepthClamp;
|
||||
} else {
|
||||
flags |= ClipInfoFlags::DepthClampFragment;
|
||||
}
|
||||
}
|
||||
|
||||
*clipInfoFlags = flags;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawEngineCommon::TestBoundingBoxFast(const float *cullMatrix, const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, BoundingDepths *depths) {
|
||||
bool DrawEngineCommon::TestBoundingBoxFast(const float *cullMatrix, const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, ClipInfoFlags *flags) {
|
||||
// Although this may lead to drawing that shouldn't happen, the viewport is more complex on VR.
|
||||
// Let's always say objects are within bounds.
|
||||
if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY)) {
|
||||
@@ -419,11 +444,11 @@ bool DrawEngineCommon::TestBoundingBoxFast(const float *cullMatrix, const void *
|
||||
|
||||
switch (vertType & GE_VTYPE_POS_MASK) {
|
||||
case GE_VTYPE_POS_8BIT:
|
||||
return ::TestBoundingBoxFast<GE_VTYPE_POS_8BIT>(cullMatrix, vdata, vertexCount, dec, decoded_, depths);
|
||||
return ::TestBoundingBoxFast<GE_VTYPE_POS_8BIT>(cullMatrix, vdata, vertexCount, dec, decoded_, flags);
|
||||
case GE_VTYPE_POS_16BIT:
|
||||
return ::TestBoundingBoxFast<GE_VTYPE_POS_16BIT>(cullMatrix, vdata, vertexCount, dec, decoded_, depths);
|
||||
return ::TestBoundingBoxFast<GE_VTYPE_POS_16BIT>(cullMatrix, vdata, vertexCount, dec, decoded_, flags);
|
||||
case GE_VTYPE_POS_FLOAT:
|
||||
return ::TestBoundingBoxFast<GE_VTYPE_POS_FLOAT>(cullMatrix, vdata, vertexCount, dec, decoded_, depths);
|
||||
return ::TestBoundingBoxFast<GE_VTYPE_POS_FLOAT>(cullMatrix, vdata, vertexCount, dec, decoded_, flags);
|
||||
default:
|
||||
// Shouldn't end up here with the checks outside this function.
|
||||
_dbg_assert_(false);
|
||||
@@ -431,35 +456,6 @@ bool DrawEngineCommon::TestBoundingBoxFast(const float *cullMatrix, const void *
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawEngineCommon::CheckBoundingDepths(bool useHWTransform) const {
|
||||
if (useHWTransform && boundingDepths_.valid) {
|
||||
if (boundingDepths_.hitClipSpaceZW) {
|
||||
// Revert to software transform so we can clip more accurately.
|
||||
//
|
||||
// This is only really needed for two known games: Flatout (water) and Sengoku Cannon (pink geometry). But there may
|
||||
// be some more.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (needFragmentMinMaxClipping()) {
|
||||
if ((boundingDepths_.minProjZ < gstate.getDepthRangeMin() || boundingDepths_.maxProjZ > gstate.getDepthRangeMax())) {
|
||||
// Revert to software transform so we can clamp more accurately.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (needFragmentDepthClamp()) {
|
||||
if ((boundingDepths_.minProjZ < 0 || boundingDepths_.maxProjZ > 65535)) {
|
||||
// Revert to software transform so we can clamp more accurately.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Also handle clamping in software if it's not supported in hardware (or always?)
|
||||
return true;
|
||||
}
|
||||
return useHWTransform;
|
||||
}
|
||||
|
||||
// 2D bounding box test against scissor. No indexing yet.
|
||||
// Only supports non-indexed draws with float positions. TODO: Add more float formats.
|
||||
bool DrawEngineCommon::TestBoundingBoxThrough(const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, int *bytesRead) {
|
||||
@@ -603,9 +599,10 @@ int DrawEngineCommon::ComputeNumVertsToDecode() const {
|
||||
}
|
||||
|
||||
// Takes a list of consecutive PRIM opcodes, and extends the current draw call to include them.
|
||||
// This is just a performance optimization.
|
||||
int DrawEngineCommon::ExtendNonIndexedPrim(const uint32_t *cmd, const uint32_t *stall, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, bool isTriangle, const BoundingDepths &depths) {
|
||||
boundingDepths_.Merge(depths);
|
||||
// This is just a performance optimization. NOTE: This isn't compatible with really accurate culling,
|
||||
// unless we refactor things a bit.
|
||||
int DrawEngineCommon::ExtendNonIndexedPrim(const uint32_t *cmd, const uint32_t *stall, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, bool isTriangle, ClipInfoFlags clipInfoFlags) {
|
||||
clipInfoFlags_ |= clipInfoFlags;
|
||||
|
||||
const uint32_t *start = cmd;
|
||||
int prevDrawVerts = numDrawVerts_ - 1;
|
||||
@@ -674,12 +671,18 @@ void DrawEngineCommon::SkipPrim(GEPrimitiveType prim, int vertexCount, const Ver
|
||||
}
|
||||
|
||||
// vertTypeID is the vertex type but with the UVGen mode smashed into the top bits.
|
||||
bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, const BoundingDepths &depths) {
|
||||
bool DrawEngineCommon::SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, ClipInfoFlags clipInfoFlags) {
|
||||
if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawVerts_ >= MAX_DEFERRED_DRAW_VERTS || numDrawInds_ >= MAX_DEFERRED_DRAW_INDS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) {
|
||||
Flush();
|
||||
}
|
||||
|
||||
boundingDepths_.Merge(depths);
|
||||
// TODO: Flush on clipinfoflags change?
|
||||
clipInfoFlags_ |= clipInfoFlags;
|
||||
|
||||
// if (clipInfoFlags_ != clipInfoFlags) {
|
||||
// Flush();
|
||||
// }
|
||||
// clipInfoFlags_ = clipInfoFlags;
|
||||
|
||||
_dbg_assert_(numDrawVerts_ < MAX_DEFERRED_DRAW_VERTS);
|
||||
_dbg_assert_(numDrawInds_ < MAX_DEFERRED_DRAW_INDS);
|
||||
|
||||
@@ -73,25 +73,15 @@ struct alignas(16) Plane8 {
|
||||
float Test(int i, const float f[3]) const { return x[i] * f[0] + y[i] * f[1] + z[i] * f[2] + w[i]; }
|
||||
};
|
||||
|
||||
struct BoundingDepths {
|
||||
bool valid = false;
|
||||
bool hitClipSpaceZW = false;
|
||||
float minProjZ = FLT_MAX;
|
||||
float maxProjZ = -FLT_MAX;
|
||||
void Merge(const BoundingDepths &other) {
|
||||
if (!valid) {
|
||||
*this = other;
|
||||
return;
|
||||
}
|
||||
hitClipSpaceZW |= other.hitClipSpaceZW;
|
||||
if (other.minProjZ < minProjZ) {
|
||||
minProjZ = other.minProjZ;
|
||||
}
|
||||
if (other.maxProjZ > maxProjZ) {
|
||||
maxProjZ = other.maxProjZ;
|
||||
}
|
||||
}
|
||||
enum class ClipInfoFlags {
|
||||
Valid = 1,
|
||||
SoftClipCull = 2,
|
||||
DepthClamp = 8,
|
||||
DepthClampFragment = 16,
|
||||
MinMaxZClip = 32,
|
||||
MinMaxZDiscard = 64,
|
||||
};
|
||||
ENUM_CLASS_BITOPS(ClipInfoFlags);
|
||||
|
||||
class DrawEngineCommon {
|
||||
public:
|
||||
@@ -115,9 +105,9 @@ public:
|
||||
// This would seem to be unnecessary now, but is still required for splines/beziers to work in the software backend since SubmitPrim
|
||||
// is different. Should probably refactor that.
|
||||
// Note that vertTypeID should be computed using GetVertTypeID().
|
||||
virtual void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead, const BoundingDepths &depths) {
|
||||
virtual void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead, ClipInfoFlags clipInfoFlags) {
|
||||
VertexDecoder *dec = GetVertexDecoder(vertTypeID);
|
||||
SubmitPrim(verts, inds, prim, vertexCount, dec, vertTypeID, clockwise, bytesRead, depths);
|
||||
SubmitPrim(verts, inds, prim, vertexCount, dec, vertTypeID, clockwise, bytesRead, clipInfoFlags);
|
||||
}
|
||||
|
||||
virtual void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation);
|
||||
@@ -126,7 +116,7 @@ public:
|
||||
|
||||
// This is a less accurate version of TestBoundingBox, but faster. Can have more false positives.
|
||||
// Doesn't support indexing.
|
||||
bool TestBoundingBoxFast(const float *cullMatrix, const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, BoundingDepths *depth);
|
||||
bool TestBoundingBoxFast(const float *cullMatrix, const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, ClipInfoFlags *clipInfoFlags);
|
||||
bool TestBoundingBoxThrough(const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, int *bytesRead);
|
||||
bool EstimateThroughPrimSafeSize(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, const VertexDecoder *dec, u32 vertType, int *safeWidth, int *safeHeight);
|
||||
|
||||
@@ -140,8 +130,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int ExtendNonIndexedPrim(const uint32_t *cmd, const uint32_t *stall, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, bool isTriangle, const BoundingDepths &depths);
|
||||
bool SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, const BoundingDepths &depths);
|
||||
int ExtendNonIndexedPrim(const uint32_t *cmd, const uint32_t *stall, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, bool isTriangle, ClipInfoFlags clipInfoFlags);
|
||||
bool SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, const VertexDecoder *dec, u32 vertTypeID, bool clockwise, int *bytesRead, ClipInfoFlags clipInfoFlags);
|
||||
void SkipPrim(GEPrimitiveType prim, int vertexCount, const VertexDecoder *dec, int *bytesRead);
|
||||
|
||||
template<class Surface>
|
||||
@@ -186,7 +176,7 @@ public:
|
||||
protected:
|
||||
virtual bool UpdateUseHWTessellation(bool enabled) const { return enabled; }
|
||||
|
||||
bool CheckBoundingDepths(bool useHwTransform) const;
|
||||
bool CheckClipFlags(bool useHwTransform) const;
|
||||
|
||||
void DecodeVerts(const VertexDecoder *dec, u8 *dest);
|
||||
int DecodeInds();
|
||||
@@ -246,7 +236,7 @@ protected:
|
||||
seenPrims_ = 0;
|
||||
anyCCWOrIndexed_ = false;
|
||||
gstate_c.vertexFullAlpha = true;
|
||||
boundingDepths_ = BoundingDepths();
|
||||
clipInfoFlags_ = {};
|
||||
|
||||
// Now seems as good a time as any to reset the min/max coords, which we may examine later.
|
||||
gstate_c.vertBounds.minU = 512;
|
||||
@@ -379,7 +369,7 @@ protected:
|
||||
uint16_t *depthIndices_ = nullptr;
|
||||
|
||||
// Depth tracking
|
||||
BoundingDepths boundingDepths_;
|
||||
ClipInfoFlags clipInfoFlags_{};
|
||||
|
||||
// Queue
|
||||
int depthVertexCount_ = 0;
|
||||
|
||||
+12
-14
@@ -12,6 +12,7 @@
|
||||
#include "GPU/Common/GPUStateUtils.h"
|
||||
#include "GPU/Common/ShaderId.h"
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/DrawEngineCommon.h" // Just for ClipInfoFlags
|
||||
|
||||
std::string VertexShaderDesc(const VShaderID &id) {
|
||||
std::stringstream desc;
|
||||
@@ -70,7 +71,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) {
|
||||
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, 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();
|
||||
@@ -164,16 +165,13 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
|
||||
}
|
||||
id.SetBit(VS_BIT_NORM_REVERSE_TESS, gstate.isPatchNormalsReversed());
|
||||
}
|
||||
} else { // !useHwTransform
|
||||
// Various conditions that require per-pixel depth manipulation (very expensive!)
|
||||
if (!isModeThrough) {
|
||||
if (needFragmentDepthClamp()) {
|
||||
id.SetBit(VS_BIT_FS_DEPTH_CLAMP);
|
||||
}
|
||||
if (needFragmentMinMaxClipping()) {
|
||||
id.SetBit(VS_BIT_FS_MINMAX_DISCARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clipInfoFlags & ClipInfoFlags::DepthClampFragment) {
|
||||
id.SetBit(VS_BIT_FS_DEPTH_CLAMP);
|
||||
}
|
||||
if (clipInfoFlags & ClipInfoFlags::MinMaxZDiscard) {
|
||||
id.SetBit(VS_BIT_FS_MINMAX_DISCARD);
|
||||
}
|
||||
|
||||
id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
|
||||
@@ -301,7 +299,7 @@ inline u32 SanitizeBlendMode(GEBlendMode mode) {
|
||||
|
||||
// Here we must take all the bits of the gstate that determine what the fragment shader will
|
||||
// look like, and concatenate them together into an ID.
|
||||
void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs, bool useHwTransform) {
|
||||
void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs, bool useHwTransform, ClipInfoFlags clipInfoFlags) {
|
||||
FShaderID id;
|
||||
bool isModeThrough = gstate.isModeThrough();
|
||||
|
||||
@@ -309,10 +307,10 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
|
||||
// draws that needs this and use software transform as the fallback for them. That logic will have to change if we change that.
|
||||
// NOTE: This check MUST be identical to the one in ComputeVertexShaderID, otherwise we might get mismatches between VS and FS and end up with no shader at all.
|
||||
if (!useHwTransform && !isModeThrough) {
|
||||
if (needFragmentDepthClamp()) {
|
||||
if (clipInfoFlags & ClipInfoFlags::DepthClampFragment) {
|
||||
id.SetBit(FS_BIT_DEPTH_CLAMP);
|
||||
}
|
||||
if (needFragmentMinMaxClipping()) {
|
||||
if (clipInfoFlags & ClipInfoFlags::MinMaxZDiscard) {
|
||||
id.SetBit(FS_BIT_MINMAX_DISCARD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
enum class ClipInfoFlags;
|
||||
|
||||
// Shared ID checks for when the vertex and fragment shaders (and host code) need to coordinate.
|
||||
|
||||
// NOTE: Both of these assume non - through - mode.Don't check these if in through mode.
|
||||
// NOTE: Both of these assume non-through-mode. Don't check these if in through mode.
|
||||
inline bool needFragmentMinMaxClipping() {
|
||||
return gstate.getDepthRangeMin() != 0 && gstate.getDepthRangeMax() != 0xFFFF && !gstate_c.Use(GPU_USE_CLIP_DISTANCE);
|
||||
return gstate.getDepthRangeMin() != 0 && gstate.getDepthRangeMax() != 0xFFFF;
|
||||
}
|
||||
|
||||
inline bool needFragmentDepthClamp() {
|
||||
@@ -261,13 +262,13 @@ namespace Draw {
|
||||
class Bugs;
|
||||
}
|
||||
|
||||
void ComputeVertexShaderID(VShaderID *id, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
|
||||
void ComputeVertexShaderID(VShaderID *id, u32 vertType, bool useHWTransform, bool useHWTessellation, 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);
|
||||
|
||||
struct ComputedPipelineState;
|
||||
void ComputeFragmentShaderID(FShaderID *id, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs, bool useHwTransform);
|
||||
void ComputeFragmentShaderID(FShaderID *id, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs, bool useHwTransform, ClipInfoFlags clipInfoFlags);
|
||||
std::string FragmentShaderDesc(const FShaderID &id);
|
||||
|
||||
// For sanity checking.
|
||||
|
||||
@@ -498,7 +498,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
|
||||
|
||||
SimpleBufferManager managedBuf(decoded_, DECODED_VERTEX_BUFFER_SIZE / 2);
|
||||
|
||||
int num_points = surface.num_points_u * surface.num_points_v;
|
||||
const int num_points = surface.num_points_u * surface.num_points_v;
|
||||
u16 index_lower_bound = 0;
|
||||
u16 index_upper_bound = num_points - 1;
|
||||
IndexConverter ConvertIndex(vertType, indices);
|
||||
@@ -523,7 +523,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
|
||||
return;
|
||||
}
|
||||
|
||||
u32 origVertType = vertType;
|
||||
const u32 origVertType = vertType;
|
||||
vertType = ::NormalizeVertices(simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, origVDecoder, vertType);
|
||||
|
||||
VertexDecoder *vdecoder = GetVertexDecoder(vertType);
|
||||
@@ -547,7 +547,7 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
|
||||
output.indices = decIndex_;
|
||||
output.count = 0;
|
||||
|
||||
int maxVerts = DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize;
|
||||
const int maxVerts = DECODED_VERTEX_BUFFER_SIZE / 2 / vertexSize;
|
||||
|
||||
surface.Init(maxVerts);
|
||||
|
||||
@@ -576,14 +576,15 @@ void DrawEngineCommon::SubmitCurve(const void *control_points, const void *indic
|
||||
vertTypeID = GetVertTypeID(vertTypeWithIndex16, gstate.getUVGenMode(), applySkinInDecode_);
|
||||
int generatedBytesRead;
|
||||
if (output.count) {
|
||||
BoundingDepths depths;
|
||||
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, true, &generatedBytesRead, depths);
|
||||
ClipInfoFlags flags{}; // Don't need any special processing.
|
||||
DispatchSubmitPrim(output.vertices, output.indices, PatchPrimToPrim(surface.primType), output.count, vertTypeID, true, &generatedBytesRead, flags);
|
||||
}
|
||||
|
||||
if (flushOnParams_)
|
||||
Flush();
|
||||
|
||||
if (origVertType & GE_VTYPE_TC_MASK) {
|
||||
// If analysis says this is uninitialized, it's wrong.
|
||||
gstate_c.uv = prevUVScale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,9 @@ void DrawEngineD3D11::Flush() {
|
||||
// Always use software for flat shading to fix the provoking index.
|
||||
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
|
||||
bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
|
||||
useHWTransform = CheckBoundingDepths(useHWTransform);
|
||||
if (clipInfoFlags_ & ClipInfoFlags::SoftClipCull) {
|
||||
useHWTransform = false;
|
||||
}
|
||||
|
||||
if (useHWTransform != lastUseHwTransform_) {
|
||||
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
|
||||
@@ -333,7 +335,7 @@ void DrawEngineD3D11::Flush() {
|
||||
|
||||
D3D11VertexShader *vshader;
|
||||
D3D11FragmentShader *fshader;
|
||||
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_);
|
||||
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, clipInfoFlags_);
|
||||
ID3D11InputLayout *inputLayout;
|
||||
SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType(), &inputLayout);
|
||||
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
|
||||
@@ -447,7 +449,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);
|
||||
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true, clipInfoFlags_);
|
||||
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
|
||||
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
|
||||
shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
|
||||
|
||||
@@ -186,20 +186,20 @@ 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) {
|
||||
void ShaderManagerD3D11::GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, 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);
|
||||
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode, clipInfoFlags);
|
||||
} else {
|
||||
VSID = lastVSID_;
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), useHWTransform);
|
||||
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), useHWTransform, clipInfoFlags);
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
||||
@@ -81,12 +81,14 @@ protected:
|
||||
|
||||
class D3D11PushBuffer;
|
||||
|
||||
enum class ClipInfoFlags;
|
||||
|
||||
class ShaderManagerD3D11 : public ShaderManagerCommon {
|
||||
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);
|
||||
void GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
|
||||
void ClearShaders() override;
|
||||
void DirtyLastShader() override;
|
||||
|
||||
|
||||
@@ -254,14 +254,16 @@ void DrawEngineGLES::Flush() {
|
||||
GEPrimitiveType prim = prevPrim_;
|
||||
|
||||
bool useHWTransform = CanUseHardwareTransform(prim);
|
||||
useHWTransform = CheckBoundingDepths(useHWTransform);
|
||||
if (clipInfoFlags_ & ClipInfoFlags::SoftClipCull) {
|
||||
useHWTransform = false;
|
||||
}
|
||||
|
||||
if (useHWTransform != lastUseHwTransform_) {
|
||||
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
|
||||
lastUseHwTransform_ = useHWTransform;
|
||||
}
|
||||
|
||||
Shader *vshader = shaderManager_->ApplyVertexShader(useHWTransform, useHWTessellation_, dec_->VertexType(), decOptions_.expandAllWeightsToFloat, applySkinInDecode_ || !useHWTransform, &vsid);
|
||||
Shader *vshader = shaderManager_->ApplyVertexShader(useHWTransform, useHWTessellation_, 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.
|
||||
|
||||
@@ -313,7 +315,7 @@ void DrawEngineGLES::Flush() {
|
||||
ApplyDrawState(prim);
|
||||
ApplyDrawStateLate(false, 0);
|
||||
|
||||
LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, true);
|
||||
LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, true, clipInfoFlags_);
|
||||
GLRInputLayout *inputLayout = SetupDecFmtForDraw(dec_->GetDecVtxFmt());
|
||||
if (useElements) {
|
||||
render_->DrawIndexed(inputLayout,
|
||||
@@ -399,7 +401,7 @@ void DrawEngineGLES::Flush() {
|
||||
ApplyDrawState(prim);
|
||||
ApplyDrawStateLate(result.setStencil, result.stencilValue);
|
||||
|
||||
LinkedShader *linked = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, false);
|
||||
LinkedShader *linked = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, false, clipInfoFlags_);
|
||||
if (!linked) {
|
||||
// Not much we can do here. Let's skip drawing.
|
||||
goto bail;
|
||||
|
||||
@@ -764,10 +764,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, VShaderID *VSID) {
|
||||
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, 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);
|
||||
ComputeVertexShaderID(VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode, clipInfoFlags);
|
||||
} else {
|
||||
*VSID = lastVSID_;
|
||||
}
|
||||
@@ -800,7 +800,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
|
||||
|
||||
// Can still work with software transform.
|
||||
VShaderID vsidTemp;
|
||||
ComputeVertexShaderID(&vsidTemp, vertexType, false, false, weightsAsFloat, true);
|
||||
ComputeVertexShaderID(&vsidTemp, vertexType, false, false, weightsAsFloat, true, clipInfoFlags);
|
||||
vs = CompileVertexShader(vsidTemp);
|
||||
}
|
||||
|
||||
@@ -808,7 +808,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
|
||||
return vs;
|
||||
}
|
||||
|
||||
LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useHwTransform) {
|
||||
LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useHwTransform, ClipInfoFlags clipInfoFlags) {
|
||||
uint64_t dirty = gstate_c.GetDirtyUniforms();
|
||||
if (dirty) {
|
||||
if (lastShader_)
|
||||
@@ -820,7 +820,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
|
||||
FShaderID FSID;
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), useHwTransform);
|
||||
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), useHwTransform, clipInfoFlags);
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ private:
|
||||
|
||||
class VertexDecoder;
|
||||
|
||||
enum class ClipInfoFlags;
|
||||
|
||||
class ShaderManagerGLES : public ShaderManagerCommon {
|
||||
public:
|
||||
ShaderManagerGLES(Draw::DrawContext *draw);
|
||||
@@ -170,8 +172,8 @@ 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, VShaderID *VSID);
|
||||
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useHWTransform);
|
||||
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertexType, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags, VShaderID *VSID);
|
||||
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useHWTransform, ClipInfoFlags clipInfoFlags);
|
||||
|
||||
void DeviceLost() override;
|
||||
void DeviceRestore(Draw::DrawContext *draw) override;
|
||||
|
||||
+10
-10
@@ -989,7 +989,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
|
||||
// This is the check from #21678 for Evangelion JO.
|
||||
// TODO: Make this less specific.
|
||||
if (gstate.isModeThrough() && gstate.isTextureMapEnabled() && gstate.getColorMask() != 0xFFFFFFFF &&
|
||||
gstate.getScissorX1() == 0 && gstate.getScissorY1() == 0 && Memory::IsVRAMAddress(gstate.getFrameBufAddress())) {
|
||||
gstate.getScissorX1() == 0 && gstate.getScissorY1() == 0 && Memory::IsVRAMAddress(gstate.getFrameBufAddress())) {
|
||||
int safeWidth;
|
||||
int safeHeight;
|
||||
// First-frame readback can happen before queued draws reach backend transform.
|
||||
@@ -1014,7 +1014,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
|
||||
|
||||
#define MAX_CULL_CHECK_COUNT 2500
|
||||
|
||||
// For now, turn off culling on platforms where we don't have SIMD bounding box tests, like RISC-V.
|
||||
// For now, turn off culling on platforms where we don't have SIMD bounding box tests, like RISC-V.
|
||||
#if PPSSPP_ARCH(ARM_NEON) || PPSSPP_ARCH(SSE2)
|
||||
|
||||
#define PASSES_CULLING ((vertexType & (GE_VTYPE_THROUGH_MASK | GE_VTYPE_MORPHCOUNT_MASK | GE_VTYPE_WEIGHT_MASK | GE_VTYPE_IDX_MASK)) || count > MAX_CULL_CHECK_COUNT)
|
||||
@@ -1025,13 +1025,13 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
|
||||
|
||||
#endif
|
||||
|
||||
BoundingDepths depths;
|
||||
ClipInfoFlags flags{};
|
||||
|
||||
// If certain conditions are true, do frustum culling.
|
||||
bool passCulling = PASSES_CULLING;
|
||||
if (!passCulling) {
|
||||
// Do software culling.
|
||||
if (drawEngineCommon_->TestBoundingBoxFast(gstate_c.cullMatrix, verts, count, decoder, vertexType, &depths)) {
|
||||
if (drawEngineCommon_->TestBoundingBoxFast(gstate_c.cullMatrix, verts, count, decoder, vertexType, &flags)) {
|
||||
passCulling = true;
|
||||
} else {
|
||||
gpuStats.perFrame.numCulledDraws++;
|
||||
@@ -1044,7 +1044,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
|
||||
// Cuts down on checking, while not losing that much efficiency.
|
||||
bool onePassed = false;
|
||||
if (passCulling) {
|
||||
if (!drawEngineCommon_->SubmitPrim(verts, inds, prim, count, decoder, vertTypeID, true, &bytesRead, depths)) {
|
||||
if (!drawEngineCommon_->SubmitPrim(verts, inds, prim, count, decoder, vertTypeID, true, &bytesRead, flags)) {
|
||||
canExtend = false;
|
||||
}
|
||||
onePassed = true;
|
||||
@@ -1090,9 +1090,9 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
|
||||
bool clockwise = !gstate.isCullEnabled() || gstate.getCullMode() == cullMode;
|
||||
if (canExtend) {
|
||||
// Non-indexed draws can be cheaply merged if vertexAddr hasn't changed, that means the vertices
|
||||
// are consecutive in memory. We also ignore culling here.
|
||||
// are consecutive in memory. We also ignore culling here which is not ideal.
|
||||
_dbg_assert_((vertexType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_NONE);
|
||||
int commandsExecuted = drawEngineCommon_->ExtendNonIndexedPrim(src, stall, decoder, vertTypeID, clockwise, &bytesRead, isTriangle, depths);
|
||||
int commandsExecuted = drawEngineCommon_->ExtendNonIndexedPrim(src, stall, decoder, vertTypeID, clockwise, &bytesRead, isTriangle, flags);
|
||||
if (!commandsExecuted) {
|
||||
goto bail;
|
||||
}
|
||||
@@ -1118,18 +1118,18 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
bool passCulling = onePassed || PASSES_CULLING;
|
||||
BoundingDepths depths;
|
||||
ClipInfoFlags flags{};
|
||||
if (!passCulling) {
|
||||
// Do software culling.
|
||||
_dbg_assert_((vertexType & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_NONE);
|
||||
if (drawEngineCommon_->TestBoundingBoxFast(gstate_c.cullMatrix, verts, count, decoder, vertexType, &depths)) {
|
||||
if (drawEngineCommon_->TestBoundingBoxFast(gstate_c.cullMatrix, verts, count, decoder, vertexType, &flags)) {
|
||||
passCulling = true;
|
||||
} else {
|
||||
gpuStats.perFrame.numCulledDraws++;
|
||||
}
|
||||
}
|
||||
if (passCulling) {
|
||||
if (!drawEngineCommon_->SubmitPrim(verts, inds, newPrim, count, decoder, vertTypeID, clockwise, &bytesRead, depths)) {
|
||||
if (!drawEngineCommon_->SubmitPrim(verts, inds, newPrim, count, decoder, vertTypeID, clockwise, &bytesRead, flags)) {
|
||||
canExtend = false;
|
||||
}
|
||||
// As soon as one passes, assume we don't need to check the rest of this batch.
|
||||
|
||||
@@ -68,7 +68,7 @@ void SoftwareDrawEngine::Flush() {
|
||||
transformUnit.Flush(gpuCommon_, "debug");
|
||||
}
|
||||
|
||||
void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead, const BoundingDepths &depths) {
|
||||
void SoftwareDrawEngine::DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead, ClipInfoFlags clipInfoFlags) {
|
||||
_assert_msg_(clockwise, "Mixed cull mode not supported.");
|
||||
transformUnit.SubmitPrimitive(verts, inds, prim, vertexCount, vertTypeID, bytesRead, this);
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ private:
|
||||
friend SoftwareVertexReader;
|
||||
};
|
||||
|
||||
enum class ClipInfoFlags;
|
||||
|
||||
class SoftwareDrawEngine : public DrawEngineCommon {
|
||||
public:
|
||||
SoftwareDrawEngine();
|
||||
@@ -171,7 +173,7 @@ public:
|
||||
|
||||
void NotifyConfigChanged() override;
|
||||
void Flush() override;
|
||||
void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, bool clockwise, int *bytesRead, const BoundingDepths &depths) override;
|
||||
void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, bool clockwise, int *bytesRead, ClipInfoFlags clipInfoFlags) override;
|
||||
void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation) override;
|
||||
|
||||
VertexDecoder *FindVertexDecoder(u32 vtype);
|
||||
|
||||
@@ -241,8 +241,11 @@ void DrawEngineVulkan::Flush() {
|
||||
provokingVertexOk = true;
|
||||
}
|
||||
bool useHWTransform = CanUseHardwareTransform(prim) && provokingVertexOk;
|
||||
useHWTransform = CheckBoundingDepths(useHWTransform);
|
||||
if (clipInfoFlags_ & ClipInfoFlags::SoftClipCull) {
|
||||
useHWTransform = false;
|
||||
}
|
||||
|
||||
// Is this still needed?
|
||||
if (useHWTransform != lastUseHwTransform_) {
|
||||
// Need to re-evaluate software transform fallbacks.
|
||||
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
|
||||
@@ -302,7 +305,7 @@ void DrawEngineVulkan::Flush() {
|
||||
VulkanVertexShader *vshader = nullptr;
|
||||
VulkanFragmentShader *fshader = nullptr;
|
||||
|
||||
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_);
|
||||
shaderManager_->GetShaders(prim, dec_->VertexType(), &vshader, &fshader, pipelineState_, true, useHWTessellation_, 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) {
|
||||
@@ -470,7 +473,7 @@ void DrawEngineVulkan::Flush() {
|
||||
VulkanVertexShader *vshader = nullptr;
|
||||
VulkanFragmentShader *fshader = nullptr;
|
||||
|
||||
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
|
||||
shaderManager_->GetShaders(prim, swDec->VertexType(), &vshader, &fshader, pipelineState_, false, 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) {
|
||||
|
||||
@@ -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) {
|
||||
void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, 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);
|
||||
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode, clipInfoFlags);
|
||||
if (VSID == lastVSID_) {
|
||||
_dbg_assert_(lastVShader_ != nullptr);
|
||||
vs = lastVShader_;
|
||||
@@ -284,7 +284,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertexType, VulkanVertexShade
|
||||
VulkanFragmentShader *fs = nullptr;
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), useHWTransform);
|
||||
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs(), useHWTransform, clipInfoFlags);
|
||||
recomputedFS = true;
|
||||
if (FSID == lastFSID_) {
|
||||
_dbg_assert_(lastFShader_ != nullptr);
|
||||
|
||||
@@ -92,6 +92,8 @@ struct Uniforms {
|
||||
UB_VS_Bones ub_bones{};
|
||||
};
|
||||
|
||||
enum class ClipInfoFlags;
|
||||
|
||||
class ShaderManagerVulkan : public ShaderManagerCommon {
|
||||
public:
|
||||
ShaderManagerVulkan(Draw::DrawContext *draw);
|
||||
@@ -100,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);
|
||||
void GetShaders(int prim, u32 vertexType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode, ClipInfoFlags clipInfoFlags);
|
||||
void ClearShaders() override;
|
||||
void DirtyLastShader() override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user