|
|
@ -53,6 +53,7 @@ protected: |
|
|
HasheableSurfaceParams() = default; |
|
|
HasheableSurfaceParams() = default; |
|
|
|
|
|
|
|
|
bool is_tiled; |
|
|
bool is_tiled; |
|
|
|
|
|
bool srgb_conversion; |
|
|
u32 block_width; |
|
|
u32 block_width; |
|
|
u32 block_height; |
|
|
u32 block_height; |
|
|
u32 block_depth; |
|
|
u32 block_depth; |
|
|
@ -92,6 +93,10 @@ public: |
|
|
return is_tiled; |
|
|
return is_tiled; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool GetSrgbConversion() const { |
|
|
|
|
|
return srgb_conversion; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
u32 GetBlockWidth() const { |
|
|
u32 GetBlockWidth() const { |
|
|
return block_width; |
|
|
return block_width; |
|
|
} |
|
|
} |
|
|
@ -211,13 +216,15 @@ private: |
|
|
/// Calculates values that can be deduced from HasheableSurfaceParams. |
|
|
/// Calculates values that can be deduced from HasheableSurfaceParams. |
|
|
void CalculateCachedValues(); |
|
|
void CalculateCachedValues(); |
|
|
|
|
|
|
|
|
/// Returns the size of a given mipmap level. |
|
|
|
|
|
std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool layer_only, |
|
|
|
|
|
bool uncompressed) const; |
|
|
|
|
|
|
|
|
/// Returns the size of a given mipmap level inside a layer. |
|
|
|
|
|
std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const; |
|
|
|
|
|
|
|
|
/// Returns the size of all mipmap levels and aligns as needed. |
|
|
/// Returns the size of all mipmap levels and aligns as needed. |
|
|
std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const; |
|
|
std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const; |
|
|
|
|
|
|
|
|
|
|
|
/// Returns the size of a layer |
|
|
|
|
|
std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const; |
|
|
|
|
|
|
|
|
/// Returns true if the passed view width and height match the size of this params in a given |
|
|
/// Returns true if the passed view width and height match the size of this params in a given |
|
|
/// mipmap level. |
|
|
/// mipmap level. |
|
|
bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const; |
|
|
bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const; |
|
|
@ -277,13 +284,13 @@ public: |
|
|
|
|
|
|
|
|
virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0; |
|
|
virtual TExecutionContext UploadTexture(TExecutionContext exctx) = 0; |
|
|
|
|
|
|
|
|
TView* TryGetView(VAddr view_addr, const SurfaceParams& view_params) { |
|
|
|
|
|
if (view_addr < cpu_addr || !params.IsFamiliar(view_params)) { |
|
|
|
|
|
|
|
|
TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) { |
|
|
|
|
|
if (view_addr < gpu_addr || !params.IsFamiliar(view_params)) { |
|
|
// It can't be a view if it's in a prior address. |
|
|
// It can't be a view if it's in a prior address. |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const auto relative_offset{static_cast<u64>(view_addr - cpu_addr)}; |
|
|
|
|
|
|
|
|
const auto relative_offset{static_cast<u64>(view_addr - gpu_addr)}; |
|
|
const auto it{view_offset_map.find(relative_offset)}; |
|
|
const auto it{view_offset_map.find(relative_offset)}; |
|
|
if (it == view_offset_map.end()) { |
|
|
if (it == view_offset_map.end()) { |
|
|
// Couldn't find an aligned view. |
|
|
// Couldn't find an aligned view. |
|
|
@ -298,6 +305,11 @@ public: |
|
|
return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels()); |
|
|
return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
GPUVAddr GetGpuAddr() const { |
|
|
|
|
|
ASSERT(is_registered); |
|
|
|
|
|
return gpu_addr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
VAddr GetCpuAddr() const { |
|
|
VAddr GetCpuAddr() const { |
|
|
ASSERT(is_registered); |
|
|
ASSERT(is_registered); |
|
|
return cpu_addr; |
|
|
return cpu_addr; |
|
|
@ -325,22 +337,20 @@ public: |
|
|
return params; |
|
|
return params; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TView* GetView(VAddr view_addr, const SurfaceParams& view_params) { |
|
|
|
|
|
|
|
|
TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) { |
|
|
TView* view{TryGetView(view_addr, view_params)}; |
|
|
TView* view{TryGetView(view_addr, view_params)}; |
|
|
ASSERT(view != nullptr); |
|
|
ASSERT(view != nullptr); |
|
|
return view; |
|
|
return view; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Register(VAddr cpu_addr_, u8* host_ptr_) { |
|
|
|
|
|
|
|
|
void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) { |
|
|
ASSERT(!is_registered); |
|
|
ASSERT(!is_registered); |
|
|
is_registered = true; |
|
|
is_registered = true; |
|
|
|
|
|
gpu_addr = gpu_addr_; |
|
|
cpu_addr = cpu_addr_; |
|
|
cpu_addr = cpu_addr_; |
|
|
host_ptr = host_ptr_; |
|
|
host_ptr = host_ptr_; |
|
|
cache_addr = ToCacheAddr(host_ptr_); |
|
|
cache_addr = ToCacheAddr(host_ptr_); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Register(VAddr cpu_addr_) { |
|
|
|
|
|
Register(cpu_addr_, Memory::GetPointer(cpu_addr_)); |
|
|
|
|
|
|
|
|
DecorateSurfaceName(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Unregister() { |
|
|
void Unregister() { |
|
|
@ -358,6 +368,8 @@ protected: |
|
|
|
|
|
|
|
|
~SurfaceBase() = default; |
|
|
~SurfaceBase() = default; |
|
|
|
|
|
|
|
|
|
|
|
virtual void DecorateSurfaceName() = 0; |
|
|
|
|
|
|
|
|
virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0; |
|
|
virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0; |
|
|
|
|
|
|
|
|
bool IsModified() const { |
|
|
bool IsModified() const { |
|
|
@ -379,6 +391,7 @@ private: |
|
|
|
|
|
|
|
|
const std::map<u64, std::pair<u32, u32>> view_offset_map; |
|
|
const std::map<u64, std::pair<u32, u32>> view_offset_map; |
|
|
|
|
|
|
|
|
|
|
|
GPUVAddr gpu_addr{}; |
|
|
VAddr cpu_addr{}; |
|
|
VAddr cpu_addr{}; |
|
|
u8* host_ptr{}; |
|
|
u8* host_ptr{}; |
|
|
CacheAddr cache_addr{}; |
|
|
CacheAddr cache_addr{}; |
|
|
@ -392,12 +405,12 @@ class TextureCache { |
|
|
static_assert(std::is_trivially_copyable_v<TExecutionContext>); |
|
|
static_assert(std::is_trivially_copyable_v<TExecutionContext>); |
|
|
|
|
|
|
|
|
using ResultType = std::tuple<TView*, TExecutionContext>; |
|
|
using ResultType = std::tuple<TView*, TExecutionContext>; |
|
|
using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<TSurface*>>; |
|
|
|
|
|
|
|
|
using IntervalMap = boost::icl::interval_map<CacheAddr, std::set<std::shared_ptr<TSurface>>>; |
|
|
using IntervalType = typename IntervalMap::interval_type; |
|
|
using IntervalType = typename IntervalMap::interval_type; |
|
|
|
|
|
|
|
|
public: |
|
|
public: |
|
|
void InvalidateRegion(CacheAddr addr, std::size_t size) { |
|
|
void InvalidateRegion(CacheAddr addr, std::size_t size) { |
|
|
for (TSurface* surface : GetSurfacesInRegion(addr, size)) { |
|
|
|
|
|
|
|
|
for (const auto& surface : GetSurfacesInRegion(addr, size)) { |
|
|
if (!surface->IsRegistered()) { |
|
|
if (!surface->IsRegistered()) { |
|
|
// Skip duplicates |
|
|
// Skip duplicates |
|
|
continue; |
|
|
continue; |
|
|
@ -408,32 +421,25 @@ public: |
|
|
|
|
|
|
|
|
ResultType GetTextureSurface(TExecutionContext exctx, |
|
|
ResultType GetTextureSurface(TExecutionContext exctx, |
|
|
const Tegra::Texture::FullTextureInfo& config) { |
|
|
const Tegra::Texture::FullTextureInfo& config) { |
|
|
auto& memory_manager{system.GPU().MemoryManager()}; |
|
|
|
|
|
const auto cpu_addr{memory_manager.GpuToCpuAddress(config.tic.Address())}; |
|
|
|
|
|
if (!cpu_addr) { |
|
|
|
|
|
|
|
|
const auto gpu_addr{config.tic.Address()}; |
|
|
|
|
|
if (!gpu_addr) { |
|
|
return {{}, exctx}; |
|
|
return {{}, exctx}; |
|
|
} |
|
|
} |
|
|
const auto params{SurfaceParams::CreateForTexture(system, config)}; |
|
|
const auto params{SurfaceParams::CreateForTexture(system, config)}; |
|
|
return GetSurfaceView(exctx, *cpu_addr, params, true); |
|
|
|
|
|
|
|
|
return GetSurfaceView(exctx, gpu_addr, params, true); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) { |
|
|
ResultType GetDepthBufferSurface(TExecutionContext exctx, bool preserve_contents) { |
|
|
const auto& regs{system.GPU().Maxwell3D().regs}; |
|
|
const auto& regs{system.GPU().Maxwell3D().regs}; |
|
|
if (!regs.zeta.Address() || !regs.zeta_enable) { |
|
|
|
|
|
|
|
|
const auto gpu_addr{regs.zeta.Address()}; |
|
|
|
|
|
if (!gpu_addr || !regs.zeta_enable) { |
|
|
return {{}, exctx}; |
|
|
return {{}, exctx}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
auto& memory_manager{system.GPU().MemoryManager()}; |
|
|
|
|
|
const auto cpu_addr{memory_manager.GpuToCpuAddress(regs.zeta.Address())}; |
|
|
|
|
|
if (!cpu_addr) { |
|
|
|
|
|
return {{}, exctx}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const auto depth_params{SurfaceParams::CreateForDepthBuffer( |
|
|
const auto depth_params{SurfaceParams::CreateForDepthBuffer( |
|
|
system, regs.zeta_width, regs.zeta_height, regs.zeta.format, |
|
|
system, regs.zeta_width, regs.zeta_height, regs.zeta.format, |
|
|
regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, |
|
|
regs.zeta.memory_layout.block_width, regs.zeta.memory_layout.block_height, |
|
|
regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; |
|
|
regs.zeta.memory_layout.block_depth, regs.zeta.memory_layout.type)}; |
|
|
return GetSurfaceView(exctx, *cpu_addr, depth_params, preserve_contents); |
|
|
|
|
|
|
|
|
return GetSurfaceView(exctx, gpu_addr, depth_params, preserve_contents); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index, |
|
|
ResultType GetColorBufferSurface(TExecutionContext exctx, std::size_t index, |
|
|
@ -448,25 +454,23 @@ public: |
|
|
|
|
|
|
|
|
auto& memory_manager{system.GPU().MemoryManager()}; |
|
|
auto& memory_manager{system.GPU().MemoryManager()}; |
|
|
const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; |
|
|
const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; |
|
|
const auto cpu_addr{memory_manager.GpuToCpuAddress( |
|
|
|
|
|
config.Address() + config.base_layer * config.layer_stride * sizeof(u32))}; |
|
|
|
|
|
if (!cpu_addr) { |
|
|
|
|
|
|
|
|
const auto gpu_addr{config.Address() + |
|
|
|
|
|
config.base_layer * config.layer_stride * sizeof(u32)}; |
|
|
|
|
|
if (!gpu_addr) { |
|
|
return {{}, exctx}; |
|
|
return {{}, exctx}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return GetSurfaceView(exctx, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index), |
|
|
|
|
|
|
|
|
return GetSurfaceView(exctx, gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), |
|
|
preserve_contents); |
|
|
preserve_contents); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ResultType GetFermiSurface(TExecutionContext exctx, |
|
|
ResultType GetFermiSurface(TExecutionContext exctx, |
|
|
const Tegra::Engines::Fermi2D::Regs::Surface& config) { |
|
|
const Tegra::Engines::Fermi2D::Regs::Surface& config) { |
|
|
const auto cpu_addr{system.GPU().MemoryManager().GpuToCpuAddress(config.Address())}; |
|
|
|
|
|
ASSERT(cpu_addr); |
|
|
|
|
|
return GetSurfaceView(exctx, *cpu_addr, SurfaceParams::CreateForFermiCopySurface(config), |
|
|
|
|
|
true); |
|
|
|
|
|
|
|
|
return GetSurfaceView(exctx, config.Address(), |
|
|
|
|
|
SurfaceParams::CreateForFermiCopySurface(config), true); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TSurface* TryFindFramebufferSurface(const u8* host_ptr) const { |
|
|
|
|
|
|
|
|
std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { |
|
|
const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))}; |
|
|
const auto it{registered_surfaces.find(ToCacheAddr(host_ptr))}; |
|
|
return it != registered_surfaces.end() ? *it->second.begin() : nullptr; |
|
|
return it != registered_surfaces.end() ? *it->second.begin() : nullptr; |
|
|
} |
|
|
} |
|
|
@ -477,56 +481,68 @@ protected: |
|
|
|
|
|
|
|
|
~TextureCache() = default; |
|
|
~TextureCache() = default; |
|
|
|
|
|
|
|
|
virtual ResultType TryFastGetSurfaceView(TExecutionContext exctx, VAddr cpu_addr, u8* host_ptr, |
|
|
|
|
|
const SurfaceParams& params, bool preserve_contents, |
|
|
|
|
|
const std::vector<TSurface*>& overlaps) = 0; |
|
|
|
|
|
|
|
|
virtual ResultType TryFastGetSurfaceView( |
|
|
|
|
|
TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
|
|
|
|
|
const SurfaceParams& params, bool preserve_contents, |
|
|
|
|
|
const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0; |
|
|
|
|
|
|
|
|
virtual std::unique_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; |
|
|
|
|
|
|
|
|
virtual std::shared_ptr<TSurface> CreateSurface(const SurfaceParams& params) = 0; |
|
|
|
|
|
|
|
|
void Register(TSurface* surface, VAddr cpu_addr, u8* host_ptr) { |
|
|
|
|
|
surface->Register(cpu_addr, host_ptr); |
|
|
|
|
|
|
|
|
void Register(std::shared_ptr<TSurface> surface, GPUVAddr gpu_addr, VAddr cpu_addr, |
|
|
|
|
|
u8* host_ptr) { |
|
|
|
|
|
surface->Register(gpu_addr, cpu_addr, host_ptr); |
|
|
registered_surfaces.add({GetSurfaceInterval(surface), {surface}}); |
|
|
registered_surfaces.add({GetSurfaceInterval(surface), {surface}}); |
|
|
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1); |
|
|
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), 1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Unregister(TSurface* surface) { |
|
|
|
|
|
|
|
|
void Unregister(std::shared_ptr<TSurface> surface) { |
|
|
registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}}); |
|
|
registered_surfaces.subtract({GetSurfaceInterval(surface), {surface}}); |
|
|
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1); |
|
|
rasterizer.UpdatePagesCachedCount(surface->GetCpuAddr(), surface->GetSizeInBytes(), -1); |
|
|
surface->Unregister(); |
|
|
surface->Unregister(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TSurface* GetUncachedSurface(const SurfaceParams& params) { |
|
|
|
|
|
if (TSurface* surface = TryGetReservedSurface(params); surface) |
|
|
|
|
|
|
|
|
std::shared_ptr<TSurface> GetUncachedSurface(const SurfaceParams& params) { |
|
|
|
|
|
if (const auto surface = TryGetReservedSurface(params); surface) |
|
|
return surface; |
|
|
return surface; |
|
|
// No reserved surface available, create a new one and reserve it |
|
|
// No reserved surface available, create a new one and reserve it |
|
|
auto new_surface{CreateSurface(params)}; |
|
|
auto new_surface{CreateSurface(params)}; |
|
|
TSurface* surface{new_surface.get()}; |
|
|
|
|
|
ReserveSurface(params, std::move(new_surface)); |
|
|
|
|
|
return surface; |
|
|
|
|
|
|
|
|
ReserveSurface(params, new_surface); |
|
|
|
|
|
return new_surface; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Core::System& system; |
|
|
Core::System& system; |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
ResultType GetSurfaceView(TExecutionContext exctx, VAddr cpu_addr, const SurfaceParams& params, |
|
|
|
|
|
bool preserve_contents) { |
|
|
|
|
|
const auto host_ptr{Memory::GetPointer(cpu_addr)}; |
|
|
|
|
|
|
|
|
ResultType GetSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, |
|
|
|
|
|
const SurfaceParams& params, bool preserve_contents) { |
|
|
|
|
|
auto& memory_manager{system.GPU().MemoryManager()}; |
|
|
|
|
|
const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; |
|
|
|
|
|
DEBUG_ASSERT(cpu_addr); |
|
|
|
|
|
|
|
|
|
|
|
const auto host_ptr{memory_manager.GetPointer(gpu_addr)}; |
|
|
const auto cache_addr{ToCacheAddr(host_ptr)}; |
|
|
const auto cache_addr{ToCacheAddr(host_ptr)}; |
|
|
const auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; |
|
|
const auto overlaps{GetSurfacesInRegion(cache_addr, params.GetGuestSizeInBytes())}; |
|
|
if (overlaps.empty()) { |
|
|
if (overlaps.empty()) { |
|
|
return LoadSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents); |
|
|
|
|
|
|
|
|
return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (overlaps.size() == 1) { |
|
|
if (overlaps.size() == 1) { |
|
|
if (TView* view = overlaps[0]->TryGetView(cpu_addr, params); view) |
|
|
|
|
|
|
|
|
if (TView* view = overlaps[0]->TryGetView(gpu_addr, params); view) { |
|
|
return {view, exctx}; |
|
|
return {view, exctx}; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TView* fast_view; |
|
|
TView* fast_view; |
|
|
std::tie(fast_view, exctx) = |
|
|
|
|
|
TryFastGetSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents, overlaps); |
|
|
|
|
|
|
|
|
std::tie(fast_view, exctx) = TryFastGetSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, |
|
|
|
|
|
params, preserve_contents, overlaps); |
|
|
|
|
|
|
|
|
|
|
|
if (!fast_view) { |
|
|
|
|
|
std::sort(overlaps.begin(), overlaps.end(), [](const auto& lhs, const auto& rhs) { |
|
|
|
|
|
return lhs->GetModificationTick() < rhs->GetModificationTick(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (TSurface* surface : overlaps) { |
|
|
|
|
|
|
|
|
for (const auto& surface : overlaps) { |
|
|
if (!fast_view) { |
|
|
if (!fast_view) { |
|
|
// Flush even when we don't care about the contents, to preserve memory not written |
|
|
// Flush even when we don't care about the contents, to preserve memory not written |
|
|
// by the new surface. |
|
|
// by the new surface. |
|
|
@ -539,57 +555,59 @@ private: |
|
|
return {fast_view, exctx}; |
|
|
return {fast_view, exctx}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return LoadSurfaceView(exctx, cpu_addr, host_ptr, params, preserve_contents); |
|
|
|
|
|
|
|
|
return LoadSurfaceView(exctx, gpu_addr, *cpu_addr, host_ptr, params, preserve_contents); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ResultType LoadSurfaceView(TExecutionContext exctx, VAddr cpu_addr, u8* host_ptr, |
|
|
|
|
|
const SurfaceParams& params, bool preserve_contents) { |
|
|
|
|
|
TSurface* new_surface{GetUncachedSurface(params)}; |
|
|
|
|
|
Register(new_surface, cpu_addr, host_ptr); |
|
|
|
|
|
|
|
|
ResultType LoadSurfaceView(TExecutionContext exctx, GPUVAddr gpu_addr, VAddr cpu_addr, |
|
|
|
|
|
u8* host_ptr, const SurfaceParams& params, bool preserve_contents) { |
|
|
|
|
|
const auto new_surface{GetUncachedSurface(params)}; |
|
|
|
|
|
Register(new_surface, gpu_addr, cpu_addr, host_ptr); |
|
|
if (preserve_contents) { |
|
|
if (preserve_contents) { |
|
|
exctx = LoadSurface(exctx, new_surface); |
|
|
exctx = LoadSurface(exctx, new_surface); |
|
|
} |
|
|
} |
|
|
return {new_surface->GetView(cpu_addr, params), exctx}; |
|
|
|
|
|
|
|
|
return {new_surface->GetView(gpu_addr, params), exctx}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TExecutionContext LoadSurface(TExecutionContext exctx, TSurface* surface) { |
|
|
|
|
|
|
|
|
TExecutionContext LoadSurface(TExecutionContext exctx, |
|
|
|
|
|
const std::shared_ptr<TSurface>& surface) { |
|
|
surface->LoadBuffer(); |
|
|
surface->LoadBuffer(); |
|
|
exctx = surface->UploadTexture(exctx); |
|
|
exctx = surface->UploadTexture(exctx); |
|
|
surface->MarkAsModified(false); |
|
|
surface->MarkAsModified(false); |
|
|
return exctx; |
|
|
return exctx; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<TSurface*> GetSurfacesInRegion(CacheAddr cache_addr, std::size_t size) const { |
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<TSurface>> GetSurfacesInRegion(CacheAddr cache_addr, |
|
|
|
|
|
std::size_t size) const { |
|
|
if (size == 0) { |
|
|
if (size == 0) { |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
const IntervalType interval{cache_addr, cache_addr + size}; |
|
|
const IntervalType interval{cache_addr, cache_addr + size}; |
|
|
|
|
|
|
|
|
std::vector<TSurface*> surfaces; |
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<TSurface>> surfaces; |
|
|
for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) { |
|
|
for (auto& pair : boost::make_iterator_range(registered_surfaces.equal_range(interval))) { |
|
|
surfaces.push_back(*pair.second.begin()); |
|
|
surfaces.push_back(*pair.second.begin()); |
|
|
} |
|
|
} |
|
|
return surfaces; |
|
|
return surfaces; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void ReserveSurface(const SurfaceParams& params, std::unique_ptr<TSurface> surface) { |
|
|
|
|
|
|
|
|
void ReserveSurface(const SurfaceParams& params, std::shared_ptr<TSurface> surface) { |
|
|
surface_reserve[params].push_back(std::move(surface)); |
|
|
surface_reserve[params].push_back(std::move(surface)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TSurface* TryGetReservedSurface(const SurfaceParams& params) { |
|
|
|
|
|
|
|
|
std::shared_ptr<TSurface> TryGetReservedSurface(const SurfaceParams& params) { |
|
|
auto search{surface_reserve.find(params)}; |
|
|
auto search{surface_reserve.find(params)}; |
|
|
if (search == surface_reserve.end()) { |
|
|
if (search == surface_reserve.end()) { |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
for (auto& surface : search->second) { |
|
|
for (auto& surface : search->second) { |
|
|
if (!surface->IsRegistered()) { |
|
|
if (!surface->IsRegistered()) { |
|
|
return surface.get(); |
|
|
|
|
|
|
|
|
return surface; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
IntervalType GetSurfaceInterval(TSurface* surface) const { |
|
|
|
|
|
|
|
|
IntervalType GetSurfaceInterval(std::shared_ptr<TSurface> surface) const { |
|
|
return IntervalType::right_open(surface->GetCacheAddr(), |
|
|
return IntervalType::right_open(surface->GetCacheAddr(), |
|
|
surface->GetCacheAddr() + surface->GetSizeInBytes()); |
|
|
surface->GetCacheAddr() + surface->GetSizeInBytes()); |
|
|
} |
|
|
} |
|
|
@ -601,7 +619,7 @@ private: |
|
|
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have |
|
|
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have |
|
|
/// previously been used. This is to prevent surfaces from being constantly created and |
|
|
/// previously been used. This is to prevent surfaces from being constantly created and |
|
|
/// destroyed when used with different surface parameters. |
|
|
/// destroyed when used with different surface parameters. |
|
|
std::unordered_map<SurfaceParams, std::list<std::unique_ptr<TSurface>>> surface_reserve; |
|
|
|
|
|
|
|
|
std::unordered_map<SurfaceParams, std::list<std::shared_ptr<TSurface>>> surface_reserve; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct DummyExecutionContext {}; |
|
|
struct DummyExecutionContext {}; |
|
|
@ -631,7 +649,7 @@ public: |
|
|
return RemoveContext(Base::GetFermiSurface({}, config)); |
|
|
return RemoveContext(Base::GetFermiSurface({}, config)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TSurface* TryFindFramebufferSurface(const u8* host_ptr) const { |
|
|
|
|
|
|
|
|
std::shared_ptr<TSurface> TryFindFramebufferSurface(const u8* host_ptr) const { |
|
|
return Base::TryFindFramebufferSurface(host_ptr); |
|
|
return Base::TryFindFramebufferSurface(host_ptr); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -640,15 +658,18 @@ protected: |
|
|
VideoCore::RasterizerInterface& rasterizer) |
|
|
VideoCore::RasterizerInterface& rasterizer) |
|
|
: TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {} |
|
|
: TextureCache<TSurface, TView, DummyExecutionContext>{system, rasterizer} {} |
|
|
|
|
|
|
|
|
virtual TView* TryFastGetSurfaceView(VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, |
|
|
|
|
|
bool preserve_contents, |
|
|
|
|
|
const std::vector<TSurface*>& overlaps) = 0; |
|
|
|
|
|
|
|
|
virtual TView* TryFastGetSurfaceView( |
|
|
|
|
|
GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, |
|
|
|
|
|
bool preserve_contents, const std::vector<std::shared_ptr<TSurface>>& overlaps) = 0; |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView( |
|
|
std::tuple<TView*, DummyExecutionContext> TryFastGetSurfaceView( |
|
|
DummyExecutionContext, VAddr cpu_addr, u8* host_ptr, const SurfaceParams& params, |
|
|
|
|
|
bool preserve_contents, const std::vector<TSurface*>& overlaps) { |
|
|
|
|
|
return {TryFastGetSurfaceView(cpu_addr, host_ptr, params, preserve_contents, overlaps), {}}; |
|
|
|
|
|
|
|
|
DummyExecutionContext, GPUVAddr gpu_addr, VAddr cpu_addr, u8* host_ptr, |
|
|
|
|
|
const SurfaceParams& params, bool preserve_contents, |
|
|
|
|
|
const std::vector<std::shared_ptr<TSurface>>& overlaps) { |
|
|
|
|
|
return {TryFastGetSurfaceView(gpu_addr, cpu_addr, host_ptr, params, preserve_contents, |
|
|
|
|
|
overlaps), |
|
|
|
|
|
{}}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) { |
|
|
TView* RemoveContext(std::tuple<TView*, DummyExecutionContext> return_value) { |
|
|
|