mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-10 21:16:24 +02:00
State handling reordering in D3D11 and D3D9 backends.
This commit is contained in:
1 parent
66aeede7b6
commit
08e2d951b4
10 files changed
+129
-99
No files matched your search
@@ -20,6 +20,8 @@
|
||||
#include "Common/Log.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/Profiler/Profiler.h"
|
||||
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Reporting.h"
|
||||
@@ -273,6 +275,8 @@ void DrawEngineD3D11::BeginFrame() {
|
||||
pushVerts_->Reset();
|
||||
pushInds_->Reset();
|
||||
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
if (--decimationCounter_ <= 0) {
|
||||
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
|
||||
} else {
|
||||
@@ -321,24 +325,31 @@ VertexArrayInfoD3D11::~VertexArrayInfoD3D11() {
|
||||
// The inline wrapper in the header checks for numDrawCalls == 0
|
||||
void DrawEngineD3D11::DoFlush() {
|
||||
gpuStats.numFlushes++;
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
|
||||
int curRenderStepId = draw_->GetCurrentStepId();
|
||||
if (lastRenderStepId_ != curRenderStepId) {
|
||||
// Dirty everything that has dynamic state that will need re-recording.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
textureCache_->ForgetLastTexture();
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
bool textureNeedsApply = false;
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
textureNeedsApply = true;
|
||||
} else if (gstate.getTextureAddress(0) == ((gstate.getFrameBufRawAddress() | 0x04000000) & 0x3FFFFFFF)) {
|
||||
// This catches the case of clearing a texture. (#10957)
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
|
||||
}
|
||||
|
||||
// This is not done on every drawcall, we collect vertex data
|
||||
// until critical state changes. That's when we draw (flush).
|
||||
|
||||
GEPrimitiveType prim = prevPrim_;
|
||||
|
||||
// SetTexture is called in here, along with setting a lot of other state.
|
||||
ApplyDrawState(prim);
|
||||
|
||||
// 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);
|
||||
@@ -510,7 +521,6 @@ rotateVBO:
|
||||
prim = indexGen.Prim();
|
||||
}
|
||||
|
||||
VERBOSE_LOG(G3D, "Flush prim %d! %d verts in one go", prim, vertexCount);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
|
||||
@@ -518,6 +528,12 @@ rotateVBO:
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
|
||||
}
|
||||
|
||||
if (textureNeedsApply) {
|
||||
textureCache_->ApplyTexture();
|
||||
}
|
||||
|
||||
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
|
||||
ApplyDrawState(prim);
|
||||
ApplyDrawStateLate(true, dynState_.stencilRef);
|
||||
|
||||
D3D11VertexShader *vshader;
|
||||
@@ -532,6 +548,7 @@ rotateVBO:
|
||||
context_->IASetInputLayout(inputLayout);
|
||||
UINT stride = dec_->GetDecVtxFmt().stride;
|
||||
context_->IASetPrimitiveTopology(d3d11prim[prim]);
|
||||
|
||||
if (!vb_) {
|
||||
// Push!
|
||||
UINT vOffset;
|
||||
@@ -563,6 +580,7 @@ rotateVBO:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PROFILE_THIS_SCOPE("soft");
|
||||
DecodeVerts(decoded);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
@@ -611,15 +629,22 @@ rotateVBO:
|
||||
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
|
||||
if (result.action == SW_NOT_READY) {
|
||||
swTransform.DetectOffsetTexture(maxIndex);
|
||||
swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
|
||||
}
|
||||
|
||||
if (textureNeedsApply)
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
|
||||
ApplyDrawState(prim);
|
||||
|
||||
if (result.action == SW_NOT_READY)
|
||||
swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
|
||||
if (result.setSafeSize)
|
||||
framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);
|
||||
|
||||
if (result.action == SW_DRAW_PRIMITIVES) {
|
||||
ApplyDrawStateLate(result.setStencil, result.stencilValue);
|
||||
ApplyDrawStateLate(result.setStencil, result.stencilValue);
|
||||
|
||||
if (result.action == SW_DRAW_PRIMITIVES) {
|
||||
D3D11VertexShader *vshader;
|
||||
D3D11FragmentShader *fshader;
|
||||
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false, false, decOptions_.expandAllWeightsToFloat);
|
||||
|
||||
@@ -124,8 +124,6 @@ static const D3D11_LOGIC_OP logicOps[] = {
|
||||
|
||||
void DrawEngineD3D11::ResetFramebufferRead() {
|
||||
if (fboTexBound_) {
|
||||
ID3D11ShaderResourceView *srv = nullptr;
|
||||
context_->PSSetShaderResources(0, 1, &srv);
|
||||
fboTexBound_ = false;
|
||||
}
|
||||
}
|
||||
@@ -167,6 +165,18 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
||||
ApplyFramebufferRead(&fboTexNeedsBind_);
|
||||
// The shader takes over the responsibility for blending, so recompute.
|
||||
ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState);
|
||||
|
||||
if (fboTexNeedsBind_) {
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
// No sampler required, we do a plain Load in the pixel shader.
|
||||
fboTexBound_ = true;
|
||||
fboTexNeedsBind_ = false;
|
||||
|
||||
framebufferManager_->RebindFramebuffer("RebindFramebuffer - ApplyDrawState");
|
||||
// Must dirty blend state here so we re-copy next time. Example: Lunar's spell effects.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
|
||||
} else if (blendState.resetFramebufferRead) {
|
||||
ResetFramebufferRead();
|
||||
@@ -416,16 +426,6 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
||||
}
|
||||
|
||||
void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) {
|
||||
if (!gstate.isModeClear()) {
|
||||
if (fboTexNeedsBind_) {
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
// No sampler required, we do a plain Load in the pixel shader.
|
||||
fboTexBound_ = true;
|
||||
fboTexNeedsBind_ = false;
|
||||
}
|
||||
textureCache_->ApplyTexture();
|
||||
}
|
||||
|
||||
// we go through Draw here because it automatically handles screen rotation, as needed in UWP on mobiles.
|
||||
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
|
||||
draw_->SetViewports(1, &dynState_.viewport);
|
||||
@@ -435,7 +435,7 @@ void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRe
|
||||
context_->RSSetState(rasterState_);
|
||||
}
|
||||
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
|
||||
// Need to do this AFTER ApplyTexture because the process of depallettization can ruin the blend state.
|
||||
// Need to do this AFTER ApplyTexture because the process of depalettization can ruin the blend state.
|
||||
float blendColor[4];
|
||||
Uint8x4ToFloat4(blendColor, dynState_.blendColor);
|
||||
if (device1_) {
|
||||
|
||||
@@ -435,16 +435,17 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer,
|
||||
CheckAlphaResult alphaStatus = CheckAlpha(clutBuf_, GetClutDestFormatD3D11(clutFormat), clutTotalColors);
|
||||
gstate_c.SetTextureFullAlpha(alphaStatus == CHECKALPHA_FULL);
|
||||
} else {
|
||||
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
|
||||
framebufferManager_->RebindFramebuffer("RebindFramebuffer - ApplyTextureFramebuffer");
|
||||
framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
|
||||
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
|
||||
}
|
||||
|
||||
SamplerCacheKey samplerKey = GetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight);
|
||||
ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, samplerKey);
|
||||
context_->PSSetSamplers(0, 1, &state);
|
||||
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE);
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
draw_->InvalidateCachedState();
|
||||
}
|
||||
|
||||
void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
|
||||
|
||||
@@ -305,6 +305,8 @@ static uint32_t SwapRB(uint32_t c) {
|
||||
}
|
||||
|
||||
void DrawEngineDX9::BeginFrame() {
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
DecimateTrackedVertexArrays();
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
@@ -313,7 +315,6 @@ void DrawEngineDX9::BeginFrame() {
|
||||
// The inline wrapper in the header checks for numDrawCalls == 0
|
||||
void DrawEngineDX9::DoFlush() {
|
||||
gpuStats.numFlushes++;
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
|
||||
int curRenderStepId = draw_->GetCurrentStepId();
|
||||
@@ -323,14 +324,23 @@ void DrawEngineDX9::DoFlush() {
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
// This is not done on every drawcall, we should collect vertex data
|
||||
// until critical state changes. That's when we draw (flush).
|
||||
bool textureNeedsApply = false;
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
textureNeedsApply = true;
|
||||
} else if (gstate.getTextureAddress(0) == ((gstate.getFrameBufRawAddress() | 0x04000000) & 0x3FFFFFFF)) {
|
||||
// This catches the case of clearing a texture. (#10957)
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
|
||||
}
|
||||
|
||||
GEPrimitiveType prim = prevPrim_;
|
||||
ApplyDrawState(prim);
|
||||
|
||||
VSShader *vshader = shaderManager_->ApplyShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat);
|
||||
// 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);
|
||||
|
||||
if (vshader->UseHWTransform()) {
|
||||
if (useHWTransform) {
|
||||
LPDIRECT3DVERTEXBUFFER9 vb_ = NULL;
|
||||
LPDIRECT3DINDEXBUFFER9 ib_ = NULL;
|
||||
|
||||
@@ -500,7 +510,6 @@ rotateVBO:
|
||||
prim = indexGen.Prim();
|
||||
}
|
||||
|
||||
VERBOSE_LOG(G3D, "Flush prim %i! %i verts in one go", prim, vertexCount);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
|
||||
@@ -508,8 +517,14 @@ rotateVBO:
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
|
||||
}
|
||||
|
||||
if (textureNeedsApply) {
|
||||
textureCache_->ApplyTexture();
|
||||
}
|
||||
|
||||
ApplyDrawState(prim);
|
||||
ApplyDrawStateLate();
|
||||
vshader = shaderManager_->ApplyShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat);
|
||||
|
||||
DX9::VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat);
|
||||
IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType());
|
||||
|
||||
if (pHardwareVertexDecl) {
|
||||
@@ -587,14 +602,21 @@ rotateVBO:
|
||||
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
|
||||
if (result.action == SW_NOT_READY) {
|
||||
swTransform.DetectOffsetTexture(maxIndex);
|
||||
swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
|
||||
}
|
||||
|
||||
if (textureNeedsApply)
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
ApplyDrawState(prim);
|
||||
|
||||
if (result.action == SW_NOT_READY)
|
||||
swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
|
||||
if (result.setSafeSize)
|
||||
framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);
|
||||
|
||||
ApplyDrawStateLate();
|
||||
vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat);
|
||||
|
||||
DX9::VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat);
|
||||
|
||||
if (result.action == SW_DRAW_PRIMITIVES) {
|
||||
if (result.setStencil) {
|
||||
|
||||
@@ -547,10 +547,6 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
|
||||
}
|
||||
|
||||
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat) {
|
||||
// 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;
|
||||
useHWTransform = useHWTransform && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
|
||||
|
||||
VShaderID VSID;
|
||||
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
|
||||
|
||||
@@ -91,14 +91,14 @@ static const D3DSTENCILOP stencilOps[] = {
|
||||
};
|
||||
|
||||
inline void DrawEngineDX9::ResetFramebufferRead() {
|
||||
if (fboTexBound_) {
|
||||
device_->SetTexture(1, nullptr);
|
||||
fboTexBound_ = false;
|
||||
}
|
||||
fboTexBound_ = false;
|
||||
}
|
||||
|
||||
void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
// TODO: All this setup is soon so expensive that we'll need dirty flags, or simply do it in the command writes where we detect dirty by xoring. Silly to do all this work on every drawcall.
|
||||
if (!gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
@@ -114,7 +114,6 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
bool useBufferedRendering = framebufferManager_->UseBufferedRendering();
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
|
||||
gstate_c.Clean(DIRTY_BLEND_STATE);
|
||||
// Unfortunately, this isn't implemented on DX9 yet.
|
||||
gstate_c.SetAllowFramebufferRead(false);
|
||||
if (gstate.isModeClear()) {
|
||||
@@ -140,6 +139,18 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
ApplyFramebufferRead(&fboTexNeedsBind_);
|
||||
// The shader takes over the responsibility for blending, so recompute.
|
||||
ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState);
|
||||
|
||||
if (fboTexNeedsBind_) {
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
fboTexBound_ = true;
|
||||
fboTexNeedsBind_ = false;
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
|
||||
} else if (blendState.resetFramebufferRead) {
|
||||
ResetFramebufferRead();
|
||||
@@ -172,7 +183,6 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_RASTER_STATE);
|
||||
bool wantCull = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && prim > GE_PRIM_LINE_STRIP && gstate.isCullEnabled();
|
||||
if (wantCull) {
|
||||
if (gstate.getCullMode() == 1) {
|
||||
@@ -192,7 +202,6 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
|
||||
gstate_c.Clean(DIRTY_DEPTHSTENCIL_STATE);
|
||||
GenericStencilFuncState stencilState;
|
||||
ConvertStencilFuncState(stencilState);
|
||||
|
||||
@@ -254,7 +263,6 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
}
|
||||
|
||||
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
|
||||
gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
ViewportAndScissor vpAndScissor;
|
||||
ConvertViewportAndScissor(useBufferedRendering,
|
||||
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
|
||||
@@ -275,26 +283,14 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
||||
gstate_c.Dirty(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
}
|
||||
|
||||
gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
void DrawEngineDX9::ApplyDrawStateLate() {
|
||||
// At this point, we know if the vertices are full alpha or not.
|
||||
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
|
||||
if (!gstate.isModeClear()) {
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
if (fboTexNeedsBind_) {
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
fboTexBound_ = true;
|
||||
fboTexNeedsBind_ = false;
|
||||
}
|
||||
|
||||
// TODO: Test texture?
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -148,7 +148,7 @@ void DrawEngineGLES::ClearInputLayoutMap() {
|
||||
}
|
||||
|
||||
void DrawEngineGLES::BeginFrame() {
|
||||
DecimateTrackedVertexArrays();
|
||||
gpuStats.numTrackedVertexArrays = 0;
|
||||
|
||||
FrameData &frameData = frameData_[render_->GetCurFrame()];
|
||||
render_->BeginPushBuffer(frameData.pushIndex);
|
||||
@@ -238,11 +238,9 @@ void *DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bind
|
||||
|
||||
void DrawEngineGLES::DoFlush() {
|
||||
PROFILE_THIS_SCOPE("flush");
|
||||
|
||||
FrameData &frameData = frameData_[render_->GetCurFrame()];
|
||||
|
||||
gpuStats.numFlushes++;
|
||||
gpuStats.numTrackedVertexArrays = 0;
|
||||
|
||||
// A new render step means we need to flush any dynamic state. Really, any state that is reset in
|
||||
// GLQueueRunner::PerformRenderPass.
|
||||
@@ -277,7 +275,6 @@ void DrawEngineGLES::DoFlush() {
|
||||
if (vshader->UseHWTransform()) {
|
||||
int vertexCount = 0;
|
||||
bool useElements = true;
|
||||
bool populateCache = false;
|
||||
|
||||
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
|
||||
// If software skinning, we've already predecoded into "decoded". So push that content.
|
||||
@@ -301,7 +298,6 @@ void DrawEngineGLES::DoFlush() {
|
||||
}
|
||||
prim = indexGen.Prim();
|
||||
|
||||
VERBOSE_LOG(G3D, "Flush prim %d! %d verts in one go", prim, vertexCount);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
|
||||
@@ -309,8 +305,9 @@ void DrawEngineGLES::DoFlush() {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
|
||||
}
|
||||
|
||||
if (textureNeedsApply)
|
||||
if (textureNeedsApply) {
|
||||
textureCache_->ApplyTexture();
|
||||
}
|
||||
|
||||
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
|
||||
ApplyDrawState(prim);
|
||||
@@ -331,6 +328,7 @@ void DrawEngineGLES::DoFlush() {
|
||||
render_->Draw(glprim[prim], 0, vertexCount);
|
||||
}
|
||||
} else {
|
||||
PROFILE_THIS_SCOPE("soft");
|
||||
DecodeVerts(decoded);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
@@ -354,7 +352,7 @@ void DrawEngineGLES::DoFlush() {
|
||||
params.transformedExpanded = transformedExpanded;
|
||||
params.fbman = framebufferManager_;
|
||||
params.texCache = textureCache_;
|
||||
params.allowClear = true;
|
||||
params.allowClear = true; // Clear in OpenGL respects scissor rects, so we'll use it.
|
||||
params.allowSeparateAlphaClear = true;
|
||||
params.provokeFlatFirst = false;
|
||||
params.flippedY = framebufferManager_->UseBufferedRendering();
|
||||
|
||||
@@ -115,7 +115,6 @@ public:
|
||||
|
||||
protected:
|
||||
bool UpdateUseHWTessellation(bool enable) override;
|
||||
void DecimateTrackedVertexArrays() {}
|
||||
|
||||
private:
|
||||
void InitDeviceObjects();
|
||||
|
||||
@@ -183,6 +183,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
|
||||
} else if (blendState.resetFramebufferRead) {
|
||||
ResetFramebufferRead();
|
||||
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
|
||||
}
|
||||
|
||||
if (blendState.enabled) {
|
||||
|
||||
@@ -268,6 +268,8 @@ void DrawEngineVulkan::DeviceRestore(Draw::DrawContext *draw) {
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::BeginFrame() {
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
lastPipeline_ = nullptr;
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
@@ -522,16 +524,17 @@ void MarkUnreliable(VertexArrayInfoVulkan *vai) {
|
||||
|
||||
// The inline wrapper in the header checks for numDrawCalls == 0
|
||||
void DrawEngineVulkan::DoFlush() {
|
||||
PROFILE_THIS_SCOPE("Flush");
|
||||
gpuStats.numFlushes++;
|
||||
// TODO: Should be enough to update this once per frame?
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
PROFILE_THIS_SCOPE("Flush");
|
||||
FrameData &frameData = GetCurFrame();
|
||||
|
||||
gpuStats.numFlushes++;
|
||||
|
||||
// TODO: Needs to be behind a check for changed render pass, at an appropriate time in this function.
|
||||
// Similar issues as with the lastRenderStepId_ check. Will need a bit of a rethink.
|
||||
lastPipeline_ = nullptr;
|
||||
|
||||
// If have a new render pass, dirty our dynamic state so it gets re-set.
|
||||
// We have to do this again after the last possible place in DoFlush that can cause a renderpass switch
|
||||
// like a shader blend blit or similar. But before we actually set the state!
|
||||
@@ -543,8 +546,6 @@ void DrawEngineVulkan::DoFlush() {
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
FrameData *frame = &GetCurFrame();
|
||||
|
||||
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
|
||||
|
||||
bool textureNeedsApply = false;
|
||||
@@ -569,10 +570,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
uint32_t vbOffset;
|
||||
|
||||
if (useHWTransform) {
|
||||
// We don't detect clears in this path, so here we can switch framebuffers if necessary.
|
||||
|
||||
int vertexCount = 0;
|
||||
int maxIndex;
|
||||
bool useElements = true;
|
||||
|
||||
// Cannot cache vertex data with morph enabled.
|
||||
@@ -602,7 +600,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
vai->minihash = ComputeMiniHash();
|
||||
vai->status = VertexArrayInfoVulkan::VAI_HASHING;
|
||||
vai->drawsUntilNextFullHash = 0;
|
||||
DecodeVertsToPushBuffer(frame->pushVertex, &vbOffset, &vbuf); // writes to indexGen
|
||||
DecodeVertsToPushBuffer(frameData.pushVertex, &vbOffset, &vbuf); // writes to indexGen
|
||||
vai->numVerts = indexGen.VertexCount();
|
||||
vai->prim = indexGen.Prim();
|
||||
vai->maxIndex = indexGen.MaxIndex();
|
||||
@@ -628,7 +626,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
}
|
||||
if (newMiniHash != vai->minihash || newHash != vai->hash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVertsToPushBuffer(frame->pushVertex, &vbOffset, &vbuf);
|
||||
DecodeVertsToPushBuffer(frameData.pushVertex, &vbOffset, &vbuf);
|
||||
goto rotateVBO;
|
||||
}
|
||||
if (vai->numVerts > 64) {
|
||||
@@ -647,7 +645,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
u32 newMiniHash = ComputeMiniHash();
|
||||
if (newMiniHash != vai->minihash) {
|
||||
MarkUnreliable(vai);
|
||||
DecodeVertsToPushBuffer(frame->pushVertex, &vbOffset, &vbuf);
|
||||
DecodeVertsToPushBuffer(frameData.pushVertex, &vbOffset, &vbuf);
|
||||
goto rotateVBO;
|
||||
}
|
||||
}
|
||||
@@ -683,7 +681,6 @@ void DrawEngineVulkan::DoFlush() {
|
||||
vbOffset = vai->vbOffset;
|
||||
ibOffset = vai->ibOffset;
|
||||
vertexCount = vai->numVerts;
|
||||
maxIndex = vai->maxIndex;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
break;
|
||||
}
|
||||
@@ -702,7 +699,6 @@ void DrawEngineVulkan::DoFlush() {
|
||||
vbOffset = vai->vbOffset;
|
||||
ibOffset = vai->ibOffset;
|
||||
vertexCount = vai->numVerts;
|
||||
maxIndex = vai->maxIndex;
|
||||
prim = static_cast<GEPrimitiveType>(vai->prim);
|
||||
|
||||
gstate_c.vertexFullAlpha = vai->flags & VAIVULKAN_FLAG_VERTEXFULLALPHA;
|
||||
@@ -715,7 +711,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
if (vai->lastFrame != gpuStats.numFlips) {
|
||||
vai->numFrames++;
|
||||
}
|
||||
DecodeVertsToPushBuffer(frame->pushVertex, &vbOffset, &vbuf);
|
||||
DecodeVertsToPushBuffer(frameData.pushVertex, &vbOffset, &vbuf);
|
||||
goto rotateVBO;
|
||||
}
|
||||
default:
|
||||
@@ -725,11 +721,11 @@ void DrawEngineVulkan::DoFlush() {
|
||||
if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
|
||||
// If software skinning, we've already predecoded into "decoded". So push that content.
|
||||
VkDeviceSize size = decodedVerts_ * dec_->GetDecVtxFmt().stride;
|
||||
u8 *dest = (u8 *)frame->pushVertex->Push(size, &vbOffset, &vbuf);
|
||||
u8 *dest = (u8 *)frameData.pushVertex->Push(size, &vbOffset, &vbuf);
|
||||
memcpy(dest, decoded, size);
|
||||
} else {
|
||||
// Decode directly into the pushbuffer
|
||||
DecodeVertsToPushBuffer(frame->pushVertex, &vbOffset, &vbuf);
|
||||
DecodeVertsToPushBuffer(frameData.pushVertex, &vbOffset, &vbuf);
|
||||
}
|
||||
|
||||
rotateVBO:
|
||||
@@ -749,8 +745,6 @@ void DrawEngineVulkan::DoFlush() {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
|
||||
}
|
||||
|
||||
PROFILE_THIS_SCOPE("updatestate");
|
||||
|
||||
if (textureNeedsApply) {
|
||||
textureCache_->ApplyTexture();
|
||||
textureCache_->GetVulkanHandles(imageView, sampler);
|
||||
@@ -809,17 +803,16 @@ void DrawEngineVulkan::DoFlush() {
|
||||
lastPrim_ = prim;
|
||||
|
||||
dirtyUniforms_ |= shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
|
||||
UpdateUBOs(frame);
|
||||
UpdateUBOs(&frameData);
|
||||
|
||||
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf, tess);
|
||||
|
||||
const uint32_t dynamicUBOOffsets[3] = {
|
||||
baseUBOOffset, lightUBOOffset, boneUBOOffset,
|
||||
};
|
||||
|
||||
if (useElements) {
|
||||
if (!ibuf) {
|
||||
ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf);
|
||||
ibOffset = (uint32_t)frameData.pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf);
|
||||
}
|
||||
renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, 1, VK_INDEX_TYPE_UINT16);
|
||||
} else {
|
||||
@@ -827,8 +820,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
}
|
||||
} else {
|
||||
PROFILE_THIS_SCOPE("soft");
|
||||
// Decode to "decoded"
|
||||
DecodeVertsToPushBuffer(nullptr, nullptr, nullptr);
|
||||
DecodeVerts(decoded);
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
|
||||
@@ -841,7 +833,6 @@ void DrawEngineVulkan::DoFlush() {
|
||||
// Undo the strip optimization, not supported by the SW code yet.
|
||||
if (prim == GE_PRIM_TRIANGLE_STRIP)
|
||||
prim = GE_PRIM_TRIANGLES;
|
||||
VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, indexGen.VertexCount());
|
||||
|
||||
u16 *inds = decIndex;
|
||||
SoftwareTransformResult result{};
|
||||
@@ -851,7 +842,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
params.transformedExpanded = transformedExpanded;
|
||||
params.fbman = framebufferManager_;
|
||||
params.texCache = textureCache_;
|
||||
// We have to force drawing of primitives if !framebufferManager_->UseBufferedRendering() because Vulkan clears
|
||||
// In Vulkan, we have to force drawing of primitives if !framebufferManager_->UseBufferedRendering() because Vulkan clears
|
||||
// do not respect scissor rects.
|
||||
params.allowClear = framebufferManager_->UseBufferedRendering();
|
||||
params.allowSeparateAlphaClear = false;
|
||||
@@ -940,12 +931,13 @@ void DrawEngineVulkan::DoFlush() {
|
||||
if (fboTexBound_)
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
|
||||
lastPrim_ = prim;
|
||||
|
||||
dirtyUniforms_ |= shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
|
||||
|
||||
// Even if the first draw is through-mode, make sure we at least have one copy of these uniforms buffered
|
||||
UpdateUBOs(frame);
|
||||
UpdateUBOs(&frameData);
|
||||
|
||||
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf, tess);
|
||||
const uint32_t dynamicUBOOffsets[3] = {
|
||||
@@ -956,12 +948,12 @@ void DrawEngineVulkan::DoFlush() {
|
||||
|
||||
if (result.drawIndexed) {
|
||||
VkBuffer vbuf, ibuf;
|
||||
vbOffset = (uint32_t)frame->pushVertex->Push(result.drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf);
|
||||
ibOffset = (uint32_t)frame->pushIndex->Push(inds, sizeof(short) * result.drawNumTrans, &ibuf);
|
||||
vbOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf);
|
||||
ibOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(short) * result.drawNumTrans, &ibuf);
|
||||
renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1, VK_INDEX_TYPE_UINT16);
|
||||
} else {
|
||||
VkBuffer vbuf;
|
||||
vbOffset = (uint32_t)frame->pushVertex->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), &vbuf);
|
||||
vbOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), &vbuf);
|
||||
renderManager->Draw(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans);
|
||||
}
|
||||
} else if (result.action == SW_CLEAR) {
|
||||
|
||||
Reference in new issue
Block a user