Not pretty, but with this, you can switch MSAA level at runtime.

This commit is contained in:
Henrik Rydgård 2022-12-01 23:41:31 +01:00
parent 28e1b532bd
commit 8a3e92aa38
12 changed files with 40 additions and 15 deletions

View file

@ -21,7 +21,7 @@ extern const float one_over_255_x4[4];
extern const float exactly_255_x4[4];
// Utilities useful for filling in std140-layout uniform buffers, and similar.
// NEON intrinsics: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491f/BABDCGGF.html
// NEON intrinsics: https://developer.arm.com/documentation/den0018/a/NEON-Intrinsics?lang=en
// LSBs in f[0], etc.
inline void Uint8x4ToFloat4(float f[4], uint32_t u) {

View file

@ -1327,10 +1327,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
VkSampleCountFlagBits fbSampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT;
if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) {
// Sample count might have started mismatching if the user changed multisampling mode. Let's get rid of all variants
// and start over.
// (We could avoid this if sample count was baked into the rpType, but I don't want that to grow too big).
graphicsPipeline->DestroyAllVariants(vulkan_);
// Shouldn't happen, pipeline invalidation after render resized should have taken care of this.
_assert_(false);
}
if (!graphicsPipeline->pipeline[(size_t)rpType]) {

View file

@ -130,10 +130,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
return success;
}
void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) {
void VKRGraphicsPipeline::DestroyVariants(VulkanContext *vulkan, bool msaaOnly) {
for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) {
if (!this->pipeline[i])
continue;
if (msaaOnly && (i & (int)RenderPassType::MULTISAMPLE) == 0)
continue;
VkPipeline pipeline = this->pipeline[i]->BlockUntilReady();
// pipeline can be nullptr here, if it failed to compile before.
if (pipeline) {
@ -145,7 +148,7 @@ void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) {
}
void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) {
DestroyAllVariants(vulkan);
DestroyVariants(vulkan, false);
vulkan->Delete().QueueCallback([](void *p) {
VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p;
delete pipeline;

View file

@ -124,7 +124,7 @@ struct VKRGraphicsPipeline {
bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount);
void DestroyAllVariants(VulkanContext *vulkan);
void DestroyVariants(VulkanContext *vulkan, bool msaaOnly);
// This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this.
void QueueForDeletion(VulkanContext *vulkan);
@ -458,6 +458,8 @@ public:
return outOfDateFrames_ > VulkanContext::MAX_INFLIGHT_FRAMES;
}
void Invalidate(InvalidationFlags flags);
void ResetStats();
private:

View file

@ -242,7 +242,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con
#endif
VkShaderModule shaderModule = VK_NULL_HANDLE;
if (vulkan->CreateShaderModule(spirv, &shaderModule, vkstage_ == VK_SHADER_STAGE_VERTEX_BIT ? "thin3d_vs" : "thin3d_fs")) {
if (vulkan->CreateShaderModule(spirv, &shaderModule, tag_.c_str())) {
module_ = Promise<VkShaderModule>::AlreadyDone(shaderModule);
ok_ = true;
} else {

View file

@ -2878,11 +2878,7 @@ static void DoRelease(T *&obj) {
obj = nullptr;
}
void FramebufferManagerCommon::DeviceLost() {
DestroyAllFBOs();
presentation_->DeviceLost();
void FramebufferManagerCommon::ReleasePipelines() {
for (int i = 0; i < ARRAY_SIZE(reinterpretFromTo_); i++) {
for (int j = 0; j < ARRAY_SIZE(reinterpretFromTo_); j++) {
DoRelease(reinterpretFromTo_[i][j]);
@ -2899,9 +2895,16 @@ void FramebufferManagerCommon::DeviceLost() {
DoRelease(draw2DPipelineDepth_);
DoRelease(draw2DPipeline565ToDepth_);
DoRelease(draw2DPipeline565ToDepthDeswizzle_);
}
void FramebufferManagerCommon::DeviceLost() {
DestroyAllFBOs();
presentation_->DeviceLost();
draw2D_.DeviceLost();
ReleasePipelines();
draw_ = nullptr;
}

View file

@ -443,6 +443,8 @@ public:
int scaleFactor, // usually unused, except for swizzle...
Draw2DPipeline *pipeline, const char *tag);
void ReleasePipelines();
protected:
virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel);
// Used for when a shader is required, such as GLES.

View file

@ -267,7 +267,7 @@ protected:
void DeviceLost() override;
void DeviceRestore() override;
void CheckRenderResized();
virtual void CheckRenderResized();
// Add additional common features dependent on other features, which may be backend-determined.
u32 CheckGPUFeaturesLate(u32 features) const;

View file

@ -465,6 +465,14 @@ void GPU_Vulkan::DestroyDeviceObjects() {
}
}
void GPU_Vulkan::CheckRenderResized() {
if (renderResized_) {
GPUCommon::CheckRenderResized();
pipelineManager_->InvalidateMSAAPipelines();
framebufferManager_->ReleasePipelines();
}
}
void GPU_Vulkan::DeviceLost() {
CancelReady();
while (!IsReady()) {

View file

@ -70,6 +70,7 @@ public:
protected:
void FinishDeferred() override;
void CheckRenderResized() override;
private:
void Flush() {

View file

@ -49,6 +49,12 @@ void PipelineManagerVulkan::Clear() {
pipelines_.Clear();
}
void PipelineManagerVulkan::InvalidateMSAAPipelines() {
pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) {
value->pipeline->DestroyVariants(vulkan_, true);
});
}
void PipelineManagerVulkan::DeviceLost() {
Clear();
if (pipelineCache_ != VK_NULL_HANDLE)

View file

@ -88,6 +88,8 @@ public:
void DeviceLost();
void DeviceRestore(VulkanContext *vulkan);
void InvalidateMSAAPipelines();
std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
std::vector<std::string> DebugGetObjectIDs(DebugShaderType type);