diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index ce98d36042..e49cbf45cd 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -461,6 +461,11 @@ static bool TestBoundingBoxFast(const float *cullMatrix, const void *vdata, cons flags |= ClipInfoFlags::SoftClipCull; } + if (minProjZ == maxProjZ) { + // Probably a 2D draw. Send it through software transform! + flags |= ClipInfoFlags::FlatZ | ClipInfoFlags::SoftClipCull; + } + if (needFragmentDepthClamp() && (minProjZ < 0 || maxProjZ > 65535)) { if (gstate_c.Use(GPU_USE_DEPTH_CLAMP)) { flags |= ClipInfoFlags::DepthClamp; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index a11e8c389f..4e38c5a7b1 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -73,16 +73,6 @@ 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]; } }; -enum class ClipInfoFlags { - Valid = 1, - SoftClipCull = 2, - DepthClamp = 8, - DepthClampFragment = 16, - MinMaxZClip = 32, - MinMaxZDiscard = 64, -}; -ENUM_CLASS_BITOPS(ClipInfoFlags); - class DrawEngineCommon { public: DrawEngineCommon(); diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index cd56bdfd89..ba839e13b6 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -26,6 +26,7 @@ #include "Core/System.h" #include "GPU/GPUState.h" #include "GPU/Math3D.h" +#include "GPU/GPUDefinitions.h" #include "GPU/GPUStateSIMDUtil.h" #include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/GPUStateUtils.h" @@ -667,44 +668,48 @@ static SoftwareTransformAction ProjectClipAndExpand(SoftwareTransformParams &par // We might actually write more vertics at the end of transformed. drawIndexCount = vertexCount; + result->pixelMapped = false; - if (throughmode) { - // Nothing to do, pass the vertices right through as-is. Well, we can go look for pixel mapping, - // but we don't do any projection, culling or clipping. - if (g_Config.bSmart2DTexFiltering && !gstate_c.textureIsVideo) { - // We check some common cases for pixel mapping. - // TODO: It's not really optimal that some previous step has removed the triangle strip. - if (vertexCount <= 6 && prim == GE_PRIM_TRIANGLES) { - // It's enough to check UV deltas vs pos deltas between vertex pairs: - // 0-1 1-3 3-2 2-0. Maybe can even skip the last one. Probably some simple math can get us that sequence. - // Unfortunately we need to reverse the previous UV scaling operation. Fortunately these are powers of two - // so the operations are exact. - bool pixelMapped = true; - const u16 *indsIn = (const u16 *)inds; - const float uscale = gstate_c.curTextureWidth; - const float vscale = gstate_c.curTextureHeight; - for (int t = 0; t < vertexCount; t += 3) { - struct { int a; int b; } pairs[] = {{0, 1}, {1, 2}, {2, 0}}; - for (int i = 0; i < ARRAY_SIZE(pairs); i++) { - int a = indsIn[t + pairs[i].a]; - int b = indsIn[t + pairs[i].b]; - float du = fabsf((transformed[a].u - transformed[b].u) * uscale); - float dv = fabsf((transformed[a].v - transformed[b].v) * vscale); - float dx = fabsf(transformed[a].x - transformed[b].x); - float dy = fabsf(transformed[a].y - transformed[b].y); - if (du != dx || dv != dy) { - pixelMapped = false; - } - } - if (!pixelMapped) { - break; - } + // Let's go look for pixel mapping. + bool lookForPixelMapping = throughmode; + if (!lookForPixelMapping) { + // If not throughmode, we can still have pixel mapping if the clip info is valid and flat Z, since that means no clipping or perspective correction will be applied. + if (((u32)params.clipInfoFlags & ((u32)(ClipInfoFlags::Valid | ClipInfoFlags::FlatZ))) == (u32)(ClipInfoFlags::Valid | ClipInfoFlags::FlatZ)) { + lookForPixelMapping = true; + } + } + if (lookForPixelMapping && g_Config.bSmart2DTexFiltering && !gstate_c.textureIsVideo) { + // We check some common cases for pixel mapping. + // It's enough to check UV deltas vs pos deltas between vertex pairs: + // 0-1 1-3 3-2 2-0. Maybe can even skip the last one. Probably some simple math can get us that sequence. + // Unfortunately we need to reverse the previous UV scaling operation. Fortunately these are powers of two + // so the operations are exact. + bool pixelMapped = true; + const u16 *indsIn = (const u16 *)inds; + const float uscale = gstate_c.curTextureWidth; + const float vscale = gstate_c.curTextureHeight; + for (int t = 0; t < vertexCount; t += 3) { + struct { int a; int b; } pairs[] = {{0, 1}, {1, 2}, {2, 0}}; + for (int i = 0; i < ARRAY_SIZE(pairs); i++) { + int a = indsIn[t + pairs[i].a]; + int b = indsIn[t + pairs[i].b]; + float du = fabsf((transformed[a].u - transformed[b].u) * uscale); + float dv = fabsf((transformed[a].v - transformed[b].v) * vscale); + float dx = fabsf(transformed[a].x - transformed[b].x); + float dy = fabsf(transformed[a].y - transformed[b].y); + if (du != dx || dv != dy) { + pixelMapped = false; } - result->pixelMapped = pixelMapped; + } + if (!pixelMapped) { + break; } } - } else { + result->pixelMapped = pixelMapped; + } + + if (!throughmode) { // Culling and clipping needs to be done here, it doesn't happen in the shader in the case of software transform. // However, fast culling should already have taken care of the Z<-W and Z>W culling, but we check for it on a per-triangle // basis here anyway. diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index f1e1c8f20c..7943658fd0 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -62,6 +62,7 @@ struct SoftwareTransformParams { u8 *decoded; TransformedVertex *transformed; TransformedVertex *transformedExpanded; + ClipInfoFlags clipInfoFlags; bool allowClear; bool allowSeparateAlphaClear; bool everUsedEqualDepth; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index db77aaa012..48bb621421 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -436,6 +436,7 @@ void DrawEngineD3D11::Flush() { params.transformedExpanded = transformedExpanded_; params.allowClear = true; params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears + params.clipInfoFlags = clipInfoFlags_; const SoftwareTransformAction action = RunSoftwareTransform(params, prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, VERTEX_BUFFER_MAX, vertexCount, inds, RemainingIndices(inds), &result); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index c798fd7f19..f04d7fb88d 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -388,6 +388,7 @@ void DrawEngineGLES::Flush() { params.transformedExpanded = transformedExpanded_; params.allowClear = true; // Clear in OpenGL respects scissor rects, so we'll use it. params.allowSeparateAlphaClear = true; + params.clipInfoFlags = clipInfoFlags_; const SoftwareTransformAction action = RunSoftwareTransform(params, prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, VERTEX_BUFFER_MAX, vertexCount, inds, RemainingIndices(inds), &result); diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index b4c79808a9..c2ee12c663 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -965,7 +965,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { const bool isTriangle = IsTrianglePrim(prim); bool canExtend = isTriangle; - u32 vertexType = gstate.vertType; + GEVertexType vertexType = (GEVertexType)gstate.vertType; if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { u32 indexAddr = gstate_c.indexAddr; const int indexShift = ((vertexType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1; @@ -1046,7 +1046,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { if (!drawEngineCommon_->SubmitPrim(verts, inds, prim, count, decoder, vertTypeID, true, &bytesRead, flags)) { canExtend = false; } - onePassed = true; + // onePassed = true; } else { // Still need to advance bytesRead. drawEngineCommon_->SkipPrim(prim, count, decoder, &bytesRead); @@ -1131,7 +1131,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { canExtend = false; } // As soon as one passes, assume we don't need to check the rest of this batch. - onePassed = true; + // onePassed = true; } else { // Still need to advance bytesRead. drawEngineCommon_->SkipPrim(newPrim, count, decoder, &bytesRead); @@ -1150,7 +1150,7 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) { goto bail; drawEngineCommon_->FlushSkin(); canExtend = false; // TODO: Might support extending between some vertex types in the future. - vertexType = data; + vertexType = (GEVertexType)(data); vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning); decoder = drawEngineCommon_->GetVertexDecoder(vertTypeID); } diff --git a/GPU/GPUDefinitions.h b/GPU/GPUDefinitions.h index ea051fdba5..e15cdae392 100644 --- a/GPU/GPUDefinitions.h +++ b/GPU/GPUDefinitions.h @@ -195,6 +195,17 @@ enum { FLAG_DIRTYONCHANGE = 64, // NOTE: Either this or FLAG_EXECUTE*, not both! }; +enum class ClipInfoFlags { + Valid = 1, + SoftClipCull = 2, + FlatZ = 4, + DepthClamp = 8, + DepthClampFragment = 16, + MinMaxZClip = 32, + MinMaxZDiscard = 64, +}; +ENUM_CLASS_BITOPS(ClipInfoFlags); + struct TransformedVertex { union { struct { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 77c3602b94..1567e608bf 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -297,7 +297,7 @@ void DrawEngineVulkan::Flush() { gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255); } - if (textureNeedsApply) { + if (textureNeedsApply || true) { textureCache_->ApplyTexture(); textureCache_->GetVulkanHandles(imageView, sampler); if (imageView == VK_NULL_HANDLE) @@ -449,6 +449,7 @@ void DrawEngineVulkan::Flush() { params.allowClear = framebufferManager_->UseBufferedRendering(); params.allowSeparateAlphaClear = false; params.everUsedEqualDepth = everUsedEqualDepth_; + params.clipInfoFlags = clipInfoFlags_; const SoftwareTransformAction action = RunSoftwareTransform(params, prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, VERTEX_BUFFER_MAX, vertexCount, inds, RemainingIndices(inds), &result); diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index 15d47b0929..c065bb5a99 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -280,58 +280,60 @@ enum GECommand : uint8_t { const char *GeCmdToString(GECommand cmd); -#define GE_VTYPE_TRANSFORM (0<<23) -#define GE_VTYPE_THROUGH (1<<23) -#define GE_VTYPE_THROUGH_MASK (1<<23) +enum GEVertexType : uint32_t { + GE_VTYPE_TRANSFORM = (0<<23), + GE_VTYPE_THROUGH = (1<<23), + GE_VTYPE_THROUGH_MASK = (1<<23), -#define GE_VTYPE_TC_NONE (0<<0) -#define GE_VTYPE_TC_8BIT (1<<0) -#define GE_VTYPE_TC_16BIT (2<<0) -#define GE_VTYPE_TC_FLOAT (3<<0) -#define GE_VTYPE_TC_MASK (3<<0) -#define GE_VTYPE_TC_SHIFT 0 + GE_VTYPE_TC_NONE = (0<<0), + GE_VTYPE_TC_8BIT = (1<<0), + GE_VTYPE_TC_16BIT = (2<<0), + GE_VTYPE_TC_FLOAT = (3<<0), + GE_VTYPE_TC_MASK = (3<<0), + GE_VTYPE_TC_SHIFT = 0, -#define GE_VTYPE_COL_NONE (0<<2) -#define GE_VTYPE_COL_565 (4<<2) -#define GE_VTYPE_COL_5551 (5<<2) -#define GE_VTYPE_COL_4444 (6<<2) -#define GE_VTYPE_COL_8888 (7<<2) -#define GE_VTYPE_COL_MASK (7<<2) -#define GE_VTYPE_COL_SHIFT 2 + GE_VTYPE_COL_NONE = (0<<2), + GE_VTYPE_COL_565 = (4<<2), + GE_VTYPE_COL_5551 = (5<<2), + GE_VTYPE_COL_4444 = (6<<2), + GE_VTYPE_COL_8888 = (7<<2), + GE_VTYPE_COL_MASK = (7<<2), + GE_VTYPE_COL_SHIFT = 2, -#define GE_VTYPE_NRM_NONE (0<<5) -#define GE_VTYPE_NRM_8BIT (1<<5) -#define GE_VTYPE_NRM_16BIT (2<<5) -#define GE_VTYPE_NRM_FLOAT (3<<5) -#define GE_VTYPE_NRM_MASK (3<<5) -#define GE_VTYPE_NRM_SHIFT 5 + GE_VTYPE_NRM_NONE = (0<<5), + GE_VTYPE_NRM_8BIT = (1<<5), + GE_VTYPE_NRM_16BIT = (2<<5), + GE_VTYPE_NRM_FLOAT = (3<<5), + GE_VTYPE_NRM_MASK = (3<<5), + GE_VTYPE_NRM_SHIFT = 5, -// No NONE, there is always a position. -#define GE_VTYPE_POS_8BIT (1<<7) -#define GE_VTYPE_POS_16BIT (2<<7) -#define GE_VTYPE_POS_FLOAT (3<<7) -#define GE_VTYPE_POS_MASK (3<<7) -#define GE_VTYPE_POS_SHIFT 7 + // No NONE, there is always a position. + GE_VTYPE_POS_8BIT = (1<<7), + GE_VTYPE_POS_16BIT = (2<<7), + GE_VTYPE_POS_FLOAT = (3<<7), + GE_VTYPE_POS_MASK = (3<<7), + GE_VTYPE_POS_SHIFT = 7, -#define GE_VTYPE_WEIGHT_NONE (0<<9) -#define GE_VTYPE_WEIGHT_8BIT (1<<9) -#define GE_VTYPE_WEIGHT_16BIT (2<<9) -#define GE_VTYPE_WEIGHT_FLOAT (3<<9) -#define GE_VTYPE_WEIGHT_MASK (3<<9) -#define GE_VTYPE_WEIGHT_SHIFT 9 + GE_VTYPE_WEIGHT_NONE = (0<<9), + GE_VTYPE_WEIGHT_8BIT = (1<<9), + GE_VTYPE_WEIGHT_16BIT = (2<<9), + GE_VTYPE_WEIGHT_FLOAT = (3<<9), + GE_VTYPE_WEIGHT_MASK = (3<<9), + GE_VTYPE_WEIGHT_SHIFT = 9, -#define GE_VTYPE_WEIGHTCOUNT_MASK (7<<14) -#define GE_VTYPE_WEIGHTCOUNT_SHIFT 14 + GE_VTYPE_WEIGHTCOUNT_MASK = (7<<14), + GE_VTYPE_WEIGHTCOUNT_SHIFT = 14, -#define GE_VTYPE_MORPHCOUNT_MASK (7<<18) -#define GE_VTYPE_MORPHCOUNT_SHIFT 18 + GE_VTYPE_MORPHCOUNT_MASK = (7<<18), + GE_VTYPE_MORPHCOUNT_SHIFT = 18, -#define GE_VTYPE_IDX_NONE (0<<11) -#define GE_VTYPE_IDX_8BIT (1<<11) -#define GE_VTYPE_IDX_16BIT (2<<11) -#define GE_VTYPE_IDX_32BIT (3<<11) -#define GE_VTYPE_IDX_MASK (3<<11) + GE_VTYPE_IDX_NONE = (0<<11), + GE_VTYPE_IDX_8BIT = (1<<11), + GE_VTYPE_IDX_16BIT = (2<<11), + GE_VTYPE_IDX_32BIT = (3<<11), + GE_VTYPE_IDX_MASK = (3<<11), #define GE_VTYPE_IDX_SHIFT 11 +}; #define GE_CLEARMODE_COLOR (1<<8) #define GE_CLEARMODE_ALPHA (1<<9) //or stencil? @@ -347,6 +349,7 @@ const char *GeCmdToString(GECommand cmd); #define GE_IMM_FOG 0x00400000 #define GE_IMM_DITHER 0x00800000 + enum GEMatrixType { GE_MTX_BONE0 = 0, GE_MTX_BONE1,