summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/VertexManagerBase.cpp
diff options
context:
space:
mode:
authorTony Wasserka <neobrainx@gmail.com>2015-01-24 13:29:57 +0100
committerTony Wasserka <neobrainx@gmail.com>2015-01-24 13:29:57 +0100
commit43036af944e706ac38821561c2f3333a500e63f6 (patch)
tree6c5b23ed4707d9af477143774dd86f9f9b9fe7be /Source/Core/VideoCommon/VertexManagerBase.cpp
parent4e9497cdb85ecbd088ca06fb501496aa0c8240a7 (diff)
parent14baf038e70a598a6af1ce71719bb557425941f9 (diff)
Merge pull request #1812 from phire/real_zfreeze
Add proper zfreeze support.
Diffstat (limited to 'Source/Core/VideoCommon/VertexManagerBase.cpp')
-rw-r--r--Source/Core/VideoCommon/VertexManagerBase.cpp150
1 files changed, 119 insertions, 31 deletions
diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp
index 38cfd19630..0c5ccdd10d 100644
--- a/Source/Core/VideoCommon/VertexManagerBase.cpp
+++ b/Source/Core/VideoCommon/VertexManagerBase.cpp
@@ -12,6 +12,7 @@
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/TextureCacheBase.h"
+#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h"
@@ -25,7 +26,10 @@ u8 *VertexManager::s_pEndBufferPointer;
PrimitiveType VertexManager::current_primitive_type;
+Slope VertexManager::ZSlope;
+
bool VertexManager::IsFlushed;
+bool VertexManager::CullAll;
static const PrimitiveType primitive_from_gx[8] = {
PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS
@@ -41,6 +45,7 @@ static const PrimitiveType primitive_from_gx[8] = {
VertexManager::VertexManager()
{
IsFlushed = true;
+ CullAll = false;
}
VertexManager::~VertexManager()
@@ -52,7 +57,7 @@ u32 VertexManager::GetRemainingSize()
return (u32)(s_pEndBufferPointer - s_pCurBufferPointer);
}
-DataReader VertexManager::PrepareForAdditionalData(int primitive, u32 count, u32 stride)
+DataReader VertexManager::PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall)
{
// The SSE vertex loader can write up to 4 bytes past the end
u32 const needed_vertex_bytes = count * stride + 4;
@@ -78,6 +83,8 @@ DataReader VertexManager::PrepareForAdditionalData(int primitive, u32 count, u32
"Increase MAXVBUFFERSIZE or we need primitive breaking after all.");
}
+ CullAll = cullall;
+
// need to alloc new buffer
if (IsFlushed)
{
@@ -189,45 +196,66 @@ void VertexManager::Flush()
(int)bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, (bpmem.alpha_test.hex>>16)&0xff);
#endif
- BitSet32 usedtextures;
- for (u32 i = 0; i < bpmem.genMode.numtevstages + 1u; ++i)
- if (bpmem.tevorders[i / 2].getEnable(i & 1))
- usedtextures[bpmem.tevorders[i/2].getTexMap(i & 1)] = true;
-
- if (bpmem.genMode.numindstages > 0)
- for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1u; ++i)
- if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
- usedtextures[bpmem.tevindref.getTexMap(bpmem.tevind[i].bt)] = true;
-
- for (unsigned int i : usedtextures)
+ // If the primitave is marked CullAll. All we need to do is update the vertex constants and calculate the zfreeze refrence slope
+ if (!CullAll)
{
- g_renderer->SetSamplerState(i & 3, i >> 2);
- const TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i);
+ BitSet32 usedtextures;
+ for (u32 i = 0; i < bpmem.genMode.numtevstages + 1u; ++i)
+ if (bpmem.tevorders[i / 2].getEnable(i & 1))
+ usedtextures[bpmem.tevorders[i/2].getTexMap(i & 1)] = true;
- if (tentry)
+ if (bpmem.genMode.numindstages > 0)
+ for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1u; ++i)
+ if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
+ usedtextures[bpmem.tevindref.getTexMap(bpmem.tevind[i].bt)] = true;
+
+ for (unsigned int i : usedtextures)
{
- // 0s are probably for no manual wrapping needed.
- PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
+ g_renderer->SetSamplerState(i & 3, i >> 2);
+ const TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i);
+
+ if (tentry)
+ {
+ // 0s are probably for no manual wrapping needed.
+ PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
+ }
+ else
+ ERROR_LOG(VIDEO, "error loading texture");
}
- else
- ERROR_LOG(VIDEO, "error loading texture");
}
- // set global constants
+ // set global vertex constants
VertexShaderManager::SetConstants();
- GeometryShaderManager::SetConstants();
- PixelShaderManager::SetConstants();
- bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass &&
- bpmem.dstalpha.enable &&
- bpmem.blendmode.alphaupdate &&
- bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24;
+ // Calculate ZSlope for zfreeze
+ if (!bpmem.genMode.zfreeze)
+ {
+ // Must be done after VertexShaderManager::SetConstants()
+ CalculateZSlope(VertexLoaderManager::GetCurrentVertexFormat());
+ }
+ else if (ZSlope.dirty && !CullAll) // or apply any dirty ZSlopes
+ {
+ PixelShaderManager::SetZSlope(ZSlope.dfdx, ZSlope.dfdy, ZSlope.f0);
+ ZSlope.dirty = false;
+ }
- if (PerfQueryBase::ShouldEmulate())
- g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
- g_vertex_manager->vFlush(useDstAlpha);
- if (PerfQueryBase::ShouldEmulate())
- g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
+ if (!CullAll)
+ {
+ // set the rest of the global constants
+ GeometryShaderManager::SetConstants();
+ PixelShaderManager::SetConstants();
+
+ bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass &&
+ bpmem.dstalpha.enable &&
+ bpmem.blendmode.alphaupdate &&
+ bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24;
+
+ if (PerfQueryBase::ShouldEmulate())
+ g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
+ g_vertex_manager->vFlush(useDstAlpha);
+ if (PerfQueryBase::ShouldEmulate())
+ g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
+ }
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
@@ -235,9 +263,69 @@ void VertexManager::Flush()
ERROR_LOG(VIDEO, "xf.numtexgens (%d) does not match bp.numtexgens (%d). Error in command stream.", xfmem.numTexGen.numTexGens, bpmem.genMode.numtexgens.Value());
IsFlushed = true;
+ CullAll = false;
}
void VertexManager::DoState(PointerWrap& p)
{
+ p.Do(ZSlope);
g_vertex_manager->vDoState(p);
}
+
+void VertexManager::CalculateZSlope(NativeVertexFormat *format)
+{
+ float vtx[9];
+ float out[12];
+ float viewOffset[2] = { xfmem.viewport.xOrig - bpmem.scissorOffset.x * 2,
+ xfmem.viewport.yOrig - bpmem.scissorOffset.y * 2};
+
+ // Global matrix ID.
+ u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx;
+ const PortableVertexDeclaration vert_decl = format->GetVertexDeclaration();
+ size_t posOff = vert_decl.position.offset;
+ size_t mtxOff = vert_decl.posmtx.offset;
+
+ // Lookup vertices of the last rendered triangle and software-transform them
+ // This allows us to determine the depth slope, which will be used if z--freeze
+ // is enabled in the following flush.
+ for (unsigned int i = 0; i < 3; ++i)
+ {
+ u8* vtx_ptr = s_pCurBufferPointer - vert_decl.stride * (3 - i);
+ vtx[0 + i * 3] = ((float*)(vtx_ptr + posOff))[0];
+ vtx[1 + i * 3] = ((float*)(vtx_ptr + posOff))[1];
+ vtx[2 + i * 3] = ((float*)(vtx_ptr + posOff))[2];
+
+ // If this vertex format has per-vertex position matrix IDs, look it up.
+ if(vert_decl.posmtx.enable)
+ mtxIdx = *((u32*)(vtx_ptr + mtxOff));
+
+ VertexShaderManager::TransformToClipSpace(&vtx[i * 3], &out[i * 4], mtxIdx);
+
+ // Transform to Screenspace
+ float inv_w = 1.0f / out[3 + i * 4];
+
+ out[0 + i * 4] = out[0 + i * 4] * inv_w * xfmem.viewport.wd + viewOffset[0];
+ out[1 + i * 4] = out[1 + i * 4] * inv_w * xfmem.viewport.ht + viewOffset[1];
+ out[2 + i * 4] = out[2 + i * 4] * inv_w * xfmem.viewport.zRange + xfmem.viewport.farZ;
+ }
+
+ float dx31 = out[8] - out[0];
+ float dx12 = out[0] - out[4];
+ float dy12 = out[1] - out[5];
+ float dy31 = out[9] - out[1];
+
+ float DF31 = out[10] - out[2];
+ float DF21 = out[6] - out[2];
+ float a = DF31 * -dy12 - DF21 * dy31;
+ float b = dx31 * DF21 + dx12 * DF31;
+ float c = -dx12 * dy31 - dx31 * -dy12;
+
+ // Sometimes we process de-generate triangles. Stop any divide by zeros
+ if (c == 0)
+ return;
+
+ ZSlope.dfdx = -a / c;
+ ZSlope.dfdy = -b / c;
+ ZSlope.f0 = out[2] - (out[0] * ZSlope.dfdx + out[1] * ZSlope.dfdy);
+ ZSlope.dirty = true;
+}