/* 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 "rend/sorter.h" #include "rend/tileclip.h" #include "rend/transform_matrix.h" #include "vulkan.h" #include "buffer.h" #include "commandpool.h" #include "pipeline.h" #include "shaders.h" #include "texture.h" #include #include class BaseDrawer { public: void SetScissor(const vk::CommandBuffer& cmdBuffer, const vk::Rect2D& scissor) { if (scissor != currentScissor) { cmdBuffer.setScissor(0, scissor); currentScissor = scissor; } } void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } protected: VulkanContext *GetContext() const { return VulkanContext::Instance(); } TileClipping SetTileClip(u32 val, vk::Rect2D& clipRect); void SetBaseScissor(); void SetProvokingVertices(); u32 align(vk::DeviceSize offset, u32 alignment) { return (u32)(alignment - (offset & (alignment - 1))); } template T MakeFragmentUniforms() { T fragUniforms; //VERT and RAM fog color constants u8* fog_colvert_bgra = (u8*)&FOG_COL_VERT; u8* fog_colram_bgra = (u8*)&FOG_COL_RAM; fragUniforms.sp_FOG_COL_VERT[0] = fog_colvert_bgra[2] / 255.0f; fragUniforms.sp_FOG_COL_VERT[1] = fog_colvert_bgra[1] / 255.0f; fragUniforms.sp_FOG_COL_VERT[2] = fog_colvert_bgra[0] / 255.0f; fragUniforms.sp_FOG_COL_RAM[0] = fog_colram_bgra[2] / 255.0f; fragUniforms.sp_FOG_COL_RAM[1] = fog_colram_bgra[1] / 255.0f; fragUniforms.sp_FOG_COL_RAM[2] = fog_colram_bgra[0] / 255.0f; //Fog density constant u8* fog_density = (u8*)&FOG_DENSITY; float fog_den_mant = fog_density[1] / 128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 s32 fog_den_exp = (s8)fog_density[0]; fragUniforms.sp_FOG_DENSITY = fog_den_mant * powf(2.0f, fog_den_exp) * settings.rend.ExtraDepthScale; fragUniforms.colorClampMin[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; fragUniforms.colorClampMin[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; fragUniforms.colorClampMin[2] = ((pvrrc.fog_clamp_min >> 0) & 0xFF) / 255.0f; fragUniforms.colorClampMin[3] = ((pvrrc.fog_clamp_min >> 24) & 0xFF) / 255.0f; fragUniforms.colorClampMax[0] = ((pvrrc.fog_clamp_max >> 16) & 0xFF) / 255.0f; fragUniforms.colorClampMax[1] = ((pvrrc.fog_clamp_max >> 8) & 0xFF) / 255.0f; fragUniforms.colorClampMax[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f; fragUniforms.colorClampMax[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f; fragUniforms.cp_AlphaTestValue = (PT_ALPHA_REF & 0xFF) / 255.0f; return fragUniforms; } vk::Rect2D baseScissor; vk::Rect2D currentScissor; TransformMatrix matrices; CommandPool *commandPool = nullptr; }; class Drawer : public BaseDrawer { public: virtual ~Drawer() = default; bool Draw(const Texture *fogTexture, const Texture *paletteTexture); virtual void EndRenderPass() = 0; protected: virtual vk::CommandBuffer BeginRenderPass() = 0; void NewImage() { imageIndex = (imageIndex + 1) % GetContext()->GetSwapChainSize(); if (perStripSorting != settings.rend.PerStripSorting) { perStripSorting = settings.rend.PerStripSorting; pipelineManager->Reset(); } } void Init(SamplerManager *samplerManager, PipelineManager *pipelineManager) { this->pipelineManager = pipelineManager; this->samplerManager = samplerManager; size_t size = GetContext()->GetSwapChainSize(); if (descriptorSets.size() > size) descriptorSets.resize(size); else while (descriptorSets.size() < size) { descriptorSets.emplace_back(); descriptorSets.back().Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout()); } } int GetCurrentImage() const { return imageIndex; } DescriptorSets& GetCurrentDescSet() { return descriptorSets[GetCurrentImage()]; } BufferData* GetMainBuffer(u32 size) { if (mainBuffers.empty()) { for (size_t i = 0; i < GetContext()->GetSwapChainSize(); i++) mainBuffers.push_back(std::unique_ptr(new BufferData(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(newSize, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eUniformBuffer)); } return mainBuffers[GetCurrentImage()].get(); }; vk::CommandBuffer currentCommandBuffer; SamplerManager *samplerManager = nullptr; private: 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); int imageIndex = 0; struct { vk::DeviceSize indexOffset = 0; vk::DeviceSize modVolOffset = 0; vk::DeviceSize vertexUniformOffset = 0; vk::DeviceSize fragmentUniformOffset = 0; } offsets; std::vector descriptorSets; std::vector> mainBuffers; PipelineManager *pipelineManager = nullptr; // Per-triangle sort results std::vector> sortedPolys; std::vector> sortedIndexes; u32 sortedIndexCount = 0; bool perStripSorting = false; }; class ScreenDrawer : public Drawer { public: void Init(SamplerManager *samplerManager, ShaderManager *shaderManager); vk::RenderPass GetRenderPass() const { return *renderPass; } virtual void EndRenderPass() override; protected: virtual vk::CommandBuffer BeginRenderPass() override; private: std::unique_ptr screenPipelineManager; vk::UniqueRenderPass renderPass; std::vector framebuffers; std::vector> colorAttachments; std::unique_ptr depthAttachment; vk::Extent2D viewport; int currentScreenScaling = 0; ShaderManager *shaderManager = nullptr; }; class TextureDrawer : public Drawer { public: void Init(SamplerManager *samplerManager, ShaderManager *shaderManager, TextureCache *textureCache); virtual void EndRenderPass() override; protected: virtual vk::CommandBuffer BeginRenderPass() override; private: u32 width = 0; u32 height = 0; u32 textureAddr = 0; std::unique_ptr rttPipelineManager; Texture *texture = nullptr; std::vector framebuffers; std::unique_ptr colorAttachment; std::unique_ptr depthAttachment; TextureCache *textureCache = nullptr; };