diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.cpp b/rpcs3/Emu/RSX/GL/GLOverlays.cpp index 36ee8624a2..32f40b25ab 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.cpp +++ b/rpcs3/Emu/RSX/GL/GLOverlays.cpp @@ -1,5 +1,7 @@ #include "GLOverlays.h" +#include "../rsx_utils.h" + namespace gl { // Lame @@ -615,20 +617,29 @@ namespace gl } void rp_ssbo_to_texture::run(gl::command_context& cmd, - const buffer* src, const texture* dst, + const buffer* src, const texture_view* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout) { const u32 row_length = static_cast(dst_region.width); - const u32 bpp = dst->pitch() / dst->width(); + const u32 bpp = dst->image()->pitch() / dst->image()->width(); program_handle.uniforms["src_pitch"] = row_length; program_handle.uniforms["swap_bytes"] = layout.swap_bytes; - program_handle.uniforms["format"] = static_cast(dst->get_internal_format()); + program_handle.uniforms["format"] = static_cast(dst->image()->get_internal_format()); src->bind_range(gl::buffer::target::ssbo, GL_COMPUTE_BUFFER_SLOT(0), src_offset, row_length * bpp * dst_region.height); cmd->stencil_mask(0xFF); overlay_pass::run(cmd, dst_region, dst->id(), dst->aspect()); } + + void rp_ssbo_to_texture::run(gl::command_context& cmd, + const buffer* src, texture* dst, + const u32 src_offset, const coordu& dst_region, + const pixel_buffer_layout& layout) + { + gl::nil_texture_view view(dst); + run(cmd, src, &view, src_offset, dst_region, layout); + } } diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index b0448abc8b..92a2f31a6b 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -117,7 +117,8 @@ namespace gl struct rp_ssbo_to_texture : public overlay_pass { rp_ssbo_to_texture(); - void run(gl::command_context& cmd, const buffer* src, const texture* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout); + void run(gl::command_context& cmd, const buffer* src, texture* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout); + void run(gl::command_context& cmd, const buffer* src, const texture_view* dst, const u32 src_offset, const coordu& dst_region, const pixel_buffer_layout& layout); }; // TODO: Replace with a proper manager diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index 29ace4c265..a765ae0c79 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -4,6 +4,7 @@ #include "GLRenderTargets.h" #include "GLOverlays.h" +#include "glutils/blitter.h" #include "glutils/ring_buffer.h" #include "../GCM.h" @@ -581,11 +582,67 @@ namespace gl }; const auto caps = gl::get_driver_caps(); - if (!(dst->aspect() & image_aspect::stencil) || caps.ARB_shader_stencil_export_supported) + if (dst->get_target() != gl::texture::target::texture1D && + (!(dst->aspect() & image_aspect::stencil) || caps.ARB_shader_stencil_export_supported)) { // We do not need to use the driver's builtin transport mechanism glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); - gl::get_overlay_pass()->run(cmd, transfer_buf, dst, out_offset, { {dst_region.x, dst_region.y}, {dst_region.width, dst_region.height} }, unpack_info); + + std::unique_ptr scratch; + std::unique_ptr scratch_view; + + coordu image_region = { {dst_region.x, dst_region.y}, {dst_region.width, dst_region.height} }; + + switch (dst->get_target()) + { + case texture::target::texture3D: + { + // Upload to splatted image and do the final copy GPU-side + image_region.height *= dst_region.depth; + scratch = std::make_unique( + GL_TEXTURE_2D, + image_region.x + image_region.width, image_region.y + image_region.height, 1, 1, + static_cast(dst->get_internal_format()), dst->format_class()); + + scratch_view = std::make_unique(scratch.get()); + break; + } + case texture::target::textureCUBE: + { + const subresource_range range = { image_aspect::depth | image_aspect::color, dst_level, 1, dst_region.z , 1 }; + scratch_view = std::make_unique(dst, GL_TEXTURE_2D, range); + break; + } + default: + { + ensure(dst->layers() == 1); + + if (dst->levels() > 1) [[ likely ]] + { + const subresource_range range = { image_aspect::depth | image_aspect::color, dst_level, 1, 0 , 1 }; + scratch_view = std::make_unique(dst, GL_TEXTURE_2D, range); + } + else + { + scratch_view = std::make_unique(dst); + } + + break; + } + } + + gl::get_overlay_pass()->run(cmd, transfer_buf, scratch_view.get(), out_offset, image_region, unpack_info); + + if (dst->get_target() == texture::target::texture3D) + { + // Memcpy + for (u32 layer = dst_region.z, i = 0; i < dst_region.depth; ++i, ++layer) + { + const position3u src_offset = { dst_region.position.x, dst_region.position.y, 0 }; + const position3u dst_offset = { dst_region.position.x, dst_region.position.y, layer }; + g_hw_blitter->copy_image(cmd, scratch.get(), dst, 0, dst_level, src_offset, dst_offset, {dst_region.width, dst_region.height, 1}); + } + } } else { diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 6c6e400f44..b1800c384b 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -13,10 +13,6 @@ class GLGSRender; namespace gl { - class blitter; - - extern blitter* g_hw_blitter; - class cached_texture_section; class texture_cache; diff --git a/rpcs3/Emu/RSX/GL/glutils/blitter.h b/rpcs3/Emu/RSX/GL/glutils/blitter.h index 20ce9d5ad8..d7adc1dd14 100644 --- a/rpcs3/Emu/RSX/GL/glutils/blitter.h +++ b/rpcs3/Emu/RSX/GL/glutils/blitter.h @@ -55,4 +55,6 @@ namespace gl copy_image(cmd, src, dst, src_level, dst_level, static_cast(src_offset), static_cast(dst_offset), static_cast(size)); } }; + + extern blitter* g_hw_blitter; } diff --git a/rpcs3/Emu/RSX/GL/glutils/image.cpp b/rpcs3/Emu/RSX/GL/glutils/image.cpp index 2591eff697..cc79766357 100644 --- a/rpcs3/Emu/RSX/GL/glutils/image.cpp +++ b/rpcs3/Emu/RSX/GL/glutils/image.cpp @@ -232,26 +232,17 @@ namespace gl } } - void texture_view::create(texture* data, GLenum target, GLenum sized_format, GLuint min_level, GLuint num_levels, GLenum aspect_flags, const GLenum* argb_swizzle) + void texture_view::create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle) { m_target = target; m_format = sizedfmt_to_ifmt(sized_format); m_image_data = data; - m_aspect_flags = aspect_flags; + m_aspect_flags = range.aspect_mask & data->aspect(); - u32 num_layers; - switch (target) - { - default: - num_layers = 1; break; - case GL_TEXTURE_CUBE_MAP: - num_layers = 6; break; - case GL_TEXTURE_2D_ARRAY: - num_layers = data->depth(); break; - } + ensure(m_aspect_flags); glGenTextures(1, &m_id); - glTextureView(m_id, target, data->id(), m_format, min_level, num_levels, 0, num_layers); + glTextureView(m_id, target, data->id(), m_format, range.min_level, range.num_levels, range.min_layer, range.num_layers); if (argb_swizzle) { @@ -271,10 +262,10 @@ namespace gl component_swizzle[3] = GL_ALPHA; } - if (aspect_flags & image_aspect::stencil) + if (range.aspect_mask & image_aspect::stencil) { constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil); - ensure((aspect_flags & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination" + ensure((range.aspect_mask & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination" gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, m_target, m_id); glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); @@ -283,9 +274,12 @@ namespace gl texture_view::~texture_view() { - gl::get_command_context()->unbind_texture(static_cast(m_target), m_id); - glDeleteTextures(1, &m_id); - m_id = GL_NONE; + if (m_id) + { + gl::get_command_context()->unbind_texture(static_cast(m_target), m_id); + glDeleteTextures(1, &m_id); + m_id = GL_NONE; + } } void texture_view::bind(gl::command_context& cmd, GLuint layer) const @@ -295,20 +289,29 @@ namespace gl texture_view* viewable_image::get_view(u32 remap_encoding, const std::pair, std::array>& remap, GLenum aspect_flags) { - auto found = views.equal_range(remap_encoding); - for (auto It = found.first; It != found.second; ++It) + const u64 view_aspect = static_cast(aspect_flags) & aspect(); + ensure(view_aspect); + + const u64 key = static_cast(remap_encoding) | (view_aspect << 32); + if (auto found = views.find(key); + found != views.end()) { - if (It->second->aspect() & aspect_flags) - { - return It->second.get(); - } + ensure(found->second.get() != nullptr); + return found->second.get(); } - ensure(aspect() & aspect_flags); - auto mapping = apply_swizzle_remap(get_native_component_layout(), remap); - auto view = std::make_unique(this, mapping.data(), aspect_flags); + std::array mapping; + GLenum* swizzle = nullptr; + + if (remap_encoding != GL_REMAP_IDENTITY) + { + mapping = apply_swizzle_remap(get_native_component_layout(), remap); + swizzle = mapping.data(); + } + + auto view = std::make_unique(this, swizzle, aspect_flags); auto result = view.get(); - views.emplace(remap_encoding, std::move(view)); + views.emplace(key, std::move(view)); return result; } diff --git a/rpcs3/Emu/RSX/GL/glutils/image.h b/rpcs3/Emu/RSX/GL/glutils/image.h index f8bd3443a5..a0164e9f84 100644 --- a/rpcs3/Emu/RSX/GL/glutils/image.h +++ b/rpcs3/Emu/RSX/GL/glutils/image.h @@ -42,6 +42,20 @@ namespace gl linear_mipmap_linear = GL_LINEAR_MIPMAP_LINEAR }; + enum remap_constants : u32 + { + GL_REMAP_IDENTITY = 0xCAFEBABE + }; + + struct subresource_range + { + GLenum aspect_mask; + GLuint min_level; + GLuint num_levels; + GLuint min_layer; + GLuint num_layers; + }; + class texture { friend class texture_view; @@ -158,7 +172,8 @@ namespace gl texture2D = GL_TEXTURE_2D, texture3D = GL_TEXTURE_3D, textureCUBE = GL_TEXTURE_CUBE_MAP, - textureBuffer = GL_TEXTURE_BUFFER + textureBuffer = GL_TEXTURE_BUFFER, + texture2DArray = GL_TEXTURE_2D_ARRAY }; protected: @@ -242,6 +257,19 @@ namespace gl return m_mipmaps; } + GLuint layers() const + { + switch (m_target) + { + case target::textureCUBE: + return 6; + case target::texture2DArray: + return m_depth; + default: + return 1; + } + } + GLuint pitch() const { return m_pitch; @@ -313,6 +341,7 @@ namespace gl class texture_view { + protected: GLuint m_id = GL_NONE; GLenum m_target = 0; GLenum m_format = 0; @@ -321,7 +350,9 @@ namespace gl GLenum component_swizzle[4]; - void create(texture* data, GLenum target, GLenum sized_format, GLuint min_level, GLuint num_levels, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr); + texture_view() = default; + + void create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle = nullptr); public: texture_view(const texture_view&) = delete; @@ -331,7 +362,7 @@ namespace gl const GLenum* argb_swizzle = nullptr, GLenum aspect_flags = image_aspect::color | image_aspect::depth) { - create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle); + create(data, target, sized_format, { aspect_flags, 0, data->levels(), 0, data->layers() }, argb_swizzle); } texture_view(texture* data, const GLenum* argb_swizzle = nullptr, @@ -339,16 +370,22 @@ namespace gl { GLenum target = static_cast(data->get_target()); GLenum sized_format = static_cast(data->get_internal_format()); - create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle); + create(data, target, sized_format, { aspect_flags, 0, data->levels(), 0, data->layers() }, argb_swizzle); } - texture_view(texture* data, GLuint mip_level, - const GLenum* argb_swizzle = nullptr, - GLenum aspect_flags = image_aspect::color | image_aspect::depth) + texture_view(texture* data, const subresource_range& range, + const GLenum* argb_swizzle = nullptr) { GLenum target = static_cast(data->get_target()); GLenum sized_format = static_cast(data->get_internal_format()); - create(data, target, sized_format, mip_level, 1, aspect_flags, argb_swizzle); + create(data, target, sized_format, range, argb_swizzle); + } + + texture_view(texture* data, GLenum target, const subresource_range& range, + const GLenum* argb_swizzle = nullptr) + { + GLenum sized_format = static_cast(data->get_internal_format()); + create(data, target, sized_format, range, argb_swizzle); } virtual ~texture_view(); @@ -400,9 +437,34 @@ namespace gl void bind(gl::command_context& cmd, GLuint layer) const; }; + // Passthrough texture view that simply wraps the original texture in a texture_view interface + class nil_texture_view : public texture_view + { + public: + nil_texture_view(texture* data) + : texture_view() + { + m_id = data->id(); + m_target = static_cast(data->get_target()); + m_format = static_cast(data->get_internal_format()); + m_aspect_flags = data->aspect(); + m_image_data = data; + + component_swizzle[0] = GL_RED; + component_swizzle[1] = GL_GREEN; + component_swizzle[2] = GL_BLUE; + component_swizzle[3] = GL_ALPHA; + } + + ~nil_texture_view() + { + m_id = GL_NONE; + } + }; + class viewable_image : public texture { - std::unordered_multimap> views; + std::unordered_map> views; public: using texture::texture;