summaryrefslogblamecommitdiffstats
path: root/src/video_core/texture_cache/surface_base.h
blob: 173f2edba02785665ddff365120c396f401eb208 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                            

                   
                        
                 
 

                                

                                                 


                                                    



                    

                       
                                   






                                        
 





                                      

                    

                            




                                                   



                                                               







                                                

                       
                                                                                       
 
                                                                                        

                                 


                        

                                                             

     
                                                                               
                                                                   
                                                                    

     


                                              

     
                              
                        

     

                                 

     


                                                    





                                                   
                                        
                                 

     

                                            

     

                                                      

     



                                



                              



                                                                          



                                                       



                                                                      



                                                                          





                                                                                           
                                                                                               
 
                                                                             
                                                                                                


          

                                                                            
                                 



                                           

                                  
                                 
                        
                     
                         
                        


                                            
 


                                                                                                 
 
                                                                                   
 
                                                                                      

  
                         
                                            
       
                                                                          
 
                                                                      
 
                                                      
                                                

                                 
 


                                                          
     
 















                                                  

                                        
     
 

                             

     
                              

                                                                      



                                 

     



                                 

                               

     





                                        





                                     
                                                                 

                                                                                                    

     




                                                                                             







                                                                                                 
                                                           

                                                 
                                                                                               


                      
                                                                                                  


         


                                                                                                

                                                             

                      
                                                           


                            
                                                   
                                                      
                                                                                               
         
                                                                            





                               
          


                                                                              


                             

                                                             
                    
                                                

        
                                          




                                                                   
                    

     

                                            
                       
                     

                         

                            
                     



                            
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <optional>
#include <tuple>
#include <unordered_map>
#include <vector>

#include "common/common_types.h"
#include "video_core/gpu.h"
#include "video_core/morton.h"
#include "video_core/texture_cache/copy_params.h"
#include "video_core/texture_cache/surface_params.h"
#include "video_core/texture_cache/surface_view.h"

namespace Tegra {
class MemoryManager;
}

namespace VideoCommon {

using VideoCore::MortonSwizzleMode;
using VideoCore::Surface::SurfaceTarget;

enum class MatchStructureResult : u32 {
    FullMatch = 0,
    SemiMatch = 1,
    None = 2,
};

enum class MatchTopologyResult : u32 {
    FullMatch = 0,
    CompressUnmatch = 1,
    None = 2,
};

class StagingCache {
public:
    explicit StagingCache();
    ~StagingCache();

    std::vector<u8>& GetBuffer(std::size_t index) {
        return staging_buffer[index];
    }

    const std::vector<u8>& GetBuffer(std::size_t index) const {
        return staging_buffer[index];
    }

    void SetSize(std::size_t size) {
        staging_buffer.resize(size);
    }

private:
    std::vector<std::vector<u8>> staging_buffer;
};

class SurfaceBaseImpl {
public:
    void LoadBuffer(Tegra::MemoryManager& memory_manager, StagingCache& staging_cache);

    void FlushBuffer(Tegra::MemoryManager& memory_manager, StagingCache& staging_cache);

    GPUVAddr GetGpuAddr() const {
        return gpu_addr;
    }

    bool Overlaps(const VAddr start, const VAddr end) const {
        return (cpu_addr < end) && (cpu_addr_end > start);
    }

    bool IsInside(const GPUVAddr other_start, const GPUVAddr other_end) const {
        const GPUVAddr gpu_addr_end = gpu_addr + guest_memory_size;
        return gpu_addr <= other_start && other_end <= gpu_addr_end;
    }

    // Use only when recycling a surface
    void SetGpuAddr(const GPUVAddr new_addr) {
        gpu_addr = new_addr;
    }

    VAddr GetCpuAddr() const {
        return cpu_addr;
    }

    VAddr GetCpuAddrEnd() const {
        return cpu_addr_end;
    }

    void SetCpuAddr(const VAddr new_addr) {
        cpu_addr = new_addr;
        cpu_addr_end = new_addr + guest_memory_size;
    }

    const SurfaceParams& GetSurfaceParams() const {
        return params;
    }

    std::size_t GetSizeInBytes() const {
        return guest_memory_size;
    }

    std::size_t GetHostSizeInBytes() const {
        return host_memory_size;
    }

    std::size_t GetMipmapSize(const u32 level) const {
        return mipmap_sizes[level];
    }

    bool IsLinear() const {
        return !params.is_tiled;
    }

    bool IsConverted() const {
        return is_converted;
    }

    bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const {
        return params.pixel_format == pixel_format;
    }

    VideoCore::Surface::PixelFormat GetFormat() const {
        return params.pixel_format;
    }

    bool MatchTarget(VideoCore::Surface::SurfaceTarget target) const {
        return params.target == target;
    }

    MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const;

    MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const;

    bool MatchesSubTexture(const SurfaceParams& rhs, const GPUVAddr other_gpu_addr) const {
        return std::tie(gpu_addr, params.target, params.num_levels) ==
                   std::tie(other_gpu_addr, rhs.target, rhs.num_levels) &&
               params.target == SurfaceTarget::Texture2D && params.num_levels == 1;
    }

    std::optional<std::pair<u32, u32>> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const;

    std::vector<CopyParams> BreakDown(const SurfaceParams& in_params) const {
        return params.is_layered ? BreakDownLayered(in_params) : BreakDownNonLayered(in_params);
    }

protected:
    explicit SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params,
                             bool is_astc_supported);
    ~SurfaceBaseImpl() = default;

    virtual void DecorateSurfaceName() = 0;

    const SurfaceParams params;
    std::size_t layer_size;
    std::size_t guest_memory_size;
    std::size_t host_memory_size;
    GPUVAddr gpu_addr{};
    VAddr cpu_addr{};
    VAddr cpu_addr_end{};
    bool is_converted{};

    std::vector<std::size_t> mipmap_sizes;
    std::vector<std::size_t> mipmap_offsets;

private:
    void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
                     u32 level);

    std::vector<CopyParams> BreakDownLayered(const SurfaceParams& in_params) const;

    std::vector<CopyParams> BreakDownNonLayered(const SurfaceParams& in_params) const;
};

template <typename TView>
class SurfaceBase : public SurfaceBaseImpl {
public:
    virtual void UploadTexture(const std::vector<u8>& staging_buffer) = 0;

    virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;

    void MarkAsModified(bool is_modified_, u64 tick) {
        is_modified = is_modified_ || is_target;
        modification_tick = tick;
    }

    void MarkAsRenderTarget(bool is_target_, u32 index_) {
        is_target = is_target_;
        index = index_;
    }

    void SetMemoryMarked(bool is_memory_marked_) {
        is_memory_marked = is_memory_marked_;
    }

    bool IsMemoryMarked() const {
        return is_memory_marked;
    }

    void SetSyncPending(bool is_sync_pending_) {
        is_sync_pending = is_sync_pending_;
    }

    bool IsSyncPending() const {
        return is_sync_pending;
    }

    void MarkAsPicked(bool is_picked_) {
        is_picked = is_picked_;
    }

    bool IsModified() const {
        return is_modified;
    }

    bool IsProtected() const {
        // Only 3D slices are to be protected
        return is_target && params.target == SurfaceTarget::Texture3D;
    }

    bool IsRenderTarget() const {
        return is_target;
    }

    u32 GetRenderTarget() const {
        return index;
    }

    bool IsRegistered() const {
        return is_registered;
    }

    bool IsPicked() const {
        return is_picked;
    }

    void MarkAsRegistered(bool is_reg) {
        is_registered = is_reg;
    }

    u64 GetModificationTick() const {
        return modification_tick;
    }

    TView EmplaceOverview(const SurfaceParams& overview_params) {
        const u32 num_layers{(params.is_layered && !overview_params.is_layered) ? 1 : params.depth};
        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,
                                              const u32 layer) {
        const auto layer_mipmap{GetLayerMipmap(view_addr + candidate_size)};
        if (!layer_mipmap) {
            return {};
        }
        const auto [end_layer, end_mipmap] = *layer_mipmap;
        if (layer != end_layer) {
            if (mipmap == 0 && end_mipmap == 0) {
                return GetView(ViewParams(view_params.target, layer, end_layer - layer, 0, 1));
            }
            return {};
        } else {
            return GetView(ViewParams(view_params.target, layer, 1, mipmap, end_mipmap - mipmap));
        }
    }

    std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr,
                                     const std::size_t candidate_size) {
        if (params.target == SurfaceTarget::Texture3D ||
            view_params.target == SurfaceTarget::Texture3D ||
            (params.num_levels == 1 && !params.is_layered)) {
            return {};
        }
        const auto layer_mipmap{GetLayerMipmap(view_addr)};
        if (!layer_mipmap) {
            return {};
        }
        const auto [layer, mipmap] = *layer_mipmap;
        if (GetMipmapSize(mipmap) != candidate_size) {
            return EmplaceIrregularView(view_params, view_addr, candidate_size, mipmap, layer);
        }
        return GetView(ViewParams(view_params.target, layer, 1, mipmap, 1));
    }

    TView GetMainView() const {
        return main_view;
    }

protected:
    explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params,
                         bool is_astc_supported)
        : SurfaceBaseImpl(gpu_addr, params, is_astc_supported) {}

    ~SurfaceBase() = default;

    virtual TView CreateView(const ViewParams& view_key) = 0;

    TView main_view;
    std::unordered_map<ViewParams, TView> views;

private:
    TView GetView(const ViewParams& key) {
        const auto [entry, is_cache_miss] = views.try_emplace(key);
        auto& view{entry->second};
        if (is_cache_miss) {
            view = CreateView(key);
        }
        return view;
    }

    static constexpr u32 NO_RT = 0xFFFFFFFF;

    bool is_modified{};
    bool is_target{};
    bool is_registered{};
    bool is_picked{};
    bool is_memory_marked{};
    bool is_sync_pending{};
    u32 index{NO_RT};
    u64 modification_tick{};
};

} // namespace VideoCommon