vulkan: direct framebuffer writes support
alternate between 2 texture drawers Fix scissor scale when pixel_double is on Ingore Present() when nothing has been rendered
This commit is contained in:
parent
fb52b38ac3
commit
e3a997b642
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "allocator.h"
|
||||
|
||||
SimpleAllocator SimpleAllocator::instance;
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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<PolyParam>& 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<std::vector<SortTrigDrawParam>> 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(); }
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <volk/volk.h>
|
||||
|
||||
#define IMGUI_VK_QUEUED_FRAMES 2
|
||||
#define IMGUI_VK_QUEUED_FRAMES 3
|
||||
|
||||
// Please zero-clear before use.
|
||||
struct ImGui_ImplVulkan_InitInfo
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<vk::WriteDescriptorSet> 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<vk::UniqueDescriptorSet> descriptorSets;
|
||||
vk::UniquePipelineLayout pipelineLayout;
|
||||
vk::UniqueDescriptorSetLayout descSetLayout;
|
||||
ShaderManager *shaderManager;
|
||||
SamplerManager *samplerManager;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<typename T>
|
||||
|
@ -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<u32, vk::UniqueShaderModule> vertexShaders;
|
||||
std::map<u32, vk::UniqueShaderModule> fragmentShaders;
|
||||
vk::UniqueShaderModule modVolVertexShader;
|
||||
vk::UniqueShaderModule modVolShader;
|
||||
vk::UniqueShaderModule quadVertexShader;
|
||||
vk::UniqueShaderModule quadFragmentShader;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <memory>
|
||||
#include <math.h>
|
||||
#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<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(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> textureDrawer;
|
||||
int curTextureDrawer = 0;
|
||||
VulkanAllocator texAllocator;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
QuadPipeline quadPipeline;
|
||||
};
|
||||
|
||||
Renderer* rend_Vulkan()
|
||||
|
|
Loading…
Reference in New Issue