diff --git a/core/rend/vulkan/shaders.cpp b/core/rend/vulkan/shaders.cpp index ffa9e6748..f9383716b 100644 --- a/core/rend/vulkan/shaders.cpp +++ b/core/rend/vulkan/shaders.cpp @@ -498,12 +498,12 @@ vk::UniqueShaderModule ShaderManager::compileShader(const FragmentShaderParams& return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eFragment, buf); } -vk::UniqueShaderModule ShaderManager::compileVertexModVolShader() +vk::UniqueShaderModule ShaderManager::compileModVolVertexShader() { return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eVertex, ModVolVertexShaderSource); } -vk::UniqueShaderModule ShaderManager::compileModVolShader() +vk::UniqueShaderModule ShaderManager::compileModVolFragmentShader() { return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eFragment, ModVolFragmentShaderSource); } diff --git a/core/rend/vulkan/shaders.h b/core/rend/vulkan/shaders.h index 1d912f732..d887c9354 100644 --- a/core/rend/vulkan/shaders.h +++ b/core/rend/vulkan/shaders.h @@ -86,13 +86,13 @@ public: vk::ShaderModule GetModVolVertexShader() { if (!modVolVertexShader) - modVolVertexShader = compileVertexModVolShader(); + modVolVertexShader = compileModVolVertexShader(); return *modVolVertexShader; } vk::ShaderModule GetModVolShader() { if (!modVolShader) - modVolShader = compileModVolShader(); + modVolShader = compileModVolFragmentShader(); return *modVolShader; } @@ -108,8 +108,8 @@ private: } vk::UniqueShaderModule compileShader(const VertexShaderParams& params); vk::UniqueShaderModule compileShader(const FragmentShaderParams& params); - vk::UniqueShaderModule compileVertexModVolShader(); - vk::UniqueShaderModule compileModVolShader(); + vk::UniqueShaderModule compileModVolVertexShader(); + vk::UniqueShaderModule compileModVolFragmentShader(); std::map vertexShaders; std::map fragmentShaders; diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp index 45b2f4179..bf0c3d21c 100644 --- a/core/rend/vulkan/texture.cpp +++ b/core/rend/vulkan/texture.cpp @@ -34,6 +34,7 @@ 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; default: verify(false); @@ -53,6 +54,9 @@ static void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image ima case vk::ImageLayout::eUndefined: sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; break; + case vk::ImageLayout::eShaderReadOnlyOptimal: + sourceStage = vk::PipelineStageFlagBits::eFragmentShader; + break; default: verify(false); break; @@ -150,8 +154,12 @@ void Texture::UploadToGPU(int width, int height, u8 *data) dataSize /= 2; break; } - Init(width, height, format); - SetImage(VulkanContext::Instance()->GetCurrentCommandPool(), dataSize, data); + bool isNew = true; + if (width != extent.width || height != extent.height || format != this->format) + Init(width, height, format); + else + isNew = false; + SetImage(dataSize, data, isNew); } void Texture::Init(u32 width, u32 height, vk::Format format) @@ -205,11 +213,12 @@ void Texture::CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk: imageView = device.createImageViewUnique(imageViewCreateInfo); } -void Texture::SetImage(const vk::CommandPool& commandPool, u32 srcSize, void *srcData) +void Texture::SetImage(u32 srcSize, void *srcData, bool isNew) { - vk::UniqueCommandBuffer commandBuffer = std::move(device.allocateCommandBuffersUnique( - vk::CommandBufferAllocateInfo(commandPool, vk::CommandBufferLevel::ePrimary, 1)).front()); - commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + + if (!isNew && !needsStaging) + setImageLayout(commandBuffer, image.get(), format, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eGeneral); vk::DeviceSize size = needsStaging ? device.getBufferMemoryRequirements(stagingBufferData->buffer.get()).size @@ -223,25 +232,19 @@ void Texture::SetImage(const vk::CommandPool& commandPool, u32 srcSize, void *sr if (needsStaging) { // Since we're going to blit to the texture image, set its layout to eTransferDstOptimal - setImageLayout(*commandBuffer, image.get(), format, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); + setImageLayout(commandBuffer, image.get(), format, isNew ? vk::ImageLayout::eUndefined : vk::ImageLayout::eShaderReadOnlyOptimal, + vk::ImageLayout::eTransferDstOptimal); vk::BufferImageCopy copyRegion(0, extent.width, extent.height, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), vk::Extent3D(extent, 1)); - commandBuffer->copyBufferToImage(stagingBufferData->buffer.get(), image.get(), vk::ImageLayout::eTransferDstOptimal, copyRegion); + commandBuffer.copyBufferToImage(stagingBufferData->buffer.get(), image.get(), vk::ImageLayout::eTransferDstOptimal, copyRegion); // Set the layout for the texture image from eTransferDstOptimal to SHADER_READ_ONLY - setImageLayout(*commandBuffer, image.get(), format, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal); + setImageLayout(commandBuffer, image.get(), format, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal); } else { // If we can use the linear tiled image as a texture, just do it - setImageLayout(*commandBuffer, image.get(), format, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal); + setImageLayout(commandBuffer, image.get(), format, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal); } - commandBuffer->end(); - VulkanContext::Instance()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &(*commandBuffer)), nullptr); + commandBuffer.end(); - // FIXME we need to wait for the command buffer to finish executing before freeing the staging and command buffers - VulkanContext::Instance()->GetGraphicsQueue().waitIdle(); - if (needsStaging) - { - // Free staging buffer - stagingBufferData = nullptr; - } + VulkanContext::Instance()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &commandBuffer), nullptr); } diff --git a/core/rend/vulkan/texture.h b/core/rend/vulkan/texture.h index 1aa525df0..0d97e4772 100644 --- a/core/rend/vulkan/texture.h +++ b/core/rend/vulkan/texture.h @@ -34,10 +34,11 @@ struct Texture : BaseTextureCacheData std::string GetId() override { char s[20]; sprintf(s, "%p", this); return s; } bool IsNew() const { return !image.get(); } vk::ImageView GetImageView() const { return *imageView; } + void SetCommandBuffer(vk::CommandBuffer commandBuffer) { this->commandBuffer = commandBuffer; } private: void Init(u32 width, u32 height, vk::Format format); - void SetImage(const vk::CommandPool& commandPool, u32 size, void *data); + void SetImage(u32 size, void *data, bool isNew); void CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageLayout initialLayout, vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask); @@ -45,6 +46,7 @@ private: vk::Extent2D extent; bool needsStaging = false; std::unique_ptr stagingBufferData; + vk::CommandBuffer commandBuffer; vk::UniqueDeviceMemory deviceMemory; vk::UniqueImageView imageView; diff --git a/core/rend/vulkan/vulkan_renderer.cpp b/core/rend/vulkan/vulkan_renderer.cpp index 3c0126138..1e2c42ae7 100644 --- a/core/rend/vulkan/vulkan_renderer.cpp +++ b/core/rend/vulkan/vulkan_renderer.cpp @@ -19,6 +19,7 @@ along with Flycast. If not, see . */ #include +#include #include #include "vulkan.h" #include "hw/pvr/Renderer_if.h" @@ -55,6 +56,7 @@ public: printf("VulkanRenderer::Term\n"); GetContext()->WaitIdle(); killtex(); + inFlightCommandBuffers.clear(); glslang::FinalizeProcess(); } @@ -66,7 +68,15 @@ 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(); + if (ProcessFrame(ctx)) return true; @@ -157,7 +167,7 @@ public: 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] = 1.5f / dc_height; // FIXME 1.5 WTF? + vtxUniforms.scale[1] = 2.0f / dc_height; vtxUniforms.scale[2] = 1 - 2 * ds2s_offs_x / screen_width; vtxUniforms.scale[3] = 1; } @@ -219,8 +229,8 @@ public: 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, static_cast(GetContext()->GetViewPort().width), - static_cast(GetContext()->GetViewPort().width), 1.0f, 0.0f)); + 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 = {}; @@ -276,7 +286,16 @@ 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->Update(); + tf->SetCommandBuffer(nullptr); + } else tf->CheckCustomTexture(); @@ -592,19 +611,29 @@ 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->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;