mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-03 16:39:01 -06:00 
			
		
		
		
	Merge pull request #4027 from ReinUsesLisp/3d-slices
texture_cache: Implement rendering to 3D textures
This commit is contained in:
		@@ -598,6 +598,7 @@ public:
 | 
			
		||||
                BitField<4, 3, u32> block_height;
 | 
			
		||||
                BitField<8, 3, u32> block_depth;
 | 
			
		||||
                BitField<12, 1, InvMemoryLayout> type;
 | 
			
		||||
                BitField<16, 1, u32> is_3d;
 | 
			
		||||
            } memory_layout;
 | 
			
		||||
            union {
 | 
			
		||||
                BitField<0, 16, u32> layers;
 | 
			
		||||
 
 | 
			
		||||
@@ -263,9 +263,14 @@ CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& param
 | 
			
		||||
    target = GetTextureTarget(params.target);
 | 
			
		||||
    texture = CreateTexture(params, target, internal_format, texture_buffer);
 | 
			
		||||
    DecorateSurfaceName();
 | 
			
		||||
    main_view = CreateViewInner(
 | 
			
		||||
        ViewParams(params.target, 0, params.is_layered ? params.depth : 1, 0, params.num_levels),
 | 
			
		||||
        true);
 | 
			
		||||
 | 
			
		||||
    u32 num_layers = 1;
 | 
			
		||||
    if (params.is_layered || params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
        num_layers = params.depth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    main_view =
 | 
			
		||||
        CreateViewInner(ViewParams(params.target, 0, num_layers, 0, params.num_levels), true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CachedSurface::~CachedSurface() = default;
 | 
			
		||||
@@ -413,37 +418,40 @@ CachedSurfaceView::CachedSurfaceView(CachedSurface& surface, const ViewParams& p
 | 
			
		||||
 | 
			
		||||
CachedSurfaceView::~CachedSurfaceView() = default;
 | 
			
		||||
 | 
			
		||||
void CachedSurfaceView::Attach(GLenum attachment, GLenum target) const {
 | 
			
		||||
void CachedSurfaceView::Attach(GLenum attachment, GLenum fb_target) const {
 | 
			
		||||
    ASSERT(params.num_levels == 1);
 | 
			
		||||
 | 
			
		||||
    if (params.num_layers > 1) {
 | 
			
		||||
        // Layered framebuffer attachments
 | 
			
		||||
        UNIMPLEMENTED_IF(params.base_layer != 0);
 | 
			
		||||
 | 
			
		||||
        switch (params.target) {
 | 
			
		||||
        case SurfaceTarget::Texture2DArray:
 | 
			
		||||
            glFramebufferTexture(target, attachment, GetTexture(), 0);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            UNIMPLEMENTED();
 | 
			
		||||
    if (params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
        if (params.num_layers > 1) {
 | 
			
		||||
            ASSERT(params.base_layer == 0);
 | 
			
		||||
            glFramebufferTexture(fb_target, attachment, surface.texture.handle, params.base_level);
 | 
			
		||||
        } else {
 | 
			
		||||
            glFramebufferTexture3D(fb_target, attachment, target, surface.texture.handle,
 | 
			
		||||
                                   params.base_level, params.base_layer);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (params.num_layers > 1) {
 | 
			
		||||
        UNIMPLEMENTED_IF(params.base_layer != 0);
 | 
			
		||||
        glFramebufferTexture(fb_target, attachment, GetTexture(), 0);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const GLenum view_target = surface.GetTarget();
 | 
			
		||||
    const GLuint texture = surface.GetTexture();
 | 
			
		||||
    switch (surface.GetSurfaceParams().target) {
 | 
			
		||||
    case SurfaceTarget::Texture1D:
 | 
			
		||||
        glFramebufferTexture1D(target, attachment, view_target, texture, params.base_level);
 | 
			
		||||
        glFramebufferTexture1D(fb_target, attachment, view_target, texture, params.base_level);
 | 
			
		||||
        break;
 | 
			
		||||
    case SurfaceTarget::Texture2D:
 | 
			
		||||
        glFramebufferTexture2D(target, attachment, view_target, texture, params.base_level);
 | 
			
		||||
        glFramebufferTexture2D(fb_target, attachment, view_target, texture, params.base_level);
 | 
			
		||||
        break;
 | 
			
		||||
    case SurfaceTarget::Texture1DArray:
 | 
			
		||||
    case SurfaceTarget::Texture2DArray:
 | 
			
		||||
    case SurfaceTarget::TextureCubemap:
 | 
			
		||||
    case SurfaceTarget::TextureCubeArray:
 | 
			
		||||
        glFramebufferTextureLayer(target, attachment, texture, params.base_level,
 | 
			
		||||
        glFramebufferTextureLayer(fb_target, attachment, texture, params.base_level,
 | 
			
		||||
                                  params.base_layer);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
@@ -500,8 +508,13 @@ OGLTextureView CachedSurfaceView::CreateTextureView() const {
 | 
			
		||||
    OGLTextureView texture_view;
 | 
			
		||||
    texture_view.Create();
 | 
			
		||||
 | 
			
		||||
    glTextureView(texture_view.handle, target, surface.texture.handle, format, params.base_level,
 | 
			
		||||
                  params.num_levels, params.base_layer, params.num_layers);
 | 
			
		||||
    if (target == GL_TEXTURE_3D) {
 | 
			
		||||
        glTextureView(texture_view.handle, target, surface.texture.handle, format,
 | 
			
		||||
                      params.base_level, params.num_levels, 0, 1);
 | 
			
		||||
    } else {
 | 
			
		||||
        glTextureView(texture_view.handle, target, surface.texture.handle, format,
 | 
			
		||||
                      params.base_level, params.num_levels, params.base_layer, params.num_layers);
 | 
			
		||||
    }
 | 
			
		||||
    ApplyTextureDefaults(surface.GetSurfaceParams(), texture_view.handle);
 | 
			
		||||
 | 
			
		||||
    return texture_view;
 | 
			
		||||
@@ -544,8 +557,8 @@ void TextureCacheOpenGL::ImageBlit(View& src_view, View& dst_view,
 | 
			
		||||
                                   const Tegra::Engines::Fermi2D::Config& copy_config) {
 | 
			
		||||
    const auto& src_params{src_view->GetSurfaceParams()};
 | 
			
		||||
    const auto& dst_params{dst_view->GetSurfaceParams()};
 | 
			
		||||
    UNIMPLEMENTED_IF(src_params.target == SurfaceTarget::Texture3D);
 | 
			
		||||
    UNIMPLEMENTED_IF(dst_params.target == SurfaceTarget::Texture3D);
 | 
			
		||||
    UNIMPLEMENTED_IF(src_params.depth != 1);
 | 
			
		||||
    UNIMPLEMENTED_IF(dst_params.depth != 1);
 | 
			
		||||
 | 
			
		||||
    state_tracker.NotifyScissor0();
 | 
			
		||||
    state_tracker.NotifyFramebuffer();
 | 
			
		||||
 
 | 
			
		||||
@@ -80,8 +80,10 @@ public:
 | 
			
		||||
    explicit CachedSurfaceView(CachedSurface& surface, const ViewParams& params, bool is_proxy);
 | 
			
		||||
    ~CachedSurfaceView();
 | 
			
		||||
 | 
			
		||||
    /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
 | 
			
		||||
    void Attach(GLenum attachment, GLenum target) const;
 | 
			
		||||
    /// @brief Attaches this texture view to the currently bound fb_target framebuffer
 | 
			
		||||
    /// @param attachment   Attachment to bind textures to
 | 
			
		||||
    /// @param fb_target    Framebuffer target to attach to (e.g. DRAW_FRAMEBUFFER)
 | 
			
		||||
    void Attach(GLenum attachment, GLenum fb_target) const;
 | 
			
		||||
 | 
			
		||||
    GLuint GetTexture(Tegra::Texture::SwizzleSource x_source,
 | 
			
		||||
                      Tegra::Texture::SwizzleSource y_source,
 | 
			
		||||
 
 | 
			
		||||
@@ -716,7 +716,7 @@ std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers(
 | 
			
		||||
        if (!view) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        key.views.push_back(view->GetHandle());
 | 
			
		||||
        key.views.push_back(view->GetAttachment());
 | 
			
		||||
        key.width = std::min(key.width, view->GetWidth());
 | 
			
		||||
        key.height = std::min(key.height, view->GetHeight());
 | 
			
		||||
        key.layers = std::min(key.layers, view->GetNumLayers());
 | 
			
		||||
@@ -1137,8 +1137,8 @@ void RasterizerVulkan::SetupTexture(const Tegra::Texture::FullTextureInfo& textu
 | 
			
		||||
    auto view = texture_cache.GetTextureSurface(texture.tic, entry);
 | 
			
		||||
    ASSERT(!view->IsBufferView());
 | 
			
		||||
 | 
			
		||||
    const auto image_view = view->GetHandle(texture.tic.x_source, texture.tic.y_source,
 | 
			
		||||
                                            texture.tic.z_source, texture.tic.w_source);
 | 
			
		||||
    const VkImageView image_view = view->GetImageView(texture.tic.x_source, texture.tic.y_source,
 | 
			
		||||
                                                      texture.tic.z_source, texture.tic.w_source);
 | 
			
		||||
    const auto sampler = sampler_cache.GetSampler(texture.tsc);
 | 
			
		||||
    update_descriptor_queue.AddSampledImage(sampler, image_view);
 | 
			
		||||
 | 
			
		||||
@@ -1164,7 +1164,8 @@ void RasterizerVulkan::SetupImage(const Tegra::Texture::TICEntry& tic, const Ima
 | 
			
		||||
 | 
			
		||||
    UNIMPLEMENTED_IF(tic.IsBuffer());
 | 
			
		||||
 | 
			
		||||
    const auto image_view = view->GetHandle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
 | 
			
		||||
    const VkImageView image_view =
 | 
			
		||||
        view->GetImageView(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
 | 
			
		||||
    update_descriptor_queue.AddImage(image_view);
 | 
			
		||||
 | 
			
		||||
    const auto image_layout = update_descriptor_queue.GetLastImageLayout();
 | 
			
		||||
 
 | 
			
		||||
@@ -167,6 +167,7 @@ VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceP
 | 
			
		||||
        ci.extent = {params.width, params.height, 1};
 | 
			
		||||
        break;
 | 
			
		||||
    case SurfaceTarget::Texture3D:
 | 
			
		||||
        ci.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
 | 
			
		||||
        ci.extent = {params.width, params.height, params.depth};
 | 
			
		||||
        break;
 | 
			
		||||
    case SurfaceTarget::TextureBuffer:
 | 
			
		||||
@@ -176,6 +177,12 @@ VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceP
 | 
			
		||||
    return ci;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, Tegra::Texture::SwizzleSource y_source,
 | 
			
		||||
                  Tegra::Texture::SwizzleSource z_source, Tegra::Texture::SwizzleSource w_source) {
 | 
			
		||||
    return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) |
 | 
			
		||||
           (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
CachedSurface::CachedSurface(Core::System& system, const VKDevice& device,
 | 
			
		||||
@@ -203,9 +210,11 @@ CachedSurface::CachedSurface(Core::System& system, const VKDevice& device,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO(Rodrigo): Move this to a virtual function.
 | 
			
		||||
    main_view = CreateViewInner(
 | 
			
		||||
        ViewParams(params.target, 0, static_cast<u32>(params.GetNumLayers()), 0, params.num_levels),
 | 
			
		||||
        true);
 | 
			
		||||
    u32 num_layers = 1;
 | 
			
		||||
    if (params.is_layered || params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
        num_layers = params.depth;
 | 
			
		||||
    }
 | 
			
		||||
    main_view = CreateView(ViewParams(params.target, 0, num_layers, 0, params.num_levels));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CachedSurface::~CachedSurface() = default;
 | 
			
		||||
@@ -253,12 +262,8 @@ void CachedSurface::DecorateSurfaceName() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
View CachedSurface::CreateView(const ViewParams& params) {
 | 
			
		||||
    return CreateViewInner(params, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
View CachedSurface::CreateViewInner(const ViewParams& params, bool is_proxy) {
 | 
			
		||||
    // TODO(Rodrigo): Add name decorations
 | 
			
		||||
    return views[params] = std::make_shared<CachedSurfaceView>(device, *this, params, is_proxy);
 | 
			
		||||
    return views[params] = std::make_shared<CachedSurfaceView>(device, *this, params);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) {
 | 
			
		||||
@@ -342,18 +347,27 @@ VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CachedSurfaceView::CachedSurfaceView(const VKDevice& device, CachedSurface& surface,
 | 
			
		||||
                                     const ViewParams& params, bool is_proxy)
 | 
			
		||||
                                     const ViewParams& params)
 | 
			
		||||
    : VideoCommon::ViewBase{params}, params{surface.GetSurfaceParams()},
 | 
			
		||||
      image{surface.GetImageHandle()}, buffer_view{surface.GetBufferViewHandle()},
 | 
			
		||||
      aspect_mask{surface.GetAspectMask()}, device{device}, surface{surface},
 | 
			
		||||
      base_layer{params.base_layer}, num_layers{params.num_layers}, base_level{params.base_level},
 | 
			
		||||
      num_levels{params.num_levels}, image_view_type{image ? GetImageViewType(params.target)
 | 
			
		||||
                                                           : VK_IMAGE_VIEW_TYPE_1D} {}
 | 
			
		||||
      base_level{params.base_level}, num_levels{params.num_levels},
 | 
			
		||||
      image_view_type{image ? GetImageViewType(params.target) : VK_IMAGE_VIEW_TYPE_1D} {
 | 
			
		||||
    if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) {
 | 
			
		||||
        base_layer = 0;
 | 
			
		||||
        num_layers = 1;
 | 
			
		||||
        base_slice = params.base_layer;
 | 
			
		||||
        num_slices = params.num_layers;
 | 
			
		||||
    } else {
 | 
			
		||||
        base_layer = params.base_layer;
 | 
			
		||||
        num_layers = params.num_layers;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CachedSurfaceView::~CachedSurfaceView() = default;
 | 
			
		||||
 | 
			
		||||
VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y_source,
 | 
			
		||||
                                         SwizzleSource z_source, SwizzleSource w_source) {
 | 
			
		||||
VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSource y_source,
 | 
			
		||||
                                            SwizzleSource z_source, SwizzleSource w_source) {
 | 
			
		||||
    const u32 new_swizzle = EncodeSwizzle(x_source, y_source, z_source, w_source);
 | 
			
		||||
    if (last_image_view && last_swizzle == new_swizzle) {
 | 
			
		||||
        return last_image_view;
 | 
			
		||||
@@ -399,6 +413,11 @@ VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) {
 | 
			
		||||
        ASSERT(base_slice == 0);
 | 
			
		||||
        ASSERT(num_slices == params.depth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkImageViewCreateInfo ci;
 | 
			
		||||
    ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 | 
			
		||||
    ci.pNext = nullptr;
 | 
			
		||||
@@ -417,6 +436,35 @@ VkImageView CachedSurfaceView::GetHandle(SwizzleSource x_source, SwizzleSource y
 | 
			
		||||
    return last_image_view = *image_view;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VkImageView CachedSurfaceView::GetAttachment() {
 | 
			
		||||
    if (render_target) {
 | 
			
		||||
        return *render_target;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkImageViewCreateInfo ci;
 | 
			
		||||
    ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 | 
			
		||||
    ci.pNext = nullptr;
 | 
			
		||||
    ci.flags = 0;
 | 
			
		||||
    ci.image = surface.GetImageHandle();
 | 
			
		||||
    ci.format = surface.GetImage().GetFormat();
 | 
			
		||||
    ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
                     VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
 | 
			
		||||
    ci.subresourceRange.aspectMask = aspect_mask;
 | 
			
		||||
    ci.subresourceRange.baseMipLevel = base_level;
 | 
			
		||||
    ci.subresourceRange.levelCount = num_levels;
 | 
			
		||||
    if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) {
 | 
			
		||||
        ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
 | 
			
		||||
        ci.subresourceRange.baseArrayLayer = base_slice;
 | 
			
		||||
        ci.subresourceRange.layerCount = num_slices;
 | 
			
		||||
    } else {
 | 
			
		||||
        ci.viewType = image_view_type;
 | 
			
		||||
        ci.subresourceRange.baseArrayLayer = base_layer;
 | 
			
		||||
        ci.subresourceRange.layerCount = num_layers;
 | 
			
		||||
    }
 | 
			
		||||
    render_target = device.GetLogical().CreateImageView(ci);
 | 
			
		||||
    return *render_target;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VKTextureCache::VKTextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                               const VKDevice& device, VKResourceManager& resource_manager,
 | 
			
		||||
                               VKMemoryManager& memory_manager, VKScheduler& scheduler,
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,6 @@ protected:
 | 
			
		||||
    void DecorateSurfaceName();
 | 
			
		||||
 | 
			
		||||
    View CreateView(const ViewParams& params) override;
 | 
			
		||||
    View CreateViewInner(const ViewParams& params, bool is_proxy);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void UploadBuffer(const std::vector<u8>& staging_buffer);
 | 
			
		||||
@@ -120,23 +119,20 @@ private:
 | 
			
		||||
class CachedSurfaceView final : public VideoCommon::ViewBase {
 | 
			
		||||
public:
 | 
			
		||||
    explicit CachedSurfaceView(const VKDevice& device, CachedSurface& surface,
 | 
			
		||||
                               const ViewParams& params, bool is_proxy);
 | 
			
		||||
                               const ViewParams& params);
 | 
			
		||||
    ~CachedSurfaceView();
 | 
			
		||||
 | 
			
		||||
    VkImageView GetHandle(Tegra::Texture::SwizzleSource x_source,
 | 
			
		||||
                          Tegra::Texture::SwizzleSource y_source,
 | 
			
		||||
                          Tegra::Texture::SwizzleSource z_source,
 | 
			
		||||
                          Tegra::Texture::SwizzleSource w_source);
 | 
			
		||||
    VkImageView GetImageView(Tegra::Texture::SwizzleSource x_source,
 | 
			
		||||
                             Tegra::Texture::SwizzleSource y_source,
 | 
			
		||||
                             Tegra::Texture::SwizzleSource z_source,
 | 
			
		||||
                             Tegra::Texture::SwizzleSource w_source);
 | 
			
		||||
 | 
			
		||||
    VkImageView GetAttachment();
 | 
			
		||||
 | 
			
		||||
    bool IsSameSurface(const CachedSurfaceView& rhs) const {
 | 
			
		||||
        return &surface == &rhs.surface;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VkImageView GetHandle() {
 | 
			
		||||
        return GetHandle(Tegra::Texture::SwizzleSource::R, Tegra::Texture::SwizzleSource::G,
 | 
			
		||||
                         Tegra::Texture::SwizzleSource::B, Tegra::Texture::SwizzleSource::A);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u32 GetWidth() const {
 | 
			
		||||
        return params.GetMipWidth(base_level);
 | 
			
		||||
    }
 | 
			
		||||
@@ -180,14 +176,6 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
 | 
			
		||||
                             Tegra::Texture::SwizzleSource y_source,
 | 
			
		||||
                             Tegra::Texture::SwizzleSource z_source,
 | 
			
		||||
                             Tegra::Texture::SwizzleSource w_source) {
 | 
			
		||||
        return (static_cast<u32>(x_source) << 24) | (static_cast<u32>(y_source) << 16) |
 | 
			
		||||
               (static_cast<u32>(z_source) << 8) | static_cast<u32>(w_source);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Store a copy of these values to avoid double dereference when reading them
 | 
			
		||||
    const SurfaceParams params;
 | 
			
		||||
    const VkImage image;
 | 
			
		||||
@@ -196,15 +184,18 @@ private:
 | 
			
		||||
 | 
			
		||||
    const VKDevice& device;
 | 
			
		||||
    CachedSurface& surface;
 | 
			
		||||
    const u32 base_layer;
 | 
			
		||||
    const u32 num_layers;
 | 
			
		||||
    const u32 base_level;
 | 
			
		||||
    const u32 num_levels;
 | 
			
		||||
    const VkImageViewType image_view_type;
 | 
			
		||||
    u32 base_layer = 0;
 | 
			
		||||
    u32 num_layers = 0;
 | 
			
		||||
    u32 base_slice = 0;
 | 
			
		||||
    u32 num_slices = 0;
 | 
			
		||||
 | 
			
		||||
    VkImageView last_image_view = nullptr;
 | 
			
		||||
    u32 last_swizzle = 0;
 | 
			
		||||
 | 
			
		||||
    vk::ImageView render_target;
 | 
			
		||||
    std::unordered_map<u32, vk::ImageView> view_cache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -248,12 +248,11 @@ void SurfaceBaseImpl::FlushBuffer(Tegra::MemoryManager& memory_manager,
 | 
			
		||||
 | 
			
		||||
    // Use an extra temporal buffer
 | 
			
		||||
    auto& tmp_buffer = staging_cache.GetBuffer(1);
 | 
			
		||||
    // Special case for 3D Texture Segments
 | 
			
		||||
    const bool must_read_current_data =
 | 
			
		||||
        params.block_depth > 0 && params.target == VideoCore::Surface::SurfaceTarget::Texture2D;
 | 
			
		||||
    tmp_buffer.resize(guest_memory_size);
 | 
			
		||||
    host_ptr = tmp_buffer.data();
 | 
			
		||||
    if (must_read_current_data) {
 | 
			
		||||
 | 
			
		||||
    if (params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
        // Special case for 3D texture segments
 | 
			
		||||
        memory_manager.ReadBlockUnsafe(gpu_addr, host_ptr, guest_memory_size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -217,8 +217,8 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsProtected() const {
 | 
			
		||||
        // Only 3D Slices are to be protected
 | 
			
		||||
        return is_target && params.block_depth > 0;
 | 
			
		||||
        // Only 3D slices are to be protected
 | 
			
		||||
        return is_target && params.target == SurfaceTarget::Texture3D;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsRenderTarget() const {
 | 
			
		||||
@@ -250,6 +250,11 @@ public:
 | 
			
		||||
        return GetView(ViewParams(overview_params.target, 0, num_layers, 0, params.num_levels));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TView Emplace3DView(u32 slice, u32 depth, u32 base_level, u32 num_levels) {
 | 
			
		||||
        return GetView(ViewParams(VideoCore::Surface::SurfaceTarget::Texture3D, slice, depth,
 | 
			
		||||
                                  base_level, num_levels));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::optional<TView> EmplaceIrregularView(const SurfaceParams& view_params,
 | 
			
		||||
                                              const GPUVAddr view_addr,
 | 
			
		||||
                                              const std::size_t candidate_size, const u32 mipmap,
 | 
			
		||||
@@ -272,8 +277,8 @@ public:
 | 
			
		||||
    std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr,
 | 
			
		||||
                                     const std::size_t candidate_size) {
 | 
			
		||||
        if (params.target == SurfaceTarget::Texture3D ||
 | 
			
		||||
            (params.num_levels == 1 && !params.is_layered) ||
 | 
			
		||||
            view_params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
            view_params.target == SurfaceTarget::Texture3D ||
 | 
			
		||||
            (params.num_levels == 1 && !params.is_layered)) {
 | 
			
		||||
            return {};
 | 
			
		||||
        }
 | 
			
		||||
        const auto layer_mipmap{GetLayerMipmap(view_addr)};
 | 
			
		||||
 
 | 
			
		||||
@@ -215,10 +215,19 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
 | 
			
		||||
    params.num_levels = 1;
 | 
			
		||||
    params.emulated_levels = 1;
 | 
			
		||||
 | 
			
		||||
    const bool is_layered = config.layers > 1 && params.block_depth == 0;
 | 
			
		||||
    params.is_layered = is_layered;
 | 
			
		||||
    params.depth = is_layered ? config.layers.Value() : 1;
 | 
			
		||||
    params.target = is_layered ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D;
 | 
			
		||||
    if (config.memory_layout.is_3d != 0) {
 | 
			
		||||
        params.depth = config.layers.Value();
 | 
			
		||||
        params.is_layered = false;
 | 
			
		||||
        params.target = SurfaceTarget::Texture3D;
 | 
			
		||||
    } else if (config.layers > 1) {
 | 
			
		||||
        params.depth = config.layers.Value();
 | 
			
		||||
        params.is_layered = true;
 | 
			
		||||
        params.target = SurfaceTarget::Texture2DArray;
 | 
			
		||||
    } else {
 | 
			
		||||
        params.depth = 1;
 | 
			
		||||
        params.is_layered = false;
 | 
			
		||||
        params.target = SurfaceTarget::Texture2D;
 | 
			
		||||
    }
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -237,7 +246,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
 | 
			
		||||
    params.width = config.width;
 | 
			
		||||
    params.height = config.height;
 | 
			
		||||
    params.pitch = config.pitch;
 | 
			
		||||
    // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters
 | 
			
		||||
    // TODO(Rodrigo): Try to guess texture arrays from parameters
 | 
			
		||||
    params.target = SurfaceTarget::Texture2D;
 | 
			
		||||
    params.depth = 1;
 | 
			
		||||
    params.num_levels = 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -298,15 +298,13 @@ public:
 | 
			
		||||
        const GPUVAddr src_gpu_addr = src_config.Address();
 | 
			
		||||
        const GPUVAddr dst_gpu_addr = dst_config.Address();
 | 
			
		||||
        DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr);
 | 
			
		||||
        const std::optional<VAddr> dst_cpu_addr =
 | 
			
		||||
            system.GPU().MemoryManager().GpuToCpuAddress(dst_gpu_addr);
 | 
			
		||||
        const std::optional<VAddr> src_cpu_addr =
 | 
			
		||||
            system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr);
 | 
			
		||||
        std::pair<TSurface, TView> dst_surface =
 | 
			
		||||
            GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false);
 | 
			
		||||
        std::pair<TSurface, TView> src_surface =
 | 
			
		||||
            GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false);
 | 
			
		||||
        ImageBlit(src_surface.second, dst_surface.second, copy_config);
 | 
			
		||||
 | 
			
		||||
        const auto& memory_manager = system.GPU().MemoryManager();
 | 
			
		||||
        const std::optional<VAddr> dst_cpu_addr = memory_manager.GpuToCpuAddress(dst_gpu_addr);
 | 
			
		||||
        const std::optional<VAddr> src_cpu_addr = memory_manager.GpuToCpuAddress(src_gpu_addr);
 | 
			
		||||
        std::pair dst_surface = GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false);
 | 
			
		||||
        TView src_surface = GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false).second;
 | 
			
		||||
        ImageBlit(src_surface, dst_surface.second, copy_config);
 | 
			
		||||
        dst_surface.first->MarkAsModified(true, Tick());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -508,12 +506,12 @@ private:
 | 
			
		||||
            return RecycleStrategy::Flush;
 | 
			
		||||
        }
 | 
			
		||||
        // 3D Textures decision
 | 
			
		||||
        if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
        if (params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
            return RecycleStrategy::Flush;
 | 
			
		||||
        }
 | 
			
		||||
        for (const auto& s : overlaps) {
 | 
			
		||||
            const auto& s_params = s->GetSurfaceParams();
 | 
			
		||||
            if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
            if (s_params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
                return RecycleStrategy::Flush;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -731,51 +729,9 @@ private:
 | 
			
		||||
     */
 | 
			
		||||
    std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(VectorSurface& overlaps,
 | 
			
		||||
                                                               const SurfaceParams& params,
 | 
			
		||||
                                                               const GPUVAddr gpu_addr,
 | 
			
		||||
                                                               const VAddr cpu_addr,
 | 
			
		||||
                                                               GPUVAddr gpu_addr, VAddr cpu_addr,
 | 
			
		||||
                                                               bool preserve_contents) {
 | 
			
		||||
        if (params.target == SurfaceTarget::Texture3D) {
 | 
			
		||||
            bool failed = false;
 | 
			
		||||
            if (params.num_levels > 1) {
 | 
			
		||||
                // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
 | 
			
		||||
                return std::nullopt;
 | 
			
		||||
            }
 | 
			
		||||
            TSurface new_surface = GetUncachedSurface(gpu_addr, params);
 | 
			
		||||
            bool modified = false;
 | 
			
		||||
            for (auto& surface : overlaps) {
 | 
			
		||||
                const SurfaceParams& src_params = surface->GetSurfaceParams();
 | 
			
		||||
                if (src_params.target != SurfaceTarget::Texture2D) {
 | 
			
		||||
                    failed = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (src_params.height != params.height) {
 | 
			
		||||
                    failed = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (src_params.block_depth != params.block_depth ||
 | 
			
		||||
                    src_params.block_height != params.block_height) {
 | 
			
		||||
                    failed = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                const u32 offset = static_cast<u32>(surface->GetCpuAddr() - cpu_addr);
 | 
			
		||||
                const auto offsets = params.GetBlockOffsetXYZ(offset);
 | 
			
		||||
                const auto z = std::get<2>(offsets);
 | 
			
		||||
                modified |= surface->IsModified();
 | 
			
		||||
                const CopyParams copy_params(0, 0, 0, 0, 0, z, 0, 0, params.width, params.height,
 | 
			
		||||
                                             1);
 | 
			
		||||
                ImageCopy(surface, new_surface, copy_params);
 | 
			
		||||
            }
 | 
			
		||||
            if (failed) {
 | 
			
		||||
                return std::nullopt;
 | 
			
		||||
            }
 | 
			
		||||
            for (const auto& surface : overlaps) {
 | 
			
		||||
                Unregister(surface);
 | 
			
		||||
            }
 | 
			
		||||
            new_surface->MarkAsModified(modified, Tick());
 | 
			
		||||
            Register(new_surface);
 | 
			
		||||
            auto view = new_surface->GetMainView();
 | 
			
		||||
            return {{std::move(new_surface), view}};
 | 
			
		||||
        } else {
 | 
			
		||||
        if (params.target != SurfaceTarget::Texture3D) {
 | 
			
		||||
            for (const auto& surface : overlaps) {
 | 
			
		||||
                if (!surface->MatchTarget(params.target)) {
 | 
			
		||||
                    if (overlaps.size() == 1 && surface->GetCpuAddr() == cpu_addr) {
 | 
			
		||||
@@ -791,11 +747,60 @@ private:
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                if (surface->MatchesStructure(params) == MatchStructureResult::FullMatch) {
 | 
			
		||||
                    return {{surface, surface->GetMainView()}};
 | 
			
		||||
                    return std::make_pair(surface, surface->GetMainView());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return InitializeSurface(gpu_addr, params, preserve_contents);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (params.num_levels > 1) {
 | 
			
		||||
            // We can't handle mipmaps in 3D textures yet, better fallback to LLE approach
 | 
			
		||||
            return std::nullopt;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (overlaps.size() == 1) {
 | 
			
		||||
            const auto& surface = overlaps[0];
 | 
			
		||||
            const SurfaceParams& overlap_params = surface->GetSurfaceParams();
 | 
			
		||||
            // Don't attempt to render to textures with more than one level for now
 | 
			
		||||
            // The texture has to be to the right or the sample address if we want to render to it
 | 
			
		||||
            if (overlap_params.num_levels == 1 && cpu_addr >= surface->GetCpuAddr()) {
 | 
			
		||||
                const u32 offset = static_cast<u32>(cpu_addr - surface->GetCpuAddr());
 | 
			
		||||
                const u32 slice = std::get<2>(params.GetBlockOffsetXYZ(offset));
 | 
			
		||||
                if (slice < overlap_params.depth) {
 | 
			
		||||
                    auto view = surface->Emplace3DView(slice, params.depth, 0, 1);
 | 
			
		||||
                    return std::make_pair(std::move(surface), std::move(view));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        TSurface new_surface = GetUncachedSurface(gpu_addr, params);
 | 
			
		||||
        bool modified = false;
 | 
			
		||||
 | 
			
		||||
        for (auto& surface : overlaps) {
 | 
			
		||||
            const SurfaceParams& src_params = surface->GetSurfaceParams();
 | 
			
		||||
            if (src_params.target != SurfaceTarget::Texture2D ||
 | 
			
		||||
                src_params.height != params.height ||
 | 
			
		||||
                src_params.block_depth != params.block_depth ||
 | 
			
		||||
                src_params.block_height != params.block_height) {
 | 
			
		||||
                return std::nullopt;
 | 
			
		||||
            }
 | 
			
		||||
            modified |= surface->IsModified();
 | 
			
		||||
 | 
			
		||||
            const u32 offset = static_cast<u32>(surface->GetCpuAddr() - cpu_addr);
 | 
			
		||||
            const u32 slice = std::get<2>(params.GetBlockOffsetXYZ(offset));
 | 
			
		||||
            const u32 width = params.width;
 | 
			
		||||
            const u32 height = params.height;
 | 
			
		||||
            const CopyParams copy_params(0, 0, 0, 0, 0, slice, 0, 0, width, height, 1);
 | 
			
		||||
            ImageCopy(surface, new_surface, copy_params);
 | 
			
		||||
        }
 | 
			
		||||
        for (const auto& surface : overlaps) {
 | 
			
		||||
            Unregister(surface);
 | 
			
		||||
        }
 | 
			
		||||
        new_surface->MarkAsModified(modified, Tick());
 | 
			
		||||
        Register(new_surface);
 | 
			
		||||
 | 
			
		||||
        TView view = new_surface->GetMainView();
 | 
			
		||||
        return std::make_pair(std::move(new_surface), std::move(view));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -873,7 +878,7 @@ private:
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if it's a 3D texture
 | 
			
		||||
        // Manage 3D textures
 | 
			
		||||
        if (params.block_depth > 0) {
 | 
			
		||||
            auto surface =
 | 
			
		||||
                Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr, preserve_contents);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user