diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.cpp b/rpcs3/Emu/RSX/GL/GLOverlays.cpp index 401dc6b0e4..9fb0e23291 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.cpp +++ b/rpcs3/Emu/RSX/GL/GLOverlays.cpp @@ -75,7 +75,7 @@ namespace gl } } - void overlay_pass::emit_geometry() + void overlay_pass::emit_geometry(gl::command_context& /*cmd*/) { int old_vao; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao); @@ -176,7 +176,7 @@ namespace gl cmd->use_program(program_handle.id()); on_load(); bind_resources(); - emit_geometry(); + emit_geometry(cmd); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); @@ -350,7 +350,7 @@ namespace gl } } - void ui_overlay_renderer::emit_geometry() + void ui_overlay_renderer::emit_geometry(gl::command_context& cmd) { if (m_current_primitive_type == rsx::overlays::primitive_type::quad_list) { @@ -378,7 +378,7 @@ namespace gl } else { - overlay_pass::emit_geometry(); + overlay_pass::emit_geometry(cmd); } } diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index 92f76160a8..5ad7065fd0 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -57,7 +57,7 @@ namespace gl m_vertex_data_buffer.data(elements_count * sizeof(T), data); } - virtual void emit_geometry(); + virtual void emit_geometry(gl::command_context& cmd); void run(gl::command_context& cmd, const areau& region, GLuint target_texture, GLuint image_aspect_bits, bool enable_blending = false); }; @@ -87,7 +87,7 @@ namespace gl void set_primitive_type(rsx::overlays::primitive_type type); - void emit_geometry() override; + void emit_geometry(gl::command_context& cmd) override; void run(gl::command_context& cmd, const areau& viewport, GLuint target, rsx::overlays::overlay& ui); }; diff --git a/rpcs3/Emu/RSX/GL/GLResolveHelper.cpp b/rpcs3/Emu/RSX/GL/GLResolveHelper.cpp index a8997519af..54899a2230 100644 --- a/rpcs3/Emu/RSX/GL/GLResolveHelper.cpp +++ b/rpcs3/Emu/RSX/GL/GLResolveHelper.cpp @@ -40,7 +40,7 @@ namespace gl { ensure(src->samples() > 1 && dst->samples() == 1); - ensure(src->format_class() == RSX_FORMAT_CLASS_COLOR); // TODO + if (src->aspect() == gl::image_aspect::color) [[ likely ]] { auto& job = g_resolve_helpers[src->get_internal_format()]; if (!job) @@ -50,7 +50,50 @@ namespace gl } job->run(cmd, src, dst); + return; } + + auto get_resolver_pass = [](GLuint aspect_bits) -> std::unique_ptr& + { + auto& pass = g_depth_resolvers[aspect_bits]; + if (!pass) + { + ds_resolve_pass_base* ptr = nullptr; + switch (aspect_bits) + { + case gl::image_aspect::depth: + ptr = new depth_only_resolver(); + break; + case gl::image_aspect::stencil: + ptr = new stencil_only_resolver(); + break; + case (gl::image_aspect::depth | gl::image_aspect::stencil): + ptr = new depth_stencil_resolver(); + break; + default: + fmt::throw_exception("Unreachable"); + } + + pass.reset(ptr); + } + + return pass; + }; + + if (src->aspect() == (gl::image_aspect::depth | gl::image_aspect::stencil) && + !gl::get_driver_caps().ARB_shader_stencil_export_supported) + { + // Special case, NVIDIA-only fallback + auto& depth_pass = get_resolver_pass(gl::image_aspect::depth); + depth_pass->run(cmd, src, dst); + + auto& stencil_pass = get_resolver_pass(gl::image_aspect::stencil); + stencil_pass->run(cmd, src, dst); + return; + } + + auto& pass = get_resolver_pass(src->aspect()); + pass->run(cmd, src, dst); } void unresolve_image(gl::command_context& cmd, gl::viewable_image* dst, gl::viewable_image* src) @@ -100,8 +143,12 @@ namespace gl if (src->aspect() == (gl::image_aspect::depth | gl::image_aspect::stencil) && !gl::get_driver_caps().ARB_shader_stencil_export_supported) { - // Special handling - rsx_log.error("Unsupported."); + // Special case, NVIDIA-only fallback + auto& depth_pass = get_unresolver_pass(gl::image_aspect::depth); + depth_pass->run(cmd, dst, src); + + auto& stencil_pass = get_unresolver_pass(gl::image_aspect::stencil); + stencil_pass->run(cmd, dst, src); return; } @@ -227,8 +274,31 @@ namespace gl rsx_log.notice("Resolve shader:\n%s", fs_src); } + void ds_resolve_pass_base::update_config() + { + ensure(multisampled && multisampled->samples() > 1); + switch (multisampled->samples()) + { + case 2: + m_config.sample_count.x = 2; + m_config.sample_count.y = 1; + break; + case 4: + m_config.sample_count.x = m_config.sample_count.y = 2; + break; + default: + fmt::throw_exception("Unsupported sample count %d", multisampled->samples()); + } + + program_handle.uniforms["sample_count"] = m_config.sample_count; + } + void ds_resolve_pass_base::run(gl::command_context& cmd, gl::viewable_image* msaa_image, gl::viewable_image* resolve_image) { + multisampled = msaa_image; + resolve = resolve_image; + update_config(); + const auto read_resource = m_config.is_unresolve ? resolve_image : msaa_image; saved_sampler_state saved(GL_TEMP_IMAGE_SLOT(0), m_sampler); cmd->bind_texture(GL_TEMP_IMAGE_SLOT(0), GL_TEXTURE_2D, read_resource->id()); @@ -242,4 +312,37 @@ namespace gl viewport.y2 = msaa_image->height(); overlay_pass::run(cmd, viewport, GL_NONE, image_aspect_bits, false); } + + void stencil_only_resolver_base::emit_geometry(gl::command_context& cmd) + { + // Modified version of the base overlay pass to emit 8 draws instead of 1 + int old_vao; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao); + m_vao.bind(); + + // Start our inner loop + for (s32 write_mask = 0x1; write_mask <= 0x80; write_mask <<= 1) + { + program_handle.uniforms["stencil_mask"] = write_mask; + cmd->stencil_mask(write_mask); + + glDrawArrays(primitives, 0, num_drawable_elements); + } + + glBindVertexArray(old_vao); + } + + void stencil_only_resolver_base::run(gl::command_context& cmd, gl::viewable_image* msaa_image, gl::viewable_image* resolve_image) + { + const auto read_resource = m_config.is_unresolve ? resolve_image : msaa_image; + auto stencil_view = read_resource->get_view(rsx::default_remap_vector.with_encoding(gl::GL_REMAP_IDENTITY), gl::image_aspect::stencil); + + saved_sampler_state saved(GL_TEMP_IMAGE_SLOT(0), m_sampler); + cmd->bind_texture(GL_TEMP_IMAGE_SLOT(0), GL_TEXTURE_2D, stencil_view->id()); + + areau viewport{}; + viewport.x2 = msaa_image->width(); + viewport.y2 = msaa_image->height(); + overlay_pass::run(cmd, viewport, GL_NONE, gl::image_aspect::stencil, false); + } } diff --git a/rpcs3/Emu/RSX/GL/GLResolveHelper.h b/rpcs3/Emu/RSX/GL/GLResolveHelper.h index d86c25d406..539903516d 100644 --- a/rpcs3/Emu/RSX/GL/GLResolveHelper.h +++ b/rpcs3/Emu/RSX/GL/GLResolveHelper.h @@ -56,11 +56,14 @@ namespace gl bool resolve_depth = false; bool resolve_stencil = false; bool is_unresolve = false; + color2i sample_count; } m_config; void build(bool depth, bool stencil, bool unresolve); - void run(gl::command_context& cmd, gl::viewable_image* msaa_image, gl::viewable_image* resolve_image); + void update_config(); + + virtual void run(gl::command_context& cmd, gl::viewable_image* msaa_image, gl::viewable_image* resolve_image); }; struct depth_only_resolver : ds_resolve_pass_base @@ -79,19 +82,33 @@ namespace gl } }; - struct stencil_only_resolver : ds_resolve_pass_base + struct stencil_only_resolver_base : ds_resolve_pass_base + { + virtual ~stencil_only_resolver_base() = default; + + void build(bool is_unresolver) + { + ds_resolve_pass_base::build(false, true, is_unresolver); + } + + void emit_geometry(gl::command_context& cmd) override; + + void run(gl::command_context& cmd, gl::viewable_image* msaa_image, gl::viewable_image* resolve_image) override; + }; + + struct stencil_only_resolver : stencil_only_resolver_base { stencil_only_resolver() { - build(false, true, false); + build(false); } }; - struct stencil_only_unresolver : ds_resolve_pass_base + struct stencil_only_unresolver : stencil_only_resolver_base { stencil_only_unresolver() { - build(false, true, true); + build(true); } }; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 2a31ffa51d..45e5e1476f 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -31,7 +31,7 @@ namespace vk bool g_drv_sanitize_fp_values = false; bool g_drv_disable_fence_reset = false; bool g_drv_emulate_cond_render = false; - bool g_drv_strict_query_scopes = false; + bool g_drv_strict_query_scopes = true; bool g_drv_force_reuse_query_pools = false; u64 g_num_processed_frames = 0;