mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Multisampling groundwork
This commit is contained in:
parent
6daecb4e2b
commit
06af304c8d
13 changed files with 157 additions and 58 deletions
|
@ -2,14 +2,41 @@
|
|||
#include "Common/GPU/Vulkan/VulkanFramebuffer.h"
|
||||
#include "Common/GPU/Vulkan/VulkanQueueRunner.h"
|
||||
|
||||
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag)
|
||||
VkSampleCountFlagBits SampleCountToFlagBits(int count) {
|
||||
// TODO: Check hardware support here, or elsewhere?
|
||||
// Some hardware only supports 4x.
|
||||
switch (count) {
|
||||
case 1: return VK_SAMPLE_COUNT_1_BIT;
|
||||
case 2: return VK_SAMPLE_COUNT_2_BIT;
|
||||
case 4: return VK_SAMPLE_COUNT_4_BIT;
|
||||
case 8: return VK_SAMPLE_COUNT_8_BIT;
|
||||
case 16: return VK_SAMPLE_COUNT_16_BIT; // rare
|
||||
default:
|
||||
_assert_(false);
|
||||
return VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag)
|
||||
: vulkan_(vk), tag_(tag), width(_width), height(_height), numLayers(_numLayers) {
|
||||
|
||||
_dbg_assert_(tag);
|
||||
|
||||
CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);
|
||||
CreateImage(vulkan_, initCmd, color, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);
|
||||
if (createDepthStencilBuffer) {
|
||||
CreateImage(vulkan_, initCmd, depth, width, height, numLayers, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);
|
||||
CreateImage(vulkan_, initCmd, depth, width, height, numLayers, VK_SAMPLE_COUNT_1_BIT, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);
|
||||
}
|
||||
|
||||
if (_numSamples > 1) {
|
||||
sampleCount = SampleCountToFlagBits(_numSamples);
|
||||
|
||||
// TODO: Create a different tag for these?
|
||||
CreateImage(vulkan_, initCmd, msaaColor, width, height, numLayers, sampleCount, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);
|
||||
if (createDepthStencilBuffer) {
|
||||
CreateImage(vulkan_, initCmd, depth, width, height, numLayers, sampleCount, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);
|
||||
}
|
||||
} else {
|
||||
sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
|
||||
UpdateTag(tag);
|
||||
|
@ -55,7 +82,7 @@ VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPas
|
|||
}
|
||||
views[1] = depth.rtView;
|
||||
}
|
||||
fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType);
|
||||
fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType, sampleCount);
|
||||
fbci.attachmentCount = hasDepth ? 2 : 1;
|
||||
fbci.pAttachments = views;
|
||||
fbci.width = width;
|
||||
|
@ -108,7 +135,7 @@ VKRFramebuffer::~VKRFramebuffer() {
|
|||
|
||||
// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture.
|
||||
// This requires a different sampling path!
|
||||
void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) {
|
||||
void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) {
|
||||
// We don't support more exotic layer setups for now. Mono or stereo.
|
||||
_dbg_assert_(numLayers == 1 || numLayers == 2);
|
||||
|
||||
|
@ -120,7 +147,7 @@ void VKRFramebuffer::CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKR
|
|||
ici.extent.depth = 1;
|
||||
ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
ici.imageType = VK_IMAGE_TYPE_2D;
|
||||
ici.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
ici.samples = sampleCount;
|
||||
ici.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
ici.format = format;
|
||||
// Strictly speaking we don't yet need VK_IMAGE_USAGE_SAMPLED_BIT for depth buffers since we do not yet sample depth buffers.
|
||||
|
@ -226,45 +253,76 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) {
|
|||
// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827
|
||||
// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies
|
||||
|
||||
VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) {
|
||||
VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType, VkSampleCountFlagBits sampleCount) {
|
||||
bool selfDependency = RenderPassTypeHasInput(rpType);
|
||||
bool isBackbuffer = rpType == RenderPassType::BACKBUFFER;
|
||||
bool hasDepth = RenderPassTypeHasDepth(rpType);
|
||||
bool multiview = RenderPassTypeHasMultiView(rpType);
|
||||
bool multisample = rpType & RenderPassType::MULTISAMPLE;
|
||||
|
||||
if (multiview) {
|
||||
// TODO: Assert that the device has multiview support enabled.
|
||||
}
|
||||
|
||||
VkAttachmentDescription attachments[2] = {};
|
||||
attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[0].loadOp = ConvertLoadAction(key.colorLoadAction);
|
||||
attachments[0].storeOp = ConvertStoreAction(key.colorStoreAction);
|
||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[0].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].flags = 0;
|
||||
int colorAttachmentIndex = 0;
|
||||
int depthAttachmentIndex = 1;
|
||||
|
||||
int attachmentCount = 0;
|
||||
VkAttachmentDescription attachments[4]{};
|
||||
attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.colorLoadAction);
|
||||
attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction);
|
||||
attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[attachmentCount].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachmentCount++;
|
||||
|
||||
if (hasDepth) {
|
||||
attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction);
|
||||
attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction);
|
||||
attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction);
|
||||
attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].flags = 0;
|
||||
attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[attachmentCount].loadOp = multisample ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : ConvertLoadAction(key.depthLoadAction);
|
||||
attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction);
|
||||
attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction);
|
||||
attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);
|
||||
attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
if (multisample) {
|
||||
colorAttachmentIndex = attachmentCount;
|
||||
attachments[attachmentCount].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[attachmentCount].samples = sampleCount;
|
||||
attachments[attachmentCount].loadOp = ConvertLoadAction(key.colorLoadAction);
|
||||
attachments[attachmentCount].storeOp = ConvertStoreAction(key.colorStoreAction);
|
||||
attachments[attachmentCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[attachmentCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[attachmentCount].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachmentCount++;
|
||||
|
||||
if (hasDepth) {
|
||||
depthAttachmentIndex = attachmentCount;
|
||||
attachments[attachmentCount].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[attachmentCount].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[attachmentCount].loadOp = ConvertLoadAction(key.depthLoadAction);
|
||||
attachments[attachmentCount].storeOp = ConvertStoreAction(key.depthStoreAction);
|
||||
attachments[attachmentCount].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction);
|
||||
attachments[attachmentCount].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);
|
||||
attachments[attachmentCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[attachmentCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachmentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
VkAttachmentReference color_reference{};
|
||||
color_reference.attachment = 0;
|
||||
color_reference.attachment = colorAttachmentIndex;
|
||||
color_reference.layout = selfDependency ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference depth_reference{};
|
||||
depth_reference.attachment = 1;
|
||||
depth_reference.attachment = depthAttachmentIndex;
|
||||
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass{};
|
||||
|
@ -279,7 +337,14 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
|
|||
}
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_reference;
|
||||
subpass.pResolveAttachments = nullptr;
|
||||
|
||||
VkAttachmentReference resolve_references[2];
|
||||
if (multisample) {
|
||||
resolve_references[0].attachment = 0; // the non-msaa color buffer.
|
||||
subpass.pResolveAttachments = resolve_references;
|
||||
} else {
|
||||
subpass.pResolveAttachments = nullptr;
|
||||
}
|
||||
if (hasDepth) {
|
||||
subpass.pDepthStencilAttachment = &depth_reference;
|
||||
}
|
||||
|
@ -291,7 +356,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
|
|||
size_t numDeps = 0;
|
||||
|
||||
VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
|
||||
rp.attachmentCount = hasDepth ? 2 : 1;
|
||||
rp.attachmentCount = attachmentCount;
|
||||
rp.pAttachments = attachments;
|
||||
rp.subpassCount = 1;
|
||||
rp.pSubpasses = &subpass;
|
||||
|
@ -342,12 +407,16 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
|
|||
return pass;
|
||||
}
|
||||
|
||||
VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType) {
|
||||
VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount) {
|
||||
// When we create a render pass, we create all "types" of it immediately,
|
||||
// practical later when referring to it. Could change to on-demand if it feels motivated
|
||||
// but I think the render pass objects are cheap.
|
||||
|
||||
// WARNING: We don't include sampleCount in the key, there's only the distinction multisampled or not
|
||||
// which comes from the rpType.
|
||||
// So you CAN NOT mix and match different non-one sample counts.
|
||||
if (!pass[(int)rpType]) {
|
||||
pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType);
|
||||
pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType, sampleCount);
|
||||
}
|
||||
return pass[(int)rpType];
|
||||
}
|
||||
|
|
|
@ -15,12 +15,13 @@ enum class RenderPassType {
|
|||
HAS_DEPTH = 1,
|
||||
COLOR_INPUT = 2, // input attachment
|
||||
MULTIVIEW = 4,
|
||||
MULTISAMPLE = 8,
|
||||
|
||||
// This is the odd one out, and gets special handling in MergeRPTypes.
|
||||
// If this flag is set, none of the other flags can be set.
|
||||
// For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible
|
||||
// so we don't bother with a non-depth version.
|
||||
BACKBUFFER = 8,
|
||||
BACKBUFFER = 16,
|
||||
|
||||
TYPE_COUNT = BACKBUFFER + 1,
|
||||
};
|
||||
|
@ -54,7 +55,7 @@ struct VKRImage {
|
|||
|
||||
class VKRFramebuffer {
|
||||
public:
|
||||
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag);
|
||||
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _numSamples, bool createDepthStencilBuffer, const char *tag);
|
||||
~VKRFramebuffer();
|
||||
|
||||
VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType);
|
||||
|
@ -62,10 +63,15 @@ public:
|
|||
int width = 0;
|
||||
int height = 0;
|
||||
int numLayers = 0;
|
||||
VkSampleCountFlagBits sampleCount;
|
||||
|
||||
VKRImage color{}; // color.image is always there.
|
||||
VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE.
|
||||
|
||||
// These are only initialized and used if numSamples > 1.
|
||||
VKRImage msaaColor{};
|
||||
VKRImage msaaDepth{};
|
||||
|
||||
const char *Tag() const {
|
||||
return tag_.c_str();
|
||||
}
|
||||
|
@ -76,13 +82,13 @@ public:
|
|||
return depth.image != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// TODO: Hide.
|
||||
VulkanContext *vulkan_;
|
||||
VulkanContext *Vulkan() const { return vulkan_; }
|
||||
private:
|
||||
static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag);
|
||||
static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag);
|
||||
|
||||
VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{};
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
std::string tag_;
|
||||
};
|
||||
|
||||
|
@ -98,6 +104,8 @@ inline bool RenderPassTypeHasMultiView(RenderPassType type) {
|
|||
return (type & RenderPassType::MULTIVIEW) != 0;
|
||||
}
|
||||
|
||||
VkSampleCountFlagBits SampleCountToFlagBits(int count);
|
||||
|
||||
// Must be the same order as Draw::RPAction
|
||||
enum class VKRRenderPassLoadAction : uint8_t {
|
||||
KEEP, // default. avoid when possible.
|
||||
|
@ -124,7 +132,7 @@ class VKRRenderPass {
|
|||
public:
|
||||
VKRRenderPass(const RPKey &key) : key_(key) {}
|
||||
|
||||
VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType);
|
||||
VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount);
|
||||
void Destroy(VulkanContext *vulkan) {
|
||||
for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) {
|
||||
if (pass[i]) {
|
||||
|
|
|
@ -198,7 +198,7 @@ bool VulkanQueueRunner::InitBackbufferFramebuffers(int width, int height) {
|
|||
VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view };
|
||||
|
||||
VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RenderPassType::BACKBUFFER);
|
||||
fb_info.renderPass = GetCompatibleRenderPass()->Get(vulkan_, RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT);
|
||||
fb_info.attachmentCount = 2;
|
||||
fb_info.pAttachments = attachments;
|
||||
fb_info.width = width;
|
||||
|
@ -1323,7 +1323,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
|||
// Maybe a middle pass. But let's try to just block and compile here for now, this doesn't
|
||||
// happen all that much.
|
||||
graphicsPipeline->pipeline[(size_t)rpType] = Promise<VkPipeline>::CreateEmpty();
|
||||
graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType), rpType);
|
||||
graphicsPipeline->Create(vulkan_, renderPass->Get(vulkan_, rpType, step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT), rpType);
|
||||
}
|
||||
|
||||
VkPipeline pipeline = graphicsPipeline->pipeline[(size_t)rpType]->BlockUntilReady();
|
||||
|
@ -1523,6 +1523,8 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR
|
|||
|
||||
bool hasDepth = RenderPassTypeHasDepth(step.render.renderPassType);
|
||||
|
||||
VkSampleCountFlagBits sampleCount;
|
||||
|
||||
if (step.render.framebuffer) {
|
||||
_dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
_dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
@ -1535,6 +1537,7 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR
|
|||
|
||||
VKRFramebuffer *fb = step.render.framebuffer;
|
||||
framebuf = fb->Get(renderPass, step.render.renderPassType);
|
||||
sampleCount = fb->sampleCount;
|
||||
_dbg_assert_(framebuf != VK_NULL_HANDLE);
|
||||
w = fb->width;
|
||||
h = fb->height;
|
||||
|
@ -1590,10 +1593,11 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR
|
|||
numClearVals = hasDepth ? 2 : 1; // We might do depth-less backbuffer in the future, though doubtful of the value.
|
||||
clearVal[1].depthStencil.depth = 0.0f;
|
||||
clearVal[1].depthStencil.stencil = 0;
|
||||
sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp_begin.renderPass = renderPass->Get(vulkan_, step.render.renderPassType);
|
||||
rp_begin.renderPass = renderPass->Get(vulkan_, step.render.renderPassType, sampleCount);
|
||||
rp_begin.framebuffer = framebuf;
|
||||
|
||||
VkRect2D rc = step.render.renderArea;
|
||||
|
|
|
@ -481,7 +481,7 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() {
|
|||
return frameData_[curFrame].GetInitCmd(vulkan_);
|
||||
}
|
||||
|
||||
VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, const char *tag) {
|
||||
VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag) {
|
||||
VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline();
|
||||
_dbg_assert_(desc->vertexShader);
|
||||
_dbg_assert_(desc->fragmentShader);
|
||||
|
@ -523,7 +523,7 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe
|
|||
}
|
||||
|
||||
pipeline->pipeline[i] = Promise<VkPipeline>::CreateEmpty();
|
||||
compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType), rpType));
|
||||
compileQueue_.push_back(CompileQueueEntry(pipeline, compatibleRenderPass->Get(vulkan_, rpType, sampleCount), rpType));
|
||||
needsCompile = true;
|
||||
}
|
||||
if (needsCompile)
|
||||
|
@ -575,17 +575,23 @@ void VulkanRenderManager::EndCurRenderStep() {
|
|||
if (curRenderStep_->render.framebuffer->numLayers > 1) {
|
||||
rpType = (RenderPassType)(rpType | RenderPassType::MULTIVIEW);
|
||||
}
|
||||
|
||||
if (curRenderStep_->render.framebuffer->sampleCount != VK_SAMPLE_COUNT_1_BIT) {
|
||||
rpType = (RenderPassType)(rpType | RenderPassType::MULTISAMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
VKRRenderPass *renderPass = queueRunner_.GetRenderPass(key);
|
||||
curRenderStep_->render.renderPassType = rpType;
|
||||
|
||||
VkSampleCountFlagBits sampleCount = curRenderStep_->render.framebuffer ? curRenderStep_->render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
compileMutex_.lock();
|
||||
bool needsCompile = false;
|
||||
for (VKRGraphicsPipeline *pipeline : pipelinesToCheck_) {
|
||||
if (!pipeline->pipeline[(size_t)rpType]) {
|
||||
pipeline->pipeline[(size_t)rpType] = Promise<VkPipeline>::CreateEmpty();
|
||||
compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType), rpType));
|
||||
compileQueue_.push_back(CompileQueueEntry(pipeline, renderPass->Get(vulkan_, rpType, sampleCount), rpType));
|
||||
needsCompile = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ public:
|
|||
// We delay creating pipelines until the end of the current render pass, so we can create the right type immediately.
|
||||
// Unless a variantBitmask is passed in, in which case we can just go ahead.
|
||||
// WARNING: desc must stick around during the lifetime of the pipeline! It's not enough to build it on the stack and drop it.
|
||||
VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, const char *tag);
|
||||
VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc, PipelineFlags pipelineFlags, uint32_t variantBitmask, VkSampleCountFlagBits sampleCount, const char *tag);
|
||||
VKRComputePipeline *CreateComputePipeline(VKRComputePipelineDesc *desc);
|
||||
|
||||
void NudgeCompilerThread() {
|
||||
|
|
|
@ -1210,7 +1210,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
|||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
raster->ToVulkan(&gDesc.rs);
|
||||
|
||||
pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, tag ? tag : "thin3d");
|
||||
pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, tag ? tag : "thin3d");
|
||||
|
||||
if (desc.uniformDesc) {
|
||||
pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize;
|
||||
|
@ -1569,7 +1569,7 @@ public:
|
|||
}
|
||||
~VKFramebuffer() {
|
||||
_assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?");
|
||||
buf_->vulkan_->Delete().QueueCallback([](void *fb) {
|
||||
buf_->Vulkan()->Delete().QueueCallback([](void *fb) {
|
||||
VKRFramebuffer *vfb = static_cast<VKRFramebuffer *>(fb);
|
||||
delete vfb;
|
||||
}, buf_);
|
||||
|
@ -1584,8 +1584,13 @@ private:
|
|||
};
|
||||
|
||||
Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) {
|
||||
_assert_(desc.numSamples > 0);
|
||||
_assert_(desc.numLayers > 0);
|
||||
_assert_(desc.width > 0);
|
||||
_assert_(desc.height > 0);
|
||||
|
||||
VkCommandBuffer cmd = renderManager_.GetInitCmd();
|
||||
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.z_stencil, desc.tag);
|
||||
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.numSamples, desc.z_stencil, desc.tag);
|
||||
return new VKFramebuffer(vkrfb);
|
||||
}
|
||||
|
||||
|
|
|
@ -300,6 +300,7 @@ struct FramebufferDesc {
|
|||
int height;
|
||||
int depth;
|
||||
int numLayers;
|
||||
int numSamples;
|
||||
bool z_stencil;
|
||||
const char *tag; // For graphics debuggers
|
||||
};
|
||||
|
|
|
@ -901,6 +901,7 @@ static ConfigSetting graphicsSettings[] = {
|
|||
|
||||
// Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine.
|
||||
ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true),
|
||||
ConfigSetting("MultiSampleLevel", &g_Config.iMultiSampleLevel, 1, true, true),
|
||||
|
||||
ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, false, true, true),
|
||||
ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true),
|
||||
|
|
|
@ -210,6 +210,7 @@ public:
|
|||
int iForceFullScreen = -1; // -1 = nope, 0 = force off, 1 = force on (not saved.)
|
||||
int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on.
|
||||
int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso
|
||||
int iMultiSampleLevel;
|
||||
int bHighQualityDepth;
|
||||
bool bReplaceTextures;
|
||||
bool bSaveNewTextures;
|
||||
|
|
|
@ -1652,7 +1652,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
|||
shaderManager_->DirtyLastShader();
|
||||
char tag[128];
|
||||
size_t len = FormatFramebufferName(vfb, tag, sizeof(tag));
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag });
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, tag });
|
||||
if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) {
|
||||
NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len);
|
||||
}
|
||||
|
@ -2019,7 +2019,7 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd
|
|||
char name[64];
|
||||
snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address);
|
||||
textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED);
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, name });
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, name });
|
||||
vfbs_.push_back(vfb);
|
||||
|
||||
u32 byteSize = ColorBufferByteSize(vfb);
|
||||
|
@ -2072,7 +2072,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram
|
|||
snprintf(name, sizeof(name), "download_temp");
|
||||
// TODO: We don't have a way to create a depth-only framebuffer yet.
|
||||
// Also, at least on Vulkan we always create both depth and color, need to rework how we handle renderpasses.
|
||||
nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, channel == RASTER_DEPTH ? true : false, name });
|
||||
nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, 1, channel == RASTER_DEPTH ? true : false, name });
|
||||
if (!nvfb->fbo) {
|
||||
ERROR_LOG(FRAMEBUF, "Error creating FBO! %d x %d", nvfb->renderWidth, nvfb->renderHeight);
|
||||
delete nvfb;
|
||||
|
@ -2466,7 +2466,7 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u
|
|||
char name[128];
|
||||
snprintf(name, sizeof(name), "tempfbo_%s_%dx%d", TempFBOReasonToString(reason), w / renderScaleFactor_, h / renderScaleFactor_);
|
||||
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), z_stencil, name });
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), 1, z_stencil, name });
|
||||
if (!fbo) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3156,7 +3156,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi
|
|||
|
||||
char tag[128];
|
||||
FormatFramebufferName(vfb, tag, sizeof(tag));
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag });
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 1, true, tag });
|
||||
vfbs_.push_back(vfb);
|
||||
}
|
||||
|
||||
|
|
|
@ -270,7 +270,7 @@ bool PresentationCommon::UpdatePostShader() {
|
|||
previousIndex_ = 0;
|
||||
|
||||
for (int i = 0; i < FRAMES; ++i) {
|
||||
previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, false, "inter_presentation" });
|
||||
previousFramebuffers_[i] = draw_->CreateFramebuffer({ w, h, 1, 1, 1, false, "inter_presentation" });
|
||||
if (!previousFramebuffers_[i]) {
|
||||
DestroyPostShader();
|
||||
return false;
|
||||
|
@ -386,7 +386,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) {
|
|||
}
|
||||
|
||||
// No depth/stencil for post processing
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, "presentation" });
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, 1, false, "presentation" });
|
||||
if (!fbo) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1299,6 +1299,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) {
|
|||
desc.depth = 1;
|
||||
desc.z_stencil = false;
|
||||
desc.numLayers = 1;
|
||||
desc.numSamples = 1;
|
||||
desc.tag = "dynamic_clut";
|
||||
dynamicClutFbo_ = draw_->CreateFramebuffer(desc);
|
||||
desc.tag = "dynamic_clut_temp";
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/GPU/Vulkan/VulkanContext.h"
|
||||
#include "Core/Config.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||
|
@ -171,7 +172,7 @@ static std::string CutFromMain(std::string str) {
|
|||
}
|
||||
|
||||
static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache,
|
||||
VkPipelineLayout layout, PipelineFlags pipelineFlags, const VulkanPipelineRasterStateKey &key,
|
||||
VkPipelineLayout layout, PipelineFlags pipelineFlags, VkSampleCountFlagBits sampleCount, const VulkanPipelineRasterStateKey &key,
|
||||
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, VulkanGeometryShader *gs, bool useHwTransform, u32 variantBitmask) {
|
||||
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
|
||||
VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc;
|
||||
|
@ -307,7 +308,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
|||
tag = FragmentShaderDesc(fs->GetID()) + " VS " + VertexShaderDesc(vs->GetID());
|
||||
#endif
|
||||
|
||||
VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, tag.c_str());
|
||||
VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, pipelineFlags, variantBitmask, sampleCount, tag.c_str());
|
||||
|
||||
vulkanPipeline->pipeline = pipeline;
|
||||
if (useBlendConstant) {
|
||||
|
@ -351,8 +352,10 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
|
|||
pipelineFlags |= PipelineFlags::USES_MULTIVIEW;
|
||||
}
|
||||
|
||||
VkSampleCountFlagBits sampleCount = SampleCountToFlagBits(g_Config.iMultiSampleLevel);
|
||||
|
||||
VulkanPipeline *pipeline = CreateVulkanPipeline(
|
||||
renderManager, pipelineCache_, layout, pipelineFlags,
|
||||
renderManager, pipelineCache_, layout, pipelineFlags, sampleCount,
|
||||
rasterKey, decFmt, vs, fs, gs, useHwTransform, variantBitmask);
|
||||
pipelines_.Insert(key, pipeline);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue