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:
Flyinghead 2019-10-14 17:41:49 +02:00
parent fb52b38ac3
commit e3a997b642
13 changed files with 384 additions and 50 deletions

View File

@ -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;

View File

@ -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:

View File

@ -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)
{

View File

@ -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(); }

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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;

View File

@ -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), &currentImage));
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), &currentImage));
currentSemaphore = (currentSemaphore + 1) % imageViews.size();
} catch (const vk::OutOfDateKHRError& e) {
// Sometimes happens when resizing the window
INFO_LOG(RENDERER, "vk::OutOfDateKHRError");
}
renderDone = false;
}
}

View File

@ -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()