From 066093553f8e80a5f95dd64212641c1a0823bf5f Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Tue, 10 Dec 2019 12:51:10 +0100 Subject: [PATCH] vulkan: copy provoking vertex. crash when rtt2vram. rtt vram stride setImageLayout was missing TransferSrcOptimal as source layout Vulkan needs the first vertex to be the provoking vertex so copy 3rd on 1st when flat shading. VRAM stride was incorrect (RTT to VRAM) --- core/rend/vulkan/drawer.cpp | 47 ++++++++++++++++++++++++++--- core/rend/vulkan/drawer.h | 1 + core/rend/vulkan/oit/oit_drawer.cpp | 20 +++++++++--- core/rend/vulkan/oit/oit_shaders.h | 32 -------------------- core/rend/vulkan/texture.cpp | 6 +++- 5 files changed, 63 insertions(+), 43 deletions(-) diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index 100f5d80b..1201ec63d 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -152,6 +152,33 @@ void BaseDrawer::SetBaseScissor() currentScissor = { 0, 0, 0, 0 }; } +// Vulkan uses the color values of the first vertex for flat shaded triangle strips. +// On Dreamcast the last vertex is the provoking one so we must copy it onto the first. +void BaseDrawer::SetProvokingVertices() +{ + auto setProvokingVertex = [](const List& list) { + for (int i = 0; i < list.used(); i++) + { + const PolyParam& pp = list.head()[i]; + if (!pp.pcw.Gouraud && pp.count > 2) + { + for (int i = 0; i < pp.count - 2; i++) + { + Vertex *vertex = &pvrrc.verts.head()[pvrrc.idx.head()[pp.first + i]]; + Vertex *lastVertex = &pvrrc.verts.head()[pvrrc.idx.head()[pp.first + i + 2]]; + memcpy(vertex->col, lastVertex->col, 4); + memcpy(vertex->spc, lastVertex->spc, 4); + memcpy(vertex->col1, lastVertex->col1, 4); + memcpy(vertex->spc1, lastVertex->spc1, 4); + } + } + } + }; + setProvokingVertex(pvrrc.global_param_op); + setProvokingVertex(pvrrc.global_param_pt); + setProvokingVertex(pvrrc.global_param_tr); +} + void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const PolyParam& poly, u32 first, u32 count) { vk::Rect2D scissorRect; @@ -331,6 +358,8 @@ bool Drawer::Draw(const Texture *fogTexture) vk::CommandBuffer cmdBuffer = BeginRenderPass(); + SetProvokingVertices(); + // Upload vertex and index buffers UploadMainBuffer(vtxUniforms, fragUniforms); @@ -530,10 +559,18 @@ void TextureDrawer::EndRenderPass() { currentCommandBuffer.endRenderPass(); + u32 clippedWidth = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; + u32 clippedHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; + + u32 stride = FB_W_LINESTRIDE.stride * 8; + if (clippedWidth * 2 > stride) + // Happens for Virtua Tennis + clippedWidth = stride / 2; + 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)); + vk::BufferImageCopy copyRegion(0, clippedWidth, clippedHeight, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), + vk::Extent3D(vk::Extent2D(clippedWidth, clippedHeight), 1)); currentCommandBuffer.copyImageToBuffer(colorAttachment->GetImage(), vk::ImageLayout::eTransferSrcOptimal, *colorAttachment->GetBufferData()->buffer, copyRegion); @@ -561,9 +598,9 @@ void TextureDrawer::EndRenderPass() u16 *dst = (u16 *)&vram[textureAddr]; PixelBuffer tmpBuf; - tmpBuf.init(width, height); - colorAttachment->GetBufferData()->download(width * height * 4, tmpBuf.data()); - WriteTextureToVRam(width, height, (u8 *)tmpBuf.data(), dst); + tmpBuf.init(clippedWidth, clippedHeight); + colorAttachment->GetBufferData()->download(clippedWidth * clippedHeight * 4, tmpBuf.data()); + WriteTextureToVRam(clippedWidth, clippedHeight, (u8 *)tmpBuf.data(), dst); return; } diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h index f93ce4f98..f9ccb0fc5 100644 --- a/core/rend/vulkan/drawer.h +++ b/core/rend/vulkan/drawer.h @@ -46,6 +46,7 @@ protected: VulkanContext *GetContext() const { return VulkanContext::Instance(); } TileClipping SetTileClip(u32 val, vk::Rect2D& clipRect); void SetBaseScissor(); + void SetProvokingVertices(); u32 align(vk::DeviceSize offset, u32 alignment) { diff --git a/core/rend/vulkan/oit/oit_drawer.cpp b/core/rend/vulkan/oit/oit_drawer.cpp index b6e164059..0da70a8c5 100644 --- a/core/rend/vulkan/oit/oit_drawer.cpp +++ b/core/rend/vulkan/oit/oit_drawer.cpp @@ -258,6 +258,8 @@ bool OITDrawer::Draw(const Texture *fogTexture) oitBuffers->OnNewFrame(cmdBuffer); + SetProvokingVertices(); + // Upload vertex and index buffers UploadMainBuffer(vtxUniforms, fragUniforms); @@ -578,11 +580,19 @@ void OITTextureDrawer::EndFrame() { currentCommandBuffer.endRenderPass(); + u32 clippedWidth = pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1; + u32 clippedHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; + + u32 stride = FB_W_LINESTRIDE.stride * 8; + if (clippedWidth * 2 > stride) + // Happens for Virtua Tennis + clippedWidth = stride / 2; + if (settings.rend.RenderToTextureBuffer) { - vk::BufferImageCopy copyRegion(0, viewport.extent.width, viewport.extent.height, + vk::BufferImageCopy copyRegion(0, clippedWidth, clippedHeight, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), - vk::Extent3D(viewport.extent, 1)); + vk::Extent3D(clippedWidth, clippedHeight, 1)); currentCommandBuffer.copyImageToBuffer(colorAttachment->GetImage(), vk::ImageLayout::eTransferSrcOptimal, *colorAttachment->GetBufferData()->buffer, copyRegion); @@ -611,9 +621,9 @@ void OITTextureDrawer::EndFrame() u16 *dst = (u16 *)&vram[textureAddr]; PixelBuffer tmpBuf; - tmpBuf.init(viewport.extent.width, viewport.extent.height); - colorAttachment->GetBufferData()->download(viewport.extent.width * viewport.extent.height * 4, tmpBuf.data()); - WriteTextureToVRam(viewport.extent.width, viewport.extent.height, (u8 *)tmpBuf.data(), dst); + tmpBuf.init(clippedWidth, clippedHeight); + colorAttachment->GetBufferData()->download(clippedWidth * clippedHeight * 4, tmpBuf.data()); + WriteTextureToVRam(clippedWidth, clippedHeight, (u8 *)tmpBuf.data(), dst); return; } diff --git a/core/rend/vulkan/oit/oit_shaders.h b/core/rend/vulkan/oit/oit_shaders.h index 80581fcfb..1d560398f 100644 --- a/core/rend/vulkan/oit/oit_shaders.h +++ b/core/rend/vulkan/oit/oit_shaders.h @@ -80,30 +80,6 @@ public: compileTrModVolFragmentShader(mode); return *trModVolShaders[(size_t)mode]; } -// vk::ShaderModule GetQuadVertexShader() -// { -// if (!quadVertexShader) -// quadVertexShader = compileQuadVertexShader(); -// return *quadVertexShader; -// } -// vk::ShaderModule GetQuadFragmentShader() -// { -// if (!quadFragmentShader) -// quadFragmentShader = compileQuadFragmentShader(); -// return *quadFragmentShader; -// } -// vk::ShaderModule GetOSDVertexShader() -// { -// if (!osdVertexShader) -// osdVertexShader = compileOSDVertexShader(); -// return *osdVertexShader; -// } -// vk::ShaderModule GetOSDFragmentShader() -// { -// if (!osdFragmentShader) -// osdFragmentShader = compileOSDFragmentShader(); -// return *osdFragmentShader; -// } vk::ShaderModule GetFinalShader(bool autosort) { @@ -148,10 +124,6 @@ private: vk::UniqueShaderModule compileModVolVertexShader(); vk::UniqueShaderModule compileModVolFragmentShader(); void compileTrModVolFragmentShader(ModVolMode mode); -// vk::UniqueShaderModule compileQuadVertexShader(); -// vk::UniqueShaderModule compileQuadFragmentShader(); -// vk::UniqueShaderModule compileOSDVertexShader(); -// vk::UniqueShaderModule compileOSDFragmentShader(); vk::UniqueShaderModule compileFinalShader(bool autosort); vk::UniqueShaderModule compileFinalVertexShader(); vk::UniqueShaderModule compileClearShader(); @@ -161,10 +133,6 @@ private: vk::UniqueShaderModule modVolVertexShader; vk::UniqueShaderModule modVolShader; std::vector trModVolShaders; -// vk::UniqueShaderModule quadVertexShader; -// vk::UniqueShaderModule quadFragmentShader; -// vk::UniqueShaderModule osdVertexShader; -// vk::UniqueShaderModule osdFragmentShader; vk::UniqueShaderModule finalVertexShader; vk::UniqueShaderModule finalAutosortShader; diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp index 60f870a1a..2e4038632 100644 --- a/core/rend/vulkan/texture.cpp +++ b/core/rend/vulkan/texture.cpp @@ -30,6 +30,9 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk: case vk::ImageLayout::eTransferDstOptimal: sourceAccessMask = vk::AccessFlagBits::eTransferWrite; break; + case vk::ImageLayout::eTransferSrcOptimal: + sourceAccessMask = vk::AccessFlagBits::eTransferRead; + break; case vk::ImageLayout::ePreinitialized: sourceAccessMask = vk::AccessFlagBits::eHostWrite; break; @@ -52,6 +55,7 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk: sourceStage = vk::PipelineStageFlagBits::eHost; break; case vk::ImageLayout::eTransferDstOptimal: + case vk::ImageLayout::eTransferSrcOptimal: sourceStage = vk::PipelineStageFlagBits::eTransfer; break; case vk::ImageLayout::eUndefined: @@ -176,7 +180,7 @@ void Texture::Init(u32 width, u32 height, vk::Format format) this->extent = vk::Extent2D(width, height); this->format = format; mipmapLevels = 1; - if (tcw.MipMapped) + if (tcw.MipMapped && settings.rend.UseMipmaps) mipmapLevels += floor(log2(std::max(width, height))); vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(format);