More explicit invalidation of any cached state in Thin3D. Fixes #13307

This commit is contained in:
Henrik Rydgård 2020-08-22 00:30:29 +02:00
parent e8779fdc88
commit 506a86300d
8 changed files with 48 additions and 41 deletions

View File

@ -539,8 +539,7 @@ void PresentationCommon::UpdateUniforms(bool hasVideo) {
}
void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1) {
// Make sure Direct3D 11 clears state, since we set shaders outside Draw.
draw_->BindPipeline(nullptr);
draw_->InvalidateCachedState();
// TODO: If shader objects have been created by now, we might have received errors.
// GLES can have the shader fail later, shader->failed / shader->error.
@ -649,6 +648,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
Draw::Framebuffer *postShaderFramebuffer = postShaderFramebuffers_[i];
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader");
if (usePostShaderOutput) {
draw_->BindFramebufferAsTexture(postShaderFramebuffers_[i - 1], 0, Draw::FB_COLOR_BIT, 0);
} else {

View File

@ -119,7 +119,6 @@ GPU_D3D11::~GPU_D3D11() {
shaderManagerD3D11_->ClearShaders();
delete shaderManagerD3D11_;
delete textureCacheD3D11_;
draw_->BindPipeline(nullptr);
stockD3D11.Destroy();
}
@ -233,8 +232,8 @@ void GPU_D3D11::ReapplyGfxState() {
}
void GPU_D3D11::EndHostFrame() {
// Tell the DrawContext that it's time to reset everything.
draw_->BindPipeline(nullptr);
// Probably not really necessary.
draw_->InvalidateCachedState();
}
void GPU_D3D11::BeginFrame() {

View File

@ -389,7 +389,9 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra
Draw::Framebuffer *depalFBO = framebufferManagerD3D11_->GetTempFBO(TempFBO::DEPAL, framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888);
shaderManager_->DirtyLastShader();
draw_->BindPipeline(nullptr);
// Not sure why or if we need this here - we're not about to actually draw using draw_, just use its framebuffer binds.
draw_->InvalidateCachedState();
float xoff = -0.5f / framebuffer->renderWidth;
float yoff = 0.5f / framebuffer->renderHeight;

View File

@ -646,7 +646,11 @@ public:
BindTextures(stage, 1, textures);
} // from sampler 0 and upwards
// Call this with nullptr to signal that you're done with the stuff you've bound, like textures and samplers and stuff.
// Clear state cached within thin3d. Must be called after directly calling API functions.
// Note that framebuffer state (which framebuffer is bounds) may not be cached.
// Must not actually perform any API calls itself since this can be called when no framebuffer is bound for rendering.
virtual void InvalidateCachedState() = 0;
virtual void BindPipeline(Pipeline *pipeline) = 0;
virtual void Draw(int vertexCount, int offset) = 0;

View File

@ -77,6 +77,8 @@ public:
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
void InvalidateCachedState() override;
void BindTextures(int start, int count, Texture **textures) override;
void BindSamplerStates(int start, int count, SamplerState **states) override;
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override;
@ -1019,19 +1021,20 @@ void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
context_->Unmap(curPipeline_->dynamicUniforms, 0);
}
void D3D11DrawContext::BindPipeline(Pipeline *pipeline) {
if (pipeline == nullptr) {
// This is a signal to forget all our caching.
curBlend_ = nullptr;
curDepth_ = nullptr;
curRaster_ = nullptr;
curPS_ = nullptr;
curVS_ = nullptr;
curGS_ = nullptr;
curInputLayout_ = nullptr;
curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
}
void D3D11DrawContext::InvalidateCachedState() {
// This is a signal to forget all our state caching.
curBlend_ = nullptr;
curDepth_ = nullptr;
curRaster_ = nullptr;
curPS_ = nullptr;
curVS_ = nullptr;
curGS_ = nullptr;
curInputLayout_ = nullptr;
curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
curPipeline_ = nullptr;
}
void D3D11DrawContext::BindPipeline(Pipeline *pipeline) {
D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline;
if (curPipeline_ == dPipeline)
return;

View File

@ -606,6 +606,8 @@ public:
return stepId_;
}
void InvalidateCachedState() override;
private:
LPDIRECT3D9 d3d_;
LPDIRECT3D9EX d3dEx_;
@ -631,6 +633,10 @@ private:
bool supportsINTZ = false;
};
void D3D9Context::InvalidateCachedState() {
curPipeline_ = nullptr;
}
#define FB_DIV 1
#define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z')))

View File

@ -481,9 +481,10 @@ public:
return renderManager_.GetCurrentStepId();
}
void InvalidateCachedState() override;
private:
void ApplySamplers();
void Unbind();
GLRenderManager renderManager_;
@ -612,14 +613,14 @@ void OpenGLContext::BeginFrame() {
}
void OpenGLContext::EndFrame() {
Unbind();
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
renderManager_.EndPushBuffer(frameData.push); // upload the data!
renderManager_.Finish();
InvalidateCachedState();
}
void OpenGLContext::Unbind() {
void OpenGLContext::InvalidateCachedState() {
// Unbind stuff.
for (auto &texture : boundTextures_) {
texture = nullptr;
@ -627,9 +628,6 @@ void OpenGLContext::Unbind() {
for (auto &sampler : boundSamplers_) {
sampler = nullptr;
}
for (int i = 0; i < ARRAY_SIZE(boundTextures_); i++) {
renderManager_.BindTexture(i, nullptr);
}
curPipeline_ = nullptr;
}
@ -1107,15 +1105,13 @@ bool OpenGLPipeline::LinkShaders() {
void OpenGLContext::BindPipeline(Pipeline *pipeline) {
curPipeline_ = (OpenGLPipeline *)pipeline;
if (curPipeline_) {
curPipeline_->blend->Apply(&renderManager_);
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_);
curPipeline_->raster->Apply(&renderManager_);
renderManager_.BindProgram(curPipeline_->program_);
} else {
// Wipe bound textures and samplers.
Unbind();
if (!curPipeline_) {
return;
}
curPipeline_->blend->Apply(&renderManager_);
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_);
curPipeline_->raster->Apply(&renderManager_);
renderManager_.BindProgram(curPipeline_->program_);
}
void OpenGLContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {

View File

@ -408,10 +408,6 @@ public:
void BindPipeline(Pipeline *pipeline) override {
curPipeline_ = (VKPipeline *)pipeline;
if (!pipeline) {
UnbindBoundState();
}
}
// TODO: Make VKBuffers proper buffers, and do a proper binding model. This is just silly.
@ -497,8 +493,9 @@ public:
return renderManager_.GetCurrentStepId();
}
void InvalidateCachedState() override;
private:
void UnbindBoundState();
VulkanTexture *GetNullTexture();
VulkanContext *vulkan_ = nullptr;
@ -923,10 +920,10 @@ void VKContext::EndFrame() {
push_ = nullptr;
// Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things).
UnbindBoundState();
InvalidateCachedState();
}
void VKContext::UnbindBoundState() {
void VKContext::InvalidateCachedState() {
curPipeline_ = nullptr;
for (auto &view : boundImageView_) {