/* Created on: Oct 8, 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 "rend/sorter.h" #include "rend/transform_matrix.h" #include "vulkan.h" #include "buffer.h" #include "commandpool.h" #include "pipeline.h" #include "shaders.h" #include "texture.h" enum class TileClipping { Inside, // render stuff outside the region Off, Outside // render stuff inside the region }; class Drawer { public: Drawer() = default; virtual ~Drawer() {} bool Draw(const Texture *fogTexture); Drawer(const Drawer& other) = delete; 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, PipelineManager *pipelineManager) { this->pipelineManager = pipelineManager; this->samplerManager = samplerManager; } virtual DescriptorSets& GetCurrentDescSet() = 0; virtual BufferData *GetMainBuffer(u32 size) = 0; VulkanContext *GetContext() const { return VulkanContext::Instance(); } PipelineManager *pipelineManager = nullptr; vk::Rect2D baseScissor; TransformMatrix matrices; private: TileClipping SetTileClip(u32 val, vk::Rect2D& clipRect); void SortTriangles(); void DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const PolyParam& poly, u32 first, u32 count); void DrawSorted(const vk::CommandBuffer& cmdBuffer, const std::vector& polys); 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 align(vk::DeviceSize offset, u32 alignment) { return (u32)(alignment - (offset & (alignment - 1))); } struct { vk::DeviceSize indexOffset = 0; vk::DeviceSize modVolOffset = 0; vk::DeviceSize vertexUniformOffset = 0; vk::DeviceSize fragmentUniformOffset = 0; } offsets; // Per-triangle sort results std::vector> sortedPolys; std::vector> sortedIndexes; u32 sortedIndexCount = 0; SamplerManager *samplerManager = nullptr; vk::Rect2D currentScissor; }; class ScreenDrawer : public Drawer { public: void Init(SamplerManager *samplerManager, ShaderManager *shaderManager) { if (!screenPipelineManager) screenPipelineManager = std::unique_ptr(new PipelineManager()); screenPipelineManager->Init(shaderManager); Drawer::Init(samplerManager, screenPipelineManager.get()); if (descriptorSets.size() > GetContext()->GetSwapChainSize()) descriptorSets.resize(GetContext()->GetSwapChainSize()); else while (descriptorSets.size() < GetContext()->GetSwapChainSize()) { descriptorSets.push_back(DescriptorSets()); descriptorSets.back().Init(samplerManager, screenPipelineManager->GetPipelineLayout(), screenPipelineManager->GetPerFrameDSLayout(), screenPipelineManager->GetPerPolyDSLayout()); } } ScreenDrawer() = default; ScreenDrawer(const ScreenDrawer& other) = delete; 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()]; } virtual BufferData* GetMainBuffer(u32 size) override { if (mainBuffers.empty()) { for (int i = 0; i < GetContext()->GetSwapChainSize(); i++) mainBuffers.push_back(std::unique_ptr(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice(), std::max(512 * 1024u, size), vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eUniformBuffer))); } else if (mainBuffers[GetCurrentImage()]->bufferSize < size) { u32 newSize = mainBuffers[GetCurrentImage()]->bufferSize; while (newSize < size) newSize *= 2; INFO_LOG(RENDERER, "Increasing main buffer size %d -> %d", (u32)mainBuffers[GetCurrentImage()]->bufferSize, newSize); mainBuffers[GetCurrentImage()] = std::unique_ptr(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice(), newSize, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eUniformBuffer)); } return mainBuffers[GetCurrentImage()].get(); }; private: int GetCurrentImage() { return GetContext()->GetCurrentImageIndex(); } std::vector descriptorSets; std::vector> mainBuffers; std::unique_ptr screenPipelineManager; }; class TextureDrawer : public Drawer { public: void Init(SamplerManager *samplerManager, VulkanAllocator *texAllocator, RttPipelineManager *pipelineManager, TextureCache *textureCache) { Drawer::Init(samplerManager, pipelineManager); descriptorSets.Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout()); fence = GetContext()->GetDevice().createFenceUnique(vk::FenceCreateInfo()); this->texAllocator = texAllocator; this->textureCache = textureCache; } void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } TextureDrawer() = default; TextureDrawer(const TextureDrawer& other) = delete; TextureDrawer(TextureDrawer&& other) = default; TextureDrawer& operator=(const TextureDrawer& other) = delete; TextureDrawer& operator=(TextureDrawer&& other) = default; virtual void EndRenderPass() override; protected: virtual vk::CommandBuffer BeginRenderPass() override; DescriptorSets& GetCurrentDescSet() override { return descriptorSets; } virtual BufferData* GetMainBuffer(u32 size) override { if (!mainBuffer || mainBuffer->bufferSize < size) { u32 newSize = mainBuffer ? mainBuffer->bufferSize : 128 * 1024u; while (newSize < size) newSize *= 2; INFO_LOG(RENDERER, "Increasing RTT main buffer size %d -> %d", !mainBuffer ? 0 : (u32)mainBuffer->bufferSize, newSize); mainBuffer = std::unique_ptr(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice(), newSize, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eUniformBuffer)); } return mainBuffer.get(); } private: u32 width = 0; u32 height = 0; u32 textureAddr = 0; Texture *texture = nullptr; vk::Image colorImage; vk::CommandBuffer currentCommandBuffer; vk::UniqueFramebuffer framebuffer; std::unique_ptr colorAttachment; std::unique_ptr depthAttachment; vk::UniqueFence fence; DescriptorSets descriptorSets; std::unique_ptr mainBuffer; CommandPool *commandPool = nullptr; VulkanAllocator *texAllocator = nullptr; TextureCache *textureCache = nullptr; };