diff --git a/core/rend/vulkan/allocator.cpp b/core/rend/vulkan/allocator.cpp
index ddb03e30a..f08130a23 100644
--- a/core/rend/vulkan/allocator.cpp
+++ b/core/rend/vulkan/allocator.cpp
@@ -1,3 +1,23 @@
+/*
+ * Created on: Oct 11, 2019
+
+ Copyright 2019 flyinghead
+
+ This file is part of Flycast.
+
+ Flycast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ Flycast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Flycast. If not, see .
+*/
#include "allocator.h"
SimpleAllocator SimpleAllocator::instance;
diff --git a/core/rend/vulkan/allocator.h b/core/rend/vulkan/allocator.h
index f06894f4a..b9a11c10e 100644
--- a/core/rend/vulkan/allocator.h
+++ b/core/rend/vulkan/allocator.h
@@ -1,3 +1,23 @@
+/*
+ * Created on: Oct 11, 2019
+
+ Copyright 2019 flyinghead
+
+ This file is part of Flycast.
+
+ Flycast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ Flycast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Flycast. If not, see .
+*/
#pragma once
#include
#include
@@ -14,6 +34,19 @@ public:
{
verify(size >= SmallestBlockSize);
freeBlocks.push_back(std::make_pair(0, PowerOf2(size)));
+ INFO_LOG(RENDERER, "Allocated memory chunk of size %zd", PowerOf2(size));
+ }
+ Chunk(const Chunk& other) = delete;
+ Chunk(Chunk&& other) = default;
+ Chunk& operator=(const Chunk& other) = delete;
+ Chunk& operator=(Chunk&& other) = default;
+
+ ~Chunk()
+ {
+ verify(usedBlocks.empty());
+ verify(freeBlocks.size() <= 1);
+ if (!freeBlocks.empty())
+ INFO_LOG(RENDERER, "Freeing memory chunk of size %zd", freeBlocks.front().second);
}
private:
diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp
index cee2b85f5..d9a28d1ce 100644
--- a/core/rend/vulkan/drawer.cpp
+++ b/core/rend/vulkan/drawer.cpp
@@ -275,19 +275,23 @@ bool Drawer::Draw(const Texture *fogTexture)
}
scale_x = 1;
+ scissor_scale_x = 1;
scale_y = 1;
if (!is_rtt && !pvrrc.isRenderFramebuffer)
{
scale_x = fb_scale_x;
+ scissor_scale_x = fb_scale_x;
scale_y = fb_scale_y;
if (SCALER_CTL.interlace == 0 && SCALER_CTL.vscalefactor > 0x400)
scale_y *= roundf((float)SCALER_CTL.vscalefactor / 0x400);
- //work out scaling parameters !
//Pixel doubling is on VO, so it does not affect any pixel operations
if (VO_CONTROL.pixel_double)
+ {
+ scissor_scale_x *= 0.5f;
scale_x *= 0.5f;
+ }
if (SCALER_CTL.hscale)
scale_x *= 2;
@@ -306,7 +310,7 @@ bool Drawer::Draw(const Texture *fogTexture)
if (is_rtt)
{
vtxUniforms.scale[0] = 2.0f / dc_width;
- vtxUniforms.scale[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
+ vtxUniforms.scale[1] = 2.0f / dc_height;
vtxUniforms.scale[2] = 1;
vtxUniforms.scale[3] = 1;
}
@@ -601,22 +605,38 @@ vk::CommandBuffer ScreenDrawer::BeginRenderPass()
GetContext()->BeginRenderPass();
vk::CommandBuffer commandBuffer = GetContext()->GetCurrentCommandBuffer();
commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float) ((screen_width)), (float) ((screen_height)), 1.0f, 0.0f));
- bool wide_screen_on = settings.rend.WideScreen
+ bool wide_screen_on = settings.rend.WideScreen && !pvrrc.isRenderFramebuffer
&& pvrrc.fb_X_CLIP.min == 0
- && lroundf((pvrrc.fb_X_CLIP.max + 1) / fb_scale_x) == 640L
+ && lroundf((pvrrc.fb_X_CLIP.max + 1) / scissor_scale_x) == 640L
&& pvrrc.fb_Y_CLIP.min == 0
&& lroundf((pvrrc.fb_Y_CLIP.max + 1) / scale_y) == 480L;
if (!wide_screen_on)
{
- float width = (pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1) / fb_scale_x;
- float height = (pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1) / scale_y;
- float min_x = pvrrc.fb_X_CLIP.min / fb_scale_x;
- float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
- if (SCALER_CTL.interlace && SCALER_CTL.vscalefactor > 0x400)
+ float width;
+ float height;
+ float min_x;
+ float min_y;
+
+ if (pvrrc.isRenderFramebuffer)
{
- // Clipping is done after scaling/filtering so account for that if enabled
- height *= (float) SCALER_CTL.vscalefactor / 0x400;
- min_y *= (float) SCALER_CTL.vscalefactor / 0x400;
+ width = 640;
+ height = 480;
+ min_x = 0;
+ min_y = 0;
+ }
+ else
+ {
+ width = (pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1) / scissor_scale_x;
+ height = (pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1) / scale_y;
+ min_x = pvrrc.fb_X_CLIP.min / scissor_scale_x;
+ min_y = pvrrc.fb_Y_CLIP.min / scale_y;
+
+ if (SCALER_CTL.interlace && SCALER_CTL.vscalefactor > 0x400)
+ {
+ // Clipping is done after scaling/filtering so account for that if enabled
+ height *= (float) SCALER_CTL.vscalefactor / 0x400;
+ min_y *= (float) SCALER_CTL.vscalefactor / 0x400;
+ }
}
if (settings.rend.Rotate90)
{
diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h
index 332c69857..e0e9d7017 100644
--- a/core/rend/vulkan/drawer.h
+++ b/core/rend/vulkan/drawer.h
@@ -44,6 +44,16 @@ public:
Drawer(Drawer&& other) = default;
Drawer& operator=(const Drawer& other) = delete;
Drawer& operator=(Drawer&& other) = default;
+ virtual vk::CommandBuffer BeginRenderPass() = 0;
+ virtual void EndRenderPass() = 0;
+ void SetScissor(const vk::CommandBuffer& cmdBuffer, vk::Rect2D scissor)
+ {
+ if (scissor != currentScissor)
+ {
+ cmdBuffer.setScissor(0, scissor);
+ currentScissor = scissor;
+ }
+ }
protected:
void Init(SamplerManager *samplerManager, ShaderManager *shaderManager)
@@ -53,8 +63,6 @@ protected:
}
virtual DescriptorSets& GetCurrentDescSet() = 0;
virtual BufferData *GetMainBuffer(u32 size) = 0;
- virtual vk::CommandBuffer BeginRenderPass() = 0;
- virtual void EndRenderPass() = 0;
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
@@ -62,6 +70,7 @@ protected:
vk::Rect2D baseScissor;
// temp stuff
float scale_x = 1.f;
+ float scissor_scale_x = 1.f;
float scale_y = 1.f;
private:
@@ -72,14 +81,6 @@ private:
void DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const List& polys, u32 first, u32 count);
void DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int count);
void UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms, u32& vertexUniformsOffset);
- void SetScissor(const vk::CommandBuffer& cmdBuffer, vk::Rect2D scissor)
- {
- if (scissor != currentScissor)
- {
- cmdBuffer.setScissor(0, scissor);
- currentScissor = scissor;
- }
- }
// Per-triangle sort results
std::vector> sortedPolys;
@@ -113,6 +114,11 @@ public:
ScreenDrawer(ScreenDrawer&& other) = default;
ScreenDrawer& operator=(const ScreenDrawer& other) = delete;
ScreenDrawer& operator=(ScreenDrawer&& other) = default;
+ virtual vk::CommandBuffer BeginRenderPass() override;
+ virtual void EndRenderPass() override
+ {
+ GetContext()->EndFrame();
+ }
protected:
virtual DescriptorSets& GetCurrentDescSet() override { return descriptorSets[GetCurrentImage()]; }
@@ -137,13 +143,6 @@ protected:
return mainBuffers[GetCurrentImage()].get();
};
- virtual vk::CommandBuffer BeginRenderPass() override;
-
- virtual void EndRenderPass() override
- {
- GetContext()->EndFrame();
- }
-
private:
int GetCurrentImage() { return GetContext()->GetCurrentImageIndex(); }
diff --git a/core/rend/vulkan/imgui_impl_vulkan.h b/core/rend/vulkan/imgui_impl_vulkan.h
index 20aab746c..c8d624cd3 100644
--- a/core/rend/vulkan/imgui_impl_vulkan.h
+++ b/core/rend/vulkan/imgui_impl_vulkan.h
@@ -15,7 +15,7 @@
#include
-#define IMGUI_VK_QUEUED_FRAMES 2
+#define IMGUI_VK_QUEUED_FRAMES 3
// Please zero-clear before use.
struct ImGui_ImplVulkan_InitInfo
diff --git a/core/rend/vulkan/pipeline.cpp b/core/rend/vulkan/pipeline.cpp
index ee2904cca..307bb966d 100644
--- a/core/rend/vulkan/pipeline.cpp
+++ b/core/rend/vulkan/pipeline.cpp
@@ -355,3 +355,63 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol
pipelines[hash(listType, sortTriangles, &pp)] = GetContext()->GetDevice()->createGraphicsPipelineUnique(GetContext()->GetPipelineCache(),
graphicsPipelineCreateInfo);
}
+
+void QuadPipeline::CreatePipeline()
+{
+ vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo;
+
+ // Input assembly state
+ vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleList);
+
+ // Viewport and scissor states
+ vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr);
+
+ // Rasterization and multisample states
+ vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo;
+ pipelineRasterizationStateCreateInfo.lineWidth = 1.0;
+ vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo;
+
+ // Depth and stencil
+ vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo;
+
+ // Color flags and blending
+ vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState;
+ pipelineColorBlendAttachmentState.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
+ | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
+ vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo
+ (
+ vk::PipelineColorBlendStateCreateFlags(), // flags
+ false, // logicOpEnable
+ vk::LogicOp::eNoOp, // logicOp
+ 1, // attachmentCount
+ &pipelineColorBlendAttachmentState, // pAttachments
+ { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants
+ );
+
+ vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
+ vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates);
+
+ vk::PipelineShaderStageCreateInfo stages[] = {
+ { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetQuadVertexShader(), "main" },
+ { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, shaderManager->GetQuadFragmentShader(), "main" },
+ };
+ vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo
+ (
+ vk::PipelineCreateFlags(), // flags
+ 2, // stageCount
+ stages, // pStages
+ &pipelineVertexInputStateCreateInfo, // pVertexInputState
+ &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState
+ nullptr, // pTessellationState
+ &pipelineViewportStateCreateInfo, // pViewportState
+ &pipelineRasterizationStateCreateInfo, // pRasterizationState
+ &pipelineMultisampleStateCreateInfo, // pMultisampleState
+ &pipelineDepthStencilStateCreateInfo, // pDepthStencilState
+ &pipelineColorBlendStateCreateInfo, // pColorBlendState
+ &pipelineDynamicStateCreateInfo, // pDynamicState
+ *pipelineLayout, // layout
+ renderPass // renderPass
+ );
+
+ pipeline = GetContext()->GetDevice()->createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo);
+}
diff --git a/core/rend/vulkan/pipeline.h b/core/rend/vulkan/pipeline.h
index 5a601836e..0fc052d19 100644
--- a/core/rend/vulkan/pipeline.h
+++ b/core/rend/vulkan/pipeline.h
@@ -284,3 +284,76 @@ public:
private:
vk::UniqueRenderPass rttRenderPass;
};
+
+class QuadPipeline
+{
+public:
+ void Init(ShaderManager *shaderManager)
+ {
+ this->shaderManager = shaderManager;
+ if (!pipelineLayout)
+ {
+ vk::DescriptorSetLayoutBinding bindings[] = {
+ { 0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// texture
+ };
+ descSetLayout = GetContext()->GetDevice()->createDescriptorSetLayoutUnique(
+ vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), ARRAY_SIZE(bindings), bindings));
+ pipelineLayout = GetContext()->GetDevice()->createPipelineLayoutUnique(
+ vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descSetLayout.get(), 0, nullptr));
+ }
+ if (!sampler)
+ {
+ sampler = VulkanContext::Instance()->GetDevice()->createSamplerUnique(
+ vk::SamplerCreateInfo(vk::SamplerCreateFlags(), vk::Filter::eLinear, vk::Filter::eLinear,
+ vk::SamplerMipmapMode::eLinear, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge,
+ vk::SamplerAddressMode::eClampToEdge, 0.0f, false, 16.0f, false,
+ vk::CompareOp::eNever, 0.0f, 0.0f, vk::BorderColor::eFloatOpaqueBlack));
+ }
+ if (GetContext()->GetRenderPass() != renderPass)
+ {
+ renderPass = GetContext()->GetRenderPass();
+ pipeline.reset();
+ }
+ descriptorSets.resize(GetContext()->GetSwapChainSize());
+ }
+
+ vk::Pipeline GetPipeline()
+ {
+ if (!pipeline)
+ CreatePipeline();
+ return *pipeline;
+ }
+
+ void SetTexture(Texture *texture)
+ {
+ vk::UniqueDescriptorSet& descriptorSet = descriptorSets[GetContext()->GetCurrentImageIndex()];
+ if (!descriptorSet)
+ {
+ descriptorSet = std::move(GetContext()->GetDevice()->allocateDescriptorSetsUnique(
+ vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), 1, &descSetLayout.get())).front());
+ }
+ vk::DescriptorImageInfo imageInfo(*sampler, texture->GetImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
+ std::vector writeDescriptorSets;
+ writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descriptorSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr));
+
+ GetContext()->GetDevice()->updateDescriptorSets(writeDescriptorSets, nullptr);
+ }
+
+ void BindDescriptorSets(vk::CommandBuffer cmdBuffer)
+ {
+ cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, 1, &descriptorSets[GetContext()->GetCurrentImageIndex()].get(), 0, nullptr);
+ }
+
+private:
+ VulkanContext *GetContext() const { return VulkanContext::Instance(); }
+ void CreatePipeline();
+
+ vk::RenderPass renderPass;
+ vk::UniquePipeline pipeline;
+ vk::UniqueSampler sampler;
+ std::vector descriptorSets;
+ vk::UniquePipelineLayout pipelineLayout;
+ vk::UniqueDescriptorSetLayout descSetLayout;
+ ShaderManager *shaderManager;
+ SamplerManager *samplerManager;
+};
diff --git a/core/rend/vulkan/shaders.cpp b/core/rend/vulkan/shaders.cpp
index 39da03265..6d912d660 100644
--- a/core/rend/vulkan/shaders.cpp
+++ b/core/rend/vulkan/shaders.cpp
@@ -295,6 +295,35 @@ void main()
}
)";
+static const char QuadVertexShaderSource[] = R"(
+#version 400
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (location = 0) out vec2 outUV;
+
+void main()
+{
+ outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
+ gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
+}
+)";
+
+static const char QuadFragmentShaderSource[] = R"(
+#version 400
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (binding = 0) uniform sampler2D tex;
+layout (location = 0) in vec2 inUV;
+layout (location = 0) out vec4 FragColor;
+
+void main()
+{
+ FragColor = texture(tex, inUV);
+}
+)";
+
static const TBuiltInResource DefaultTBuiltInResource = {
/* .MaxLights = */ 32,
/* .MaxClipPlanes = */ 6,
@@ -501,3 +530,13 @@ vk::UniqueShaderModule ShaderManager::compileModVolFragmentShader()
{
return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eFragment, ModVolFragmentShaderSource);
}
+
+vk::UniqueShaderModule ShaderManager::compileQuadVertexShader()
+{
+ return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eVertex, QuadVertexShaderSource);
+}
+
+vk::UniqueShaderModule ShaderManager::compileQuadFragmentShader()
+{
+ return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eFragment, QuadFragmentShaderSource);
+}
diff --git a/core/rend/vulkan/shaders.h b/core/rend/vulkan/shaders.h
index 6896a9736..6360365e5 100644
--- a/core/rend/vulkan/shaders.h
+++ b/core/rend/vulkan/shaders.h
@@ -99,6 +99,18 @@ public:
modVolShader = compileModVolFragmentShader();
return *modVolShader;
}
+ vk::ShaderModule GetQuadVertexShader()
+ {
+ if (!quadVertexShader)
+ quadVertexShader = compileQuadVertexShader();
+ return *quadVertexShader;
+ }
+ vk::ShaderModule GetQuadFragmentShader()
+ {
+ if (!quadFragmentShader)
+ quadFragmentShader = compileQuadFragmentShader();
+ return *quadFragmentShader;
+ }
private:
template
@@ -114,9 +126,13 @@ private:
vk::UniqueShaderModule compileShader(const FragmentShaderParams& params);
vk::UniqueShaderModule compileModVolVertexShader();
vk::UniqueShaderModule compileModVolFragmentShader();
+ vk::UniqueShaderModule compileQuadVertexShader();
+ vk::UniqueShaderModule compileQuadFragmentShader();
std::map vertexShaders;
std::map fragmentShaders;
vk::UniqueShaderModule modVolVertexShader;
vk::UniqueShaderModule modVolShader;
+ vk::UniqueShaderModule quadVertexShader;
+ vk::UniqueShaderModule quadFragmentShader;
};
diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp
index 3959884a0..beefed3c9 100644
--- a/core/rend/vulkan/texture.cpp
+++ b/core/rend/vulkan/texture.cpp
@@ -35,7 +35,6 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk:
break;
case vk::ImageLayout::eGeneral: // sourceAccessMask is empty
case vk::ImageLayout::eUndefined:
-// case vk::ImageLayout::eShaderReadOnlyOptimal:
break;
case vk::ImageLayout::eShaderReadOnlyOptimal:
sourceAccessMask = vk::AccessFlagBits::eShaderRead;
@@ -287,7 +286,7 @@ void Texture::GenerateMipmaps()
for (int i = 1; i < mipmapLevels; i++)
{
- // Transition previous mipmap level from dst optimal to src optimal
+ // Transition previous mipmap level from dst optimal/preinit to src optimal
barrier.subresourceRange.baseMipLevel = i - 1;
if (i == 1 && !needsStaging)
{
diff --git a/core/rend/vulkan/vulkan.h b/core/rend/vulkan/vulkan.h
index 003f707b1..8c6cd9344 100644
--- a/core/rend/vulkan/vulkan.h
+++ b/core/rend/vulkan/vulkan.h
@@ -52,8 +52,8 @@ public:
vk::UniqueDevice& GetDevice() { return device; }
vk::PipelineCache GetPipelineCache() const { return *pipelineCache; }
vk::RenderPass GetRenderPass() const { return *renderPass; }
- vk::CommandPool GetCurrentCommandPool() const { return *commandPools[currentImage]; }
- vk::CommandBuffer GetCurrentCommandBuffer() const { return *commandBuffers[currentImage]; }
+ vk::CommandPool GetCurrentCommandPool() const { return *commandPools[GetCurrentImageIndex()]; }
+ vk::CommandBuffer GetCurrentCommandBuffer() const { return *commandBuffers[GetCurrentImageIndex()]; }
vk::DescriptorPool GetDescriptorPool() const { return *descriptorPool; }
vk::Extent2D GetViewPort() const { return { width, height }; }
int GetSwapChainSize() const { return (int)imageViews.size(); }
@@ -93,6 +93,7 @@ private:
}
bool rendering = false;
+ bool renderDone = false;
u32 width = 0;
u32 height = 0;
vk::UniqueInstance instance;
diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp
index 514f11747..f0b086145 100644
--- a/core/rend/vulkan/vulkan_context.cpp
+++ b/core/rend/vulkan/vulkan_context.cpp
@@ -537,16 +537,21 @@ void VulkanContext::EndFrame()
graphicsQueue.submit(1, &submitInfo, *drawFences[currentImage]);
verify(rendering);
rendering = false;
+ renderDone = true;
}
void VulkanContext::Present()
{
- try {
- presentQueue.presentKHR(vk::PresentInfoKHR(1, &(*renderCompleteSemaphores[currentSemaphore]), 1, &(*swapChain), ¤tImage));
- currentSemaphore = (currentSemaphore + 1) % imageViews.size();
- } catch (const vk::OutOfDateKHRError& e) {
- // Sometimes happens when resizing the window
- INFO_LOG(RENDERER, "vk::OutOfDateKHRError");
+ if (renderDone)
+ {
+ try {
+ presentQueue.presentKHR(vk::PresentInfoKHR(1, &(*renderCompleteSemaphores[currentSemaphore]), 1, &(*swapChain), ¤tImage));
+ currentSemaphore = (currentSemaphore + 1) % imageViews.size();
+ } catch (const vk::OutOfDateKHRError& e) {
+ // Sometimes happens when resizing the window
+ INFO_LOG(RENDERER, "vk::OutOfDateKHRError");
+ }
+ renderDone = false;
}
}
diff --git a/core/rend/vulkan/vulkan_renderer.cpp b/core/rend/vulkan/vulkan_renderer.cpp
index 3761203d2..d1d43c9e2 100644
--- a/core/rend/vulkan/vulkan_renderer.cpp
+++ b/core/rend/vulkan/vulkan_renderer.cpp
@@ -19,12 +19,14 @@
along with Flycast. If not, see .
*/
#include
+#include
#include "vulkan.h"
#include "hw/pvr/Renderer_if.h"
#include "allocator.h"
#include "commandpool.h"
#include "drawer.h"
#include "shaders.h"
+#include "../gui.h"
extern bool ProcessFrame(TA_context* ctx);
@@ -38,9 +40,14 @@ public:
texCommandPool.Init();
texAllocator.SetChunkSize(16 * 1024 * 1024);
- textureDrawer.Init(&samplerManager, &shaderManager, &texAllocator);
- textureDrawer.SetCommandPool(&texCommandPool);
+ while (textureDrawer.size() < 2)
+ textureDrawer.emplace_back();
+ textureDrawer[0].Init(&samplerManager, &shaderManager, &texAllocator);
+ textureDrawer[0].SetCommandPool(&texCommandPool);
+ textureDrawer[1].Init(&samplerManager, &shaderManager, &texAllocator);
+ textureDrawer[1].SetCommandPool(&texCommandPool);
screenDrawer.Init(&samplerManager, &shaderManager);
+ quadPipeline.Init(&shaderManager);
return true;
}
@@ -61,21 +68,73 @@ public:
shaderManager.Term();
}
- void RenderFramebuffer()
+ bool RenderFramebuffer()
{
- // TODO
+ if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
+ return false;
+
+ PixelBuffer pb;
+ int width;
+ int height;
+ ReadFramebuffer(pb, width, height);
+
+ if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
+ framebufferTextures.resize(GetContext()->GetSwapChainSize());
+ std::unique_ptr& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
+ if (!curTexture)
+ {
+ curTexture = std::unique_ptr(new Texture(GetContext()->GetPhysicalDevice(), *GetContext()->GetDevice(), &texAllocator));
+ curTexture->tex_type = TextureType::_8888;
+ curTexture->tcw.full = 0;
+ curTexture->tsp.full = 0;
+ }
+ curTexture->SetCommandBuffer(texCommandPool.Allocate());
+ curTexture->UploadToGPU(width, height, (u8*)pb.data());
+ curTexture->SetCommandBuffer(nullptr);
+ texCommandPool.EndFrame();
+
+ float screen_stretching = settings.rend.ScreenStretching / 100.f;
+ float dc2s_scale_h, ds2s_offs_x;
+ if (settings.rend.Rotate90)
+ {
+ dc2s_scale_h = screen_height / 640.0f;
+ ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2;
+ }
+ else
+ {
+ dc2s_scale_h = screen_height / 480.0f;
+ ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2;
+ }
+
+ vk::CommandBuffer cmdBuffer = screenDrawer.BeginRenderPass();
+
+ vk::Pipeline pipeline = quadPipeline.GetPipeline();
+ cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
+
+ quadPipeline.SetTexture(curTexture.get());
+ quadPipeline.BindDescriptorSets(cmdBuffer);
+
+ // FIXME scaling, stretching...
+ vk::Viewport viewport(ds2s_offs_x, 0.f, screen_width - ds2s_offs_x * 2, (float)screen_height);
+ cmdBuffer.setViewport(0, 1, &viewport);
+ cmdBuffer.draw(3, 1, 0, 0);
+
+ gui_display_osd();
+
+ screenDrawer.EndRenderPass();
+
+ return true;
}
bool Process(TA_context* ctx) override
{
+ texCommandPool.BeginFrame();
+
if (ctx->rend.isRenderFramebuffer)
{
- RenderFramebuffer();
- return false;
+ return RenderFramebuffer();
}
- texCommandPool.BeginFrame();
-
bool result = ProcessFrame(ctx);
if (result)
@@ -93,8 +152,15 @@ public:
bool Render() override
{
+ if (pvrrc.isRenderFramebuffer)
+ return true;
+
if (pvrrc.isRTT)
- return textureDrawer.Draw(fogTexture.get());
+ {
+ textureDrawer[curTextureDrawer].Draw(fogTexture.get());
+ curTextureDrawer ^= 1;
+ return false;
+ }
else
return screenDrawer.Draw(fogTexture.get());
}
@@ -155,8 +221,11 @@ private:
SamplerManager samplerManager;
ShaderManager shaderManager;
ScreenDrawer screenDrawer;
- TextureDrawer textureDrawer;
+ std::vector textureDrawer;
+ int curTextureDrawer = 0;
VulkanAllocator texAllocator;
+ std::vector> framebufferTextures;
+ QuadPipeline quadPipeline;
};
Renderer* rend_Vulkan()