diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_base.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_base.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 152 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.cpp | 143 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_blit_screen.h | 13 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 4 |
8 files changed, 247 insertions, 75 deletions
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index 3ea72fda9..a99c33c37 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp | |||
| @@ -27,7 +27,7 @@ void RendererBase::UpdateCurrentFramebufferLayout() { | |||
| 27 | render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height); | 27 | render_window.UpdateCurrentFramebufferLayout(layout.width, layout.height); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | void RendererBase::RequestScreenshot(void* data, std::function<void()> callback, | 30 | void RendererBase::RequestScreenshot(void* data, std::function<void(bool)> callback, |
| 31 | const Layout::FramebufferLayout& layout) { | 31 | const Layout::FramebufferLayout& layout) { |
| 32 | if (renderer_settings.screenshot_requested) { | 32 | if (renderer_settings.screenshot_requested) { |
| 33 | LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request"); | 33 | LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request"); |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 22b80c328..bb204454e 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -24,7 +24,7 @@ struct RendererSettings { | |||
| 24 | // Screenshot | 24 | // Screenshot |
| 25 | std::atomic<bool> screenshot_requested{false}; | 25 | std::atomic<bool> screenshot_requested{false}; |
| 26 | void* screenshot_bits{}; | 26 | void* screenshot_bits{}; |
| 27 | std::function<void()> screenshot_complete_callback; | 27 | std::function<void(bool)> screenshot_complete_callback; |
| 28 | Layout::FramebufferLayout screenshot_framebuffer_layout; | 28 | Layout::FramebufferLayout screenshot_framebuffer_layout; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| @@ -80,7 +80,7 @@ public: | |||
| 80 | void RefreshBaseSettings(); | 80 | void RefreshBaseSettings(); |
| 81 | 81 | ||
| 82 | /// Request a screenshot of the next frame | 82 | /// Request a screenshot of the next frame |
| 83 | void RequestScreenshot(void* data, std::function<void()> callback, | 83 | void RequestScreenshot(void* data, std::function<void(bool)> callback, |
| 84 | const Layout::FramebufferLayout& layout); | 84 | const Layout::FramebufferLayout& layout); |
| 85 | 85 | ||
| 86 | protected: | 86 | protected: |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f1b00c24c..7d7cba69c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -486,7 +486,7 @@ void RendererOpenGL::RenderScreenshot() { | |||
| 486 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); | 486 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); |
| 487 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | 487 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); |
| 488 | 488 | ||
| 489 | renderer_settings.screenshot_complete_callback(); | 489 | renderer_settings.screenshot_complete_callback(true); |
| 490 | renderer_settings.screenshot_requested = false; | 490 | renderer_settings.screenshot_requested = false; |
| 491 | } | 491 | } |
| 492 | 492 | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index a8d04dc61..7c9b0d6db 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -138,6 +138,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 138 | const bool use_accelerated = | 138 | const bool use_accelerated = |
| 139 | rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); | 139 | rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); |
| 140 | const bool is_srgb = use_accelerated && screen_info.is_srgb; | 140 | const bool is_srgb = use_accelerated && screen_info.is_srgb; |
| 141 | RenderScreenshot(*framebuffer, use_accelerated); | ||
| 141 | 142 | ||
| 142 | bool has_been_recreated = false; | 143 | bool has_been_recreated = false; |
| 143 | const auto recreate_swapchain = [&] { | 144 | const auto recreate_swapchain = [&] { |
| @@ -162,7 +163,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 162 | if (has_been_recreated) { | 163 | if (has_been_recreated) { |
| 163 | blit_screen.Recreate(); | 164 | blit_screen.Recreate(); |
| 164 | } | 165 | } |
| 165 | const VkSemaphore render_semaphore = blit_screen.Draw(*framebuffer, use_accelerated); | 166 | const VkSemaphore render_semaphore = blit_screen.DrawToSwapchain(*framebuffer, use_accelerated); |
| 166 | scheduler.Flush(render_semaphore); | 167 | scheduler.Flush(render_semaphore); |
| 167 | scheduler.WaitWorker(); | 168 | scheduler.WaitWorker(); |
| 168 | swapchain.Present(render_semaphore); | 169 | swapchain.Present(render_semaphore); |
| @@ -193,4 +194,153 @@ void RendererVulkan::Report() const { | |||
| 193 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); | 194 | telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); |
| 194 | } | 195 | } |
| 195 | 196 | ||
| 197 | void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, | ||
| 198 | bool use_accelerated) { | ||
| 199 | if (!renderer_settings.screenshot_requested) { | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | ||
| 203 | vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{ | ||
| 204 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | ||
| 205 | .pNext = nullptr, | ||
| 206 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | ||
| 207 | .imageType = VK_IMAGE_TYPE_2D, | ||
| 208 | .format = VK_FORMAT_B8G8R8A8_UNORM, | ||
| 209 | .extent = | ||
| 210 | { | ||
| 211 | .width = layout.width, | ||
| 212 | .height = layout.height, | ||
| 213 | .depth = 1, | ||
| 214 | }, | ||
| 215 | .mipLevels = 1, | ||
| 216 | .arrayLayers = 1, | ||
| 217 | .samples = VK_SAMPLE_COUNT_1_BIT, | ||
| 218 | .tiling = VK_IMAGE_TILING_OPTIMAL, | ||
| 219 | .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | | ||
| 220 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | ||
| 221 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 222 | .queueFamilyIndexCount = 0, | ||
| 223 | .pQueueFamilyIndices = nullptr, | ||
| 224 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 225 | }); | ||
| 226 | const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal); | ||
| 227 | |||
| 228 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | ||
| 229 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | ||
| 230 | .pNext = nullptr, | ||
| 231 | .flags = 0, | ||
| 232 | .image = *staging_image, | ||
| 233 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | ||
| 234 | .format = screen_info.is_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM, | ||
| 235 | .components{ | ||
| 236 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 237 | .g = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 238 | .b = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 239 | .a = VK_COMPONENT_SWIZZLE_IDENTITY, | ||
| 240 | }, | ||
| 241 | .subresourceRange{ | ||
| 242 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 243 | .baseMipLevel = 0, | ||
| 244 | .levelCount = 1, | ||
| 245 | .baseArrayLayer = 0, | ||
| 246 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 247 | }, | ||
| 248 | }); | ||
| 249 | const VkExtent2D render_area{.width = layout.width, .height = layout.height}; | ||
| 250 | const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); | ||
| 251 | // Since we're not rendering to the screen, ignore the render semaphore. | ||
| 252 | void(blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated)); | ||
| 253 | |||
| 254 | const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); | ||
| 255 | const VkBufferCreateInfo dst_buffer_info{ | ||
| 256 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | ||
| 257 | .pNext = nullptr, | ||
| 258 | .flags = 0, | ||
| 259 | .size = buffer_size, | ||
| 260 | .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, | ||
| 261 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||
| 262 | .queueFamilyIndexCount = 0, | ||
| 263 | .pQueueFamilyIndices = nullptr, | ||
| 264 | }; | ||
| 265 | const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); | ||
| 266 | MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); | ||
| 267 | |||
| 268 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 269 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | ||
| 270 | const VkImageMemoryBarrier read_barrier{ | ||
| 271 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 272 | .pNext = nullptr, | ||
| 273 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 274 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 275 | .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, | ||
| 276 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 277 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 278 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 279 | .image = *staging_image, | ||
| 280 | .subresourceRange{ | ||
| 281 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 282 | .baseMipLevel = 0, | ||
| 283 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 284 | .baseArrayLayer = 0, | ||
| 285 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 286 | }, | ||
| 287 | }; | ||
| 288 | const VkImageMemoryBarrier image_write_barrier{ | ||
| 289 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 290 | .pNext = nullptr, | ||
| 291 | .srcAccessMask = 0, | ||
| 292 | .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 293 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 294 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 295 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 296 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 297 | .image = *staging_image, | ||
| 298 | .subresourceRange{ | ||
| 299 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 300 | .baseMipLevel = 0, | ||
| 301 | .levelCount = VK_REMAINING_MIP_LEVELS, | ||
| 302 | .baseArrayLayer = 0, | ||
| 303 | .layerCount = VK_REMAINING_ARRAY_LAYERS, | ||
| 304 | }, | ||
| 305 | }; | ||
| 306 | static constexpr VkMemoryBarrier memory_write_barrier{ | ||
| 307 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 308 | .pNext = nullptr, | ||
| 309 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 310 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 311 | }; | ||
| 312 | const VkBufferImageCopy copy{ | ||
| 313 | .bufferOffset = 0, | ||
| 314 | .bufferRowLength = 0, | ||
| 315 | .bufferImageHeight = 0, | ||
| 316 | .imageSubresource{ | ||
| 317 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | ||
| 318 | .mipLevel = 0, | ||
| 319 | .baseArrayLayer = 0, | ||
| 320 | .layerCount = 1, | ||
| 321 | }, | ||
| 322 | .imageOffset{.x = 0, .y = 0, .z = 0}, | ||
| 323 | .imageExtent{ | ||
| 324 | .width = layout.width, | ||
| 325 | .height = layout.height, | ||
| 326 | .depth = 1, | ||
| 327 | }, | ||
| 328 | }; | ||
| 329 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 330 | 0, read_barrier); | ||
| 331 | cmdbuf.CopyImageToBuffer(*staging_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *dst_buffer, | ||
| 332 | copy); | ||
| 333 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 334 | 0, memory_write_barrier, nullptr, image_write_barrier); | ||
| 335 | }); | ||
| 336 | // Ensure the copy is fully completed before saving the screenshot | ||
| 337 | scheduler.Finish(); | ||
| 338 | |||
| 339 | // Copy backing image data to the QImage screenshot buffer | ||
| 340 | const auto dst_memory_map = dst_buffer_memory.Map(); | ||
| 341 | std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size()); | ||
| 342 | renderer_settings.screenshot_complete_callback(false); | ||
| 343 | renderer_settings.screenshot_requested = false; | ||
| 344 | } | ||
| 345 | |||
| 196 | } // namespace Vulkan | 346 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index d7d17e110..6dc985109 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -54,6 +54,8 @@ public: | |||
| 54 | private: | 54 | private: |
| 55 | void Report() const; | 55 | void Report() const; |
| 56 | 56 | ||
| 57 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated); | ||
| 58 | |||
| 57 | Core::TelemetrySession& telemetry_session; | 59 | Core::TelemetrySession& telemetry_session; |
| 58 | Core::Memory::Memory& cpu_memory; | 60 | Core::Memory::Memory& cpu_memory; |
| 59 | Tegra::GPU& gpu; | 61 | Tegra::GPU& gpu; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 516f428e7..5c43b8acf 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -130,7 +130,10 @@ void VKBlitScreen::Recreate() { | |||
| 130 | CreateDynamicResources(); | 130 | CreateDynamicResources(); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool use_accelerated) { | 133 | VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, |
| 134 | const VkFramebuffer& host_framebuffer, | ||
| 135 | const Layout::FramebufferLayout layout, VkExtent2D render_area, | ||
| 136 | bool use_accelerated) { | ||
| 134 | RefreshResources(framebuffer); | 137 | RefreshResources(framebuffer); |
| 135 | 138 | ||
| 136 | // Finish any pending renderpass | 139 | // Finish any pending renderpass |
| @@ -145,8 +148,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 145 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]); | 148 | use_accelerated ? screen_info.image_view : *raw_image_views[image_index]); |
| 146 | 149 | ||
| 147 | BufferData data; | 150 | BufferData data; |
| 148 | SetUniformData(data, framebuffer); | 151 | SetUniformData(data, layout); |
| 149 | SetVertexData(data, framebuffer); | 152 | SetVertexData(data, framebuffer, layout); |
| 150 | 153 | ||
| 151 | const std::span<u8> mapped_span = buffer_commit.Map(); | 154 | const std::span<u8> mapped_span = buffer_commit.Map(); |
| 152 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | 155 | std::memcpy(mapped_span.data(), &data, sizeof(data)); |
| @@ -220,52 +223,75 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool | |||
| 220 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); | 223 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); |
| 221 | }); | 224 | }); |
| 222 | } | 225 | } |
| 223 | scheduler.Record([this, image_index, size = swapchain.GetSize()](vk::CommandBuffer cmdbuf) { | 226 | scheduler.Record( |
| 224 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; | 227 | [this, host_framebuffer, image_index, size = render_area](vk::CommandBuffer cmdbuf) { |
| 225 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; | 228 | const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; |
| 226 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; | 229 | const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; |
| 227 | const VkClearValue clear_color{ | 230 | const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; |
| 228 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, | 231 | const VkClearValue clear_color{ |
| 229 | }; | 232 | .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, |
| 230 | const VkRenderPassBeginInfo renderpass_bi{ | 233 | }; |
| 231 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | 234 | const VkRenderPassBeginInfo renderpass_bi{ |
| 232 | .pNext = nullptr, | 235 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, |
| 233 | .renderPass = *renderpass, | 236 | .pNext = nullptr, |
| 234 | .framebuffer = *framebuffers[image_index], | 237 | .renderPass = *renderpass, |
| 235 | .renderArea = | 238 | .framebuffer = host_framebuffer, |
| 236 | { | 239 | .renderArea = |
| 237 | .offset = {0, 0}, | 240 | { |
| 238 | .extent = size, | 241 | .offset = {0, 0}, |
| 239 | }, | 242 | .extent = size, |
| 240 | .clearValueCount = 1, | 243 | }, |
| 241 | .pClearValues = &clear_color, | 244 | .clearValueCount = 1, |
| 242 | }; | 245 | .pClearValues = &clear_color, |
| 243 | const VkViewport viewport{ | 246 | }; |
| 244 | .x = 0.0f, | 247 | const VkViewport viewport{ |
| 245 | .y = 0.0f, | 248 | .x = 0.0f, |
| 246 | .width = static_cast<float>(size.width), | 249 | .y = 0.0f, |
| 247 | .height = static_cast<float>(size.height), | 250 | .width = static_cast<float>(size.width), |
| 248 | .minDepth = 0.0f, | 251 | .height = static_cast<float>(size.height), |
| 249 | .maxDepth = 1.0f, | 252 | .minDepth = 0.0f, |
| 250 | }; | 253 | .maxDepth = 1.0f, |
| 251 | const VkRect2D scissor{ | 254 | }; |
| 252 | .offset = {0, 0}, | 255 | const VkRect2D scissor{ |
| 253 | .extent = size, | 256 | .offset = {0, 0}, |
| 254 | }; | 257 | .extent = size, |
| 255 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | 258 | }; |
| 256 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); | 259 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); |
| 257 | cmdbuf.SetViewport(0, viewport); | 260 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| 258 | cmdbuf.SetScissor(0, scissor); | 261 | cmdbuf.SetViewport(0, viewport); |
| 259 | 262 | cmdbuf.SetScissor(0, scissor); | |
| 260 | cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); | 263 | |
| 261 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, | 264 | cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); |
| 262 | descriptor_sets[image_index], {}); | 265 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, |
| 263 | cmdbuf.Draw(4, 1, 0, 0); | 266 | descriptor_sets[image_index], {}); |
| 264 | cmdbuf.EndRenderPass(); | 267 | cmdbuf.Draw(4, 1, 0, 0); |
| 265 | }); | 268 | cmdbuf.EndRenderPass(); |
| 269 | }); | ||
| 266 | return *semaphores[image_index]; | 270 | return *semaphores[image_index]; |
| 267 | } | 271 | } |
| 268 | 272 | ||
| 273 | VkSemaphore VKBlitScreen::DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, | ||
| 274 | bool use_accelerated) { | ||
| 275 | const std::size_t image_index = swapchain.GetImageIndex(); | ||
| 276 | const VkExtent2D render_area = swapchain.GetSize(); | ||
| 277 | const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | ||
| 278 | return Draw(framebuffer, *framebuffers[image_index], layout, render_area, use_accelerated); | ||
| 279 | } | ||
| 280 | |||
| 281 | vk::Framebuffer VKBlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { | ||
| 282 | return device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{ | ||
| 283 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | ||
| 284 | .pNext = nullptr, | ||
| 285 | .flags = 0, | ||
| 286 | .renderPass = *renderpass, | ||
| 287 | .attachmentCount = 1, | ||
| 288 | .pAttachments = &image_view, | ||
| 289 | .width = extent.width, | ||
| 290 | .height = extent.height, | ||
| 291 | .layers = 1, | ||
| 292 | }); | ||
| 293 | } | ||
| 294 | |||
| 269 | void VKBlitScreen::CreateStaticResources() { | 295 | void VKBlitScreen::CreateStaticResources() { |
| 270 | CreateShaders(); | 296 | CreateShaders(); |
| 271 | CreateSemaphores(); | 297 | CreateSemaphores(); |
| @@ -609,22 +635,9 @@ void VKBlitScreen::CreateFramebuffers() { | |||
| 609 | const VkExtent2D size{swapchain.GetSize()}; | 635 | const VkExtent2D size{swapchain.GetSize()}; |
| 610 | framebuffers.resize(image_count); | 636 | framebuffers.resize(image_count); |
| 611 | 637 | ||
| 612 | VkFramebufferCreateInfo ci{ | ||
| 613 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | ||
| 614 | .pNext = nullptr, | ||
| 615 | .flags = 0, | ||
| 616 | .renderPass = *renderpass, | ||
| 617 | .attachmentCount = 1, | ||
| 618 | .pAttachments = nullptr, | ||
| 619 | .width = size.width, | ||
| 620 | .height = size.height, | ||
| 621 | .layers = 1, | ||
| 622 | }; | ||
| 623 | |||
| 624 | for (std::size_t i = 0; i < image_count; ++i) { | 638 | for (std::size_t i = 0; i < image_count; ++i) { |
| 625 | const VkImageView image_view{swapchain.GetImageViewIndex(i)}; | 639 | const VkImageView image_view{swapchain.GetImageViewIndex(i)}; |
| 626 | ci.pAttachments = &image_view; | 640 | framebuffers[i] = CreateFramebuffer(image_view, size); |
| 627 | framebuffers[i] = device.GetLogical().CreateFramebuffer(ci); | ||
| 628 | } | 641 | } |
| 629 | } | 642 | } |
| 630 | 643 | ||
| @@ -752,15 +765,13 @@ void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView imag | |||
| 752 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); | 765 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); |
| 753 | } | 766 | } |
| 754 | 767 | ||
| 755 | void VKBlitScreen::SetUniformData(BufferData& data, | 768 | void VKBlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const { |
| 756 | const Tegra::FramebufferConfig& framebuffer) const { | ||
| 757 | const auto& layout = render_window.GetFramebufferLayout(); | ||
| 758 | data.uniform.modelview_matrix = | 769 | data.uniform.modelview_matrix = |
| 759 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); | 770 | MakeOrthographicMatrix(static_cast<f32>(layout.width), static_cast<f32>(layout.height)); |
| 760 | } | 771 | } |
| 761 | 772 | ||
| 762 | void VKBlitScreen::SetVertexData(BufferData& data, | 773 | void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, |
| 763 | const Tegra::FramebufferConfig& framebuffer) const { | 774 | const Layout::FramebufferLayout layout) const { |
| 764 | const auto& framebuffer_transform_flags = framebuffer.transform_flags; | 775 | const auto& framebuffer_transform_flags = framebuffer.transform_flags; |
| 765 | const auto& framebuffer_crop_rect = framebuffer.crop_rect; | 776 | const auto& framebuffer_crop_rect = framebuffer.crop_rect; |
| 766 | 777 | ||
| @@ -798,7 +809,7 @@ void VKBlitScreen::SetVertexData(BufferData& data, | |||
| 798 | static_cast<f32>(screen_info.height); | 809 | static_cast<f32>(screen_info.height); |
| 799 | } | 810 | } |
| 800 | 811 | ||
| 801 | const auto& screen = render_window.GetFramebufferLayout().screen; | 812 | const auto& screen = layout.screen; |
| 802 | const auto x = static_cast<f32>(screen.left); | 813 | const auto x = static_cast<f32>(screen.left); |
| 803 | const auto y = static_cast<f32>(screen.top); | 814 | const auto y = static_cast<f32>(screen.top); |
| 804 | const auto w = static_cast<f32>(screen.GetWidth()); | 815 | const auto w = static_cast<f32>(screen.GetWidth()); |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 5e3177685..430bcfbca 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -56,8 +56,16 @@ public: | |||
| 56 | void Recreate(); | 56 | void Recreate(); |
| 57 | 57 | ||
| 58 | [[nodiscard]] VkSemaphore Draw(const Tegra::FramebufferConfig& framebuffer, | 58 | [[nodiscard]] VkSemaphore Draw(const Tegra::FramebufferConfig& framebuffer, |
| 59 | const VkFramebuffer& host_framebuffer, | ||
| 60 | const Layout::FramebufferLayout layout, VkExtent2D render_area, | ||
| 59 | bool use_accelerated); | 61 | bool use_accelerated); |
| 60 | 62 | ||
| 63 | [[nodiscard]] VkSemaphore DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, | ||
| 64 | bool use_accelerated); | ||
| 65 | |||
| 66 | [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, | ||
| 67 | VkExtent2D extent); | ||
| 68 | |||
| 61 | private: | 69 | private: |
| 62 | struct BufferData; | 70 | struct BufferData; |
| 63 | 71 | ||
| @@ -81,8 +89,9 @@ private: | |||
| 81 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); | 89 | void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); |
| 82 | 90 | ||
| 83 | void UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const; | 91 | void UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const; |
| 84 | void SetUniformData(BufferData& data, const Tegra::FramebufferConfig& framebuffer) const; | 92 | void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; |
| 85 | void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer) const; | 93 | void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, |
| 94 | const Layout::FramebufferLayout layout) const; | ||
| 86 | 95 | ||
| 87 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; | 96 | u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; |
| 88 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, | 97 | u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 25b658b2a..2e0ade815 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -632,9 +632,9 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p | |||
| 632 | screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); | 632 | screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); |
| 633 | renderer.RequestScreenshot( | 633 | renderer.RequestScreenshot( |
| 634 | screenshot_image.bits(), | 634 | screenshot_image.bits(), |
| 635 | [=, this] { | 635 | [=, this](bool invert_y) { |
| 636 | const std::string std_screenshot_path = screenshot_path.toStdString(); | 636 | const std::string std_screenshot_path = screenshot_path.toStdString(); |
| 637 | if (screenshot_image.mirrored(false, true).save(screenshot_path)) { | 637 | if (screenshot_image.mirrored(false, invert_y).save(screenshot_path)) { |
| 638 | LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); | 638 | LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); |
| 639 | } else { | 639 | } else { |
| 640 | LOG_ERROR(Frontend, "Failed to save screenshot to \"{}\"", std_screenshot_path); | 640 | LOG_ERROR(Frontend, "Failed to save screenshot to \"{}\"", std_screenshot_path); |