From 6406523720d4b26116756f078777f942ed4f506a Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Wed, 9 Oct 2019 21:16:12 +0200 Subject: [PATCH] vulkan: RTT support --- core/rend/vulkan/buffer.h | 10 + core/rend/vulkan/commandpool.h | 104 +++++ core/rend/vulkan/drawer.cpp | 609 +++++++++++++++++++++++++++ core/rend/vulkan/drawer.h | 179 ++++++++ core/rend/vulkan/pipeline.cpp | 16 +- core/rend/vulkan/pipeline.h | 270 +++++++----- core/rend/vulkan/shaders.h | 4 + core/rend/vulkan/texture.cpp | 47 ++- core/rend/vulkan/texture.h | 165 +++++++- core/rend/vulkan/utils.h | 17 - core/rend/vulkan/vulkan.h | 13 +- core/rend/vulkan/vulkan_context.cpp | 19 +- core/rend/vulkan/vulkan_renderer.cpp | 554 ++---------------------- 13 files changed, 1327 insertions(+), 680 deletions(-) create mode 100644 core/rend/vulkan/commandpool.h create mode 100644 core/rend/vulkan/drawer.cpp create mode 100644 core/rend/vulkan/drawer.h diff --git a/core/rend/vulkan/buffer.h b/core/rend/vulkan/buffer.h index 1becd317a..671f4c052 100644 --- a/core/rend/vulkan/buffer.h +++ b/core/rend/vulkan/buffer.h @@ -53,6 +53,16 @@ struct BufferData device.unmapMemory(*this->deviceMemory); } + void download(vk::Device const& device, u32 size, void *data, u32 offset = 0) const + { + verify((m_propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent) && (m_propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible)); + verify(offset + size <= m_size); + + void* dataPtr = device.mapMemory(*this->deviceMemory, offset, size); + memcpy(data, dataPtr, size); + device.unmapMemory(*this->deviceMemory); + } + vk::UniqueDeviceMemory deviceMemory; vk::UniqueBuffer buffer; vk::DeviceSize m_size; diff --git a/core/rend/vulkan/commandpool.h b/core/rend/vulkan/commandpool.h new file mode 100644 index 000000000..0bb31d35d --- /dev/null +++ b/core/rend/vulkan/commandpool.h @@ -0,0 +1,104 @@ +/* + 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 "vulkan.h" + +class CommandPool +{ +public: + void Init() + { + size_t size = VulkanContext::Instance()->GetSwapChainSize(); + + if (commandPools.size() > size) + { + commandPools.resize(size); + fences.resize(size); + } + else + { + while (commandPools.size() < size) + { + commandPools.emplace_back(std::move(VulkanContext::Instance()->GetDevice()->createCommandPoolUnique( + vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlagBits::eTransient, VulkanContext::Instance()->GetGraphicsQueueFamilyIndex())))); + fences.emplace_back(std::move(VulkanContext::Instance()->GetDevice()->createFenceUnique(vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled)))); + } + } + if (freeBuffers.size() != size) + freeBuffers.resize(size); + if (inFlightBuffers.size() != size) + inFlightBuffers.resize(size); + } + + void Term() + { + freeBuffers.clear(); + inFlightBuffers.clear(); + fences.clear(); + commandPools.clear(); + } + + void EndFrame() + { + vk::CommandBuffer commandBuffer = Allocate(); + commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + commandBuffer.end(); + VulkanContext::Instance()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &commandBuffer), *fences[index]); + } + + void BeginFrame() + { + index = (index + 1) % VulkanContext::Instance()->GetSwapChainSize(); + VulkanContext::Instance()->GetDevice()->waitForFences(1, &fences[index].get(), true, UINT64_MAX); + VulkanContext::Instance()->GetDevice()->resetFences(1, &fences[index].get()); + std::vector& inFlight = inFlightBuffers[index]; + std::vector& freeBuf = freeBuffers[index]; + while (!inFlight.empty()) + { + freeBuf.emplace_back(std::move(inFlight.back())); + inFlight.pop_back(); + } + VulkanContext::Instance()->GetDevice()->resetCommandPool(*commandPools[index], vk::CommandPoolResetFlagBits::eReleaseResources); + } + + vk::CommandBuffer Allocate() + { + if (freeBuffers[index].empty()) + { + inFlightBuffers[index].emplace_back(std::move( + VulkanContext::Instance()->GetDevice()->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(*commandPools[index], vk::CommandBufferLevel::ePrimary, 1)) + .front())); + } + else + { + inFlightBuffers[index].emplace_back(std::move(freeBuffers[index].back())); + freeBuffers[index].pop_back(); + } + return *inFlightBuffers[index].back(); + } + +private: + int index = 0; + std::vector> freeBuffers; + std::vector> inFlightBuffers; + std::vector commandPools; + std::vector fences; +}; diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp new file mode 100644 index 000000000..a886c3eb0 --- /dev/null +++ b/core/rend/vulkan/drawer.cpp @@ -0,0 +1,609 @@ +/* + 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 . +*/ +#include +#include "drawer.h" +#include "../gui.h" +#include "hw/pvr/pvr_mem.h" + +void Drawer::SortTriangles() +{ + sortedPolys.resize(pvrrc.render_passes.used()); + sortedIndexes.resize(pvrrc.render_passes.used()); + sortedIndexCount = 0; + RenderPass previousPass = {}; + + for (int render_pass = 0; render_pass < pvrrc.render_passes.used(); render_pass++) + { + const RenderPass& current_pass = pvrrc.render_passes.head()[render_pass]; + sortedIndexes[render_pass].clear(); + if (current_pass.autosort) + { + GenSorted(previousPass.tr_count, current_pass.tr_count - previousPass.tr_count, sortedPolys[render_pass], sortedIndexes[render_pass]); + for (auto& poly : sortedPolys[render_pass]) + poly.first += sortedIndexCount; + sortedIndexCount += sortedIndexes[render_pass].size(); + } + else + sortedPolys[render_pass].clear(); + previousPass = current_pass; + } +} + +// FIXME Code dup +s32 Drawer::SetTileClip(u32 val, float *values) +{ + if (!settings.rend.Clipping) + return 0; + + u32 clipmode = val >> 28; + s32 clip_mode; + if (clipmode < 2) + { + clip_mode = 0; //always passes + } + else if (clipmode & 1) + clip_mode = -1; //render stuff outside the region + else + clip_mode = 1; //render stuff inside the region + + float csx = 0, csy = 0, cex = 0, cey = 0; + + + csx = (float)(val & 63); + cex = (float)((val >> 6) & 63); + csy = (float)((val >> 12) & 31); + cey = (float)((val >> 17) & 31); + csx = csx * 32; + cex = cex * 32 + 32; + csy = csy * 32; + cey = cey * 32 + 32; + + if (csx <= 0 && csy <= 0 && cex >= 640 && cey >= 480) + return 0; + + if (values != nullptr && clip_mode) + { + if (!pvrrc.isRTT) + { + csx /= scale_x; + csy /= scale_y; + cex /= scale_x; + cey /= scale_y; + float dc2s_scale_h; + float ds2s_offs_x; + float screen_stretching = settings.rend.ScreenStretching / 100.f; + + if (settings.rend.Rotate90) + { + float t = cex; + cex = cey; + cey = 640 - csx; + csx = csy; + csy = 640 - t; + dc2s_scale_h = screen_height / 640.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2; + } + else + { + dc2s_scale_h = screen_height / 480.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2; + } + csx = csx * dc2s_scale_h * screen_stretching + ds2s_offs_x; + cex = cex * dc2s_scale_h * screen_stretching + ds2s_offs_x; + csy = csy * dc2s_scale_h; + cey = cey * dc2s_scale_h; + } + else if (!settings.rend.RenderToTextureBuffer) + { + csx *= settings.rend.RenderToTextureUpscale; + csy *= settings.rend.RenderToTextureUpscale; + cex *= settings.rend.RenderToTextureUpscale; + cey *= settings.rend.RenderToTextureUpscale; + } + values[0] = csx; + values[1] = csy; + values[2] = cex; + values[3] = cey; + } + + return clip_mode; +} + +void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const PolyParam& poly, u32 first, u32 count) +{ + float trilinearAlpha; + if (poly.pcw.Texture && poly.tsp.FilterMode > 1 && listType != ListType_Punch_Through) + { + trilinearAlpha = 0.25 * (poly.tsp.MipMapD & 0x3); + if (poly.tsp.FilterMode == 2) + // Trilinear pass A + trilinearAlpha = 1.0 - trilinearAlpha; + } + else + trilinearAlpha = 1.f; + + std::array pushConstants = { 0, 0, 0, 0, trilinearAlpha }; + SetTileClip(poly.tileclip, &pushConstants[0]); + cmdBuffer.pushConstants(pipelineManager->GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); + + if (poly.pcw.Texture) + GetCurrentDescSet().SetTexture(poly.texid, poly.tsp); + + vk::Pipeline pipeline = pipelineManager->GetPipeline(listType, sortTriangles, poly); + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + if (poly.pcw.Texture) + GetCurrentDescSet().BindPerPolyDescriptorSets(cmdBuffer, poly.texid, poly.tsp); + + cmdBuffer.drawIndexed(count, 1, first, 0, 0); +} + +void Drawer::DrawSorted(const vk::CommandBuffer& cmdBuffer, const std::vector& polys) +{ + for (const SortTrigDrawParam& param : polys) + { + DrawPoly(cmdBuffer, ListType_Translucent, true, *param.ppid, pvrrc.idx.used() + param.first, param.count); + } +} + +void Drawer::DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const List& polys, u32 first, u32 count) +{ + for (u32 i = first; i < count; i++) + { + const PolyParam &pp = polys.head()[i]; + DrawPoly(cmdBuffer, listType, sortTriangles, pp, pp.first, pp.count); + } +} + +void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int count) +{ + if (count == 0 || pvrrc.modtrig.used() == 0) + return; + + vk::DeviceSize offsets[] = { (vk::DeviceSize)pvrrc.verts.bytes() }; + vk::Buffer buffer = GetMainBuffer(0)->buffer.get(); + cmdBuffer.bindVertexBuffers(0, 1, &buffer, offsets); + + ModifierVolumeParam* params = &pvrrc.global_param_mvo.head()[first]; + + int mod_base = -1; + vk::Pipeline pipeline; + + for (u32 cmv = 0; cmv < count; cmv++) + { + ModifierVolumeParam& param = params[cmv]; + + if (param.count == 0) + continue; + + u32 mv_mode = param.isp.DepthMode; + + if (mod_base == -1) + mod_base = param.first; + + if (!param.isp.VolumeLast && mv_mode > 0) + pipeline = pipelineManager->GetModifierVolumePipeline(ModVolMode::Or); // OR'ing (open volume or quad) + else + pipeline = pipelineManager->GetModifierVolumePipeline(ModVolMode::Xor); // XOR'ing (closed volume) + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + cmdBuffer.draw(param.count * 3, 1, param.first * 3, 0); + + if (mv_mode == 1 || mv_mode == 2) + { + // Sum the area + pipeline = pipelineManager->GetModifierVolumePipeline(mv_mode == 1 ? ModVolMode::Inclusion : ModVolMode::Exclusion); + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + cmdBuffer.draw((param.first + param.count - mod_base) * 3, 1, mod_base * 3, 0); + mod_base = -1; + } + } + offsets[0] = 0; + cmdBuffer.bindVertexBuffers(0, 1, &buffer, offsets); + + std::array pushConstants = { 1 - FPU_SHAD_SCALE.scale_factor / 256.f, 0, 0, 0, 0 }; + cmdBuffer.pushConstants(pipelineManager->GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); + + pipeline = pipelineManager->GetModifierVolumePipeline(ModVolMode::Final); + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + cmdBuffer.drawIndexed(4, 1, 0, 0, 0); +} + +void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms, u32& vertexUniformsOffset) +{ + vertexUniformsOffset = pvrrc.verts.bytes() + pvrrc.idx.bytes() + pvrrc.modtrig.bytes() + sortedIndexCount * sizeof(u32); + u32 totalSize = vertexUniformsOffset + sizeof(VertexShaderUniforms) + sizeof(FragmentShaderUniforms); + + BufferData *buffer = GetMainBuffer(totalSize); + + std::vector chunks; + std::vector chunkSizes; + + chunks.push_back(pvrrc.verts.head()); + chunkSizes.push_back(pvrrc.verts.bytes()); + chunks.push_back(pvrrc.modtrig.head()); + chunkSizes.push_back(pvrrc.modtrig.bytes()); + chunks.push_back(pvrrc.idx.head()); + chunkSizes.push_back(pvrrc.idx.bytes()); + for (const std::vector& idx : sortedIndexes) + { + if (!idx.empty()) + { + chunks.push_back(&idx[0]); + chunkSizes.push_back(idx.size() * sizeof(u32)); + } + } + chunks.push_back(&vertexUniforms); + chunkSizes.push_back(sizeof(vertexUniforms)); + chunks.push_back(&fragmentUniforms); + chunkSizes.push_back(sizeof(fragmentUniforms)); + buffer->upload(GetContext()->GetDevice().get(), chunks.size(), &chunkSizes[0], &chunks[0]); +} + +bool Drawer::Draw(const Texture *fogTexture) +{ + extern float fb_scale_x, fb_scale_y; + extern bool fog_needs_update; + + bool is_rtt = pvrrc.isRTT; + float dc_width = 640; + float dc_height = 480; + + if (is_rtt) + { + dc_width = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; + dc_height = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; + } + + scale_x = 1; + scale_y = 1; + + float scissoring_scale_x = 1; + + if (!is_rtt && !pvrrc.isRenderFramebuffer) + { + 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 + //A second scaling is used here for scissoring + if (VO_CONTROL.pixel_double) + { + scissoring_scale_x = 0.5f; + scale_x *= 0.5f; + } + + if (SCALER_CTL.hscale) + { + scissoring_scale_x /= 2; + scale_x*=2; + } + } + + dc_width *= scale_x; + dc_height *= scale_y; + + float screen_stretching = settings.rend.ScreenStretching / 100.f; + float screen_scaling = settings.rend.ScreenScaling / 100.f; + + float dc2s_scale_h; + float ds2s_offs_x; + + VertexShaderUniforms vtxUniforms; + 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[2] = 1; + vtxUniforms.scale[3] = 1; + } + else + { + if (settings.rend.Rotate90) + { + dc2s_scale_h = screen_height / 640.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2; + vtxUniforms.scale[0] = -2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; + vtxUniforms.scale[1] = 2.0f / dc_width; + vtxUniforms.scale[2] = 1 - 2 * ds2s_offs_x / screen_width; + vtxUniforms.scale[3] = 1; + } + else + { + dc2s_scale_h = screen_height / 480.0f; + ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2; + vtxUniforms.scale[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; + vtxUniforms.scale[1] = 2.0f / dc_height; + vtxUniforms.scale[2] = 1 - 2 * ds2s_offs_x / screen_width; + vtxUniforms.scale[3] = 1; + } + //-1 -> too much to left + } + vtxUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; + + FragmentShaderUniforms fragUniforms; + fragUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; + + //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); + + 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; + + SortTriangles(); + + vk::CommandBuffer cmdBuffer = BeginRenderPass(); + + // Upload vertex and index buffers + u32 vertexUniformsOffset; + UploadMainBuffer(vtxUniforms, fragUniforms, vertexUniformsOffset); + + // Update per-frame descriptor set and bind it + GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), vertexUniformsOffset, fogTexture->GetImageView()); + GetCurrentDescSet().BindPerFrameDescriptorSets(cmdBuffer); + // Reset per-poly descriptor set pool + GetCurrentDescSet().Reset(); + + // Bind vertex and index buffers + const vk::DeviceSize offsets[] = { 0 }; + const vk::Buffer buffer = GetMainBuffer(0)->buffer.get(); + cmdBuffer.bindVertexBuffers(0, 1, &buffer, offsets); + cmdBuffer.bindIndexBuffer(buffer, pvrrc.verts.bytes() + pvrrc.modtrig.bytes(), vk::IndexType::eUint32); + + // FIXME + if (!is_rtt) + cmdBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), GetContext()->GetViewPort())); + + RenderPass previous_pass = {}; + for (int render_pass = 0; render_pass < pvrrc.render_passes.used(); render_pass++) + { + const RenderPass& current_pass = pvrrc.render_passes.head()[render_pass]; + + DEBUG_LOG(RENDERER, "Render pass %d OP %d PT %d TR %d MV %d", render_pass + 1, + current_pass.op_count - previous_pass.op_count, + current_pass.pt_count - previous_pass.pt_count, + current_pass.tr_count - previous_pass.tr_count, + current_pass.mvo_count - previous_pass.mvo_count); + DrawList(cmdBuffer, ListType_Opaque, false, pvrrc.global_param_op, previous_pass.op_count, current_pass.op_count - previous_pass.op_count); + DrawList(cmdBuffer, ListType_Punch_Through, false, pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count - previous_pass.pt_count); + DrawModVols(cmdBuffer, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count); + if (current_pass.autosort) + { + if (!settings.rend.PerStripSorting) + { + DrawSorted(cmdBuffer, sortedPolys[render_pass]); + } + else + { + SortPParams(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); + DrawList(cmdBuffer, ListType_Translucent, true, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); + } + } + else + DrawList(cmdBuffer, ListType_Translucent, false, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); + previous_pass = current_pass; + } + if (!is_rtt) + gui_display_osd(); + + EndRenderPass(); + + return !is_rtt; +} + +vk::CommandBuffer TextureDrawer::BeginRenderPass() +{ + DEBUG_LOG(RENDERER, "RenderToTexture packmode=%d stride=%d - %d,%d -> %d,%d", FB_W_CTRL.fb_packmode, FB_W_LINESTRIDE.stride * 8, + FB_X_CLIP.min, FB_Y_CLIP.min, FB_X_CLIP.max, FB_Y_CLIP.max); + textureAddr = FB_W_SOF1 & VRAM_MASK; + u32 origWidth = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; + u32 origHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; + u32 upscaledWidth = origWidth; + u32 upscaledHeight = origHeight; + int heightPow2 = 2; + while (heightPow2 < upscaledHeight) + heightPow2 *= 2; + int widthPow2 = 2; + while (widthPow2 < upscaledWidth) + widthPow2 *= 2; + + if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + { + upscaledWidth *= settings.rend.RenderToTextureUpscale; + upscaledHeight *= settings.rend.RenderToTextureUpscale; + widthPow2 *= settings.rend.RenderToTextureUpscale; + heightPow2 *= settings.rend.RenderToTextureUpscale; + } + + VulkanContext *context = GetContext(); + vk::Device device = *context->GetDevice(); + + vk::CommandBuffer commandBuffer = commandPool->Allocate(); + commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + + if (widthPow2 != this->width || heightPow2 != this->height || !depthAttachment) + { + if (!depthAttachment) + depthAttachment = std::unique_ptr(new FramebufferAttachment(context->GetPhysicalDevice(), device)); + depthAttachment->Init(widthPow2, heightPow2, vk::Format::eD32SfloatS8Uint); + } + vk::ImageView colorImageView; + vk::ImageLayout colorImageCurrentLayout; + + if (!settings.rend.RenderToTextureBuffer) + { + // TexAddr : fb_rtt.TexAddr, Reserved : 0, StrideSel : 0, ScanOrder : 1 + TCW tcw = { { textureAddr >> 3, 0, 0, 1 } }; + switch (FB_W_CTRL.fb_packmode) { + case 0: + case 3: + tcw.PixelFmt = Pixel1555; + break; + case 1: + tcw.PixelFmt = Pixel565; + break; + case 2: + tcw.PixelFmt = Pixel4444; + break; + } + + TSP tsp = { 0 }; + for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < origWidth; tsp.TexU++); + for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < origHeight; tsp.TexV++); + + texture = static_cast(getTextureCacheData(tsp, tcw, [](){ + return (BaseTextureCacheData *)new Texture(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice()); + })); + if (texture->IsNew()) + texture->Create(); + if (texture->format != vk::Format::eR8G8B8A8Unorm) + { + //texture->Init(newWidth, newHeight, format); + texture->extent = vk::Extent2D(widthPow2, heightPow2); + texture->format = vk::Format::eR8G8B8A8Unorm; + texture->CreateImage(vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled, + vk::ImageLayout::eUndefined, vk::MemoryPropertyFlags(), vk::ImageAspectFlagBits::eColor); + colorImageCurrentLayout = vk::ImageLayout::eUndefined; + } + else + { + colorImageCurrentLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + } + colorImage = *texture->image; + colorImageView = texture->GetImageView(); + } + else + { + if (widthPow2 != this->width || heightPow2 != this->height || !colorAttachment) + { + if (!colorAttachment) + { + colorAttachment = std::unique_ptr(new FramebufferAttachment(VulkanContext::Instance()->GetPhysicalDevice(), + *VulkanContext::Instance()->GetDevice())); + } + colorAttachment->Init(widthPow2, heightPow2, vk::Format::eR8G8B8A8Unorm); + } + colorImage = *colorAttachment->GetImage(); + colorImageView = *colorAttachment->GetImageView(); + colorImageCurrentLayout = vk::ImageLayout::eUndefined; + } + width = widthPow2; + height = heightPow2; + + setImageLayout(commandBuffer, colorImage, vk::Format::eR8G8B8A8Unorm, colorImageCurrentLayout, vk::ImageLayout::eColorAttachmentOptimal); + + vk::ImageView imageViews[] = { + colorImageView, + *depthAttachment->GetImageView(), + }; + framebuffer = context->GetDevice()->createFramebufferUnique(vk::FramebufferCreateInfo(vk::FramebufferCreateFlags(), + pipelineManager->GetRenderPass(), ARRAY_SIZE(imageViews), imageViews, widthPow2, heightPow2, 1)); + + const vk::ClearValue clear_colors[] = { vk::ClearColorValue(std::array { 0.f, 0.f, 0.f, 1.f }), vk::ClearDepthStencilValue { 0.f, 0 } }; + commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(pipelineManager->GetRenderPass(), *framebuffer, + vk::Rect2D( { 0, 0 }, { width, height }), 2, clear_colors), vk::SubpassContents::eInline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)upscaledWidth, (float)upscaledHeight, 1.0f, 0.0f)); + // FIXME + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), { upscaledWidth, upscaledHeight })); + currentCommandBuffer = commandBuffer; + + return commandBuffer; +} + +void TextureDrawer::EndRenderPass() +{ + currentCommandBuffer.endRenderPass(); + + if (settings.rend.RenderToTextureBuffer) + { + vk::BufferImageCopy copyRegion(0, width, height, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), + vk::Extent3D(vk::Extent2D(width, height), 1)); + currentCommandBuffer.copyImageToBuffer(*colorAttachment->GetImage(), vk::ImageLayout::eTransferSrcOptimal, + *colorAttachment->GetBufferData()->buffer, copyRegion); + + vk::BufferMemoryBarrier bufferMemoryBarrier( + vk::AccessFlagBits::eTransferWrite, + vk::AccessFlagBits::eHostRead, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + *colorAttachment->GetBufferData()->buffer, + 0, + VK_WHOLE_SIZE); + currentCommandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eHost, {}, nullptr, bufferMemoryBarrier, nullptr); + } + currentCommandBuffer.end(); + + GetContext()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, ¤tCommandBuffer), + settings.rend.RenderToTextureBuffer ? *fence : nullptr); + colorImage = nullptr; + currentCommandBuffer = nullptr; + commandPool->EndFrame(); + + + + if (settings.rend.RenderToTextureBuffer) + { + GetContext()->GetDevice()->waitForFences(1, &fence.get(), true, UINT64_MAX); + GetContext()->GetDevice()->resetFences(1, &fence.get()); + + u16 *dst = (u16 *)&vram[textureAddr]; + + PixelBuffer tmpBuf; + tmpBuf.init(width, height); + colorAttachment->GetBufferData()->download(*GetContext()->GetDevice(), width * height * 4, tmpBuf.data()); + WriteTextureToVRam(width, height, (u8 *)tmpBuf.data(), dst); + + return; + } + //memset(&vram[fb_rtt.TexAddr << 3], '\0', size); + + if (width > 1024 || height > 1024) + return; + + texture->dirty = 0; + if (texture->lock_block == NULL) + texture->lock_block = libCore_vramlock_Lock(texture->sa_tex, texture->sa + texture->size - 1, texture); +} diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h new file mode 100644 index 000000000..7f90e3cf2 --- /dev/null +++ b/core/rend/vulkan/drawer.h @@ -0,0 +1,179 @@ +/* + 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 "vulkan.h" +#include "buffer.h" +#include "commandpool.h" +#include "pipeline.h" +#include "shaders.h" +#include "texture.h" + +class Drawer +{ +public: + virtual ~Drawer() {} + bool Draw(const Texture *fogTexture); + +protected: + virtual void Init(SamplerManager *samplerManager, ShaderManager *shaderManager) + { + this->samplerManager = samplerManager; + pipelineManager->Init(shaderManager); + } + 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(); } + + std::unique_ptr pipelineManager; + +private: + s32 SetTileClip(u32 val, float *values); + 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& vertexUniformsOffset); + + // temp stuff + float scale_x; + float scale_y; + // Per-triangle sort results + std::vector> sortedPolys; + std::vector> sortedIndexes; + u32 sortedIndexCount; + + SamplerManager *samplerManager; +}; + +class ScreenDrawer : public Drawer +{ +public: + void Init(SamplerManager *samplerManager, ShaderManager *shaderManager) override + { + pipelineManager = std::unique_ptr(new PipelineManager()); + Drawer::Init(samplerManager, shaderManager); + + while (descriptorSets.size() < GetContext()->GetSwapChainSize()) + { + descriptorSets.push_back(DescriptorSets()); + descriptorSets.back().Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout()); + } + } + +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().get(), + std::max(512 * 1024u, size), + vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eUniformBuffer))); + } + else if (mainBuffers[GetCurrentImage()]->m_size < size) + { + u32 newSize = mainBuffers[GetCurrentImage()]->m_size; + while (newSize < size) + newSize *= 2; + INFO_LOG(RENDERER, "Increasing main buffer size %d -> %d", (u32)mainBuffers[GetCurrentImage()]->m_size, newSize); + mainBuffers[GetCurrentImage()] = std::unique_ptr(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice().get(), newSize, + vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eUniformBuffer)); + } + return mainBuffers[GetCurrentImage()].get(); + }; + + virtual vk::CommandBuffer BeginRenderPass() override + { + GetContext()->NewFrame(); + 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)); + return commandBuffer; + } + + virtual void EndRenderPass() override + { + GetContext()->EndFrame(); + } + +private: + int GetCurrentImage() { return GetContext()->GetCurrentImageIndex(); } + + std::vector descriptorSets; + std::vector> mainBuffers; +}; + +class TextureDrawer : public Drawer +{ +public: + void Init(SamplerManager *samplerManager, ShaderManager *shaderManager) override + { + pipelineManager = std::unique_ptr(new RttPipelineManager()); + Drawer::Init(samplerManager, shaderManager); + + descriptorSets.Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout()); + fence = GetContext()->GetDevice()->createFenceUnique(vk::FenceCreateInfo()); + } + void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } + +protected: + virtual vk::CommandBuffer BeginRenderPass() override; + virtual void EndRenderPass() override; + DescriptorSets& GetCurrentDescSet() override { return descriptorSets; } + + virtual BufferData* GetMainBuffer(u32 size) override + { + if (!mainBuffer || mainBuffer->m_size < size) + { + u32 newSize = mainBuffer ? mainBuffer->m_size : 128 * 1024u; + while (newSize < size) + newSize *= 2; + INFO_LOG(RENDERER, "Increasing RTT main buffer size %d -> %d", !mainBuffer ? 0 : (u32)mainBuffer->m_size, 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; +}; diff --git a/core/rend/vulkan/pipeline.cpp b/core/rend/vulkan/pipeline.cpp index fb799a445..b57cde47f 100644 --- a/core/rend/vulkan/pipeline.cpp +++ b/core/rend/vulkan/pipeline.cpp @@ -171,8 +171,8 @@ void PipelineManager::CreateModVolPipeline(ModVolMode mode) vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates); - vk::ShaderModule vertex_module = shaderManager.GetModVolVertexShader(); - vk::ShaderModule fragment_module = shaderManager.GetModVolShader(); + vk::ShaderModule vertex_module = shaderManager->GetModVolVertexShader(); + vk::ShaderModule fragment_module = shaderManager->GetModVolShader(); vk::PipelineShaderStageCreateInfo stages[] = { { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_module, "main" }, @@ -192,8 +192,8 @@ void PipelineManager::CreateModVolPipeline(ModVolMode mode) &pipelineDepthStencilStateCreateInfo, // pDepthStencilState &pipelineColorBlendStateCreateInfo, // pColorBlendState &pipelineDynamicStateCreateInfo, // pDynamicState - descriptorSets.GetPipelineLayout(), // layout - GetContext()->GetRenderPass() // renderPass + *pipelineLayout, // layout + renderPass // renderPass ); if (modVolPipelines.empty()) @@ -314,7 +314,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates); - vk::ShaderModule vertex_module = shaderManager.GetVertexShader(VertexShaderParams{ pp.pcw.Gouraud == 1, false }); // TODO rotate90 + vk::ShaderModule vertex_module = shaderManager->GetVertexShader(VertexShaderParams{ pp.pcw.Gouraud == 1, false }); // TODO rotate90 FragmentShaderParams params = {}; params.alphaTest = listType == ListType_Punch_Through; params.bumpmap = pp.tcw.PixelFmt == PixelBumpMap; @@ -339,7 +339,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol params.texture = pp.pcw.Texture; params.trilinear = pp.pcw.Texture && pp.tsp.FilterMode > 1 && listType != ListType_Punch_Through; params.useAlpha = pp.tsp.UseAlpha; - vk::ShaderModule fragment_module = shaderManager.GetFragmentShader(params); + vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params); vk::PipelineShaderStageCreateInfo stages[] = { { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertex_module, "main" }, @@ -359,8 +359,8 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol &pipelineDepthStencilStateCreateInfo, // pDepthStencilState &pipelineColorBlendStateCreateInfo, // pColorBlendState &pipelineDynamicStateCreateInfo, // pDynamicState - descriptorSets.GetPipelineLayout(), // layout - GetContext()->GetRenderPass() // renderPass + *pipelineLayout, // layout + renderPass // renderPass ); pipelines[hash(listType, sortTriangles, &pp)] = GetContext()->GetDevice()->createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), diff --git a/core/rend/vulkan/pipeline.h b/core/rend/vulkan/pipeline.h index 783abe2cc..2e397e83f 100644 --- a/core/rend/vulkan/pipeline.h +++ b/core/rend/vulkan/pipeline.h @@ -29,10 +29,107 @@ enum class ModVolMode { Xor, Or, Inclusion, Exclusion, Final }; class DescriptorSets { public: - vk::PipelineLayout GetPipelineLayout() const { return *pipelineLayout; } - - void Init() + void Init(SamplerManager* samplerManager, vk::PipelineLayout pipelineLayout, vk::DescriptorSetLayout perFrameLayout, vk::DescriptorSetLayout perPolyLayout) { + this->samplerManager = samplerManager; + this->pipelineLayout = pipelineLayout; + this->perFrameLayout = perFrameLayout; + this->perPolyLayout = perPolyLayout; + + } + void UpdateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, vk::ImageView fogImageView) + { + if (!perFrameDescSet) + { + perFrameDescSet = std::move(GetContext()->GetDevice()->allocateDescriptorSetsUnique( + vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), 1, &perFrameLayout)).front()); + } + std::vector bufferInfos; + bufferInfos.push_back(vk::DescriptorBufferInfo(buffer, vertexUniformOffset, sizeof(VertexShaderUniforms))); + bufferInfos.push_back(vk::DescriptorBufferInfo(buffer, vertexUniformOffset + sizeof(VertexShaderUniforms), sizeof(FragmentShaderUniforms))); + + std::vector writeDescriptorSets; + writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 0, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfos[0], nullptr)); + writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 1, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfos[1], nullptr)); + if (fogImageView) + { + TSP fogTsp = {}; + fogTsp.FilterMode = 1; + fogTsp.ClampU = 1; + fogTsp.ClampV = 1; + vk::Sampler fogSampler = samplerManager->GetSampler(fogTsp); + vk::DescriptorImageInfo imageInfo(fogSampler, fogImageView, vk::ImageLayout::eShaderReadOnlyOptimal); + writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 2, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr)); + } + GetContext()->GetDevice()->updateDescriptorSets(writeDescriptorSets, nullptr); + } + + void SetTexture(u64 textureId, TSP tsp) + { + auto& inFlight = perPolyDescSetsInFlight; + std::pair index = std::make_pair(textureId, tsp.full & SamplerManager::TSP_Mask); + if (inFlight.find(index) != inFlight.end()) + return; + + if (perPolyDescSets.empty()) + { + std::vector layouts(10, perPolyLayout); + perPolyDescSets = GetContext()->GetDevice()->allocateDescriptorSetsUnique( + vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), layouts.size(), &layouts[0])); + } + Texture *texture = reinterpret_cast(textureId); + vk::DescriptorImageInfo imageInfo(samplerManager->GetSampler(tsp), texture->GetImageView(), vk::ImageLayout::eShaderReadOnlyOptimal); + + std::vector writeDescriptorSets; + writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perPolyDescSets.back(), 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr)); + + GetContext()->GetDevice()->updateDescriptorSets(writeDescriptorSets, nullptr); + inFlight[index] = std::move(perPolyDescSets.back()); + perPolyDescSets.pop_back(); + } + + void BindPerFrameDescriptorSets(vk::CommandBuffer cmdBuffer) + { + cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, 1, &perFrameDescSet.get(), 0, nullptr); + } + + void BindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, u64 textureId, TSP tsp) + { + cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1, + &perPolyDescSetsInFlight[std::make_pair(textureId, tsp.full & SamplerManager::TSP_Mask)].get(), 0, nullptr); + } + + void Reset() + { + for (auto& pair : perPolyDescSetsInFlight) + perPolyDescSets.emplace_back(std::move(pair.second)); + perPolyDescSetsInFlight.clear(); + + } + +private: + VulkanContext *GetContext() const { return VulkanContext::Instance(); } + + vk::DescriptorSetLayout perFrameLayout; + vk::DescriptorSetLayout perPolyLayout; + vk::PipelineLayout pipelineLayout; + + vk::UniqueDescriptorSet perFrameDescSet; + std::vector perPolyDescSets; + std::map, vk::UniqueDescriptorSet> perPolyDescSetsInFlight; + + SamplerManager* samplerManager; +}; + +class PipelineManager +{ +public: + virtual ~PipelineManager() {} + + virtual void Init(ShaderManager *shaderManager) + { + this->shaderManager = shaderManager; + // Descriptor set and pipeline layout vk::DescriptorSetLayoutBinding perFrameBindings[] = { { 0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex }, // vertex uniforms @@ -50,114 +147,10 @@ public: vk::PushConstantRange pushConstant(vk::ShaderStageFlagBits::eFragment, 0, 20); pipelineLayout = GetContext()->GetDevice()->createPipelineLayoutUnique( vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), ARRAY_SIZE(layouts), layouts, 1, &pushConstant)); + + renderPass = VulkanContext::Instance()->GetRenderPass(); } - void UpdateUniforms(const vk::Buffer& vertexUniformBuffer, const vk::Buffer& fragmentUniformBuffer, vk::ImageView fogImageView) - { - if (perFrameDescSets.empty()) - { - std::vector layouts(GetContext()->GetSwapChainSize(), *perFrameLayout); - perFrameDescSets = GetContext()->GetDevice()->allocateDescriptorSetsUnique( - vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), layouts.size(), &layouts[0])); - } - while (perPolyDescSets.size() < GetContext()->GetSwapChainSize()) - perPolyDescSets.push_back(std::vector()); - while (perPolyDescSetsInFlight.size() < GetContext()->GetSwapChainSize()) - perPolyDescSetsInFlight.push_back(std::map, vk::UniqueDescriptorSet>()); - int currentImage = GetContext()->GetCurrentImageIndex(); - - std::vector bufferInfos; - bufferInfos.push_back(vk::DescriptorBufferInfo(vertexUniformBuffer, 0, VK_WHOLE_SIZE)); - bufferInfos.push_back(vk::DescriptorBufferInfo(fragmentUniformBuffer, 0, VK_WHOLE_SIZE)); - - std::vector writeDescriptorSets; - writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSets[currentImage], 0, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfos[0], nullptr)); - writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSets[currentImage], 1, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfos[1], nullptr)); - if (fogImageView) - { - TSP fogTsp = {}; - fogTsp.FilterMode = 1; - fogTsp.ClampU = 1; - fogTsp.ClampV = 1; - vk::Sampler fogSampler = samplerManager.GetSampler(fogTsp); - vk::DescriptorImageInfo imageInfo(fogSampler, fogImageView, vk::ImageLayout::eShaderReadOnlyOptimal); - writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSets[currentImage], 2, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr)); - } - GetContext()->GetDevice()->updateDescriptorSets(writeDescriptorSets, nullptr); - } - - void SetTexture(u64 textureId, TSP tsp) - { - int currentImage = GetContext()->GetCurrentImageIndex(); - auto& inFlight = perPolyDescSetsInFlight[currentImage]; - std::pair index = std::make_pair(textureId, tsp.full & SamplerManager::TSP_Mask); - if (inFlight.find(index) != inFlight.end()) - return; - - auto& descSets = perPolyDescSets[currentImage]; - if (descSets.empty()) - { - std::vector layouts(10, *perPolyLayout); - descSets = GetContext()->GetDevice()->allocateDescriptorSetsUnique( - vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), layouts.size(), &layouts[0])); - } - Texture *texture = reinterpret_cast(textureId); - vk::DescriptorImageInfo imageInfo(samplerManager.GetSampler(tsp), texture->GetImageView(), vk::ImageLayout::eShaderReadOnlyOptimal); - - std::vector writeDescriptorSets; - writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descSets.back(), 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr)); - - GetContext()->GetDevice()->updateDescriptorSets(writeDescriptorSets, nullptr); - inFlight[index] = std::move(descSets.back()); - descSets.pop_back(); - } - - void BindPerFrameDescriptorSets(vk::CommandBuffer cmdBuffer) - { - int currentImage = GetContext()->GetCurrentImageIndex(); - cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, 1, &perFrameDescSets[currentImage].get(), 0, nullptr); - } - - void BindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, u64 textureId, TSP tsp) - { - int currentImage = GetContext()->GetCurrentImageIndex(); - cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 1, 1, - &perPolyDescSetsInFlight[currentImage][std::make_pair(textureId, tsp.full & SamplerManager::TSP_Mask)].get(), 0, nullptr); - } - - void Reset() - { - int currentImage = GetContext()->GetCurrentImageIndex(); - for (auto& pair : perPolyDescSetsInFlight[currentImage]) - perPolyDescSets[currentImage].emplace_back(std::move(pair.second)); - perPolyDescSetsInFlight[currentImage].clear(); - - } - -private: - VulkanContext *GetContext() const { return VulkanContext::Instance(); } - - vk::UniqueDescriptorSetLayout perFrameLayout; - vk::UniqueDescriptorSetLayout perPolyLayout; - vk::UniquePipelineLayout pipelineLayout; - - std::vector perFrameDescSets; - std::vector> perPolyDescSets; - std::vector, vk::UniqueDescriptorSet>> perPolyDescSetsInFlight; - - SamplerManager samplerManager; -}; - -class PipelineManager -{ -public: - void Init() - { - shaderManager.Init(); - descriptorSets.Init(); - } - DescriptorSets& GetDescriptorSets() { return descriptorSets; } - vk::Pipeline GetPipeline(u32 listType, bool sortTriangles, const PolyParam& pp) { u32 pipehash = hash(listType, sortTriangles, &pp); @@ -176,9 +169,12 @@ public: CreateModVolPipeline(mode); return *modVolPipelines[(size_t)mode]; } + vk::PipelineLayout GetPipelineLayout() const { return *pipelineLayout; } + vk::DescriptorSetLayout GetPerFrameDSLayout() const { return *perFrameLayout; } + vk::DescriptorSetLayout GetPerPolyDSLayout() const { return *perPolyLayout; } + vk::RenderPass GetRenderPass() const { return renderPass; } private: - VulkanContext *GetContext() const { return VulkanContext::Instance(); } void CreateModVolPipeline(ModVolMode mode); u32 hash(u32 listType, bool sortTriangles, const PolyParam *pp) const @@ -226,8 +222,58 @@ private: std::map pipelines; std::vector modVolPipelines; - ShaderManager shaderManager; - DescriptorSets descriptorSets; + ShaderManager *shaderManager; + + vk::UniquePipelineLayout pipelineLayout; + vk::UniqueDescriptorSetLayout perFrameLayout; + vk::UniqueDescriptorSetLayout perPolyLayout; + +protected: + VulkanContext *GetContext() const { return VulkanContext::Instance(); } + + vk::RenderPass renderPass; }; +class RttPipelineManager : public PipelineManager +{ +public: + void Init(ShaderManager *shaderManager) override + { + PipelineManager::Init(shaderManager); + // RTT render pass + vk::AttachmentDescription attachmentDescriptions[] = { + vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, +// vk::ImageLayout::eUndefined, settings.rend.RenderToTextureBuffer ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eColorAttachmentOptimal), + vk::ImageLayout::eColorAttachmentOptimal, + settings.rend.RenderToTextureBuffer ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eShaderReadOnlyOptimal), + vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eD32SfloatS8Uint, vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, + vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal), + }; + vk::AttachmentReference colorReference(0, vk::ImageLayout::eColorAttachmentOptimal); + vk::AttachmentReference depthReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); + vk::SubpassDescription subpass(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 0, nullptr, 1, &colorReference, nullptr, &depthReference); + vk::SubpassDependency dependencies[] { + vk::SubpassDependency(VK_SUBPASS_EXTERNAL, 0, vk::PipelineStageFlagBits::eFragmentShader, vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::AccessFlagBits::eShaderRead, vk::AccessFlagBits::eColorAttachmentWrite), + vk::SubpassDependency(0, VK_SUBPASS_EXTERNAL, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eFragmentShader, + vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eShaderRead), + }; + vk::SubpassDependency vramWriteDeps[] { + vk::SubpassDependency(0, VK_SUBPASS_EXTERNAL, + vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost, + vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eHostRead), + }; + + rttRenderPass = GetContext()->GetDevice()->createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), 2, attachmentDescriptions, + 1, &subpass, ARRAY_SIZE(settings.rend.RenderToTextureBuffer ? vramWriteDeps : dependencies), + settings.rend.RenderToTextureBuffer ? vramWriteDeps : dependencies)); + renderPass = *rttRenderPass; + printf("RttPipelineManager renderPass %p created\n", (VkRenderPass)renderPass); + } + +private: + vk::UniqueRenderPass rttRenderPass; +}; diff --git a/core/rend/vulkan/shaders.h b/core/rend/vulkan/shaders.h index d887c9354..09e41a204 100644 --- a/core/rend/vulkan/shaders.h +++ b/core/rend/vulkan/shaders.h @@ -81,6 +81,10 @@ public: { verify(glslang::InitializeProcess()); } + void Term() + { + glslang::FinalizeProcess(); + } vk::ShaderModule GetVertexShader(const VertexShaderParams& params) { return getShader(vertexShaders, params); } vk::ShaderModule GetFragmentShader(const FragmentShaderParams& params) { return getShader(fragmentShaders, params); } vk::ShaderModule GetModVolVertexShader() diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp index bf0c3d21c..666688d51 100644 --- a/core/rend/vulkan/texture.cpp +++ b/core/rend/vulkan/texture.cpp @@ -21,7 +21,7 @@ #include "texture.h" #include "utils.h" -static void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout) +void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout) { vk::AccessFlags sourceAccessMask; switch (oldImageLayout) @@ -34,7 +34,10 @@ static void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image ima 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; break; default: verify(false); @@ -190,7 +193,7 @@ void Texture::Init(u32 width, u32 height, vk::Format format) initialLayout = vk::ImageLayout::ePreinitialized; requirements = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible; } - CreateImage(imageTiling, usageFlags | vk::ImageUsageFlagBits::eSampled, initialLayout, requirements, + CreateImage(imageTiling, usageFlags, initialLayout, requirements, vk::ImageAspectFlagBits::eColor); } @@ -248,3 +251,43 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew) VulkanContext::Instance()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &commandBuffer), nullptr); } + +void FramebufferAttachment::Init(u32 width, u32 height, vk::Format format) +{ + this->format = format; + this->extent = vk::Extent2D { width, height }; + bool depth = format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint; + + vk::ImageUsageFlags usage; + if (depth) + { + usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; + } + else + { + usage = vk::ImageUsageFlagBits::eColorAttachment; + if (settings.rend.RenderToTextureBuffer) + { + usage |= vk::ImageUsageFlagBits::eTransferSrc; + stagingBufferData = std::unique_ptr(new BufferData(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice(), + width * height * 4, vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)); + } + else + { + usage |= vk::ImageUsageFlagBits::eSampled; + } + } + vk::ImageCreateInfo imageCreateInfo(vk::ImageCreateFlags(), vk::ImageType::e2D, format, vk::Extent3D(extent, 1), 1, 1, vk::SampleCountFlagBits::e1, + vk::ImageTiling::eOptimal, usage, + vk::SharingMode::eExclusive, 0, nullptr, vk::ImageLayout::eUndefined); + image = device.createImageUnique(imageCreateInfo); + vk::MemoryRequirements memReq = device.getImageMemoryRequirements(image.get()); + u32 memoryTypeIndex = findMemoryType(physicalDevice.getMemoryProperties(), memReq.memoryTypeBits, + vk::MemoryPropertyFlagBits::eDeviceLocal); + deviceMemory = device.allocateMemoryUnique(vk::MemoryAllocateInfo(memReq.size, memoryTypeIndex)); + device.bindImageMemory(image.get(), deviceMemory.get(), 0); + vk::ImageViewCreateInfo imageViewCreateInfo(vk::ImageViewCreateFlags(), image.get(), vk::ImageViewType::e2D, + format, vk::ComponentMapping(), vk::ImageSubresourceRange(depth ? vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)); + imageView = device.createImageViewUnique(imageViewCreateInfo); +} diff --git a/core/rend/vulkan/texture.h b/core/rend/vulkan/texture.h index 0d97e4772..5fe4ba3d5 100644 --- a/core/rend/vulkan/texture.h +++ b/core/rend/vulkan/texture.h @@ -23,11 +23,14 @@ #include "vulkan.h" #include "buffer.h" #include "rend/TexCache.h" +#include "hw/pvr/Renderer_if.h" + +void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout); struct Texture : BaseTextureCacheData { Texture(vk::PhysicalDevice physicalDevice, vk::Device device) - : physicalDevice(physicalDevice), device(device), format(vk::Format::eR8G8B8A8Unorm) + : physicalDevice(physicalDevice), device(device), format(vk::Format::eUndefined) {} void UploadToGPU(int width, int height, u8 *data) override; u64 GetIntId() { return (u64)reinterpret_cast(this); } @@ -54,6 +57,8 @@ private: vk::PhysicalDevice physicalDevice; vk::Device device; + + friend class TextureDrawer; }; class SamplerManager @@ -83,3 +88,161 @@ public: private: std::map samplers; }; + +class FramebufferAttachment +{ +public: + FramebufferAttachment(vk::PhysicalDevice physicalDevice, vk::Device device) + : physicalDevice(physicalDevice), device(device), format(vk::Format::eUndefined) + {} + void Init(u32 width, u32 height, vk::Format format); + void Reset() { image.reset(); imageView.reset(); deviceMemory.reset(); } + + vk::UniqueImageView& GetImageView() { return imageView; } + vk::UniqueImage& GetImage() { return image; } + vk::UniqueDeviceMemory& GetDeviceMemory() { return deviceMemory; } + const BufferData* GetBufferData() const { return stagingBufferData.get(); } + +private: + vk::Format format; + vk::Extent2D extent; + + std::unique_ptr stagingBufferData; + vk::UniqueDeviceMemory deviceMemory; + vk::UniqueImageView imageView; + vk::UniqueImage image; + + vk::PhysicalDevice physicalDevice; + vk::Device device; +}; + +class RenderToTexture +{ +public: + RenderToTexture() : colorAttachment(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice()), + depthAttachment(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice()) + {} + + void PrepareRender(vk::RenderPass rttRenderPass) + { + DEBUG_LOG(RENDERER, "RenderToTexture packmode=%d stride=%d - %d,%d -> %d,%d", FB_W_CTRL.fb_packmode, FB_W_LINESTRIDE.stride * 8, + FB_X_CLIP.min, FB_Y_CLIP.min, FB_X_CLIP.max, FB_Y_CLIP.max); + u32 newWidth = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; + u32 newHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; + int fbh = 2; + while (fbh < newHeight) + fbh *= 2; + int fbw = 2; + while (fbw < newWidth) + fbw *= 2; + + if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + { + newWidth *= settings.rend.RenderToTextureUpscale; + newHeight *= settings.rend.RenderToTextureUpscale; + fbw *= settings.rend.RenderToTextureUpscale; + fbh *= settings.rend.RenderToTextureUpscale; + } + + VulkanContext *context = VulkanContext::Instance(); + if (newWidth != this->width || newHeight != this->height) + { + width = newWidth; + height = newHeight; + colorAttachment.Init(width, height, vk::Format::eR8G8B8A8Unorm); + depthAttachment.Init(width, height, vk::Format::eD32SfloatS8Uint); + vk::ImageView imageViews[] = { + *colorAttachment.GetImageView(), + *depthAttachment.GetImageView(), + }; + framebuffer = context->GetDevice()->createFramebufferUnique(vk::FramebufferCreateInfo(vk::FramebufferCreateFlags(), + rttRenderPass, ARRAY_SIZE(imageViews), imageViews, newWidth, newHeight, 1)); + } + const vk::ClearValue clear_colors[] = { vk::ClearColorValue(std::array{0.f, 0.f, 0.f, 1.f}), vk::ClearDepthStencilValue{ 0.f, 0 } }; + VulkanContext::Instance()->GetCurrentCommandBuffer().beginRenderPass(vk::RenderPassBeginInfo(rttRenderPass, *framebuffer, + vk::Rect2D({0, 0}, {width, height}), 2, clear_colors), vk::SubpassContents::eInline); + VulkanContext::Instance()->GetCurrentCommandBuffer().setViewport(0, vk::Viewport(0.0f, 0.0f, (float)width, (float)height, 1.0f, 0.0f)); + // FIXME if the texture exists, need to transition it first + } + + void EndRender() + { + VulkanContext::Instance()->GetCurrentCommandBuffer().endRenderPass(); + u32 w = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; + u32 h = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; + + u32 stride = FB_W_LINESTRIDE.stride * 8; + if (stride == 0) + stride = w * 2; + else if (w * 2 > stride) { + // Happens for Virtua Tennis + w = stride / 2; + } + u32 size = w * h * 2; + + const u8 fb_packmode = FB_W_CTRL.fb_packmode; + + if (settings.rend.RenderToTextureBuffer) + { + // wait! need to synchronize buddy! + // FIXME wtf? need a different cmd buffer if writing back to vram PITA + u32 tex_addr = FB_W_SOF1 & VRAM_MASK; + + // Remove all vram locks before calling glReadPixels + // (deadlock on rpi) + u32 page_tex_addr = tex_addr & PAGE_MASK; + u32 page_size = size + tex_addr - page_tex_addr; + page_size = ((page_size - 1) / PAGE_SIZE + 1) * PAGE_SIZE; + for (u32 page = page_tex_addr; page < page_tex_addr + page_size; page += PAGE_SIZE) + VramLockedWriteOffset(page); + + die("Not implemented"); + } + else + { + //memset(&vram[fb_rtt.TexAddr << 3], '\0', size); + } + + if (w > 1024 || h > 1024 || settings.rend.RenderToTextureBuffer) { + // TODO glcache.DeleteTextures(1, &gl.rtt.tex); + } + else + { + // TexAddr : fb_rtt.TexAddr, Reserved : 0, StrideSel : 0, ScanOrder : 1 + TCW tcw = { { (FB_W_SOF1 & VRAM_MASK) >> 3, 0, 0, 1 } }; + switch (fb_packmode) { + case 0: + case 3: + tcw.PixelFmt = Pixel1555; + break; + case 1: + tcw.PixelFmt = Pixel565; + break; + case 2: + tcw.PixelFmt = Pixel4444; + break; + } + TSP tsp = { 0 }; + for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < w; tsp.TexU++); + for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < h; tsp.TexV++); + + Texture* texture = static_cast(getTextureCacheData(tsp, tcw, [](){ + return (BaseTextureCacheData *)new Texture(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice()); + })); + if (texture->IsNew()) + texture->Create(); + // TODO replace tex vk:: stuff + texture->dirty = 0; + if (texture->lock_block == NULL) + texture->lock_block = libCore_vramlock_Lock(texture->sa_tex, texture->sa + texture->size - 1, texture); + } + } + +private: + u32 width = 0; + u32 height = 0; + + vk::UniqueFramebuffer framebuffer; + FramebufferAttachment colorAttachment; + FramebufferAttachment depthAttachment; +}; diff --git a/core/rend/vulkan/utils.h b/core/rend/vulkan/utils.h index 24cea1679..c87395721 100644 --- a/core/rend/vulkan/utils.h +++ b/core/rend/vulkan/utils.h @@ -44,20 +44,3 @@ static inline vk::UniqueDeviceMemory allocateMemory(vk::Device const& device, vk return device.allocateMemoryUnique(vk::MemoryAllocateInfo(memoryRequirements.size, memoryTypeIndex)); } - -template -void oneTimeSubmit(vk::CommandBuffer const& commandBuffer, vk::Queue const& queue, Func const& func) -{ - commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); - func(commandBuffer); - commandBuffer.end(); - queue.submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &commandBuffer), nullptr); - queue.waitIdle(); -} - -template -void oneTimeSubmit(vk::Device const& device, vk::CommandPool const& commandPool, vk::Queue const& queue, Func const& func) -{ - vk::UniqueCommandBuffer commandBuffer = std::move(device.allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool, vk::CommandBufferLevel::ePrimary, 1)).front()); - oneTimeSubmit(*commandBuffer, queue, func); -} diff --git a/core/rend/vulkan/vulkan.h b/core/rend/vulkan/vulkan.h index 984246d0a..123dfc62f 100644 --- a/core/rend/vulkan/vulkan.h +++ b/core/rend/vulkan/vulkan.h @@ -21,16 +21,6 @@ #pragma once #include "types.h" -//#if defined(_WIN32) -//# define VK_USE_PLATFORM_WIN32_KHR -//#elif defined(__linux__) || defined(__unix__) -//# define VK_USE_PLATFORM_XLIB_KHR -//#elif defined(__APPLE__) -//# define VK_USE_PLATFORM_MACOS_MVK -//#else -//# error "Platform not supported" -//#endif - #include "volk/volk.h" #undef VK_NO_PROTOTYPES #include "vulkan/vulkan.hpp" @@ -50,6 +40,7 @@ public: VkInstance GetInstance() const { return static_cast(instance.get()); } u32 GetGraphicsQueueFamilyIndex() const { return graphicsQueueIndex; } + VkSurfaceKHR GetSurface() { return this->surface; } void SetSurface(VkSurfaceKHR surface) { this->surface = vk::SurfaceKHR(surface); } void SetWindowSize(u32 width, u32 height) { this->width = screen_width = width; this->height = screen_height = height; } void NewFrame(); @@ -111,7 +102,7 @@ private: u32 presentQueueIndex = 0; vk::UniqueDevice device; - vk::SurfaceKHR surface; // FIXME needs to be destroyed manually + vk::SurfaceKHR surface; vk::UniqueSwapchainKHR swapChain; std::vector imageViews; diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index 874e20c37..e227bb953 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -419,7 +419,7 @@ void VulkanContext::CreateSwapChain() imageViews.push_back(device->createImageViewUnique(imageViewCreateInfo)); // create a UniqueCommandPool to allocate a CommandBuffer from - commandPools.push_back(device->createCommandPoolUnique(vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlags(), graphicsQueueIndex))); + commandPools.push_back(device->createCommandPoolUnique(vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlagBits::eTransient, graphicsQueueIndex))); // allocate a CommandBuffer from the CommandPool commandBuffers.push_back(std::move(device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(*commandPools.back(), vk::CommandBufferLevel::ePrimary, 1)).front())); @@ -433,7 +433,7 @@ void VulkanContext::CreateSwapChain() attachmentDescriptions[0] = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), colorFormat, vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR); attachmentDescriptions[1] = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), depthFormat, vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, - vk::AttachmentStoreOp::eDontCare, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal); + vk::AttachmentStoreOp::eDontCare, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::AttachmentReference colorReference(0, vk::ImageLayout::eColorAttachmentOptimal); vk::AttachmentReference depthReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); @@ -532,6 +532,21 @@ VulkanContext::~VulkanContext() fclose(f); } } + swapChain.reset(); + imageViews.clear(); + framebuffers.clear(); + renderPass.reset(); + descriptorPool.reset(); + depthView.reset(); + depthMemory.reset(); + depthImage.reset(); + commandBuffers.clear(); + commandPools.clear(); + imageAcquiredSemaphores.clear(); + renderCompleteSemaphores.clear(); + drawFences.clear(); + vkDestroySurfaceKHR((VkInstance)*instance, (VkSurfaceKHR)surface, nullptr); + verify(contextInstance == this); contextInstance = nullptr; } diff --git a/core/rend/vulkan/vulkan_renderer.cpp b/core/rend/vulkan/vulkan_renderer.cpp index 1e2c42ae7..b5222cce8 100644 --- a/core/rend/vulkan/vulkan_renderer.cpp +++ b/core/rend/vulkan/vulkan_renderer.cpp @@ -19,18 +19,11 @@ along with Flycast. If not, see . */ #include -#include -#include #include "vulkan.h" #include "hw/pvr/Renderer_if.h" -#include "hw/pvr/ta_ctx.h" -#include "../gui.h" -#include "rend/sorter.h" -#include "buffer.h" -#include "pipeline.h" +#include "commandpool.h" +#include "drawer.h" #include "shaders.h" -#include "texture.h" -#include "utils.h" extern bool ProcessFrame(TA_context* ctx); @@ -40,9 +33,12 @@ public: bool Init() override { printf("VulkanRenderer::Init\n"); - InitUniforms(); + shaderManager.Init(); + texCommandPool.Init(); - pipelineManager.Init(); + textureDrawer.Init(&samplerManager, &shaderManager); + textureDrawer.SetCommandPool(&texCommandPool); + screenDrawer.Init(&samplerManager, &shaderManager); return true; } @@ -56,9 +52,8 @@ public: printf("VulkanRenderer::Term\n"); GetContext()->WaitIdle(); killtex(); - inFlightCommandBuffers.clear(); - glslang::FinalizeProcess(); - + texCommandPool.Term(); + shaderManager.Term(); } bool Process(TA_context* ctx) override @@ -68,23 +63,18 @@ public: // TODO RenderFramebuffer(); return false; } - // FIXME We shouldn't wait for the next vk image if doing a RTT - if (ctx->rend.isRTT) - return false; - GetContext()->NewFrame(); - if (inFlightCommandBuffers.size() != GetContext()->GetSwapChainSize()) - inFlightCommandBuffers.resize(GetContext()->GetSwapChainSize()); - inFlightCommandBuffers[GetCurrentImage()].clear(); + texCommandPool.BeginFrame(); - if (ProcessFrame(ctx)) - return true; + bool result = ProcessFrame(ctx); - // FIXME - GetContext()->BeginRenderPass(); - GetContext()->EndFrame(); - GetContext()->Present(); - return false; + if (result) + CheckFogTexture(); + + if (!result || !ctx->rend.isRTT) + texCommandPool.EndFrame(); + + return result; } void DrawOSD(bool clear_screen) override @@ -93,181 +83,10 @@ public: bool Render() override { - extern float fb_scale_x, fb_scale_y; - extern bool fog_needs_update; - - bool is_rtt = pvrrc.isRTT; - float dc_width = 640; - float dc_height = 480; - - if (is_rtt) - { - dc_width = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; - dc_height = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; - } - - scale_x = 1; - scale_y = 1; - - float scissoring_scale_x = 1; - - if (!is_rtt && !pvrrc.isRenderFramebuffer) - { - 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 - //A second scaling is used here for scissoring - if (VO_CONTROL.pixel_double) - { - scissoring_scale_x = 0.5f; - scale_x *= 0.5f; - } - - if (SCALER_CTL.hscale) - { - scissoring_scale_x /= 2; - scale_x*=2; - } - } - - dc_width *= scale_x; - dc_height *= scale_y; - - float screen_stretching = settings.rend.ScreenStretching / 100.f; - float screen_scaling = settings.rend.ScreenScaling / 100.f; - - float dc2s_scale_h; - float ds2s_offs_x; - - VertexShaderUniforms vtxUniforms; - 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[2] = 1; - vtxUniforms.scale[3] = 1; - } + if (pvrrc.isRTT) + return textureDrawer.Draw(fogTexture.get()); else - { - if (settings.rend.Rotate90) - { - dc2s_scale_h = screen_height / 640.0f; - ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2; - vtxUniforms.scale[0] = -2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; - vtxUniforms.scale[1] = 2.0f / dc_width; - vtxUniforms.scale[2] = 1 - 2 * ds2s_offs_x / screen_width; - vtxUniforms.scale[3] = 1; - } - else - { - dc2s_scale_h = screen_height / 480.0f; - ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2; - vtxUniforms.scale[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching; - vtxUniforms.scale[1] = 2.0f / dc_height; - vtxUniforms.scale[2] = 1 - 2 * ds2s_offs_x / screen_width; - vtxUniforms.scale[3] = 1; - } - //-1 -> too much to left - } - vtxUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; - - FragmentShaderUniforms fragUniforms; - fragUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; - - //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); - - 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; - - CheckFogTexture(); - - fragUniforms.cp_AlphaTestValue = (PT_ALPHA_REF & 0xFF) / 255.0f; - - SortTriangles(); - - UploadUniforms(vtxUniforms, fragUniforms); - - GetContext()->BeginRenderPass(); - vk::CommandBuffer cmdBuffer = GetContext()->GetCurrentCommandBuffer(); - // Upload vertex and index buffers - UploadMainBuffer(); - - // Update per-frame descriptor set and bind it - pipelineManager.GetDescriptorSets().UpdateUniforms(*vertexUniformBuffer, *fragmentUniformBuffer, fogTexture->GetImageView()); - pipelineManager.GetDescriptorSets().BindPerFrameDescriptorSets(cmdBuffer); - // Reset per-poly descriptor set pool - pipelineManager.GetDescriptorSets().Reset(); - - // Bind vertex and index buffers - const vk::DeviceSize offsets[] = { 0 }; - cmdBuffer.bindVertexBuffers(0, 1, &mainBuffers[GetCurrentImage()]->buffer.get(), offsets); - cmdBuffer.bindIndexBuffer(*mainBuffers[GetCurrentImage()]->buffer, pvrrc.verts.bytes() + pvrrc.modtrig.bytes(), vk::IndexType::eUint32); - - cmdBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)GetContext()->GetViewPort().width, - (float)GetContext()->GetViewPort().height, 1.0f, 0.0f)); - cmdBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), GetContext()->GetViewPort())); - - RenderPass previous_pass = {}; - for (int render_pass = 0; render_pass < pvrrc.render_passes.used(); render_pass++) - { - const RenderPass& current_pass = pvrrc.render_passes.head()[render_pass]; - - DEBUG_LOG(RENDERER, "Render pass %d OP %d PT %d TR %d MV %d", render_pass + 1, - current_pass.op_count - previous_pass.op_count, - current_pass.pt_count - previous_pass.pt_count, - current_pass.tr_count - previous_pass.tr_count, - current_pass.mvo_count - previous_pass.mvo_count); - DrawList(cmdBuffer, ListType_Opaque, false, pvrrc.global_param_op, previous_pass.op_count, current_pass.op_count - previous_pass.op_count); - DrawList(cmdBuffer, ListType_Punch_Through, false, pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count - previous_pass.pt_count); - DrawModVols(cmdBuffer, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count); - if (current_pass.autosort) - { - if (!settings.rend.PerStripSorting) - { - DrawSorted(cmdBuffer, sortedPolys[render_pass]); - } - else - { - SortPParams(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); - DrawList(cmdBuffer, ListType_Translucent, true, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); - } - } - else - DrawList(cmdBuffer, ListType_Translucent, false, pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); - previous_pass = current_pass; - } - if (!is_rtt) - gui_display_osd(); - - GetContext()->EndFrame(); - - return !is_rtt; + return screenDrawer.Draw(fogTexture.get()); } void Present() override @@ -287,12 +106,7 @@ public: //update if needed if (tf->NeedsUpdate()) { - int previousImage = GetCurrentImage() - 1; - if (previousImage < 0) - previousImage = GetContext()->GetSwapChainSize() - 1; - inFlightCommandBuffers[GetCurrentImage()].emplace_back(std::move(GetContext()->GetDevice()->allocateCommandBuffersUnique( - vk::CommandBufferAllocateInfo(GetContext()->GetCurrentCommandPool(), vk::CommandBufferLevel::ePrimary, 1)).front())); - tf->SetCommandBuffer(*inFlightCommandBuffers[GetCurrentImage()].back()); + tf->SetCommandBuffer(texCommandPool.Allocate()); tf->Update(); tf->SetCommandBuffer(nullptr); } @@ -304,299 +118,6 @@ public: private: VulkanContext *GetContext() const { return VulkanContext::Instance(); } - int GetCurrentImage() const { return GetContext()->GetCurrentImageIndex(); } - - // FIXME Code dup - s32 SetTileClip(u32 val, float *values) - { - if (!settings.rend.Clipping) - return 0; - - u32 clipmode = val >> 28; - s32 clip_mode; - if (clipmode < 2) - { - clip_mode = 0; //always passes - } - else if (clipmode & 1) - clip_mode = -1; //render stuff outside the region - else - clip_mode = 1; //render stuff inside the region - - float csx = 0, csy = 0, cex = 0, cey = 0; - - - csx = (float)(val & 63); - cex = (float)((val >> 6) & 63); - csy = (float)((val >> 12) & 31); - cey = (float)((val >> 17) & 31); - csx = csx * 32; - cex = cex * 32 + 32; - csy = csy * 32; - cey = cey * 32 + 32; - - if (csx <= 0 && csy <= 0 && cex >= 640 && cey >= 480) - return 0; - - if (values != nullptr && clip_mode) - { - if (!pvrrc.isRTT) - { - csx /= scale_x; - csy /= scale_y; - cex /= scale_x; - cey /= scale_y; - float dc2s_scale_h; - float ds2s_offs_x; - float screen_stretching = settings.rend.ScreenStretching / 100.f; - - if (settings.rend.Rotate90) - { - float t = cex; - cex = cey; - cey = 640 - csx; - csx = csy; - csy = 640 - t; - dc2s_scale_h = screen_height / 640.0f; - ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2; - } - else - { - dc2s_scale_h = screen_height / 480.0f; - ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2; - } - csx = csx * dc2s_scale_h * screen_stretching + ds2s_offs_x; - cex = cex * dc2s_scale_h * screen_stretching + ds2s_offs_x; - csy = csy * dc2s_scale_h; - cey = cey * dc2s_scale_h; - } - else if (!settings.rend.RenderToTextureBuffer) - { - csx *= settings.rend.RenderToTextureUpscale; - csy *= settings.rend.RenderToTextureUpscale; - cex *= settings.rend.RenderToTextureUpscale; - cey *= settings.rend.RenderToTextureUpscale; - } - values[0] = csx; - values[1] = csy; - values[2] = cex; - values[3] = cey; - } - - return clip_mode; - } - - void DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const List& polys, u32 first, u32 count) - { - for (u32 i = first; i < count; i++) - { - const PolyParam &pp = polys.head()[i]; - float trilinearAlpha; - if (pp.pcw.Texture && pp.tsp.FilterMode > 1 && listType != ListType_Punch_Through) - { - trilinearAlpha = 0.25 * (pp.tsp.MipMapD & 0x3); - if (pp.tsp.FilterMode == 2) - // Trilinear pass A - trilinearAlpha = 1.0 - trilinearAlpha; - } - else - trilinearAlpha = 1.f; - - std::array pushConstants = { 0, 0, 0, 0, trilinearAlpha }; - SetTileClip(pp.tileclip, &pushConstants[0]); - cmdBuffer.pushConstants(pipelineManager.GetDescriptorSets().GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); - - if (pp.pcw.Texture) - pipelineManager.GetDescriptorSets().SetTexture(pp.texid, pp.tsp); - - vk::Pipeline pipeline = pipelineManager.GetPipeline(listType, sortTriangles, pp); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - if (pp.pcw.Texture) - pipelineManager.GetDescriptorSets().BindPerPolyDescriptorSets(cmdBuffer, pp.texid, pp.tsp); - - cmdBuffer.drawIndexed(pp.count, 1, pp.first, 0, 0); - } - } - - void SortTriangles() - { - sortedPolys.resize(pvrrc.render_passes.used()); - sortedIndexes.resize(pvrrc.render_passes.used()); - sortedIndexCount = 0; - RenderPass previousPass = {}; - - for (int render_pass = 0; render_pass < pvrrc.render_passes.used(); render_pass++) - { - const RenderPass& current_pass = pvrrc.render_passes.head()[render_pass]; - sortedIndexes[render_pass].clear(); - if (current_pass.autosort) - { - GenSorted(previousPass.tr_count, current_pass.tr_count - previousPass.tr_count, sortedPolys[render_pass], sortedIndexes[render_pass]); - for (auto& poly : sortedPolys[render_pass]) - poly.first += sortedIndexCount; - sortedIndexCount += sortedIndexes[render_pass].size(); - } - else - sortedPolys[render_pass].clear(); - previousPass = current_pass; - } - } - - // FIXME Code dup with DrawList() - void DrawSorted(const vk::CommandBuffer& cmdBuffer, const std::vector& polys) - { - for (const SortTrigDrawParam& param : polys) - { - float trilinearAlpha; - if (param.ppid->pcw.Texture && param.ppid->tsp.FilterMode > 1) - { - trilinearAlpha = 0.25 * (param.ppid->tsp.MipMapD & 0x3); - if (param.ppid->tsp.FilterMode == 2) - // Trilinear pass A - trilinearAlpha = 1.0 - trilinearAlpha; - } - else - trilinearAlpha = 1.f; - - std::array pushConstants = { 0, 0, 0, 0, trilinearAlpha }; - SetTileClip(param.ppid->tileclip, &pushConstants[0]); - cmdBuffer.pushConstants(pipelineManager.GetDescriptorSets().GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); - - if (param.ppid->pcw.Texture) - pipelineManager.GetDescriptorSets().SetTexture(param.ppid->texid, param.ppid->tsp); - - vk::Pipeline pipeline = pipelineManager.GetPipeline(ListType_Translucent, true, *param.ppid); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - if (param.ppid->pcw.Texture) - pipelineManager.GetDescriptorSets().BindPerPolyDescriptorSets(cmdBuffer, param.ppid->texid, param.ppid->tsp); - - cmdBuffer.drawIndexed(param.count, 1, pvrrc.idx.used() + param.first, 0, 0); - - } - } - - void DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int count) - { - if (count == 0 || pvrrc.modtrig.used() == 0) - return; - - vk::DeviceSize offsets[] = { (vk::DeviceSize)pvrrc.verts.bytes() }; - cmdBuffer.bindVertexBuffers(0, 1, &mainBuffers[GetCurrentImage()]->buffer.get(), offsets); - - ModifierVolumeParam* params = &pvrrc.global_param_mvo.head()[first]; - - int mod_base = -1; - vk::Pipeline pipeline; - - for (u32 cmv = 0; cmv < count; cmv++) - { - ModifierVolumeParam& param = params[cmv]; - - if (param.count == 0) - continue; - - u32 mv_mode = param.isp.DepthMode; - - if (mod_base == -1) - mod_base = param.first; - - if (!param.isp.VolumeLast && mv_mode > 0) - pipeline = pipelineManager.GetModifierVolumePipeline(ModVolMode::Or); // OR'ing (open volume or quad) - else - pipeline = pipelineManager.GetModifierVolumePipeline(ModVolMode::Xor); // XOR'ing (closed volume) - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - cmdBuffer.draw(param.count * 3, 1, param.first * 3, 0); - - if (mv_mode == 1 || mv_mode == 2) - { - // Sum the area - pipeline = pipelineManager.GetModifierVolumePipeline(mv_mode == 1 ? ModVolMode::Inclusion : ModVolMode::Exclusion); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - cmdBuffer.draw((param.first + param.count - mod_base) * 3, 1, mod_base * 3, 0); - mod_base = -1; - } - } - offsets[0] = 0; - cmdBuffer.bindVertexBuffers(0, 1, &mainBuffers[GetCurrentImage()]->buffer.get(), offsets); - - std::array pushConstants = { 1 - FPU_SHAD_SCALE.scale_factor / 256.f, 0, 0, 0, 0 }; - cmdBuffer.pushConstants(pipelineManager.GetDescriptorSets().GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); - - pipeline = pipelineManager.GetModifierVolumePipeline(ModVolMode::Final); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - cmdBuffer.drawIndexed(4, 1, 0, 0, 0); - } - - void InitUniforms() - { - vertexUniformBuffer = GetContext()->GetDevice()->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), - sizeof(VertexShaderUniforms), vk::BufferUsageFlagBits::eUniformBuffer)); - vk::MemoryRequirements memRequirements = GetContext()->GetDevice()->getBufferMemoryRequirements(vertexUniformBuffer.get()); - vertexUniformMemSize = memRequirements.size; - u32 typeIndex = findMemoryType(GetContext()->GetPhysicalDevice().getMemoryProperties(), memRequirements.memoryTypeBits, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); - vertexUniformMemory = GetContext()->GetDevice()->allocateMemoryUnique(vk::MemoryAllocateInfo(vertexUniformMemSize, typeIndex)); - GetContext()->GetDevice()->bindBufferMemory(vertexUniformBuffer.get(), vertexUniformMemory.get(), 0); - - fragmentUniformBuffer = GetContext()->GetDevice()->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), - sizeof(FragmentShaderUniforms), vk::BufferUsageFlagBits::eUniformBuffer)); - memRequirements = GetContext()->GetDevice()->getBufferMemoryRequirements(fragmentUniformBuffer.get()); - fragmentUniformsMemSize = memRequirements.size; - typeIndex = findMemoryType(GetContext()->GetPhysicalDevice().getMemoryProperties(), memRequirements.memoryTypeBits, - vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); - fragmentUniformMemory = GetContext()->GetDevice()->allocateMemoryUnique(vk::MemoryAllocateInfo(fragmentUniformsMemSize, typeIndex)); - GetContext()->GetDevice()->bindBufferMemory(fragmentUniformBuffer.get(), fragmentUniformMemory.get(), 0); - } - - void UploadUniforms(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms) - { - uint8_t* pData = static_cast(GetContext()->GetDevice()->mapMemory(vertexUniformMemory.get(), 0, vertexUniformMemSize)); - memcpy(pData, &vertexUniforms, sizeof(vertexUniforms)); - GetContext()->GetDevice()->unmapMemory(vertexUniformMemory.get()); - - pData = static_cast(GetContext()->GetDevice()->mapMemory(fragmentUniformMemory.get(), 0, fragmentUniformsMemSize)); - memcpy(pData, &fragmentUniforms, sizeof(fragmentUniforms)); - GetContext()->GetDevice()->unmapMemory(fragmentUniformMemory.get()); - } - - void UploadMainBuffer() - { - u32 totalSize = pvrrc.verts.bytes() + pvrrc.idx.bytes() + pvrrc.modtrig.bytes() + sortedIndexCount * sizeof(u32); - if (mainBuffers.empty()) - { - for (int i = 0; i < GetContext()->GetSwapChainSize(); i++) - mainBuffers.push_back(std::unique_ptr(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice().get(), - std::max(512 * 1024u, totalSize), vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer))); - } - else if (mainBuffers[GetCurrentImage()]->m_size < totalSize) - { - u32 newSize = mainBuffers[GetCurrentImage()]->m_size; - while (newSize < totalSize) - newSize *= 2; - INFO_LOG(RENDERER, "Increasing main buffer size %d -> %d", (u32)mainBuffers[GetCurrentImage()]->m_size, newSize); - mainBuffers[GetCurrentImage()] = std::unique_ptr(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice().get(), newSize, - vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer)); - } - - std::vector chunks; - std::vector chunkSizes; - - chunks.push_back(pvrrc.verts.head()); - chunkSizes.push_back(pvrrc.verts.bytes()); - chunks.push_back(pvrrc.modtrig.head()); - chunkSizes.push_back(pvrrc.modtrig.bytes()); - chunks.push_back(pvrrc.idx.head()); - chunkSizes.push_back(pvrrc.idx.bytes()); - for (const std::vector& idx : sortedIndexes) - { - if (!idx.empty()) - { - chunks.push_back(&idx[0]); - chunkSizes.push_back(idx.size() * sizeof(u32)); - } - } - mainBuffers[GetCurrentImage()]->upload(GetContext()->GetDevice().get(), chunks.size(), &chunkSizes[0], &chunks[0]); - } void CheckFogTexture() { @@ -611,41 +132,20 @@ private: fog_needs_update = false; u8 texData[256]; MakeFogTexture(texData); - inFlightCommandBuffers[GetCurrentImage()].emplace_back(std::move(GetContext()->GetDevice()->allocateCommandBuffersUnique( - vk::CommandBufferAllocateInfo(GetContext()->GetCurrentCommandPool(), vk::CommandBufferLevel::ePrimary, 1)).front())); - fogTexture->SetCommandBuffer(*inFlightCommandBuffers[GetCurrentImage()].back()); + fogTexture->SetCommandBuffer(texCommandPool.Allocate()); fogTexture->UploadToGPU(128, 2, texData); fogTexture->SetCommandBuffer(nullptr); } - // temp stuff - float scale_x; - float scale_y; - - // Per-triangle sort results - std::vector> sortedPolys; - std::vector> sortedIndexes; - u32 sortedIndexCount; - std::unique_ptr fogTexture; - std::vector> inFlightCommandBuffers; - - // Uniforms - // TODO put these in the main buffer - vk::UniqueBuffer vertexUniformBuffer; - vk::UniqueBuffer fragmentUniformBuffer; - vk::UniqueDeviceMemory vertexUniformMemory; - vk::UniqueDeviceMemory fragmentUniformMemory; - vk::DeviceSize vertexUniformMemSize; - vk::DeviceSize fragmentUniformsMemSize; - - // Buffers - std::vector> mainBuffers; + CommandPool texCommandPool; + SamplerManager samplerManager; ShaderManager shaderManager; - PipelineManager pipelineManager; + ScreenDrawer screenDrawer; + TextureDrawer textureDrawer; }; Renderer* rend_Vulkan()