mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
More multiview work
This commit is contained in:
parent
d3804ec2e5
commit
fb250c4b29
38 changed files with 302 additions and 157 deletions
|
@ -94,11 +94,8 @@ public:
|
|||
bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override;
|
||||
|
||||
// These functions should be self explanatory.
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
|
||||
Framebuffer *GetCurrentRenderTarget() override {
|
||||
return curRenderTarget_;
|
||||
}
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override;
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;
|
||||
|
||||
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
|
||||
|
||||
|
@ -1658,7 +1655,8 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel
|
|||
return true;
|
||||
}
|
||||
|
||||
void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
|
||||
void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) {
|
||||
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D
|
||||
// TODO: deviceContext1 can actually discard. Useful on Windows Mobile.
|
||||
if (fbo) {
|
||||
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
|
||||
|
@ -1704,8 +1702,9 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren
|
|||
stepId_++;
|
||||
}
|
||||
|
||||
void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
|
||||
_assert_(binding < MAX_BOUND_TEXTURES);
|
||||
void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
|
||||
_dbg_assert_(binding < MAX_BOUND_TEXTURES);
|
||||
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D
|
||||
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
|
||||
switch (channelBit) {
|
||||
case FBChannel::FB_COLOR_BIT:
|
||||
|
|
|
@ -531,12 +531,9 @@ public:
|
|||
bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override;
|
||||
|
||||
// These functions should be self explanatory.
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
|
||||
Framebuffer *GetCurrentRenderTarget() override {
|
||||
return curRenderTarget_;
|
||||
}
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;
|
||||
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override;
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;
|
||||
|
||||
uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override;
|
||||
|
||||
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
|
||||
|
@ -1292,7 +1289,8 @@ D3D9Framebuffer::~D3D9Framebuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
|
||||
void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) {
|
||||
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support
|
||||
if (fbo) {
|
||||
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
|
||||
device_->SetRenderTarget(0, fb->surf);
|
||||
|
@ -1351,8 +1349,9 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit
|
|||
}
|
||||
}
|
||||
|
||||
void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
|
||||
_assert_(binding < MAX_BOUND_TEXTURES);
|
||||
void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
|
||||
_dbg_assert_(binding < MAX_BOUND_TEXTURES);
|
||||
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support
|
||||
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
|
||||
switch (channelBit) {
|
||||
case FB_DEPTH_BIT:
|
||||
|
|
|
@ -354,11 +354,8 @@ public:
|
|||
bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override;
|
||||
|
||||
// These functions should be self explanatory.
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
|
||||
Framebuffer *GetCurrentRenderTarget() override {
|
||||
return curRenderTarget_;
|
||||
}
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override;
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;
|
||||
|
||||
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
|
||||
|
||||
|
@ -1398,7 +1395,9 @@ Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) {
|
|||
return fbo;
|
||||
}
|
||||
|
||||
void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
|
||||
void OpenGLContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) {
|
||||
_dbg_assert_(layer == ALL_LAYERS || layer == 0);
|
||||
|
||||
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
|
||||
GLRRenderPassAction color = (GLRRenderPassAction)rp.color;
|
||||
GLRRenderPassAction depth = (GLRRenderPassAction)rp.depth;
|
||||
|
@ -1439,7 +1438,7 @@ bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, in
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
|
||||
void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
|
||||
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
|
||||
_assert_(binding < MAX_TEXTURE_SLOTS);
|
||||
|
||||
|
|
|
@ -608,8 +608,7 @@ void VulkanContext::ChooseDevice(int physical_device) {
|
|||
deviceFeatures_.enabled.standard.geometryShader = deviceFeatures_.available.standard.geometryShader;
|
||||
|
||||
deviceFeatures_.enabled.multiview = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES };
|
||||
// Don't yet enable these.
|
||||
// deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview;
|
||||
deviceFeatures_.enabled.multiview.multiview = deviceFeatures_.available.multiview.multiview;
|
||||
// deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader;
|
||||
|
||||
GetDeviceLayerExtensionList(nullptr, device_extension_properties_);
|
||||
|
@ -1246,7 +1245,7 @@ bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkSha
|
|||
}
|
||||
}
|
||||
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, VkImageAspectFlags aspectMask,
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int numMipLevels, int numLayers, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) {
|
||||
|
@ -1259,7 +1258,7 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int
|
|||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = baseMip;
|
||||
image_memory_barrier.subresourceRange.levelCount = numMipLevels;
|
||||
image_memory_barrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS.
|
||||
image_memory_barrier.subresourceRange.layerCount = numLayers; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS.
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
|
||||
|
|
|
@ -441,7 +441,7 @@ private:
|
|||
};
|
||||
|
||||
// Detailed control.
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, VkImageAspectFlags aspectMask,
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, int baseMip, int mipLevels, int numLayers, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
|
||||
|
|
|
@ -87,7 +87,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, i
|
|||
switch (initialLayout) {
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
TransitionImageLayout2(cmd, image_, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, image_, 0, numMips, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, initialLayout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
|
@ -164,7 +164,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo
|
|||
_assert_msg_(firstMipToGenerate < numMips_, "Can't generate levels beyond storage");
|
||||
|
||||
// Transition the pre-set levels to GENERAL.
|
||||
TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, image_, 0, firstMipToGenerate, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
fromCompute ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
fromCompute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
|
@ -173,7 +173,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo
|
|||
VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
||||
// Do the same with the uninitialized levels.
|
||||
TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate,
|
||||
TransitionImageLayout2(cmd, image_, firstMipToGenerate, numMips_ - firstMipToGenerate, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
|
@ -206,7 +206,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo
|
|||
|
||||
vkCmdBlitImage(cmd, image_, VK_IMAGE_LAYOUT_GENERAL, image_, VK_IMAGE_LAYOUT_GENERAL, 1, &blit, VK_FILTER_LINEAR);
|
||||
|
||||
TransitionImageLayout2(cmd, image_, mip, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, image_, mip, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
@ -214,7 +214,7 @@ void VulkanTexture::GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bo
|
|||
}
|
||||
|
||||
void VulkanTexture::EndCreate(VkCommandBuffer cmd, bool vertexTexture, VkPipelineStageFlags prevStage, VkImageLayout layout) {
|
||||
TransitionImageLayout2(cmd, image_, 0, numMips_,
|
||||
TransitionImageLayout2(cmd, image_, 0, numMips_, 1,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
prevStage, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
|
@ -121,6 +122,15 @@ public:
|
|||
return writePtr_ + off;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void PushUBOData(const T &data, VkDescriptorBufferInfo *info) {
|
||||
uint32_t bindOffset;
|
||||
void *ptr = PushAligned(sizeof(T), &bindOffset, &info->buffer, vulkan_->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment);
|
||||
memcpy(ptr, &data, sizeof(T));
|
||||
info->offset = bindOffset;
|
||||
info->range = sizeof(T);
|
||||
}
|
||||
|
||||
size_t GetTotalSize() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -249,7 +249,7 @@ bool VulkanQueueRunner::InitDepthStencilBuffer(VkCommandBuffer cmd) {
|
|||
|
||||
vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth");
|
||||
|
||||
TransitionImageLayout2(cmd, depth_.image, 0, 1,
|
||||
TransitionImageLayout2(cmd, depth_.image, 0, 1, 1,
|
||||
aspectMask,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
|
@ -331,6 +331,10 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
|
|||
bool hasDepth = RenderPassTypeHasDepth(rpType);
|
||||
bool multiview = RenderPassTypeHasMultiView(rpType);
|
||||
|
||||
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;
|
||||
|
@ -905,6 +909,10 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const {
|
|||
case RP_TYPE_COLOR_DEPTH: renderCmd = "RENDER_DEPTH"; break;
|
||||
case RP_TYPE_COLOR_INPUT: renderCmd = "RENDER_INPUT"; break;
|
||||
case RP_TYPE_COLOR_DEPTH_INPUT: renderCmd = "RENDER_DEPTH_INPUT"; break;
|
||||
case RP_TYPE_MULTIVIEW_COLOR: renderCmd = "MV_RENDER"; break;
|
||||
case RP_TYPE_MULTIVIEW_COLOR_DEPTH: renderCmd = "MV_RENDER_DEPTH"; break;
|
||||
case RP_TYPE_MULTIVIEW_COLOR_INPUT: renderCmd = "MV_RENDER_INPUT"; break;
|
||||
case RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT: renderCmd = "MV_RENDER_DEPTH_INPUT"; break;
|
||||
default: renderCmd = "N/A";
|
||||
}
|
||||
snprintf(buffer, sizeof(buffer), "%s %s %s (draws: %d, %dx%d/%dx%d)", renderCmd, step.tag, step.render.framebuffer ? step.render.framebuffer->Tag() : "", step.render.numDraws, actual_w, actual_h, w, h);
|
||||
|
@ -1565,6 +1573,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
|||
vkCmdDraw(cmd, c.draw.count, 1, c.draw.offset, 0);
|
||||
break;
|
||||
|
||||
case VKRRenderCommand::BIND_DESCRIPTOR_SET:
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, c.bindDescSet.setIndex, 1, &c.bindDescSet.descSet, 0, nullptr);
|
||||
break;
|
||||
|
||||
case VKRRenderCommand::CLEAR:
|
||||
{
|
||||
// If we get here, we failed to merge a clear into a render pass load op. This is bad for perf.
|
||||
|
@ -1643,7 +1655,8 @@ VKRRenderPass *VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKR
|
|||
renderPass = GetRenderPass(key);
|
||||
|
||||
VKRFramebuffer *fb = step.render.framebuffer;
|
||||
framebuf = fb->Get(renderPass, step.render.renderPassType);
|
||||
framebuf = fb->Get(renderPass, step.render.renderPassType, step.render.layer);
|
||||
_dbg_assert_(framebuf != VK_NULL_HANDLE);
|
||||
w = fb->width;
|
||||
h = fb->height;
|
||||
|
||||
|
@ -2014,7 +2027,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
|||
if (step.readback.src == nullptr) {
|
||||
// We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT,
|
||||
// and then back into it.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
@ -2048,7 +2061,7 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
|||
if (step.readback.src == nullptr) {
|
||||
// We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT,
|
||||
// and then back into it.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
TransitionImageLayout2(cmd, backbufferImage_, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, 0);
|
||||
|
@ -2079,7 +2092,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe
|
|||
vkCmdCopyImageToBuffer(cmd, step.readback_image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuffer_, 1, ®ion);
|
||||
|
||||
// Now transfer it back to a texture.
|
||||
TransitionImageLayout2(cmd, step.readback_image.image, 0, 1,
|
||||
TransitionImageLayout2(cmd, step.readback_image.image, 0, 1, 1, // TODO: Handle multiple layers
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
|
|
|
@ -37,12 +37,13 @@ enum class VKRRenderCommand : uint8_t {
|
|||
DRAW,
|
||||
DRAW_INDEXED,
|
||||
PUSH_CONSTANTS,
|
||||
BIND_DESCRIPTOR_SET,
|
||||
SELF_DEPENDENCY_BARRIER,
|
||||
DEBUG_ANNOTATION,
|
||||
NUM_RENDER_COMMANDS,
|
||||
};
|
||||
|
||||
enum class PipelineFlags {
|
||||
enum class PipelineFlags : u8 {
|
||||
NONE = 0,
|
||||
USES_BLEND_CONSTANT = (1 << 1),
|
||||
USES_DEPTH_STENCIL = (1 << 2), // Reads or writes the depth or stencil buffers.
|
||||
|
@ -115,7 +116,7 @@ struct VkRenderData {
|
|||
VkDescriptorSet ds;
|
||||
int numUboOffsets;
|
||||
uint32_t uboOffsets[3];
|
||||
VkBuffer vbuffer; // might need to increase at some point
|
||||
VkBuffer vbuffer;
|
||||
VkBuffer ibuffer;
|
||||
uint32_t voffset;
|
||||
uint32_t ioffset;
|
||||
|
@ -152,6 +153,10 @@ struct VkRenderData {
|
|||
struct {
|
||||
const char *annotation;
|
||||
} debugAnnotation;
|
||||
struct {
|
||||
uint32_t setIndex;
|
||||
VkDescriptorSet descSet;
|
||||
} bindDescSet;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -207,6 +212,7 @@ struct VKRStep {
|
|||
VKRRenderPassStoreAction depthStore;
|
||||
VKRRenderPassStoreAction stencilStore;
|
||||
u8 clearStencil;
|
||||
s8 layer;
|
||||
uint32_t clearColor;
|
||||
float clearDepth;
|
||||
int numDraws;
|
||||
|
|
|
@ -182,43 +182,51 @@ void VKRFramebuffer::UpdateTag(const char *newTag) {
|
|||
vulkan_->SetDebugName(depth.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name);
|
||||
}
|
||||
for (int rpType = 0; rpType < RP_TYPE_COUNT; rpType++) {
|
||||
if (framebuf[rpType]) {
|
||||
snprintf(name, sizeof(name), "fb_%s", tag_.c_str());
|
||||
vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, name);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (framebuf[rpType][i]) {
|
||||
snprintf(name, sizeof(name), "fb_%s_%d", tag_.c_str(), i);
|
||||
vulkan_->SetDebugName(framebuf[(int)rpType][i], VK_OBJECT_TYPE_FRAMEBUFFER, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) {
|
||||
if (framebuf[(int)rpType]) {
|
||||
return framebuf[(int)rpType];
|
||||
VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType, int layer) {
|
||||
bool multiview = RenderPassTypeHasMultiView(rpType);
|
||||
|
||||
if (RenderPassTypeHasMultiView(rpType)) {
|
||||
_dbg_assert_(layer == -1);
|
||||
layer = 0;
|
||||
}
|
||||
|
||||
if (framebuf[(int)rpType][layer]) {
|
||||
return framebuf[(int)rpType][layer];
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
VkImageView views[2]{};
|
||||
|
||||
bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
|
||||
views[0] = color.imageView;
|
||||
bool hasDepth = RenderPassTypeHasDepth(rpType);
|
||||
views[0] = (multiview || numLayers == 0) ? color.imageView : color.layerViews[layer];
|
||||
if (hasDepth) {
|
||||
_dbg_assert_(depth.imageView != VK_NULL_HANDLE);
|
||||
views[1] = depth.imageView;
|
||||
views[1] = (multiview || numLayers == 0) ? depth.imageView : depth.layerViews[layer];
|
||||
}
|
||||
fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType);
|
||||
fbci.attachmentCount = hasDepth ? 2 : 1;
|
||||
fbci.pAttachments = views;
|
||||
fbci.width = width;
|
||||
fbci.height = height;
|
||||
fbci.layers = 1;
|
||||
fbci.layers = 1; // With multiview, this should be set as 1.
|
||||
|
||||
VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]);
|
||||
VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType][layer]);
|
||||
_assert_(res == VK_SUCCESS);
|
||||
|
||||
if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) {
|
||||
vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str());
|
||||
vulkan_->SetDebugName(framebuf[(int)rpType][layer], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s_%d", tag_.c_str(), layer).c_str());
|
||||
}
|
||||
|
||||
return framebuf[(int)rpType];
|
||||
return framebuf[(int)rpType][layer];
|
||||
}
|
||||
|
||||
VKRFramebuffer::~VKRFramebuffer() {
|
||||
|
@ -236,13 +244,27 @@ VKRFramebuffer::~VKRFramebuffer() {
|
|||
}
|
||||
if (depth.depthSampleView)
|
||||
vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (color.layerViews[i]) {
|
||||
vulkan_->Delete().QueueDeleteImageView(color.layerViews[i]);
|
||||
}
|
||||
if (depth.layerViews[i]) {
|
||||
vulkan_->Delete().QueueDeleteImageView(depth.layerViews[i]);
|
||||
}
|
||||
}
|
||||
for (auto &fb : framebuf) {
|
||||
if (fb)
|
||||
vulkan_->Delete().QueueDeleteFramebuffer(fb);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (fb[i]) {
|
||||
vulkan_->Delete().QueueDeleteFramebuffer(fb[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, 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);
|
||||
|
||||
VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
ici.arrayLayers = numLayers;
|
||||
ici.mipLevels = 1;
|
||||
|
@ -275,11 +297,12 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int
|
|||
ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
|
||||
ivci.format = ici.format;
|
||||
ivci.image = img.image;
|
||||
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
ivci.viewType = numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
ivci.subresourceRange.aspectMask = aspects;
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
ivci.subresourceRange.layerCount = numLayers;
|
||||
ivci.subresourceRange.levelCount = 1;
|
||||
res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.imageView);
|
||||
|
||||
_dbg_assert_(res == VK_SUCCESS);
|
||||
|
||||
// Separate view for texture sampling that only exposes depth.
|
||||
|
@ -291,6 +314,18 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int
|
|||
img.depthSampleView = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// Create 2D views for both layers, if layered.
|
||||
// Useful when multipassing shaders that don't yet exist in a single-pass-stereo version.
|
||||
if (numLayers == 2) {
|
||||
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.layerViews[0]);
|
||||
_dbg_assert_(res == VK_SUCCESS);
|
||||
ivci.subresourceRange.baseArrayLayer = 1;
|
||||
res = vkCreateImageView(vulkan->GetDevice(), &ivci, nullptr, &img.layerViews[1]);
|
||||
_dbg_assert_(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkPipelineStageFlags dstStage;
|
||||
VkAccessFlagBits dstAccessMask;
|
||||
switch (initialLayout) {
|
||||
|
@ -311,12 +346,11 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int
|
|||
return;
|
||||
}
|
||||
|
||||
TransitionImageLayout2(cmd, img.image, 0, 1, aspects,
|
||||
TransitionImageLayout2(cmd, img.image, 0, 1, numLayers, aspects,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, initialLayout,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, dstStage,
|
||||
0, dstAccessMask);
|
||||
img.layout = initialLayout;
|
||||
|
||||
img.format = format;
|
||||
img.tag = tag ? tag : "N/A";
|
||||
}
|
||||
|
@ -710,10 +744,18 @@ void VulkanRenderManager::EndCurRenderStep() {
|
|||
RenderPassType rpType = depthStencil ? RP_TYPE_COLOR_DEPTH : RP_TYPE_COLOR;
|
||||
if (!curRenderStep_->render.framebuffer) {
|
||||
rpType = RP_TYPE_BACKBUFFER;
|
||||
} else if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) {
|
||||
// Not allowed on backbuffers.
|
||||
rpType = depthStencil ? RP_TYPE_COLOR_DEPTH_INPUT : RP_TYPE_COLOR_INPUT;
|
||||
} else {
|
||||
if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) {
|
||||
// Not allowed on backbuffers.
|
||||
rpType = depthStencil ? RP_TYPE_COLOR_DEPTH_INPUT : RP_TYPE_COLOR_INPUT;
|
||||
}
|
||||
// Framebuffers can be stereo, and if so, will control the render pass type to match.
|
||||
// Pipelines can be mono and render fine to stereo etc, so not checking them here.
|
||||
if (curRenderStep_->render.framebuffer->numLayers > 1) {
|
||||
rpType = (RenderPassType)(rpType | RP_TYPE_MULTIVIEW_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Also add render pass types for depth/stencil-less.
|
||||
|
||||
VKRRenderPass *renderPass = queueRunner_.GetRenderPass(key);
|
||||
|
@ -752,7 +794,7 @@ void VulkanRenderManager::BindCurrentFramebufferAsInputAttachment0(VkImageAspect
|
|||
curRenderStep_->commands.push_back(VkRenderData{ VKRRenderCommand::SELF_DEPENDENCY_BARRIER });
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
|
||||
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, int layer, const char *tag) {
|
||||
_dbg_assert_(insideFrame_);
|
||||
// Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible.
|
||||
if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
|
||||
|
@ -833,6 +875,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
|||
|
||||
VKRStep *step = new VKRStep{ VKRStepType::RENDER };
|
||||
step->render.framebuffer = fb;
|
||||
step->render.layer = layer;
|
||||
step->render.colorLoad = color;
|
||||
step->render.depthLoad = depth;
|
||||
step->render.stencilLoad = stencil;
|
||||
|
@ -1175,7 +1218,7 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
|
|||
steps_.push_back(step);
|
||||
}
|
||||
|
||||
VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit) {
|
||||
VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int layer) {
|
||||
_dbg_assert_(curRenderStep_ != nullptr);
|
||||
|
||||
// We don't support texturing from stencil, neither do we support texturing from depth|stencil together (nonsensical).
|
||||
|
@ -1210,7 +1253,12 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in
|
|||
// Add this pretransition unless we already have it.
|
||||
TransitionRequest rq{ fb, aspectBit, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
|
||||
curRenderStep_->preTransitions.insert(rq); // Note that insert avoids inserting duplicates.
|
||||
return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView;
|
||||
|
||||
if (layer == -1 || (layer == 0 && fb->numLayers == 1)) {
|
||||
return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.imageView : fb->depth.depthSampleView;
|
||||
} else {
|
||||
return aspectBit == VK_IMAGE_ASPECT_COLOR_BIT ? fb->color.layerViews[layer] : fb->depth.layerViews[layer];
|
||||
}
|
||||
}
|
||||
|
||||
// Called on main thread.
|
||||
|
|
|
@ -24,13 +24,19 @@
|
|||
// Forward declaration
|
||||
VK_DEFINE_HANDLE(VmaAllocation);
|
||||
|
||||
// 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. Until it's not fine. We'll see.
|
||||
// Simple independent framebuffer image.
|
||||
struct VKRImage {
|
||||
// These four are "immutable".
|
||||
VkImage image;
|
||||
|
||||
// These are 2D if single layer, 2D_ARRAY if multiple. Need to take that into account when picking
|
||||
// shaders, or use layerViews below and multiple passes to work around it.
|
||||
VkImageView imageView;
|
||||
VkImageView depthSampleView;
|
||||
|
||||
// If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo.
|
||||
VkImageView layerViews[2]{};
|
||||
|
||||
VmaAllocation alloc;
|
||||
VkFormat format;
|
||||
|
||||
|
@ -40,6 +46,9 @@ struct VKRImage {
|
|||
// For debugging.
|
||||
std::string tag;
|
||||
};
|
||||
|
||||
// NOTE: If numLayers > 1, it will create an array texture, rather than a normal 2D texture.
|
||||
// This requires a different sampling path!
|
||||
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag);
|
||||
|
||||
class VKRFramebuffer {
|
||||
|
@ -47,7 +56,7 @@ public:
|
|||
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, bool createDepthStencilBuffer, const char *tag);
|
||||
~VKRFramebuffer();
|
||||
|
||||
VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType);
|
||||
VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType, int layer);
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
@ -65,7 +74,7 @@ public:
|
|||
// TODO: Hide.
|
||||
VulkanContext *vulkan_;
|
||||
private:
|
||||
VkFramebuffer framebuf[RP_TYPE_COUNT]{};
|
||||
VkFramebuffer framebuf[RP_TYPE_COUNT][2]{};
|
||||
|
||||
std::string tag_;
|
||||
};
|
||||
|
@ -213,7 +222,7 @@ 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();
|
||||
|
||||
// This starts a new step containing a render pass.
|
||||
// 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
|
||||
// making any new render state changes or draw calls.
|
||||
|
@ -228,11 +237,16 @@ public:
|
|||
//
|
||||
// It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're
|
||||
// not keeping track of your calls to this function on your own.
|
||||
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag);
|
||||
//
|
||||
// For layer, we use the same convention as thin3d, where layer = -1 means all layers together. For texturing, that means that you
|
||||
// get an array texture view.
|
||||
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, int layer, const char *tag);
|
||||
|
||||
// Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface
|
||||
// as the other backends, even though there's no actual binding happening here.
|
||||
VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits);
|
||||
// For layer, we use the same convention as thin3d, where layer = -1 means all layers together. For texturing, that means that you
|
||||
// get an array texture view.
|
||||
VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBits, int layer);
|
||||
|
||||
void BindCurrentFramebufferAsInputAttachment0(VkImageAspectFlags aspectBits);
|
||||
|
||||
|
@ -256,6 +270,15 @@ public:
|
|||
compileMutex_.unlock();
|
||||
}
|
||||
|
||||
// We always pass in desc set 0 directly in draw commands. This is used only to bind higher descriptor sets.
|
||||
void BindDescriptorSet(int index, const VkDescriptorSet descSet) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET };
|
||||
data.bindDescSet.setIndex = index;
|
||||
data.bindDescSet.descSet = descSet;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_(pipeline != nullptr);
|
||||
|
|
|
@ -404,11 +404,8 @@ public:
|
|||
DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) override;
|
||||
|
||||
// These functions should be self explanatory.
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
|
||||
Framebuffer *GetCurrentRenderTarget() override {
|
||||
return (Framebuffer *)curFramebuffer_.ptr;
|
||||
}
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;
|
||||
void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) override;
|
||||
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;
|
||||
void BindCurrentFramebufferForColorInput() override;
|
||||
|
||||
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
|
||||
|
@ -1505,7 +1502,7 @@ private:
|
|||
|
||||
Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) {
|
||||
VkCommandBuffer cmd = renderManager_.GetInitCmd();
|
||||
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.z_stencil, desc.numLayers, desc.tag);
|
||||
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetQueueRunner()->GetCompatibleRenderPass(), desc.width, desc.height, desc.numLayers, desc.z_stencil, desc.tag);
|
||||
return new VKFramebuffer(vkrfb);
|
||||
}
|
||||
|
||||
|
@ -1556,17 +1553,17 @@ DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) {
|
|||
return DrawContext::PreferredFramebufferReadbackFormat(src);
|
||||
}
|
||||
|
||||
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
|
||||
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) {
|
||||
VKFramebuffer *fb = (VKFramebuffer *)fbo;
|
||||
VKRRenderPassLoadAction color = (VKRRenderPassLoadAction)rp.color;
|
||||
VKRRenderPassLoadAction depth = (VKRRenderPassLoadAction)rp.depth;
|
||||
VKRRenderPassLoadAction stencil = (VKRRenderPassLoadAction)rp.stencil;
|
||||
|
||||
renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag);
|
||||
renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, layer, tag);
|
||||
curFramebuffer_ = fb;
|
||||
}
|
||||
|
||||
void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
|
||||
void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
|
||||
VKFramebuffer *fb = (VKFramebuffer *)fbo;
|
||||
_assert_(binding < MAX_BOUND_TEXTURES);
|
||||
|
||||
|
@ -1588,7 +1585,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne
|
|||
}
|
||||
|
||||
boundTextures_[binding] = nullptr;
|
||||
boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect);
|
||||
boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, layer);
|
||||
}
|
||||
|
||||
void VKContext::BindCurrentFramebufferForColorInput() {
|
||||
|
|
|
@ -415,9 +415,11 @@ class Framebuffer : public RefCountedObject {
|
|||
public:
|
||||
int Width() { return width_; }
|
||||
int Height() { return height_; }
|
||||
int Layers() { return layers_; }
|
||||
|
||||
virtual void UpdateTag(const char *tag) {}
|
||||
protected:
|
||||
int width_ = -1, height_ = -1;
|
||||
int width_ = -1, height_ = -1, layers_ = 1;
|
||||
};
|
||||
|
||||
class Buffer : public RefCountedObject {
|
||||
|
@ -593,6 +595,8 @@ struct RenderPassInfo {
|
|||
const char *tag;
|
||||
};
|
||||
|
||||
const int ALL_LAYERS = -1;
|
||||
|
||||
class DrawContext {
|
||||
public:
|
||||
virtual ~DrawContext();
|
||||
|
@ -654,11 +658,10 @@ public:
|
|||
|
||||
// These functions should be self explanatory.
|
||||
// Binding a zero render target means binding the backbuffer.
|
||||
virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) = 0;
|
||||
virtual Framebuffer *GetCurrentRenderTarget() = 0;
|
||||
virtual void BindFramebufferAsRenderTarget(Framebuffer *fbo, int layer, const RenderPassInfo &rp, const char *tag) = 0;
|
||||
|
||||
// binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2).
|
||||
virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) = 0;
|
||||
virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) = 0;
|
||||
|
||||
// Framebuffer fetch / input attachment support, needs to be explicit in Vulkan.
|
||||
virtual void BindCurrentFramebufferForColorInput() {}
|
||||
|
|
|
@ -85,7 +85,7 @@ void UIScreen::preRender() {
|
|||
}
|
||||
draw->BeginFrame();
|
||||
// Bind and clear the back buffer
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI");
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, ALL_LAYERS, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI");
|
||||
screenManager()->getUIContext()->BeginFrame();
|
||||
|
||||
Draw::Viewport viewport;
|
||||
|
|
|
@ -89,6 +89,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ);
|
||||
bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA);
|
||||
|
||||
bool arrayTexture = id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE);
|
||||
bool arrayTextureFramebuffer = id.Bit(FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE);
|
||||
|
||||
bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled;
|
||||
|
||||
bool doFlatShading = id.Bit(FS_BIT_FLATSHADE) && !flatBug;
|
||||
|
@ -155,11 +158,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
|||
|
||||
WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr);
|
||||
if (doTexture) {
|
||||
WRITE(p, "layout (binding = 0) uniform %s tex;\n", texture3D ? "sampler3D" : "sampler2D");
|
||||
WRITE(p, "layout (binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "array" : "");
|
||||
}
|
||||
|
||||
if (readFramebufferTex) {
|
||||
WRITE(p, "layout (binding = 1) uniform sampler2D fbotex;\n");
|
||||
WRITE(p, "layout (binding = 1) uniform sampler2D%s fbotex;\n", arrayTextureFramebuffer ? "array" : "");
|
||||
} else if (fetchFramebuffer) {
|
||||
WRITE(p, "layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n");
|
||||
if (fragmentShaderFlags) {
|
||||
|
|
|
@ -863,7 +863,7 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra
|
|||
|
||||
if (currentRenderVfb_ && dst != currentRenderVfb_ && tookActions) {
|
||||
// Will probably just change the name of the current renderpass, since one was started by the reinterpret itself.
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After Reinterpret");
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After Reinterpret");
|
||||
}
|
||||
|
||||
shaderManager_->DirtyLastShader();
|
||||
|
@ -1011,7 +1011,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
|
|||
if (useBufferedRendering_) {
|
||||
if (vfb->fbo) {
|
||||
shaderManager_->DirtyLastShader();
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "FBSwitch");
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch");
|
||||
} else {
|
||||
// This should only happen very briefly when toggling useBufferedRendering_.
|
||||
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
|
||||
|
@ -1115,7 +1115,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
|
|||
} else {
|
||||
flags = DRAWTEX_LINEAR;
|
||||
}
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag);
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag);
|
||||
SetViewport2D(0, 0, vfb->renderWidth, vfb->renderHeight);
|
||||
draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight);
|
||||
} else {
|
||||
|
@ -1153,7 +1153,7 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
|
|||
}
|
||||
}
|
||||
|
||||
bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
|
||||
bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer) {
|
||||
if (!framebuffer->fbo || !useBufferedRendering_) {
|
||||
draw_->BindTexture(stage, nullptr);
|
||||
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
|
||||
|
@ -1173,17 +1173,17 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF
|
|||
if (renderCopy) {
|
||||
VirtualFramebuffer copyInfo = *framebuffer;
|
||||
copyInfo.fbo = renderCopy;
|
||||
CopyFramebufferForColorTexture(©Info, framebuffer, flags);
|
||||
CopyFramebufferForColorTexture(©Info, framebuffer, flags, layer);
|
||||
RebindFramebuffer("After BindFramebufferAsColorTexture");
|
||||
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, layer);
|
||||
gpuStats.numCopiesForSelfTex++;
|
||||
} else {
|
||||
// Failed to get temp FBO? Weird.
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, layer);
|
||||
}
|
||||
return true;
|
||||
} else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) {
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, layer);
|
||||
return true;
|
||||
} else {
|
||||
ERROR_LOG_REPORT_ONCE(selfTextureFail, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags);
|
||||
|
@ -1197,7 +1197,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF
|
|||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags) {
|
||||
void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = src->drawnWidth;
|
||||
|
@ -1369,7 +1369,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
|||
DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black");
|
||||
// No framebuffer to display! Clear to black.
|
||||
if (useBufferedRendering_) {
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput");
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput");
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
return;
|
||||
|
@ -1433,7 +1433,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
|||
// No framebuffer to display! Clear to black.
|
||||
if (useBufferedRendering_) {
|
||||
// Bind and clear the backbuffer. This should be the first time during the frame that it's bound.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO");
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO");
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
return;
|
||||
|
@ -1619,7 +1619,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, 1, true, tag });
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag });
|
||||
if (Memory::IsVRAMAddress(vfb->fb_address) && vfb->fb_stride != 0) {
|
||||
NotifyMemInfo(MemBlockFlags::ALLOC, vfb->fb_address, ColorBufferByteSize(vfb), tag, len);
|
||||
}
|
||||
|
@ -1631,7 +1631,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
|||
if (old.fbo) {
|
||||
INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->fb_format));
|
||||
if (vfb->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
|
||||
if (!skipCopy) {
|
||||
BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0, RASTER_COLOR, "BlitColor_ResizeFramebufFBO");
|
||||
}
|
||||
|
@ -1640,9 +1640,9 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
|||
}
|
||||
}
|
||||
fbosToDelete_.push_back(old.fbo);
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO");
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "ResizeFramebufFBO");
|
||||
} else {
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, Draw::ALL_LAYERS, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
|
||||
}
|
||||
currentRenderVfb_ = vfb;
|
||||
|
||||
|
@ -1986,7 +1986,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, 1, true, name });
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, name });
|
||||
vfbs_.push_back(vfb);
|
||||
|
||||
u32 byteSize = ColorBufferByteSize(vfb);
|
||||
|
@ -2407,7 +2407,8 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u
|
|||
bool z_stencil = reason == TempFBO::STENCIL;
|
||||
char name[128];
|
||||
snprintf(name, sizeof(name), "temp_fbo_%dx%d%s", w / renderScaleFactor_, h / renderScaleFactor_, z_stencil ? "_depth" : "");
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, name });
|
||||
|
||||
Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, GetFramebufferLayers(), z_stencil, name });
|
||||
if (!fbo) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2784,10 +2785,10 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) {
|
|||
draw_->InvalidateCachedState();
|
||||
shaderManager_->DirtyLastShader();
|
||||
if (currentRenderVfb_ && currentRenderVfb_->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag);
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, Draw::ALL_LAYERS, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag);
|
||||
} else {
|
||||
// Should this even happen? It could while debugging, but maybe we can just skip binding at all.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad");
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2906,7 +2907,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX
|
|||
// This can happen if they recently switched from non-buffered.
|
||||
if (useBufferedRendering_) {
|
||||
// Just bind the back buffer for rendering, forget about doing anything else as we're in a weird state.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer");
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -3029,8 +3030,8 @@ void FramebufferManagerCommon::BlitUsingRaster(
|
|||
// Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily).
|
||||
draw_->BindTexture(0, nullptr);
|
||||
// This will get optimized away in case it's already bound (in VK and GL at least..)
|
||||
draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster");
|
||||
draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT);
|
||||
draw_->BindFramebufferAsRenderTarget(dest, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag ? tag : "BlitUsingRaster");
|
||||
draw_->BindFramebufferAsTexture(src, 0, pipeline->info.readChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0);
|
||||
|
||||
if (destX1 == 0.0f && destY1 == 0.0f && destX2 >= destW && destY2 >= destH) {
|
||||
// We overwrite the whole channel of the framebuffer, so we can invalidate the current contents.
|
||||
|
@ -3046,6 +3047,14 @@ void FramebufferManagerCommon::BlitUsingRaster(
|
|||
gstate_c.Dirty(DIRTY_ALL_RENDER_STATE);
|
||||
}
|
||||
|
||||
int FramebufferManagerCommon::GetFramebufferLayers() const {
|
||||
int layers = 1;
|
||||
if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
|
||||
layers = 2;
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(VirtualFramebuffer *src, GEBufferFormat newFormat) {
|
||||
// Look for an identical framebuffer with the new format
|
||||
_dbg_assert_(src->fb_format != newFormat);
|
||||
|
@ -3089,7 +3098,7 @@ VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(Vi
|
|||
|
||||
char tag[128];
|
||||
FormatFramebufferName(vfb, tag, sizeof(tag));
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, tag });
|
||||
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), true, tag });
|
||||
vfbs_.push_back(vfb);
|
||||
}
|
||||
|
||||
|
|
|
@ -322,7 +322,7 @@ public:
|
|||
// Otherwise it doesn't get called.
|
||||
void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);
|
||||
|
||||
bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
|
||||
bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer);
|
||||
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel);
|
||||
|
||||
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
|
||||
|
@ -460,7 +460,7 @@ protected:
|
|||
// Used by ReadFramebufferToMemory and later framebuffer block copies
|
||||
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, RasterChannel channel, const char *tag);
|
||||
|
||||
void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags);
|
||||
void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer);
|
||||
|
||||
void EstimateDrawingSize(u32 fb_address, int fb_stride, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int &drawing_width, int &drawing_height);
|
||||
u32 ColorBufferByteSize(const VirtualFramebuffer *vfb) const;
|
||||
|
@ -486,6 +486,8 @@ protected:
|
|||
|
||||
void UpdateFramebufUsage(VirtualFramebuffer *vfb);
|
||||
|
||||
int GetFramebufferLayers() const;
|
||||
|
||||
static void SetColorUpdated(VirtualFramebuffer *dstBuffer, int skipDrawReason) {
|
||||
dstBuffer->memoryUpdated = false;
|
||||
dstBuffer->clutUpdatedBytes = 0;
|
||||
|
|
|
@ -566,7 +566,7 @@ void PresentationCommon::BindSource(int binding) {
|
|||
if (srcTexture_) {
|
||||
draw_->BindTexture(binding, srcTexture_);
|
||||
} else if (srcFramebuffer_) {
|
||||
draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(srcFramebuffer_, binding, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
_assert_(false);
|
||||
}
|
||||
|
@ -685,13 +685,13 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
PostShaderUniforms uniforms;
|
||||
const auto performShaderPass = [&](const ShaderInfo *shaderInfo, Draw::Framebuffer *postShaderFramebuffer, Draw::Pipeline *postShaderPipeline) {
|
||||
if (postShaderOutput) {
|
||||
draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
BindSource(0);
|
||||
}
|
||||
BindSource(1);
|
||||
if (shaderInfo->usePreviousFrame)
|
||||
draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(previousFramebuffer, 2, Draw::FB_COLOR_BIT, 0);
|
||||
|
||||
int nextWidth, nextHeight;
|
||||
draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight);
|
||||
|
@ -743,7 +743,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
postShaderFramebuffer = previousFramebuffers_[previousIndex_];
|
||||
}
|
||||
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader");
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PostShader");
|
||||
performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline);
|
||||
}
|
||||
|
||||
|
@ -764,7 +764,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
previousIndex_ = 0;
|
||||
Draw::Framebuffer *postShaderFramebuffer = previousFramebuffers_[previousIndex_];
|
||||
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit");
|
||||
draw_->BindFramebufferAsRenderTarget(postShaderFramebuffer, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "InterFrameBlit");
|
||||
performShaderPass(shaderInfo, postShaderFramebuffer, postShaderPipeline);
|
||||
}
|
||||
|
||||
|
@ -773,13 +773,13 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
|
|||
pipeline = postShaderPipelines_.back();
|
||||
}
|
||||
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit");
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "FinalBlit");
|
||||
draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_);
|
||||
|
||||
draw_->BindPipeline(pipeline);
|
||||
|
||||
if (postShaderOutput) {
|
||||
draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(postShaderOutput, 0, Draw::FB_COLOR_BIT, 0);
|
||||
} else {
|
||||
BindSource(0);
|
||||
}
|
||||
|
|
|
@ -362,6 +362,15 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
|
|||
|
||||
id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask);
|
||||
|
||||
// Stereo support
|
||||
if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
|
||||
// All framebuffers are array textures in this mode.
|
||||
if (gstate_c.arrayTexture) {
|
||||
id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE);
|
||||
}
|
||||
id.SetBit(FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE);
|
||||
}
|
||||
|
||||
if (g_Config.bVendorBugChecksEnabled && bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
|
||||
bool stencilWithoutDepth = !IsStencilTestOutputDisabled() && (!gstate.isDepthTestEnabled() || !gstate.isDepthWriteEnabled());
|
||||
if (stencilWithoutDepth) {
|
||||
|
|
|
@ -98,6 +98,8 @@ enum FShaderBit : uint8_t {
|
|||
FS_BIT_COLOR_WRITEMASK = 50,
|
||||
FS_BIT_REPLACE_LOGIC_OP = 51, // 4 bits. GE_LOGIC_COPY means no-op/off.
|
||||
FS_BIT_SHADER_DEPAL_MODE = 55, // 2 bits (ShaderDepalMode)
|
||||
FS_BIT_SAMPLE_ARRAY_TEXTURE = 57, // For multiview, framebuffers are array textures and we need to sample the two layers correctly.
|
||||
FS_BIT_FRAMEBUFFER_ARRAY_TEXTURE = 58, // Framebuffer texture might also be stereo.
|
||||
};
|
||||
|
||||
static inline FShaderBit operator +(FShaderBit bit, int i) {
|
||||
|
|
|
@ -131,6 +131,16 @@ static const char * const ub_vs_bonesStr =
|
|||
R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bone4; mat3x4 u_bone5; mat3x4 u_bone6; mat3x4 u_bone7; mat3x4 u_bone8;
|
||||
)";
|
||||
|
||||
|
||||
static const char * const ub_frame_globalstr =
|
||||
R"( vec4 unused;
|
||||
)";
|
||||
|
||||
// VR stuff will go here.
|
||||
struct UB_FrameGlobal {
|
||||
float unused[4];
|
||||
};
|
||||
|
||||
void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ);
|
||||
|
||||
void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport, bool useBufferedRendering);
|
||||
|
|
|
@ -187,7 +187,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size,
|
|||
// Otherwise, we can skip alpha in many cases, in which case we don't even use a shader.
|
||||
if (flags & WriteStencil::IGNORE_ALPHA) {
|
||||
if (dstBuffer->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Clear");
|
||||
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Clear");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -281,9 +281,9 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size,
|
|||
Draw::Framebuffer *blitFBO = nullptr;
|
||||
if (useBlit) {
|
||||
blitFBO = GetTempFBO(TempFBO::STENCIL, w, h);
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Blit");
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_Blit");
|
||||
} else if (dstBuffer->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_NoBlit");
|
||||
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, 0, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "WriteStencilFromMemory_NoBlit");
|
||||
}
|
||||
|
||||
Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f };
|
||||
|
|
|
@ -2121,7 +2121,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
|||
// Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture.
|
||||
BindAsClutTexture(clutTexture.texture, smoothedDepal);
|
||||
|
||||
framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
|
||||
framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, 0);
|
||||
// Vulkan needs to do some extra work here to pick out the native handle from Draw.
|
||||
BoundFramebufferTexture();
|
||||
|
||||
|
@ -2191,13 +2191,13 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
|||
Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, depalWidth, framebuffer->renderHeight);
|
||||
draw_->BindTexture(0, nullptr);
|
||||
draw_->BindTexture(1, nullptr);
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal");
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, Draw::ALL_LAYERS, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal");
|
||||
draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT);
|
||||
draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1);
|
||||
Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &vp);
|
||||
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, 0);
|
||||
draw_->BindTexture(1, clutTexture.texture);
|
||||
Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false);
|
||||
Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(smoothedDepal);
|
||||
|
@ -2213,7 +2213,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
|||
draw_->BindTexture(0, nullptr);
|
||||
framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer");
|
||||
|
||||
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0);
|
||||
BoundFramebufferTexture();
|
||||
|
||||
const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16);
|
||||
|
@ -2226,7 +2226,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
|||
shaderManager_->DirtyLastShader();
|
||||
} else {
|
||||
framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer");
|
||||
framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET);
|
||||
framebufferManager_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET, 0);
|
||||
BoundFramebufferTexture();
|
||||
|
||||
gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF);
|
||||
|
@ -2292,14 +2292,14 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) {
|
|||
Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO(TempFBO::DEPAL, texWidth, texHeight);
|
||||
draw_->BindTexture(0, nullptr);
|
||||
draw_->BindTexture(1, nullptr);
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal");
|
||||
draw_->BindFramebufferAsRenderTarget(depalFBO, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal");
|
||||
draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT);
|
||||
draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1);
|
||||
Draw::Viewport vp{ 0.0f, 0.0f, (float)texWidth, (float)texHeight, 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &vp);
|
||||
|
||||
draw_->BindNativeTexture(0, GetNativeTextureView(entry));
|
||||
draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT, 0);
|
||||
Draw::SamplerState *nearest = textureShaderCache_->GetSampler(false);
|
||||
Draw::SamplerState *clutSampler = textureShaderCache_->GetSampler(false);
|
||||
draw_->BindSamplerStates(0, 1, &nearest);
|
||||
|
@ -2314,7 +2314,7 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) {
|
|||
draw_->BindTexture(0, nullptr);
|
||||
framebufferManager_->RebindFramebuffer("ApplyTextureFramebuffer");
|
||||
|
||||
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT);
|
||||
draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0);
|
||||
BoundFramebufferTexture();
|
||||
|
||||
const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16);
|
||||
|
|
|
@ -159,7 +159,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
|
|||
ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState);
|
||||
|
||||
if (fboTexBindState == FBO_TEX_COPY_BIND_TEX) {
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0);
|
||||
// No sampler required, we do a plain Load in the pixel shader.
|
||||
fboTexBound_ = true;
|
||||
fboTexBindState = FBO_TEX_NONE;
|
||||
|
|
|
@ -101,7 +101,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
|||
|
||||
if (fboTexBindState_ = FBO_TEX_COPY_BIND_TEX) {
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
|
@ -139,7 +139,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) {
|
|||
|
||||
if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) {
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
|
|
|
@ -204,11 +204,11 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int
|
|||
|
||||
shaderManager_->DirtyLastShader();
|
||||
auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height());
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync");
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync");
|
||||
Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
|
||||
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT);
|
||||
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0);
|
||||
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &depthReadbackSampler_);
|
||||
|
||||
// We must bind the program after starting the render pass.
|
||||
|
@ -322,11 +322,11 @@ bool FramebufferManagerGLES::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, i
|
|||
|
||||
shaderManager_->DirtyLastShader();
|
||||
auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height());
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync");
|
||||
draw_->BindFramebufferAsRenderTarget(blitFBO, 0, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync");
|
||||
Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f };
|
||||
draw_->SetViewports(1, &viewport);
|
||||
|
||||
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT);
|
||||
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT, 0);
|
||||
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilReadbackSampler_);
|
||||
|
||||
// We must bind the program after starting the render pass.
|
||||
|
|
|
@ -54,9 +54,9 @@ void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb)
|
|||
|
||||
// Discard the previous contents of this buffer where possible.
|
||||
if (gl_extensions.GLES3) {
|
||||
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer");
|
||||
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, 0, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "UpdateDownloadTempBuffer");
|
||||
} else if (gl_extensions.IsGLES) {
|
||||
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer");
|
||||
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, 0, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "UpdateDownloadTempBuffer");
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
|||
// fboTexNeedsBind_ won't be set if we can read directly from the target.
|
||||
if (fboTexBindState == FBO_TEX_COPY_BIND_TEX) {
|
||||
// Note that this is positions, not UVs, that we need the copy from.
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0);
|
||||
// If we are rendering at a higher resolution, linear is probably best for the dest color.
|
||||
renderManager->SetTextureSampler(1, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR, 0.0f);
|
||||
fboTexBound_ = true;
|
||||
|
|
|
@ -583,6 +583,7 @@ struct GPUStateCache {
|
|||
|
||||
bool bgraTexture;
|
||||
bool needShaderTexClamp;
|
||||
bool arrayTexture;
|
||||
|
||||
float morphWeights[8];
|
||||
u32 deferredVertTypeDirty;
|
||||
|
|
|
@ -618,7 +618,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
|||
u1 = 1.0f;
|
||||
}
|
||||
if (!hasImage) {
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam");
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "CopyToCurrentFboFromDisplayRam");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/SoftwareTransformCommon.h"
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "GPU/Common/ShaderUniforms.h"
|
||||
#include "GPU/Debugger/Debugger.h"
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
|
@ -184,8 +185,9 @@ void DrawEngineVulkan::InitDeviceObjects() {
|
|||
VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
||||
pl.pPushConstantRanges = nullptr;
|
||||
pl.pushConstantRangeCount = 0;
|
||||
pl.setLayoutCount = 1;
|
||||
pl.pSetLayouts = &descriptorSetLayout_;
|
||||
VkDescriptorSetLayout layouts[1] = { descriptorSetLayout_ };
|
||||
pl.setLayoutCount = ARRAY_SIZE(layouts);
|
||||
pl.pSetLayouts = layouts;
|
||||
pl.flags = 0;
|
||||
res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_);
|
||||
_dbg_assert_(VK_SUCCESS == res);
|
||||
|
@ -303,6 +305,7 @@ void DrawEngineVulkan::BeginFrame() {
|
|||
frame->pushIndex->Reset();
|
||||
|
||||
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
|
||||
|
||||
frame->pushUBO->Begin(vulkan);
|
||||
frame->pushVertex->Begin(vulkan);
|
||||
frame->pushIndex->Begin(vulkan);
|
||||
|
|
|
@ -211,8 +211,9 @@ private:
|
|||
|
||||
Draw::DrawContext *draw_;
|
||||
|
||||
// We use a single descriptor set layout for all PSP draws.
|
||||
// We use a shared descriptor set layout for all PSP draws.
|
||||
VkDescriptorSetLayout descriptorSetLayout_;
|
||||
|
||||
VkPipelineLayout pipelineLayout_;
|
||||
VulkanPipeline *lastPipeline_;
|
||||
VkDescriptorSet lastDs_ = VK_NULL_HANDLE;
|
||||
|
|
|
@ -268,6 +268,11 @@ u32 GPU_Vulkan::CheckGPUFeatures() const {
|
|||
features |= GPU_ROUND_DEPTH_TO_16BIT;
|
||||
}
|
||||
|
||||
if (true) {
|
||||
features |= GPU_USE_SINGLE_PASS_STEREO;
|
||||
features &= ~GPU_USE_FRAMEBUFFER_FETCH; // Need to figure out if this can be supported with multiview rendering
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,7 @@ void DrawEngineVulkan::BindShaderBlendTex() {
|
|||
// Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
|
||||
if (!gstate.isModeClear()) {
|
||||
if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) {
|
||||
bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY);
|
||||
bool bindResult = framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, Draw::ALL_LAYERS);
|
||||
_dbg_assert_(bindResult);
|
||||
boundSecondary_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE1_IMAGEVIEW);
|
||||
boundSecondaryIsInputAttachment_ = false;
|
||||
|
|
|
@ -1359,9 +1359,9 @@ void EmuScreen::preRender() {
|
|||
if ((!useBufferedRendering && !g_Config.bSoftwareRendering) || Core_IsStepping()) {
|
||||
// We need to clear here already so that drawing during the frame is done on a clean slate.
|
||||
if (Core_IsStepping() && gpuStats.numFlips != 0) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer");
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_BackBuffer");
|
||||
} else {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer");
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "EmuScreen_BackBuffer");
|
||||
}
|
||||
|
||||
Viewport viewport;
|
||||
|
@ -1400,7 +1400,7 @@ void EmuScreen::render() {
|
|||
// It's possible this might be set outside PSP_RunLoopFor().
|
||||
// In this case, we need to double check it here.
|
||||
checkPowerDown();
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid");
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_Invalid");
|
||||
renderUI();
|
||||
return;
|
||||
}
|
||||
|
@ -1439,12 +1439,12 @@ void EmuScreen::render() {
|
|||
// Clear to blue background screen
|
||||
bool dangerousSettings = !Reporting::IsSupported();
|
||||
uint32_t color = dangerousSettings ? 0xFF900050 : 0xFF900000;
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, color }, "EmuScreen_RuntimeError");
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, color }, "EmuScreen_RuntimeError");
|
||||
// The info is drawn later in renderUI
|
||||
} else {
|
||||
// If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output.
|
||||
// This won't work in non-buffered, but that's fine.
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping");
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping");
|
||||
// Just to make sure.
|
||||
if (PSP_IsInited()) {
|
||||
gpu->CopyDisplayToOutput(true);
|
||||
|
@ -1456,7 +1456,7 @@ void EmuScreen::render() {
|
|||
// Didn't actually reach the end of the frame, ran out of the blockTicks cycles.
|
||||
// In this case we need to bind and wipe the backbuffer, at least.
|
||||
// It's possible we never ended up outputted anything - make sure we have the backbuffer cleared
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame");
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1470,7 +1470,7 @@ void EmuScreen::render() {
|
|||
|
||||
if (hasVisibleUI()) {
|
||||
// In most cases, this should already be bound and a no-op.
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI");
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, 0, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_UI");
|
||||
cardboardDisableButton_->SetVisibility(g_Config.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE);
|
||||
screenManager()->getUIContext()->BeginFrame();
|
||||
renderUI();
|
||||
|
|
|
@ -1498,6 +1498,7 @@
|
|||
<None Include="..\android\jni\Locals.mk" />
|
||||
<None Include="..\appveyor.yml" />
|
||||
<None Include="..\assets\compat.ini" />
|
||||
<None Include="..\assets\compatvr.ini" />
|
||||
<None Include="..\assets\knownfuncs.ini" />
|
||||
<None Include="..\assets\langregion.ini" />
|
||||
<None Include="..\atlasscript.txt" />
|
||||
|
|
|
@ -711,6 +711,9 @@
|
|||
<None Include="..\SDL\buildassets.sh">
|
||||
<Filter>Other Platforms\SDL</Filter>
|
||||
</None>
|
||||
<None Include="..\assets\compatvr.ini">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ppsspp.rc">
|
||||
|
|
|
@ -240,7 +240,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const
|
|||
PSP_EndHostFrame();
|
||||
|
||||
if (draw) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless");
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, 0, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Headless");
|
||||
// Vulkan may get angry if we don't do a final present.
|
||||
if (gpu)
|
||||
gpu->CopyDisplayToOutput(true);
|
||||
|
|
Loading…
Add table
Reference in a new issue