mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Further steps towards Vulkan framebuffer support
This commit is contained in:
parent
6bcfe539f7
commit
a7dd6d6085
10 changed files with 278 additions and 107 deletions
|
@ -258,6 +258,9 @@ public:
|
|||
|
||||
VkCommandBuffer GetInitCommandBuffer();
|
||||
|
||||
VkFramebuffer GetSurfaceFramebuffer() {
|
||||
return framebuffers_[current_buffer];
|
||||
}
|
||||
// This must only be accessed between BeginSurfaceRenderPass and EndSurfaceRenderPass.
|
||||
VkCommandBuffer GetSurfaceCommandBuffer() {
|
||||
return frame_[curFrame_ & 1].cmdBuf;
|
||||
|
|
|
@ -825,7 +825,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
|||
if (displayFramebufPtr_ == 0) {
|
||||
DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black");
|
||||
// No framebuffer to display! Clear to black.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
if (useBufferedRendering_) {
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{457F45D2-556F-47BC-A31D-AFF0D15BEAED}</ProjectGuid>
|
||||
<RootNamespace>GPU</RootNamespace>
|
||||
<WindowsTargetPlatformVersion></WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>
|
||||
</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
|
|
|
@ -408,9 +408,6 @@
|
|||
<ClCompile Include="Vulkan\FragmentShaderGeneratorVulkan.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\FramebufferVulkan.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\GPU_Vulkan.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
|
@ -510,5 +507,8 @@
|
|||
<ClCompile Include="Common\ShaderCommon.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\FramebufferVulkan.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -883,6 +883,7 @@ void DrawEngineVulkan::DoFlush(VkCommandBuffer cmd) {
|
|||
// Note: we won't get here if the clear is alpha but not color, or color but not alpha.
|
||||
|
||||
// We let the framebuffer manager handle the clear. It can use renderpasses to optimize on tilers.
|
||||
// If non-buffered though, it'll just do a plain clear.
|
||||
framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth);
|
||||
|
||||
int scissorX1 = gstate.getScissorX1();
|
||||
|
|
|
@ -52,8 +52,6 @@
|
|||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
const VkFormat framebufFormat = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
|
||||
static const char tex_fs[] = R"(#version 400
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
@ -92,7 +90,8 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
|
|||
pixelBufObj_(nullptr),
|
||||
currentPBO_(0),
|
||||
curFrame_(0),
|
||||
pipelineBasicTex_(VK_NULL_HANDLE),
|
||||
pipelineBasicTexBackBuffer_(VK_NULL_HANDLE),
|
||||
pipelineBasicTexFrameBuffer_(VK_NULL_HANDLE),
|
||||
pipelinePostShader_(VK_NULL_HANDLE),
|
||||
vulkan2D_(vulkan) {
|
||||
|
||||
|
@ -117,67 +116,6 @@ void FramebufferManagerVulkan::SetShaderManager(ShaderManagerVulkan *sm) {
|
|||
}
|
||||
|
||||
void FramebufferManagerVulkan::InitDeviceObjects() {
|
||||
// Create a bunch of render pass objects, for normal rendering with a depth buffer,
|
||||
// with and without pre-clearing of both depth/stencil and color, so 4 combos.
|
||||
VkAttachmentDescription attachments[2] = {};
|
||||
attachments[0].format = framebufFormat;
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].flags = 0;
|
||||
|
||||
attachments[1].format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].flags = 0;
|
||||
|
||||
VkAttachmentReference color_reference = {};
|
||||
color_reference.attachment = 0;
|
||||
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference depth_reference = {};
|
||||
depth_reference.attachment = 1;
|
||||
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.flags = 0;
|
||||
subpass.inputAttachmentCount = 0;
|
||||
subpass.pInputAttachments = NULL;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_reference;
|
||||
subpass.pResolveAttachments = NULL;
|
||||
subpass.pDepthStencilAttachment = &depth_reference;
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = NULL;
|
||||
|
||||
VkRenderPassCreateInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
|
||||
rp.attachmentCount = 2;
|
||||
rp.pAttachments = attachments;
|
||||
rp.subpassCount = 1;
|
||||
rp.pSubpasses = &subpass;
|
||||
rp.dependencyCount = 0;
|
||||
rp.pDependencies = NULL;
|
||||
|
||||
// TODO: Maybe LOAD_OP_DONT_CARE makes sense in some situations. Additionally,
|
||||
// there is often no need to store the depth buffer afterwards, although hard to know up front.
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &rpLoadColorLoadDepth_);
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &rpClearColorLoadDepth_);
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &rpClearColorClearDepth_);
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &rpLoadColorClearDepth_);
|
||||
|
||||
// Initialize framedata
|
||||
for (int i = 0; i < 2; i++) {
|
||||
VkCommandPoolCreateInfo cp = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
||||
|
@ -196,7 +134,9 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
|
|||
assert(fsBasicTex_ != VK_NULL_HANDLE);
|
||||
assert(vsBasicTex_ != VK_NULL_HANDLE);
|
||||
|
||||
pipelineBasicTex_ = vulkan2D_.GetPipeline(pipelineCache2D_, rpClearColorClearDepth_, vsBasicTex_, fsBasicTex_);
|
||||
// Get a representative render pass and use when creating the pipeline.
|
||||
pipelineBasicTexBackBuffer_ = vulkan2D_.GetPipeline(pipelineCache2D_, vulkan_->GetSurfaceRenderPass(), vsBasicTex_, fsBasicTex_);
|
||||
pipelineBasicTexFrameBuffer_ = vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS), vsBasicTex_, fsBasicTex_);
|
||||
|
||||
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
||||
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
|
@ -213,15 +153,6 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
|
|||
}
|
||||
|
||||
void FramebufferManagerVulkan::DestroyDeviceObjects() {
|
||||
if (rpLoadColorLoadDepth_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeleteRenderPass(rpLoadColorLoadDepth_);
|
||||
if (rpClearColorLoadDepth_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeleteRenderPass(rpClearColorLoadDepth_);
|
||||
if (rpClearColorClearDepth_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeleteRenderPass(rpClearColorClearDepth_);
|
||||
if (rpLoadColorClearDepth_ != VK_NULL_HANDLE)
|
||||
vulkan_->Delete().QueueDeleteRenderPass(rpLoadColorClearDepth_);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (frameData_[i].numCommandBuffers_ > 0) {
|
||||
vkFreeCommandBuffers(vulkan_->GetDevice(), frameData_[i].cmdPool_, frameData_[i].numCommandBuffers_, frameData_[i].commandBuffers_);
|
||||
|
|
|
@ -188,18 +188,14 @@ private:
|
|||
// This gets copied to the current frame's push buffer as needed.
|
||||
PostShaderUniforms postUniforms_;
|
||||
|
||||
// Renderpasses, all combination of preserving or clearing fb contents
|
||||
VkRenderPass rpLoadColorLoadDepth_;
|
||||
VkRenderPass rpClearColorLoadDepth_;
|
||||
VkRenderPass rpLoadColorClearDepth_;
|
||||
VkRenderPass rpClearColorClearDepth_;
|
||||
|
||||
VkPipelineCache pipelineCache2D_;
|
||||
|
||||
// Basic shaders
|
||||
VkShaderModule fsBasicTex_;
|
||||
VkShaderModule vsBasicTex_;
|
||||
VkPipeline pipelineBasicTex_;
|
||||
// Might need different pipelines for rendering to backbuffer vs framebuffers due to color format incompatibility
|
||||
VkPipeline pipelineBasicTexBackBuffer_;
|
||||
VkPipeline pipelineBasicTexFrameBuffer_;
|
||||
|
||||
// Postprocessing
|
||||
VkPipeline pipelinePostShader_;
|
||||
|
|
|
@ -321,6 +321,7 @@ enum class NativeObject {
|
|||
BACKBUFFER_COLOR_TEX,
|
||||
BACKBUFFER_DEPTH_TEX,
|
||||
FEATURE_LEVEL,
|
||||
RENDERPASS,
|
||||
};
|
||||
|
||||
enum FBColorDepth {
|
||||
|
|
|
@ -411,7 +411,12 @@ public:
|
|||
std::vector<std::string> GetFeatureList() const override;
|
||||
|
||||
uintptr_t GetNativeObject(NativeObject obj) const override {
|
||||
return 0;
|
||||
switch (obj) {
|
||||
case NativeObject::RENDERPASS:
|
||||
return (uintptr_t)renderPasses_[0];
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
|
||||
|
@ -432,6 +437,13 @@ private:
|
|||
VkPipelineLayout pipelineLayout_;
|
||||
VkPipelineCache pipelineCache_;
|
||||
|
||||
inline int RPIndex(RPAction color, RPAction depth) {
|
||||
return (int)depth * 3 + (int)color;
|
||||
}
|
||||
|
||||
// Renderpasses, all combination of preserving or clearing or dont-care-ing fb contents.
|
||||
VkRenderPass renderPasses_[9];
|
||||
|
||||
VkCommandPool cmdPool_;
|
||||
VkDevice device_;
|
||||
VkQueue queue_;
|
||||
|
@ -464,6 +476,9 @@ private:
|
|||
VulkanPushBuffer *push_ = nullptr;
|
||||
|
||||
DeviceCaps caps_{};
|
||||
|
||||
VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;;
|
||||
VkRenderPass curRenderPass_ = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
static int GetBpp(VkFormat format) {
|
||||
|
@ -714,9 +729,79 @@ VKContext::VKContext(VulkanContext *vulkan)
|
|||
assert(VK_SUCCESS == res);
|
||||
|
||||
pipelineCache_ = vulkan_->CreatePipelineCache();
|
||||
|
||||
// Create a bunch of render pass objects, for normal rendering with a depth buffer,
|
||||
// with and without pre-clearing of both depth/stencil and color, so 4 combos.
|
||||
VkAttachmentDescription attachments[2] = {};
|
||||
attachments[0].format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].flags = 0;
|
||||
|
||||
attachments[1].format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].flags = 0;
|
||||
|
||||
VkAttachmentReference color_reference = {};
|
||||
color_reference.attachment = 0;
|
||||
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference depth_reference = {};
|
||||
depth_reference.attachment = 1;
|
||||
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.flags = 0;
|
||||
subpass.inputAttachmentCount = 0;
|
||||
subpass.pInputAttachments = NULL;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_reference;
|
||||
subpass.pResolveAttachments = NULL;
|
||||
subpass.pDepthStencilAttachment = &depth_reference;
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = NULL;
|
||||
|
||||
VkRenderPassCreateInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
|
||||
rp.attachmentCount = 2;
|
||||
rp.pAttachments = attachments;
|
||||
rp.subpassCount = 1;
|
||||
rp.pSubpasses = &subpass;
|
||||
rp.dependencyCount = 0;
|
||||
rp.pDependencies = NULL;
|
||||
|
||||
for (int depth = 0; depth < 3; depth++) {
|
||||
switch ((RPAction)depth) {
|
||||
case RPAction::CLEAR: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
|
||||
case RPAction::KEEP: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
|
||||
case RPAction::DONT_CARE: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
|
||||
}
|
||||
for (int color = 0; color < 3; color++) {
|
||||
switch ((RPAction)color) {
|
||||
case RPAction::CLEAR: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
|
||||
case RPAction::KEEP: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
|
||||
case RPAction::DONT_CARE: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
|
||||
}
|
||||
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &renderPasses_[RPIndex((RPAction)color, (RPAction)depth)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKContext::~VKContext() {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]);
|
||||
}
|
||||
vulkan_->Delete().QueueDeleteCommandPool(cmdPool_);
|
||||
// This also destroys all descriptor sets.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
@ -748,26 +833,14 @@ void VKContext::BeginFrame() {
|
|||
scissor_.extent.height = pixel_yres;
|
||||
scissorDirty_ = true;
|
||||
viewportDirty_ = true;
|
||||
|
||||
int colorval = 0xFF000000;
|
||||
float depthVal = 0.0;
|
||||
int stencilVal = 0;
|
||||
|
||||
VkClearValue clearVal[2] = {};
|
||||
Uint8x4ToFloat4(colorval, clearVal[0].color.float32);
|
||||
|
||||
// // Debug flicker - used to see if we swap at all. no longer necessary
|
||||
// if (frameNum_ & 1)
|
||||
// clearVal[0].color.float32[2] = 1.0f;
|
||||
|
||||
clearVal[1].depthStencil.depth = depthVal;
|
||||
clearVal[1].depthStencil.stencil = stencilVal;
|
||||
|
||||
vulkan_->BeginSurfaceRenderPass(clearVal);
|
||||
}
|
||||
|
||||
void VKContext::EndFrame() {
|
||||
vulkan_->EndSurfaceRenderPass();
|
||||
if (curRenderPass_) {
|
||||
vulkan_->EndSurfaceRenderPass();
|
||||
curRenderPass_ = VK_NULL_HANDLE;
|
||||
curFramebuffer_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// Stop collecting data in the frame's data pushbuffer.
|
||||
push_->End();
|
||||
|
@ -1277,18 +1350,124 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const {
|
|||
}
|
||||
}
|
||||
|
||||
// Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine
|
||||
// to let them have individual non-pooled allocations.
|
||||
struct VKImage {
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
VkDeviceMemory memory;
|
||||
VkImageLayout layout;
|
||||
};
|
||||
|
||||
void CreateImage(VulkanContext *vulkan, VKImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) {
|
||||
VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
ici.arrayLayers = 1;
|
||||
ici.mipLevels = 1;
|
||||
ici.extent.width = width;
|
||||
ici.extent.height = height;
|
||||
ici.extent.depth = 1;
|
||||
ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
ici.imageType = VK_IMAGE_TYPE_2D;
|
||||
ici.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
ici.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
ici.format = format;
|
||||
ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
if (color) {
|
||||
ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
} else {
|
||||
ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
}
|
||||
vkCreateImage(vulkan->GetDevice(), &ici, nullptr, &img.image);
|
||||
|
||||
VkMemoryRequirements memreq;
|
||||
vkGetImageMemoryRequirements(vulkan->GetDevice(), img.image, &memreq);
|
||||
|
||||
VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
alloc.allocationSize = memreq.size;
|
||||
vulkan->MemoryTypeFromProperties(memreq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &alloc.memoryTypeIndex);
|
||||
VkResult res = vkAllocateMemory(vulkan->GetDevice(), &alloc, nullptr, &img.memory);
|
||||
assert(res);
|
||||
res = vkBindImageMemory(vulkan->GetDevice(), img.image, img.memory, 0);
|
||||
assert(res);
|
||||
img.layout = initialLayout;
|
||||
|
||||
VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||
ivci.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
||||
ivci.format = ici.format;
|
||||
ivci.image = img.image;
|
||||
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
ivci.subresourceRange.aspectMask = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
ivci.subresourceRange.levelCount = 1;
|
||||
res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.view);
|
||||
assert(res);
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.image = img.image;
|
||||
barrier.srcAccessMask = 0;
|
||||
switch (initialLayout) {
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
break;
|
||||
}
|
||||
barrier.newLayout = initialLayout;
|
||||
barrier.subresourceRange.aspectMask = ivci.subresourceRange.aspectMask;
|
||||
vkCmdPipelineBarrier(vulkan->GetInitCommandBuffer(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &barrier);
|
||||
}
|
||||
|
||||
// A VKFramebuffer is a VkFramebuffer plus all the textures it owns.
|
||||
class VKFramebuffer : public Framebuffer {
|
||||
public:
|
||||
VKFramebuffer(VulkanContext *vk) : vulkan_(vk) {}
|
||||
~VKFramebuffer() {
|
||||
vulkan_->Delete().QueueDeleteImage(color.image);
|
||||
vulkan_->Delete().QueueDeleteImage(depth.image);
|
||||
vulkan_->Delete().QueueDeleteImageView(color.view);
|
||||
vulkan_->Delete().QueueDeleteImageView(depth.view);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(color.memory);
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory);
|
||||
vulkan_->Delete().QueueDeleteFramebuffer(framebuf);
|
||||
}
|
||||
VkFramebuffer framebuf;
|
||||
VKImage color;
|
||||
VKImage depth;
|
||||
int width;
|
||||
int height;
|
||||
private:
|
||||
VulkanContext *vulkan_;
|
||||
};
|
||||
|
||||
Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) {
|
||||
VKFramebuffer *fb = new VKFramebuffer();
|
||||
VKFramebuffer *fb = new VKFramebuffer(vulkan_);
|
||||
fb->width = desc.width;
|
||||
fb->height = desc.height;
|
||||
|
||||
CreateImage(vulkan_, fb->color, fb->width, fb->height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true);
|
||||
CreateImage(vulkan_, fb->depth, fb->width, fb->height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false);
|
||||
|
||||
VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
VkImageView views[2]{};
|
||||
|
||||
fbci.renderPass = renderPasses_[0];
|
||||
fbci.attachmentCount = 2;
|
||||
fbci.pAttachments = views;
|
||||
views[0] = fb->color.view;
|
||||
views[1] = fb->depth.view;
|
||||
fbci.width = fb->width;
|
||||
fbci.height = fb->height;
|
||||
fbci.layers = 1;
|
||||
|
||||
vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &fb->framebuf);
|
||||
return fb;
|
||||
}
|
||||
|
||||
|
@ -1305,11 +1484,67 @@ bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int sr
|
|||
|
||||
// These functions should be self explanatory.
|
||||
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) {
|
||||
VkFramebuffer framebuf;
|
||||
int w;
|
||||
int h;
|
||||
if (fbo) {
|
||||
VKFramebuffer *fb = (VKFramebuffer *)fbo;
|
||||
framebuf = fb->framebuf;
|
||||
w = fb->width;
|
||||
h = fb->height;
|
||||
} else {
|
||||
|
||||
framebuf = vulkan_->GetSurfaceFramebuffer();
|
||||
w = vulkan_->GetWidth();
|
||||
h = vulkan_->GetHeight();
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = vulkan_->GetSurfaceCommandBuffer();
|
||||
if (framebuf == curFramebuffer_) {
|
||||
// If we're asking to clear, but already bound, we'll just keep it bound but send a clear command.
|
||||
// We will try to avoid this as much as possible. Also, TODO, do a single vkCmdClearAttachments to clear both.
|
||||
if (rp.color == RPAction::CLEAR) {
|
||||
VkClearAttachment clear{};
|
||||
clear.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
Uint8x4ToFloat4(rp.clearColor, clear.clearValue.color.float32);
|
||||
clear.colorAttachment = 0;
|
||||
VkClearRect rc{ {0,0,(uint32_t)w,(uint32_t)h}, 0, 1 };
|
||||
vkCmdClearAttachments(cmd, 1, &clear, 1, &rc);
|
||||
}
|
||||
if (rp.depth == RPAction::CLEAR) {
|
||||
VkClearAttachment clear{};
|
||||
clear.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
clear.clearValue.depthStencil.depth = rp.clearDepth;
|
||||
clear.clearValue.depthStencil.stencil = rp.clearStencil;
|
||||
clear.colorAttachment = 0;
|
||||
VkClearRect rc{ { 0,0,w,h }, 0, 1 };
|
||||
vkCmdClearAttachments(cmd, 1, &clear, 1, &rc);
|
||||
}
|
||||
// We're done.
|
||||
return;
|
||||
}
|
||||
|
||||
// OK, we're switching framebuffers.
|
||||
if (curRenderPass_ != VK_NULL_HANDLE) {
|
||||
vkCmdEndRenderPass(cmd);
|
||||
}
|
||||
|
||||
VkClearValue clearVal[2] = {};
|
||||
Uint8x4ToFloat4(rp.clearColor, clearVal[0].color.float32);
|
||||
clearVal[1].depthStencil.depth = rp.clearDepth;
|
||||
clearVal[1].depthStencil.stencil = rp.clearStencil;
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp_begin.renderPass = fbo ? renderPasses_[RPIndex(rp.color, rp.depth)] : vulkan_->GetSurfaceRenderPass();
|
||||
rp_begin.framebuffer = framebuf;
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
rp_begin.renderArea.extent.width = w;
|
||||
rp_begin.renderArea.extent.height = h;
|
||||
rp_begin.clearValueCount = 2;
|
||||
rp_begin.pClearValues = clearVal;
|
||||
vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
curFramebuffer_ = framebuf;
|
||||
curRenderPass_ = rp_begin.renderPass;
|
||||
}
|
||||
|
||||
// color must be 0, for now.
|
||||
|
@ -1317,6 +1552,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne
|
|||
VKFramebuffer *fb = (VKFramebuffer *)fbo;
|
||||
|
||||
}
|
||||
|
||||
void VKContext::BindFramebufferForRead(Framebuffer *fbo) { /* noop */ }
|
||||
|
||||
uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e18cface3db64ccb96738dc128fe769b28fff65c
|
||||
Subproject commit d02ba7407050f445edf9e908374ad4bf3b2f237b
|
Loading…
Add table
Reference in a new issue