diff --git a/src/common/math_util.h b/src/common/math_util.h index 382d0197d..449d68668 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h @@ -39,6 +39,8 @@ struct Rectangle { return Rectangle{left, top, static_cast(left + GetWidth() * s), static_cast(top + GetHeight() * s)}; } + + auto operator <=> (const Rectangle& other) const = default; }; template diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index baea523d1..a39cd629f 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -280,7 +280,7 @@ void RendererVulkan::CreateVulkanObjects() { // Generate VBO handle for drawing VKBuffer::Info vertex_info{ - .size = sizeof(ScreenRectVertex) * 4, + .size = sizeof(ScreenRectVertex) * 10, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal, .usage = vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst @@ -340,19 +340,23 @@ void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU:: * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD * rotation. */ -void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, - float w, float h) { +void RendererVulkan::DrawSingleScreenRotated(u32 screen_id, float x, float y, float w, float h) { + auto& screen_info = screen_infos[screen_id]; const auto& texcoords = screen_info.display_texcoords; + u32 size = sizeof(ScreenRectVertex) * 4; + auto [ptr, offset, invalidate] = vertex_buffer.Map(size); + const std::array vertices{ - ScreenRectVertex(x, y, texcoords.bottom, texcoords.left), - ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right), - ScreenRectVertex(x, y + h, texcoords.top, texcoords.left), - ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right), + ScreenRectVertex(x, y, texcoords.bottom, texcoords.left, screen_id), + ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right, screen_id), + ScreenRectVertex(x, y + h, texcoords.top, texcoords.left, screen_id), + ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right, screen_id), }; - auto data = std::as_bytes(std::span(vertices)); - vertex_buffer.Upload(data, 0); + std::memcpy(ptr, vertices.data(), size); + vertex_buffer.Commit(size, vk::AccessFlagBits::eVertexAttributeRead, + vk::PipelineStageFlagBits::eVertexInput); // As this is the "DrawSingleScreenRotated" function, the output resolution dimensions have been // swapped. If a non-rotated draw-screen function were to be added for book-mode games, those @@ -365,34 +369,32 @@ void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa 1.0f / (height * scale_factor)}; draw_info.o_resolution = glm::vec4{h, w, 1.0f / h, 1.0f / w}; - auto& image = swapchain->GetCurrentImage(); auto& state = VulkanState::Get(); - - state.BeginRendering(image, std::nullopt, false, clear_color, vk::AttachmentLoadOp::eClear); state.SetPresentData(draw_info); - state.SetPresentTexture(*screen_info.display_texture); - state.ApplyPresentState(); auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); - vk::DeviceSize offset = 0; - cmdbuffer.bindVertexBuffers(0, 1, &vertex_buffer.GetBuffer(), &offset); - cmdbuffer.draw(4, 1, 0, 0); + cmdbuffer.bindVertexBuffers(0, vertex_buffer.GetBuffer(), {0}); + cmdbuffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0); } -void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, - float h) { +void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w, float h) { + auto& screen_info = screen_infos[screen_id]; const auto& texcoords = screen_info.display_texcoords; + u32 size = sizeof(ScreenRectVertex) * 4; + auto [ptr, offset, invalidate] = vertex_buffer.Map(size); + const std::array vertices{ - ScreenRectVertex(x, y, texcoords.bottom, texcoords.right), - ScreenRectVertex(x + w, y, texcoords.top, texcoords.right), - ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left), - ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left), + ScreenRectVertex(x, y, texcoords.bottom, texcoords.right, screen_id), + ScreenRectVertex(x + w, y, texcoords.top, texcoords.right, screen_id), + ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left, screen_id), + ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left, screen_id), }; - auto data = std::as_bytes(std::span(vertices)); - vertex_buffer.Upload(data, 0); + std::memcpy(ptr, vertices.data(), size); + vertex_buffer.Commit(size, vk::AccessFlagBits::eVertexAttributeRead, + vk::PipelineStageFlagBits::eVertexInput); const u16 scale_factor = VideoCore::GetResolutionScaleFactor(); auto [width, height] = screen_info.texture.GetArea().extent; @@ -403,17 +405,13 @@ void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl 1.0f / (height * scale_factor)}; draw_info.o_resolution = glm::vec4{h, w, 1.0f / h, 1.0f / w}; - auto& image = swapchain->GetCurrentImage(); auto& state = VulkanState::Get(); - - state.BeginRendering(image, std::nullopt, false, clear_color, vk::AttachmentLoadOp::eClear); state.SetPresentData(draw_info); - state.SetPresentTexture(*screen_info.display_texture); - state.ApplyPresentState(); auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); + cmdbuffer.bindVertexBuffers(0, vertex_buffer.GetBuffer(), {0}); - cmdbuffer.draw(4, 1, 0, 0); + cmdbuffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0); } /** @@ -423,7 +421,8 @@ void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl void RendererVulkan::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r, float x, float y, float w, float h) { - DrawSingleScreenRotated(screen_info_l, x, y, w, h); + ASSERT(false); + //DrawSingleScreenRotated(screen_info_l, x, y, w, h); /*const auto& texcoords = screen_info_l.display_texcoords; const std::array vertices = {{ @@ -460,7 +459,8 @@ void RendererVulkan::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info void RendererVulkan::DrawSingleScreenStereo(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r, float x, float y, float w, float h) { - DrawSingleScreen(screen_info_l, x, y, w, h); + ASSERT(false); + //DrawSingleScreen(screen_info_l, x, y, w, h); /*const auto& texcoords = screen_info_l.display_texcoords; const std::array vertices = {{ @@ -518,8 +518,9 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f const auto& bottom_screen = layout.bottom_screen; // Set projection matrix - draw_info.modelview = MakeOrthographicMatrix((float)layout.width, (float)layout.height, flipped); - + draw_info.modelview = glm::transpose(glm::ortho(0.f, static_cast(layout.width), + static_cast(layout.height), 0.0f, + 0.f, 1.f)); const bool stereo_single_screen = false /* Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph || Settings::values.render_3d == Settings::StereoRenderOption::Interlaced || @@ -530,28 +531,37 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f //glUniform1i(uniform_color_texture_r, 1); } + auto& image = swapchain->GetCurrentImage(); + auto& state = VulkanState::Get(); + + state.BeginRendering(image, std::nullopt, false, clear_color, vk::AttachmentLoadOp::eClear); + state.SetPresentTextures(screen_infos[0].display_texture->GetView(), + screen_infos[1].display_texture->GetView(), + screen_infos[2].display_texture->GetView()); + state.ApplyPresentState(); + draw_info.layer = 0; if (layout.top_screen_enabled) { if (layout.is_rotated) { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { - DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, - (float)top_screen.top, (float)top_screen.GetWidth(), - (float)top_screen.GetHeight()); + DrawSingleScreenRotated(0, top_screen.left, + top_screen.top, top_screen.GetWidth(), + top_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { - DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2, + DrawSingleScreenRotated(0, (float)top_screen.left / 2, (float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreenRotated(screen_infos[1], + DrawSingleScreenRotated(1, ((float)top_screen.left / 2) + ((float)layout.width / 2), (float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { - DrawSingleScreenRotated(screen_infos[0], layout.top_screen.left, + DrawSingleScreenRotated(0, layout.top_screen.left, layout.top_screen.top, layout.top_screen.GetWidth(), layout.top_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreenRotated(screen_infos[1], + DrawSingleScreenRotated(1, layout.cardboard.top_screen_right_eye + ((float)layout.width / 2), layout.top_screen.top, layout.top_screen.GetWidth(), @@ -563,21 +573,21 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f } } else { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { - DrawSingleScreen(screen_infos[0], (float)top_screen.left, (float)top_screen.top, + DrawSingleScreen(0, (float)top_screen.left, (float)top_screen.top, (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { - DrawSingleScreen(screen_infos[0], (float)top_screen.left / 2, (float)top_screen.top, + DrawSingleScreen(0, (float)top_screen.left / 2, (float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreen(screen_infos[1], + DrawSingleScreen(1, ((float)top_screen.left / 2) + ((float)layout.width / 2), (float)top_screen.top, (float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { - DrawSingleScreen(screen_infos[0], layout.top_screen.left, layout.top_screen.top, + DrawSingleScreen(0, layout.top_screen.left, layout.top_screen.top, layout.top_screen.GetWidth(), layout.top_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreen(screen_infos[1], + DrawSingleScreen(1, layout.cardboard.top_screen_right_eye + ((float)layout.width / 2), layout.top_screen.top, layout.top_screen.GetWidth(), layout.top_screen.GetHeight()); @@ -588,28 +598,29 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f } } } + draw_info.layer = 0; - if (/*layout.bottom_screen_enabled*/false) { + if (layout.bottom_screen_enabled) { if (layout.is_rotated) { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { - DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left, + DrawSingleScreenRotated(2, (float)bottom_screen.left, (float)bottom_screen.top, (float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { DrawSingleScreenRotated( - screen_infos[2], (float)bottom_screen.left / 2, (float)bottom_screen.top, + 2, (float)bottom_screen.left / 2, (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); draw_info.layer = 1; DrawSingleScreenRotated( - screen_infos[2], ((float)bottom_screen.left / 2) + ((float)layout.width / 2), + 2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2), (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { - DrawSingleScreenRotated(screen_infos[2], layout.bottom_screen.left, + DrawSingleScreenRotated(2, layout.bottom_screen.left, layout.bottom_screen.top, layout.bottom_screen.GetWidth(), layout.bottom_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreenRotated(screen_infos[2], + DrawSingleScreenRotated(2, layout.cardboard.bottom_screen_right_eye + ((float)layout.width / 2), layout.bottom_screen.top, layout.bottom_screen.GetWidth(), @@ -622,24 +633,24 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f } } else { if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { - DrawSingleScreen(screen_infos[2], (float)bottom_screen.left, + DrawSingleScreen(2, (float)bottom_screen.left, (float)bottom_screen.top, (float)bottom_screen.GetWidth(), (float)bottom_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { - DrawSingleScreen(screen_infos[2], (float)bottom_screen.left / 2, + DrawSingleScreen(2, (float)bottom_screen.left / 2, (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreen(screen_infos[2], + DrawSingleScreen(2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2), (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); } else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) { - DrawSingleScreen(screen_infos[2], layout.bottom_screen.left, + DrawSingleScreen(2, layout.bottom_screen.left, layout.bottom_screen.top, layout.bottom_screen.GetWidth(), layout.bottom_screen.GetHeight()); draw_info.layer = 1; - DrawSingleScreen(screen_infos[2], + DrawSingleScreen(2, layout.cardboard.bottom_screen_right_eye + ((float)layout.width / 2), layout.bottom_screen.top, layout.bottom_screen.GetWidth(), diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 56b788d64..22b883c70 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -52,8 +52,8 @@ private: void ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer); void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped); - void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h); - void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h); + void DrawSingleScreenRotated(u32 screen_id, float x, float y, float w, float h); + void DrawSingleScreen(u32 screen_id, float x, float y, float w, float h); void DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r, float x, float y, float w, float h); void DrawSingleScreenStereo(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r, @@ -70,7 +70,7 @@ private: private: // Vulkan state DrawInfo draw_info{}; - VKBuffer vertex_buffer; + StreamBuffer vertex_buffer; vk::ClearColorValue clear_color{}; /// Display information for top and bottom screens respectively diff --git a/src/video_core/renderer_vulkan/vk_buffer.cpp b/src/video_core/renderer_vulkan/vk_buffer.cpp index 4774fcfe8..58b5dd9ed 100644 --- a/src/video_core/renderer_vulkan/vk_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer.cpp @@ -133,7 +133,7 @@ std::tuple StreamBuffer::Map(u32 size, u32 alignment) { auto [staging_ptr, staging_offset] = g_vk_task_scheduler->RequestStaging(size); mapped_chunk = vk::BufferCopy{staging_offset, buffer_pos, size}; - return std::make_tuple(staging_ptr + buffer_pos, buffer_pos, invalidate); + return std::make_tuple(staging_ptr, buffer_pos, invalidate); } void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block, @@ -148,7 +148,7 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block, vk::BufferMemoryBarrier barrier{ vk::AccessFlagBits::eTransferWrite, access_to_block, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - buffer, mapped_chunk.srcOffset, mapped_chunk.size + buffer, mapped_chunk.dstOffset, mapped_chunk.size }; // Add a pipeline barrier for the region modified @@ -158,9 +158,6 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block, buffer_pos += size; } - else { - printf("f"); - } } } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp b/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp index bb0689fef..8707667b1 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp @@ -288,6 +288,55 @@ static bool BlitTextures(const Surface& src_surface, const Common::Rectangle fill_buffer, + Common::Rectangle rect) { + if (surface->GetScaledRect() != rect) { + // TODO: use vkCmdClearAttachments to clear subrects + LOG_ERROR(Render_Vulkan, "Partial surface fills not implemented"); + } + + vk::ImageSubresourceRange image_range{{}, 0, 1, 0, 1}; + switch (surface->type) { + case SurfaceParams::SurfaceType::Color: + case SurfaceParams::SurfaceType::Texture: + image_range.aspectMask = vk::ImageAspectFlagBits::eColor; + break; + case SurfaceParams::SurfaceType::Depth: + image_range.aspectMask = vk::ImageAspectFlagBits::eDepth; + break; + case SurfaceParams::SurfaceType::DepthStencil: + image_range.aspectMask = + vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil; + break; + default: + UNIMPLEMENTED(); + } + + auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); + switch (surface->type) { + case SurfaceParams::SurfaceType::Color: + case SurfaceParams::SurfaceType::Texture: { + Pica::Texture::TextureInfo tex_info{}; + tex_info.format = static_cast(surface->pixel_format); + + auto color_vec = Pica::Texture::LookupTexture(fill_buffer.data(), 0, 0, tex_info) / 255.0f; + const std::array color{color_vec.x, color_vec.y, color_vec.z, color_vec.w}; + + auto& texture = surface->texture; + texture.Transition(cmdbuffer, vk::ImageLayout::eTransferDstOptimal); + + cmdbuffer.clearColorImage(texture.GetHandle(), vk::ImageLayout::eTransferDstOptimal, + color, image_range); + + texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal); + return true; + } + default: + LOG_ERROR(Render_Vulkan, "non-color fills not implemented"); + return false; + } +} + static vk::Rect2D FromRect(Common::Rectangle rect) { vk::Offset2D offset{static_cast(rect.left), static_cast(rect.bottom)}; vk::Extent2D extent{rect.GetWidth(), rect.GetHeight()}; @@ -412,7 +461,16 @@ void RasterizerCacheVulkan::CopySurface(const Surface& src_surface, const Surfac // This is only called when CanCopy is true, no need to run checks here if (src_surface->type == SurfaceType::Fill) { - // NO-OP Vulkan does not allow easy clearing for arbitary textures with rectangle + // FillSurface needs a 4 bytes buffer + const u32 fill_offset = + (boost::icl::first(copy_interval) - src_surface->addr) % src_surface->fill_size; + std::array fill_buffer; + + u32 fill_buff_pos = fill_offset; + for (int i : {0, 1, 2, 3}) + fill_buffer[i] = src_surface->fill_data[fill_buff_pos++ % src_surface->fill_size]; + + FillSurface(dst_surface, fill_buffer, dst_surface->GetScaledSubRect(subrect_params)); return; } if (src_surface->CanSubRect(subrect_params)) { diff --git a/src/video_core/renderer_vulkan/vk_shader_gen.cpp b/src/video_core/renderer_vulkan/vk_shader_gen.cpp index fbf7334cf..f6928af2f 100644 --- a/src/video_core/renderer_vulkan/vk_shader_gen.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_gen.cpp @@ -33,37 +33,30 @@ using VSOutputAttributes = RasterizerRegs::VSOutputAttributes; namespace Vulkan { static const char present_vertex_shader_source[] = R"( -#version 450 +#version 450 core #extension GL_ARB_separate_shader_objects : enable layout (location = 0) in vec2 vert_position; -layout (location = 1) in vec2 vert_tex_coord; -layout (location = 0) out vec2 frag_tex_coord; +layout (location = 1) in vec3 vert_tex_coord; +layout (location = 0) out vec3 frag_tex_coord; -// This is a truncated 3x3 matrix for 2D transformations: -// The upper-left 2x2 submatrix performs scaling/rotation/mirroring. -// The third column performs translation. -// The third row could be used for projection, which we don't need in 2D. It hence is assumed to -// implicitly be [0, 0, 1] layout (push_constant) uniform DrawInfo { - mat3x2 modelview_matrix; + mat4 modelview_matrix; vec4 i_resolution; vec4 o_resolution; int layer; }; void main() { - // Multiply input position by the rotscale part of the matrix and then manually translate by - // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector - // to `vec3(vert_position.xy, 1.0)` - gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); + vec4 position = vec4(vert_position, 0.0, 1.0) * modelview_matrix; + gl_Position = vec4(position.x, -position.y, 0.0, 1.0); frag_tex_coord = vert_tex_coord; } )"; static const char present_fragment_shader_source[] = R"( -#version 450 +#version 450 core #extension GL_ARB_separate_shader_objects : enable -layout (location = 0) in vec2 frag_tex_coord; +layout (location = 0) in vec3 frag_tex_coord; layout (location = 0) out vec4 color; layout (push_constant) uniform DrawInfo { @@ -73,10 +66,11 @@ layout (push_constant) uniform DrawInfo { int layer; }; -layout (set = 0, binding = 0) uniform sampler2D color_texture; +layout (set = 0, binding = 0) uniform sampler2D screen_textures[3]; void main() { - color = texture(color_texture, frag_tex_coord); + color = texture(screen_textures[int(frag_tex_coord.z)], frag_tex_coord.xy); + //color = vec4(0.5, 0.0, 0.5, 1.0); } )"; diff --git a/src/video_core/renderer_vulkan/vk_shader_state.h b/src/video_core/renderer_vulkan/vk_shader_state.h index 648ceaf80..7f6960306 100644 --- a/src/video_core/renderer_vulkan/vk_shader_state.h +++ b/src/video_core/renderer_vulkan/vk_shader_state.h @@ -84,25 +84,26 @@ struct HardwareVertex : public VertexBase { struct ScreenRectVertexBase { ScreenRectVertexBase() = default; - ScreenRectVertexBase(float x, float y, float u, float v) { + ScreenRectVertexBase(float x, float y, float u, float v, float s) { position.x = x; position.y = y; tex_coord.x = u; tex_coord.y = v; + tex_coord.z = s; } glm::vec2 position; - glm::vec2 tex_coord; + glm::vec3 tex_coord; }; struct ScreenRectVertex : public ScreenRectVertexBase { ScreenRectVertex() = default; - ScreenRectVertex(float x, float y, float u, float v) : ScreenRectVertexBase(x, y, u, v) {}; + ScreenRectVertex(float x, float y, float u, float v, float s) : ScreenRectVertexBase(x, y, u, v, s) {}; static constexpr auto binding_desc = vk::VertexInputBindingDescription(0, sizeof(ScreenRectVertexBase)); static constexpr std::array attribute_desc = { vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32Sfloat, offsetof(ScreenRectVertexBase, position)), - vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32Sfloat, offsetof(ScreenRectVertexBase, tex_coord)), + vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(ScreenRectVertexBase, tex_coord)), }; }; diff --git a/src/video_core/renderer_vulkan/vk_state.cpp b/src/video_core/renderer_vulkan/vk_state.cpp index c38ddc4a9..baf49012c 100644 --- a/src/video_core/renderer_vulkan/vk_state.cpp +++ b/src/video_core/renderer_vulkan/vk_state.cpp @@ -25,43 +25,56 @@ auto IsStencil = [](vk::Format format) -> bool { }; }; +void DescriptorUpdater::Reset() { + write_count = 0; + buffer_count = 0; + image_count = 0; +} + void DescriptorUpdater::Update() { - assert(update_count > 0); + assert(write_count > 0); auto device = g_vk_instace->GetDevice(); - device.updateDescriptorSets(update_count, writes.data(), 0, nullptr); + device.updateDescriptorSets(write_count, writes.data(), 0, nullptr); Reset(); } +void DescriptorUpdater::PushTextureArrayUpdate(vk::DescriptorSet set, u32 binding, vk::Sampler sampler, + std::span views) { + ASSERT(image_count < MAX_UPDATES); + + u32 start = image_count; + for (auto& view : views) { + image_infos[image_count++] = {sampler, view, vk::ImageLayout::eShaderReadOnlyOptimal}; + } + + writes[write_count++] = vk::WriteDescriptorSet{set, binding, 0, static_cast(views.size()), + vk::DescriptorType::eCombinedImageSampler, + image_infos.data() + start}; +} + void DescriptorUpdater::PushCombinedImageSamplerUpdate(vk::DescriptorSet set, u32 binding, vk::Sampler sampler, vk::ImageView view) { - assert(update_count < MAX_DESCRIPTORS); + ASSERT(image_count < MAX_UPDATES); - auto& info = update_queue[update_count]; - info.image_info = vk::DescriptorImageInfo{sampler, view, vk::ImageLayout::eShaderReadOnlyOptimal}; + image_infos[image_count] = {sampler, view, vk::ImageLayout::eShaderReadOnlyOptimal}; - writes[update_count++] = vk::WriteDescriptorSet{ - set, binding, 0, 1, - vk::DescriptorType::eCombinedImageSampler, - &info.image_info - }; + writes[write_count++] = vk::WriteDescriptorSet{set, binding, 0, 1, + vk::DescriptorType::eCombinedImageSampler, + &image_infos[image_count++]}; } void DescriptorUpdater::PushBufferUpdate(vk::DescriptorSet set, u32 binding, vk::DescriptorType buffer_type, u32 offset, u32 size, vk::Buffer buffer, const vk::BufferView& view) { - assert(update_count < MAX_DESCRIPTORS); + ASSERT(buffer_count < MAX_UPDATES); - auto& info = update_queue[update_count]; - info.buffer_info = vk::DescriptorBufferInfo{buffer, offset, size}; - info.buffer_view = view; + buffer_infos[buffer_count] = vk::DescriptorBufferInfo{buffer, offset, size}; - writes[update_count++] = vk::WriteDescriptorSet{ - set, binding, 0, 1, - buffer_type, nullptr, - &info.buffer_info, &info.buffer_view - }; + writes[write_count++] = vk::WriteDescriptorSet{set, binding, 0, 1, buffer_type, nullptr, + &buffer_infos[buffer_count++], + view ? &view : nullptr}; } VulkanState::VulkanState(const std::shared_ptr& swapchain) : swapchain(swapchain) { @@ -169,15 +182,19 @@ void VulkanState::SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuff descriptors_dirty = true; } -void VulkanState::SetPresentTexture(const VKTexture& image) { +void VulkanState::SetPresentTextures(vk::ImageView view0, vk::ImageView view1, vk::ImageView view2) { auto& set = descriptor_sets[3]; - updater.PushCombinedImageSamplerUpdate(set, 0, present_sampler, image.GetView()); - present_view = image.GetView(); + + std::array views{view0, view1, view2}; + updater.PushTextureArrayUpdate(set, 0, present_sampler, views); descriptors_dirty = true; } void VulkanState::SetPresentData(DrawInfo data) { - present_data = data; + auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); + cmdbuffer.pushConstants(present_pipeline_layout, vk::ShaderStageFlagBits::eFragment | + vk::ShaderStageFlagBits::eVertex, 0, sizeof(data), &data); + } void VulkanState::SetPlaceholderColor(u8 red, u8 green, u8 blue, u8 alpha) { @@ -480,8 +497,6 @@ void VulkanState::ApplyPresentState() { // Bind present pipeline and descriptors auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipeline.get()); - cmdbuffer.pushConstants(present_pipeline_layout, vk::ShaderStageFlagBits::eFragment | - vk::ShaderStageFlagBits::eVertex, 0, sizeof(present_data), &present_data); ApplyCommonState(false); @@ -561,7 +576,7 @@ void VulkanState::BuildDescriptorLayouts() { {2, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba }}; std::array present_set{{ - {0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment} + {0, vk::DescriptorType::eCombinedImageSampler, 3, vk::ShaderStageFlagBits::eFragment} }}; std::array create_infos{{ diff --git a/src/video_core/renderer_vulkan/vk_state.h b/src/video_core/renderer_vulkan/vk_state.h index aed22cdac..50dbbc460 100644 --- a/src/video_core/renderer_vulkan/vk_state.h +++ b/src/video_core/renderer_vulkan/vk_state.h @@ -21,7 +21,7 @@ template using OptRef = std::optional>; struct DrawInfo { - glm::mat2x3 modelview; + glm::mat4 modelview; glm::vec4 i_resolution; glm::vec4 o_resolution; int layer; @@ -32,9 +32,11 @@ public: DescriptorUpdater() { Reset(); } ~DescriptorUpdater() = default; - void Reset() { update_count = 0; } + void Reset(); void Update(); + void PushTextureArrayUpdate(vk::DescriptorSet, u32 biding, vk::Sampler sampler, + std::span views); void PushCombinedImageSamplerUpdate(vk::DescriptorSet set, u32 binding, vk::Sampler sampler, vk::ImageView view); void PushBufferUpdate(vk::DescriptorSet set, u32 binding, @@ -43,15 +45,16 @@ public: private: static constexpr u32 MAX_DESCRIPTORS = 10; + static constexpr u32 MAX_UPDATES = 20; struct Descriptor { vk::DescriptorImageInfo image_info; vk::DescriptorBufferInfo buffer_info; - vk::BufferView buffer_view; }; std::array writes; - std::array update_queue; - u32 update_count{}; + std::array image_infos; + std::array buffer_infos; + u32 image_count{0}, buffer_count{0}, write_count{0}; }; class VKSwapChain; @@ -105,7 +108,7 @@ public: void SetUniformBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer); void SetTexture(u32 binding, const VKTexture& texture); void SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer, u32 view_index); - void SetPresentTexture(const VKTexture& image); + void SetPresentTextures(vk::ImageView view0, vk::ImageView view1, vk::ImageView view2); void SetPresentData(DrawInfo data); void SetPlaceholderColor(u8 red, u8 green, u8 blue, u8 alpha); void UnbindTexture(const VKTexture& image); @@ -128,7 +131,6 @@ private: bool rendering{false}; vk::ImageView present_view; std::array render_views; - DrawInfo present_data; vk::Sampler render_sampler, present_sampler; VKTexture placeholder; diff --git a/src/video_core/renderer_vulkan/vk_texture.cpp b/src/video_core/renderer_vulkan/vk_texture.cpp index 1060dd06d..7a067b46b 100644 --- a/src/video_core/renderer_vulkan/vk_texture.cpp +++ b/src/video_core/renderer_vulkan/vk_texture.cpp @@ -75,6 +75,8 @@ void VKTexture::Create(const Info& create_info) { info.format = vk::Format::eD32SfloatS8Uint; } + std::cout << "New surface!\n"; + // Create the texture image_size = info.width * info.height * BytesPerPixel(info.format); aspect = GetImageAspect(info.format); @@ -136,9 +138,12 @@ void VKTexture::Destroy() { auto deleter = [this]() { auto device = g_vk_instace->GetDevice(); - device.destroyImage(texture); - device.destroyImageView(view); - device.freeMemory(memory); + if (texture) { + std::cout << "Surface destroyed!\n"; + device.destroyImage(texture); + device.destroyImageView(view); + device.freeMemory(memory); + } }; // Schedule deletion of the texture after it's no longer used @@ -270,7 +275,7 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, } else if (is_d24s8) { auto data = D24S8ToD32S8(pixels); - std::memcpy(buffer, data.data(), data.size()); + std::memcpy(buffer, data.data(), data.size() * sizeof(data[0])); } else { std::memcpy(buffer, pixels.data(), pixels.size()); @@ -322,7 +327,7 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region } else if (is_d24s8) { auto data = D32S8ToD24S8(memory); - std::memcpy(buffer, data.data(), data.size()); + std::memcpy(buffer, data.data(), data.size() * sizeof(data[0])); } else { std::memcpy(buffer, memory.data(), memory.size());