diff --git a/rpcs3/Emu/RSX/VK/VKFramebuffer.cpp b/rpcs3/Emu/RSX/VK/VKFramebuffer.cpp index 961c784c77..1dcbb00d00 100644 --- a/rpcs3/Emu/RSX/VK/VKFramebuffer.cpp +++ b/rpcs3/Emu/RSX/VK/VKFramebuffer.cpp @@ -25,7 +25,7 @@ namespace vk for (auto &e : image_list) { const VkImageSubresourceRange subres = { e->aspect(), 0, 1, 0, 1 }; - image_views.push_back(std::make_unique(dev, e, vk::default_component_map(), subres)); + image_views.push_back(std::make_unique(dev, e, VK_IMAGE_VIEW_TYPE_2D, vk::default_component_map(), subres)); } auto value = std::make_unique(dev, renderpass, width, height, std::move(image_views)); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index af88095362..34e8041820 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -230,6 +230,22 @@ namespace vk fmt::throw_exception("Unknown cull face value: 0x%x" HERE, static_cast(cfv)); } } + + VkImageViewType get_view_type(rsx::texture_dimension_extended type) + { + switch (type) + { + case rsx::texture_dimension_extended::texture_dimension_1d: + return VK_IMAGE_VIEW_TYPE_1D; + case rsx::texture_dimension_extended::texture_dimension_2d: + return VK_IMAGE_VIEW_TYPE_2D; + case rsx::texture_dimension_extended::texture_dimension_cubemap: + return VK_IMAGE_VIEW_TYPE_CUBE; + case rsx::texture_dimension_extended::texture_dimension_3d: + return VK_IMAGE_VIEW_TYPE_3D; + default: ASSUME(0); + }; + } } namespace @@ -1669,14 +1685,15 @@ void VKGSRender::end() } else { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i)); + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, ::glsl::program_domain::glsl_fragment_program, m_current_frame->descriptor_set); if (current_fragment_program.redirected_textures & (1 << i)) { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, ::glsl::program_domain::glsl_fragment_program, m_current_frame->descriptor_set, @@ -1692,7 +1709,8 @@ void VKGSRender::end() { if (!rsx::method_registers.vertex_textures[i].enabled()) { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, ::glsl::program_domain::glsl_vertex_program, m_current_frame->descriptor_set); @@ -1712,7 +1730,9 @@ void VKGSRender::end() if (!image_ptr) { rsx_log.error("Texture upload failed to vtexture index %d. Binding null sampler.", i); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); + + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, ::glsl::program_domain::glsl_vertex_program, m_current_frame->descriptor_set); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index b205142f86..8723f64611 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -67,8 +67,8 @@ namespace vk const render_device* g_current_renderer; std::unique_ptr g_null_texture; - std::unique_ptr g_null_image_view; std::unique_ptr g_scratch_buffer; + std::unordered_map> g_null_image_views; std::unordered_map> g_typeless_textures; std::unordered_map> g_compute_tasks; @@ -289,26 +289,32 @@ namespace vk return g_null_sampler; } - vk::image_view* null_image_view(vk::command_buffer &cmd) + vk::image_view* null_image_view(vk::command_buffer &cmd, VkImageViewType type) { - if (g_null_image_view) - return g_null_image_view.get(); + if (auto found = g_null_image_views.find(type); + found != g_null_image_views.end()) + { + return found->second.get(); + } - g_null_texture = std::make_unique(*g_current_renderer, g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, 4, 4, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0); + if (!g_null_texture) + { + g_null_texture = std::make_unique(*g_current_renderer, g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, 4, 4, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0); - g_null_image_view = std::make_unique(*g_current_renderer, g_null_texture.get()); + // Initialize memory to transparent black + VkClearColorValue clear_color = {}; + VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); + vkCmdClearColorImage(cmd, g_null_texture->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &range); - // Initialize memory to transparent black - VkClearColorValue clear_color = {}; - VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); - vkCmdClearColorImage(cmd, g_null_texture->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &range); + // Prep for shader access + change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); + } - // Prep for shader access - change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); - return g_null_image_view.get(); + auto& ret = g_null_image_views[type] = std::make_unique(*g_current_renderer, g_null_texture.get(), type); + return ret.get(); } vk::image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height) @@ -396,7 +402,7 @@ namespace vk vk::get_resource_manager()->destroy(); g_null_texture.reset(); - g_null_image_view.reset(); + g_null_image_views.clear(); g_scratch_buffer.reset(); g_upload_heap.destroy(); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index e6f87a752d..b90a4d604f 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -141,7 +141,7 @@ namespace vk VkImageAspectFlags get_aspect_flags(VkFormat format); VkSampler null_sampler(); - image_view* null_image_view(vk::command_buffer&); + image_view* null_image_view(vk::command_buffer&, VkImageViewType type); image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height); buffer* get_scratch_buffer(u32 min_required_size = 0); data_heap* get_upload_heap(); @@ -1387,6 +1387,11 @@ private: return info.mipLevels; } + u32 layers() const + { + return info.arrayLayers; + } + u8 samples() const { return u8(info.samples); @@ -1456,8 +1461,9 @@ private: } image_view(VkDevice dev, vk::image* resource, - const VkComponentMapping mapping = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }, - const VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}) + VkImageViewType view_type = VK_IMAGE_VIEW_TYPE_MAX_ENUM, + const VkComponentMapping& mapping = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }, + const VkImageSubresourceRange& range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}) : m_device(dev), m_resource(resource) { info.format = resource->info.format; @@ -1466,23 +1472,34 @@ private: info.components = mapping; info.subresourceRange = range; - switch (resource->info.imageType) + if (view_type == VK_IMAGE_VIEW_TYPE_MAX_ENUM) { - case VK_IMAGE_TYPE_1D: - info.viewType = VK_IMAGE_VIEW_TYPE_1D; - break; - case VK_IMAGE_TYPE_2D: - if (resource->info.flags == VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) - info.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - else - info.viewType = VK_IMAGE_VIEW_TYPE_2D; - break; - case VK_IMAGE_TYPE_3D: - info.viewType = VK_IMAGE_VIEW_TYPE_3D; - break; - default: - ASSUME(0); - break; + switch (resource->info.imageType) + { + case VK_IMAGE_TYPE_1D: + info.viewType = VK_IMAGE_VIEW_TYPE_1D; + break; + case VK_IMAGE_TYPE_2D: + if (resource->info.flags == VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) + info.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + else if (resource->info.arrayLayers == 1) + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + else + info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + break; + case VK_IMAGE_TYPE_3D: + info.viewType = VK_IMAGE_VIEW_TYPE_3D; + break; + default: + ASSUME(0); + break; + } + + info.subresourceRange.layerCount = resource->info.arrayLayers; + } + else + { + info.viewType = view_type; } create_impl(); @@ -1588,7 +1605,7 @@ private: const auto range = vk::get_image_subresource_range(0, 0, info.arrayLayers, info.mipLevels, aspect() & mask); verify(HERE), range.aspectMask; - auto view = std::make_unique(*get_current_renderer(), this, real_mapping, range); + auto view = std::make_unique(*get_current_renderer(), this, VK_IMAGE_VIEW_TYPE_MAX_ENUM, real_mapping, range); auto result = view.get(); views.emplace(remap_encoding, std::move(view)); diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index f9081e82cd..669172816d 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -4,6 +4,7 @@ #include "VKFragmentProgram.h" #include "VKRenderTargets.h" #include "VKFramebuffer.h" +#include "VKResourceManager.h" #include "../Overlays/overlays.h" @@ -529,6 +530,7 @@ namespace vk "#version 420\n" "#extension GL_ARB_separate_shader_objects : enable\n" "layout(set=0, binding=1) uniform sampler2D fs0;\n" + "layout(set=0, binding=2) uniform sampler2DArray fs1;\n" "layout(location=0) in vec2 tc0;\n" "layout(location=1) in vec4 color;\n" "layout(location=2) in vec4 parameters;\n" @@ -602,16 +604,29 @@ namespace vk " diff_color.a *= (sin(parameters.x) + 1.f) * 0.5f;\n" "\n" " if (parameters.z < 1.)\n" + " {\n" " ocol = diff_color;\n" + " }\n" + " else if (parameters.z > 2.)\n" + " {\n" + " ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))).rrrr * diff_color;\n" + " }\n" " else if (parameters.z > 1.)\n" + " {\n" " ocol = texture(fs0, tc0).rrrr * diff_color;\n" + " }\n" " else\n" + " {\n" " ocol = sample_image(fs0, tc0, parameters2.x).bgra * diff_color;\n" + " }\n" "}\n"; // Allow mixed primitive rendering multi_primitive = true; + // 2 input textures + m_num_usable_samplers = 2; + renderpass_config.set_attachment_count(1); renderpass_config.set_color_mask(0, true, true, true, true); renderpass_config.set_depth_mask(false); @@ -622,18 +637,18 @@ namespace vk } vk::image_view* upload_simple_texture(vk::render_device &dev, vk::command_buffer &cmd, - vk::data_heap& upload_heap, u64 key, int w, int h, bool font, bool temp, void *pixel_src, u32 owner_uid) + vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, void *pixel_src, u32 owner_uid) { const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM; const u32 pitch = (font) ? w : w * 4; - const u32 data_size = pitch * h; + const u32 data_size = pitch * h * layers; const auto offset = upload_heap.alloc<512>(data_size); const auto addr = upload_heap.map(offset, data_size); - const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers }; auto tex = std::make_unique(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - VK_IMAGE_TYPE_2D, format, std::max(w, 1), std::max(h, 1), 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0); @@ -645,12 +660,12 @@ namespace vk upload_heap.unmap(); VkBufferImageCopy region; - region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers }; region.bufferOffset = offset; region.bufferRowLength = w; region.bufferImageHeight = h; region.imageOffset = {}; - region.imageExtent = { static_cast(w), static_cast(h), 1u}; + region.imageExtent = { static_cast(w), static_cast(h), 1u }; change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); vkCmdCopyBufferToImage(cmd, upload_heap.heap->value, tex->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); @@ -686,7 +701,7 @@ namespace vk u64 storage_key = 1; for (const auto &res : configuration.texture_raw_data) { - upload_simple_texture(dev, cmd, upload_heap, storage_key++, res->w, res->h, false, false, res->data, UINT32_MAX); + upload_simple_texture(dev, cmd, upload_heap, storage_key++, res->w, res->h, 1, false, false, res->data, UINT32_MAX); } configuration.free_resources(); @@ -724,14 +739,33 @@ namespace vk vk::image_view* find_font(rsx::overlays::font *font, vk::command_buffer &cmd, vk::data_heap &upload_heap) { + const auto image_size = font->get_glyph_data_dimensions(); + u64 key = reinterpret_cast(font); auto found = view_cache.find(key); if (found != view_cache.end()) - return found->second.get(); + { + if (const auto raw = found->second->image(); + image_size.width == raw->width() && + image_size.height == raw->height() && + image_size.depth == raw->layers()) + { + return found->second.get(); + } + else + { + auto gc = vk::get_resource_manager(); + gc->dispose(font_cache[key]); + gc->dispose(view_cache[key]); + } + } - //Create font file - return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, font->width, font->height, - true, false, font->glyph_data.data(), UINT32_MAX); + // Create font resource + std::vector bytes; + font->get_glyph_data(bytes); + + return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, image_size.width, image_size.height, image_size.depth, + true, false, bytes.data(), UINT32_MAX); } vk::image_view* find_temp_image(rsx::overlays::image_info *desc, vk::command_buffer &cmd, vk::data_heap &upload_heap, u32 owner_uid) @@ -741,7 +775,7 @@ namespace vk if (found != temp_view_cache.end()) return found->second.get(); - return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, + return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1, false, true, desc->data, owner_uid); } @@ -834,6 +868,12 @@ namespace vk m_time = static_cast(get_system_time() / 1000) * 0.005f; m_viewport = { { static_cast(viewport.x1), static_cast(viewport.y1) }, { static_cast(viewport.width()), static_cast(viewport.height()) } }; + std::vector image_views + { + vk::null_image_view(cmd, VK_IMAGE_VIEW_TYPE_2D), + vk::null_image_view(cmd, VK_IMAGE_VIEW_TYPE_2D_ARRAY) + }; + for (auto &command : ui.get_compiled().draw_commands) { num_drawable_elements = static_cast(command.verts.size()); @@ -850,7 +890,7 @@ namespace vk m_clip_region = command.config.clip_rect; m_texture_type = 1; - auto src = vk::null_image_view(cmd); + vk::image_view* src = nullptr; switch (command.config.texture_ref) { case rsx::overlays::image_resource_id::game_icon: @@ -860,8 +900,8 @@ namespace vk m_skip_texture_read = true; break; case rsx::overlays::image_resource_id::font_file: - m_texture_type = 2; src = find_font(command.config.font_ref, cmd, upload_heap); + m_texture_type = src->image()->layers() == 1 ? 2 : 3; break; case rsx::overlays::image_resource_id::raw_image: src = find_temp_image(static_cast(command.config.external_data_ref), cmd, upload_heap, ui.uid); @@ -871,7 +911,13 @@ namespace vk break; } - overlay_pass::run(cmd, viewport, target, { src }, render_pass); + if (src) + { + const int res_id = src->image()->layers() > 1 ? 1 : 0; + image_views[res_id] = src; + } + + overlay_pass::run(cmd, viewport, target, image_views, render_pass); } ui.update(); diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.h b/rpcs3/Emu/RSX/VK/VKResourceManager.h index a07382a5df..3a4877e647 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.h +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.h @@ -12,6 +12,8 @@ namespace vk u64 eid; const vk::render_device* m_device; std::vector> m_disposed_buffers; + std::vector> m_disposed_image_views; + std::vector> m_disposed_images; rsx::simple_array m_disposed_events; eid_scope_t(u64 _eid): @@ -36,6 +38,8 @@ namespace vk } m_disposed_buffers.clear(); + m_disposed_image_views.clear(); + m_disposed_images.clear(); } }; @@ -132,6 +136,16 @@ namespace vk get_current_eid_scope().m_disposed_buffers.emplace_back(std::move(buf)); } + void dispose(std::unique_ptr& view) + { + get_current_eid_scope().m_disposed_image_views.emplace_back(std::move(view)); + } + + void dispose(std::unique_ptr& img) + { + get_current_eid_scope().m_disposed_images.emplace_back(std::move(img)); + } + void dispose(VkEvent& event) { get_current_eid_scope().m_disposed_events.push_back(event);