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