Replace the "GetCurrentStepId"-based state invalidation with callbacks

This commit is contained in:
Henrik Rydgård 2022-11-24 10:38:49 +01:00
parent a1c61abdda
commit 70d1d8fa07
21 changed files with 140 additions and 115 deletions

View file

@ -606,6 +606,7 @@ add_library(Common STATIC
Common/File/FileDescriptor.cpp
Common/File/FileDescriptor.h
Common/GPU/DataFormat.h
Common/GPU/MiscTypes.h
Common/GPU/thin3d.cpp
Common/GPU/thin3d.h
Common/GPU/thin3d_create.h

View file

@ -432,6 +432,7 @@
<ClInclude Include="GPU\D3D9\D3D9ShaderCompiler.h" />
<ClInclude Include="GPU\D3D9\D3D9StateCache.h" />
<ClInclude Include="GPU\DataFormat.h" />
<ClInclude Include="GPU\MiscTypes.h" />
<ClInclude Include="GPU\OpenGL\DataFormatGL.h" />
<ClInclude Include="GPU\OpenGL\gl3stub.h" />
<ClInclude Include="GPU\OpenGL\GLFeatures.h" />

View file

@ -452,6 +452,9 @@
<ClInclude Include="Render\ManagedTexture.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="GPU\MiscTypes.h">
<Filter>GPU</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />

View file

@ -163,8 +163,8 @@ public:
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
int GetCurrentStepId() const override {
return stepId_;
void SetInvalidationCallback(InvalidationCallback callback) override {
invalidationCallback_ = callback;
}
private:
@ -177,7 +177,6 @@ private:
ID3D11DeviceContext *context_;
ID3D11Device1 *device1_;
ID3D11DeviceContext1 *context1_;
int stepId_ = -1;
ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED
ID3D11RenderTargetView *bbRenderTargetView_ = nullptr;
@ -216,6 +215,8 @@ private:
ID3D11Buffer *nextIndexBuffer_ = nullptr;
int nextIndexBufferOffset_ = 0;
InvalidationCallback invalidationCallback_;
// Dynamic state
float blendFactor_[4]{};
bool blendFactorDirty_ = false;
@ -399,7 +400,6 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1
// Make sure that we don't eliminate the next time the render target is set.
curRenderTargetView_ = nullptr;
curDepthStencilView_ = nullptr;
stepId_ = 0;
break;
}
}
@ -1500,13 +1500,11 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x
D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) };
context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox);
}
stepId_++;
}
bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) {
// Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead.
Crash();
stepId_++;
return false;
}
@ -1652,7 +1650,6 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel
if (!useGlobalPacktex) {
packTex->Release();
}
stepId_++;
return true;
}
@ -1699,7 +1696,9 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren
context_->ClearDepthStencilView(curDepthStencilView_, mask, rp.clearDepth, rp.clearStencil);
}
stepId_++;
if (invalidationCallback_) {
invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE);
}
}
void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {

View file

@ -610,18 +610,17 @@ public:
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
int GetCurrentStepId() const override {
return stepId_;
}
void InvalidateCachedState() override;
void SetInvalidationCallback(InvalidationCallback callback) override {
invalidationCallback_ = callback;
}
private:
LPDIRECT3D9 d3d_;
LPDIRECT3D9EX d3dEx_;
LPDIRECT3DDEVICE9 device_;
LPDIRECT3DDEVICE9EX deviceEx_;
int stepId_ = -1;
int adapterId_ = -1;
D3DADAPTER_IDENTIFIER9 identifier_{};
D3DCAPS9 d3dCaps_;
@ -647,6 +646,8 @@ private:
// Dynamic state
uint8_t stencilRef_ = 0;
InvalidationCallback invalidationCallback_;
};
void D3D9Context::InvalidateCachedState() {
@ -1319,7 +1320,10 @@ void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPa
dxstate.scissorRect.restore();
dxstate.scissorTest.restore();
dxstate.viewport.restore();
stepId_++;
if (invalidationCallback_) {
invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE);
}
}
uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) {
@ -1398,7 +1402,6 @@ bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int
} else {
return false;
}
stepId_++;
return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, (filter == FB_BLIT_LINEAR && channelBits == FB_COLOR_BIT) ? D3DTEXF_LINEAR : D3DTEXF_POINT));
}
@ -1519,7 +1522,6 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi
device_->GetDepthStencilSurface(&deviceDSsurf);
break;
case Event::PRESENTED:
stepId_ = 0;
break;
}
}

11
Common/GPU/MiscTypes.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "Common/Common.h"
enum class InvalidationFlags {
RENDER_PASS_STATE = 1,
COMMAND_BUFFER_STATE = 2,
};
ENUM_CLASS_BITOPS(InvalidationFlags);
typedef std::function<void(InvalidationFlags)> InvalidationCallback;

View file

@ -354,6 +354,10 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende
step->dependencies.insert(fb);
}
}
if (invalidationCallback_) {
invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE);
}
}
void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit) {
@ -480,7 +484,6 @@ void GLRenderManager::BeginFrame() {
// In GL, we have to do deletes on the submission thread.
insideFrame_ = true;
renderStepOffset_ = 0;
}
void GLRenderManager::Finish() {
@ -612,9 +615,6 @@ void GLRenderManager::Run(int frame) {
}
void GLRenderManager::FlushSync() {
// TODO: Reset curRenderStep_?
renderStepOffset_ += (int)steps_.size();
int curFrame = curFrame_;
FrameData &frameData = frameData_[curFrame];
{

View file

@ -10,6 +10,7 @@
#include <condition_variable>
#include "Common/GPU/OpenGL/GLCommon.h"
#include "Common/GPU/MiscTypes.h"
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Log.h"
#include "GLQueueRunner.h"
@ -368,6 +369,9 @@ public:
GLRenderManager() {}
~GLRenderManager();
void SetInvalidationCallback(InvalidationCallback callback) {
invalidationCallback_ = callback;
}
void SetErrorCallback(ErrorCallbackFn callback, void *userdata) {
queueRunner_.SetErrorCallback(callback, userdata);
}
@ -980,12 +984,6 @@ public:
skipGLCalls_ = true;
}
// Gets a frame-unique ID of the current step being recorded. Can be used to figure out
// when the current step has changed, which means the caller will need to re-record its state.
int GetCurrentStepId() const {
return renderStepOffset_ + (int)steps_.size();
}
private:
void BeginSubmitFrame(int frame);
void EndSubmitFrame(int frame);
@ -1033,8 +1031,7 @@ private:
// Submission time state
bool insideFrame_ = false;
// This is the offset within this frame, in case of a mid-frame sync.
int renderStepOffset_ = 0;
GLRStep *curRenderStep_ = nullptr;
std::vector<GLRStep *> steps_;
std::vector<GLRInitStep> initSteps_;
@ -1074,4 +1071,6 @@ private:
GLRProgram *curProgram_ = nullptr;
#endif
Draw::DeviceCaps caps_{};
InvalidationCallback invalidationCallback_;
};

View file

@ -466,12 +466,12 @@ public:
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {}
int GetCurrentStepId() const override {
return renderManager_.GetCurrentStepId();
}
void InvalidateCachedState() override;
void SetInvalidationCallback(InvalidationCallback callback) {
renderManager_.SetInvalidationCallback(callback);
}
private:
void ApplySamplers();

View file

@ -668,8 +668,6 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling, bool enableLogProfile
insideFrame_ = true;
vulkan_->BeginFrame(enableLogProfiler ? GetInitCmd() : VK_NULL_HANDLE);
renderStepOffset_ = 0;
frameData.profile.timestampDescriptions.clear();
if (frameData.profilingEnabled_) {
// For various reasons, we need to always use an init cmd buffer in this case to perform the vkCmdResetQueryPool,
@ -956,6 +954,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
data.clear.clearMask = lateClearMask;
curRenderStep_->commands.push_back(data);
}
if (invalidationCallback_) {
invalidationCallback_(InvalidationFlags::RENDER_PASS_STATE);
}
}
bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) {
@ -1414,7 +1416,9 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) {
// Called from main thread.
void VulkanRenderManager::FlushSync() {
renderStepOffset_ += (int)steps_.size();
if (invalidationCallback_) {
invalidationCallback_(InvalidationFlags::COMMAND_BUFFER_STATE);
}
int curFrame = vulkan_->GetCurFrame();
FrameData &frameData = frameData_[curFrame];

View file

@ -19,6 +19,7 @@
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Math/math_util.h"
#include "Common/GPU/DataFormat.h"
#include "Common/GPU/MiscTypes.h"
#include "Common/GPU/Vulkan/VulkanQueueRunner.h"
// Forward declaration
@ -235,6 +236,10 @@ public:
// Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown.
void Wipe();
void SetInvalidationCallback(InvalidationCallback callback) {
invalidationCallback_ = callback;
}
// This starts a new step containing a render pass (unless it can be trivially merged into the previous one, which is pretty common).
//
// After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce
@ -475,12 +480,6 @@ public:
VkCommandBuffer GetInitCmd();
// Gets a frame-unique ID of the current step being recorded. Can be used to figure out
// when the current step has changed, which means the caller will need to re-record its state.
int GetCurrentStepId() const {
return renderStepOffset_ + (int)steps_.size();
}
bool CreateBackbuffers();
void DestroyBackbuffers();
@ -520,7 +519,6 @@ private:
void DrainCompileQueue();
void Run(VKRRenderThreadTask &task);
void BeginSubmitFrame(int frame);
// Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot).
void FlushSync();
@ -548,7 +546,6 @@ private:
bool run_ = false;
// This is the offset within this frame, in case of a mid-frame sync.
int renderStepOffset_ = 0;
VKRStep *curRenderStep_ = nullptr;
bool curStepHasViewport_ = false;
bool curStepHasScissor_ = false;
@ -587,4 +584,6 @@ private:
SimpleStat initTimeMs_;
SimpleStat totalGPUTimeMs_;
SimpleStat renderCPUTimeMs_;
std::function<void(InvalidationFlags)> invalidationCallback_;
};

View file

@ -498,14 +498,14 @@ public:
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
int GetCurrentStepId() const override {
return renderManager_.GetCurrentStepId();
}
void InvalidateCachedState() override;
void InvalidateFramebuffer(FBInvalidationStage stage, uint32_t channels) override;
void SetInvalidationCallback(InvalidationCallback callback) {
renderManager_.SetInvalidationCallback(callback);
}
private:
VulkanTexture *GetNullTexture();
VulkanContext *vulkan_ = nullptr;

View file

@ -16,6 +16,7 @@
#include "Common/Common.h"
#include "Common/GPU/DataFormat.h"
#include "Common/GPU/Shader.h"
#include "Common/GPU/MiscTypes.h"
#include "Common/Data/Collections/Slice.h"
namespace Lin {
@ -769,7 +770,9 @@ public:
// This is called when we launch a new game, so any collected internal stats in the backends don't carry over.
virtual void ResetStats() {}
virtual int GetCurrentStepId() const = 0;
// Used by the DrawEngines to know when they have to re-apply some state.
// Not very elegant, but more elegant than the old passId hack.
virtual void SetInvalidationCallback(InvalidationCallback callback) = 0;
protected:
ShaderModule *vsPresets_[VS_MAX_PRESET];

View file

@ -113,6 +113,8 @@ void DrawEngineD3D11::InitDeviceObjects() {
tessDataTransferD3D11 = new TessellationDataTransferD3D11(context_, device_);
tessDataTransfer = tessDataTransferD3D11;
draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1));
}
void DrawEngineD3D11::ClearTrackedVertexArrays() {
@ -136,6 +138,8 @@ void DrawEngineD3D11::NotifyConfigChanged() {
}
void DrawEngineD3D11::DestroyDeviceObjects() {
draw_->SetInvalidationCallback(InvalidationCallback());
ClearTrackedVertexArrays();
ClearInputLayoutMap();
delete tessDataTransferD3D11;
@ -322,19 +326,18 @@ VertexArrayInfoD3D11::~VertexArrayInfoD3D11() {
ebo->Release();
}
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
void DrawEngineD3D11::Invalidate(InvalidationFlags flags) {
if (flags & InvalidationFlags::RENDER_PASS_STATE) {
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
textureCache_->ForgetLastTexture();
}
}
// The inline wrapper in the header checks for numDrawCalls == 0
void DrawEngineD3D11::DoFlush() {
gpuStats.numFlushes++;
// 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();

View file

@ -155,6 +155,8 @@ public:
void ClearInputLayoutMap();
private:
void Invalidate(InvalidationFlags flags);
void DoFlush();
void ApplyDrawState(int prim);

View file

@ -126,10 +126,11 @@ DrawEngineDX9::~DrawEngineDX9() {
}
void DrawEngineDX9::InitDeviceObjects() {
draw_->SetInvalidationCallback(std::bind(&DrawEngineDX9::Invalidate, this, std::placeholders::_1));
}
void DrawEngineDX9::DestroyDeviceObjects() {
draw_->SetInvalidationCallback(InvalidationCallback());
ClearTrackedVertexArrays();
}
@ -310,18 +311,17 @@ void DrawEngineDX9::BeginFrame() {
lastRenderStepId_ = -1;
}
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
void DrawEngineDX9::Invalidate(InvalidationFlags flags) {
if (flags & InvalidationFlags::RENDER_PASS_STATE) {
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
}
}
// The inline wrapper in the header checks for numDrawCalls == 0
void DrawEngineDX9::DoFlush() {
gpuStats.numFlushes++;
// 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);
lastRenderStepId_ = curRenderStepId;
}
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
textureCache_->SetTexture();

View file

@ -144,6 +144,7 @@ protected:
void DecimateTrackedVertexArrays();
private:
void Invalidate(InvalidationFlags flags);
void DoFlush();
void ApplyDrawState(int prim);

View file

@ -117,9 +117,13 @@ void DrawEngineGLES::InitDeviceObjects() {
entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color1) });
entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, fog) });
softwareInputLayout_ = render_->CreateInputLayout(entries);
draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1));
}
void DrawEngineGLES::DestroyDeviceObjects() {
draw_->SetInvalidationCallback(InvalidationCallback());
// Beware: this could be called twice in a row, sometimes.
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
if (!frameData_[i].pushVertex && !frameData_[i].pushIndex)
@ -238,22 +242,22 @@ void *DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bind
return dest;
}
// A new render step means we need to flush any dynamic state. Really, any state that is reset in
// GLQueueRunner::PerformRenderPass.
void DrawEngineGLES::Invalidate(InvalidationFlags flags) {
if (flags & InvalidationFlags::RENDER_PASS_STATE) {
// Dirty everything that has dynamic state that will need re-recording.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
textureCache_->ForgetLastTexture();
}
}
void DrawEngineGLES::DoFlush() {
PROFILE_THIS_SCOPE("flush");
FrameData &frameData = frameData_[render_->GetCurFrame()];
gpuStats.numFlushes++;
// A new render step means we need to flush any dynamic state. Really, any state that is reset in
// GLQueueRunner::PerformRenderPass.
int curRenderStepId = render_->GetCurrentStepId();
if (lastRenderStepId_ != curRenderStepId) {
// Dirty everything that has dynamic state that will need re-recording.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_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();

View file

@ -84,7 +84,6 @@ public:
void BeginFrame();
void EndFrame();
// So that this can be inlined
void Flush() {
if (!numDrawCalls)
@ -117,6 +116,8 @@ protected:
bool UpdateUseHWTessellation(bool enable) override;
private:
void Invalidate(InvalidationFlags flags);
void InitDeviceObjects();
void DestroyDeviceObjects();

View file

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <functional>
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Profiler/Profiler.h"
@ -150,7 +151,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
dpTypes[3].descriptorCount = DEFAULT_DESC_POOL_SIZE; // TODO: Use a separate layout when no spline stuff is needed to reduce the need for these.
dpTypes[3].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
dpTypes[4].descriptorCount = 1; // For the frame global uniform buffer.
dpTypes[4].descriptorCount = DEFAULT_DESC_POOL_SIZE; // For the frame global uniform buffer. Might need to allocate multiple times.
dpTypes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
@ -204,6 +205,8 @@ void DrawEngineVulkan::InitDeviceObjects() {
tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan);
tessDataTransfer = tessDataTransferVulkan;
draw_->SetInvalidationCallback(std::bind(&DrawEngineVulkan::Invalidate, this, std::placeholders::_1));
}
DrawEngineVulkan::~DrawEngineVulkan() {
@ -234,7 +237,14 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) {
}
void DrawEngineVulkan::DestroyDeviceObjects() {
VulkanContext *vulkan = draw_ ? (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT) : nullptr;
if (!draw_) {
// We've already done this from LostDevice.
return;
}
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
draw_->SetInvalidationCallback(InvalidationCallback());
delete tessDataTransferVulkan;
tessDataTransfer = nullptr;
@ -283,8 +293,6 @@ void DrawEngineVulkan::BeginFrame() {
lastPipeline_ = nullptr;
lastRenderStepId_ = -1;
FrameData *frame = &GetCurFrame();
// First reset all buffers, then begin. This is so that Reset can free memory and Begin can allocate it,
@ -536,6 +544,21 @@ void MarkUnreliable(VertexArrayInfoVulkan *vai) {
// For now we just leave it in the pushbuffer.
}
void DrawEngineVulkan::Invalidate(InvalidationFlags flags) {
if (flags & InvalidationFlags::COMMAND_BUFFER_STATE) {
GetCurFrame().frameDescSetUpdated = false;
}
if (flags & InvalidationFlags::RENDER_PASS_STATE) {
// 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!
//
// Dirty everything that has dynamic state that will need re-recording.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
lastPipeline_ = nullptr;
}
}
// The inline wrapper in the header checks for numDrawCalls == 0
void DrawEngineVulkan::DoFlush() {
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
@ -545,18 +568,6 @@ void DrawEngineVulkan::DoFlush() {
gpuStats.numFlushes++;
// 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!
int curRenderStepId = renderManager->GetCurrentStepId();
if (lastRenderStepId_ != curRenderStepId) {
// Dirty everything that has dynamic state that will need re-recording.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
textureCache_->ForgetLastTexture();
lastRenderStepId_ = curRenderStepId;
lastPipeline_ = nullptr;
}
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
bool textureNeedsApply = false;
@ -785,16 +796,6 @@ void DrawEngineVulkan::DoFlush() {
}
BindShaderBlendTex(); // This might cause copies so important to do before BindPipeline.
// If have a new render pass, dirty our dynamic state so it gets re-set.
// WARNING: We have to do this 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!
int curRenderStepId = renderManager->GetCurrentStepId();
if (lastRenderStepId_ != curRenderStepId) {
// Dirty everything that has dynamic state that will need re-recording.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE);
lastRenderStepId_ = curRenderStepId;
}
renderManager->BindPipeline(pipeline->pipeline, pipeline->pipelineFlags, pipelineLayout_);
if (pipeline != lastPipeline_) {
if (lastPipeline_ && !(lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant())) {
@ -928,16 +929,6 @@ void DrawEngineVulkan::DoFlush() {
}
BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline.
// If have a new render pass, dirty our dynamic state so it gets re-set.
// WARNING: We have to do this 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!
int curRenderStepId = renderManager->GetCurrentStepId();
if (lastRenderStepId_ != curRenderStepId) {
// Dirty everything that has dynamic state that will need re-recording.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE);
lastRenderStepId_ = curRenderStepId;
}
renderManager->BindPipeline(pipeline->pipeline, pipeline->pipelineFlags, pipelineLayout_);
if (pipeline != lastPipeline_) {
if (lastPipeline_ && !lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant()) {

View file

@ -43,6 +43,7 @@
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Vulkan/StateMappingVulkan.h"
#include "GPU/Vulkan/VulkanRenderManager.h"
struct DecVtxFormat;
struct UVScale;
@ -208,6 +209,8 @@ public:
}
private:
void Invalidate(InvalidationFlags flags);
struct FrameData;
void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
@ -308,6 +311,4 @@ private:
// Hardware tessellation
TessellationDataTransferVulkan *tessDataTransferVulkan;
int lastRenderStepId_ = -1;
};