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