|
|
@ -108,7 +108,7 @@ public:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)};
|
|
|
|
const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)};
|
|
|
|
const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, true, false);
|
|
|
|
const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, false);
|
|
|
|
if (guard_samplers) {
|
|
|
|
if (guard_samplers) {
|
|
|
|
sampled_textures.push_back(surface);
|
|
|
|
sampled_textures.push_back(surface);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -128,7 +128,7 @@ public:
|
|
|
|
return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
|
|
|
|
return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)};
|
|
|
|
const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)};
|
|
|
|
const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, true, false);
|
|
|
|
const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, false);
|
|
|
|
if (guard_samplers) {
|
|
|
|
if (guard_samplers) {
|
|
|
|
sampled_textures.push_back(surface);
|
|
|
|
sampled_textures.push_back(surface);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -143,7 +143,7 @@ public:
|
|
|
|
return any_rt;
|
|
|
|
return any_rt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TView GetDepthBufferSurface(bool preserve_contents) {
|
|
|
|
TView GetDepthBufferSurface() {
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D();
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D();
|
|
|
|
if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
|
|
|
|
if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
|
|
|
@ -164,7 +164,7 @@ public:
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)};
|
|
|
|
const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)};
|
|
|
|
auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, preserve_contents, true);
|
|
|
|
auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, true);
|
|
|
|
if (depth_buffer.target)
|
|
|
|
if (depth_buffer.target)
|
|
|
|
depth_buffer.target->MarkAsRenderTarget(false, NO_RT);
|
|
|
|
depth_buffer.target->MarkAsRenderTarget(false, NO_RT);
|
|
|
|
depth_buffer.target = surface_view.first;
|
|
|
|
depth_buffer.target = surface_view.first;
|
|
|
@ -174,7 +174,7 @@ public:
|
|
|
|
return surface_view.second;
|
|
|
|
return surface_view.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TView GetColorBufferSurface(std::size_t index, bool preserve_contents) {
|
|
|
|
TView GetColorBufferSurface(std::size_t index) {
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
|
|
|
|
ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D();
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D();
|
|
|
@ -204,9 +204,8 @@ public:
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto surface_view =
|
|
|
|
auto surface_view = GetSurface(gpu_addr, *cpu_addr,
|
|
|
|
GetSurface(gpu_addr, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index),
|
|
|
|
SurfaceParams::CreateForFramebuffer(system, index), true);
|
|
|
|
preserve_contents, true);
|
|
|
|
|
|
|
|
if (render_targets[index].target)
|
|
|
|
if (render_targets[index].target)
|
|
|
|
render_targets[index].target->MarkAsRenderTarget(false, NO_RT);
|
|
|
|
render_targets[index].target->MarkAsRenderTarget(false, NO_RT);
|
|
|
|
render_targets[index].target = surface_view.first;
|
|
|
|
render_targets[index].target = surface_view.first;
|
|
|
@ -260,9 +259,9 @@ public:
|
|
|
|
const std::optional<VAddr> src_cpu_addr =
|
|
|
|
const std::optional<VAddr> src_cpu_addr =
|
|
|
|
system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr);
|
|
|
|
system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr);
|
|
|
|
std::pair<TSurface, TView> dst_surface =
|
|
|
|
std::pair<TSurface, TView> dst_surface =
|
|
|
|
GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false);
|
|
|
|
GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, false);
|
|
|
|
std::pair<TSurface, TView> src_surface =
|
|
|
|
std::pair<TSurface, TView> src_surface =
|
|
|
|
GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false);
|
|
|
|
GetSurface(src_gpu_addr, *src_cpu_addr, src_params, false);
|
|
|
|
ImageBlit(src_surface.second, dst_surface.second, copy_config);
|
|
|
|
ImageBlit(src_surface.second, dst_surface.second, copy_config);
|
|
|
|
dst_surface.first->MarkAsModified(true, Tick());
|
|
|
|
dst_surface.first->MarkAsModified(true, Tick());
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -451,22 +450,18 @@ private:
|
|
|
|
* @param overlaps The overlapping surfaces registered in the cache.
|
|
|
|
* @param overlaps The overlapping surfaces registered in the cache.
|
|
|
|
* @param params The parameters for the new surface.
|
|
|
|
* @param params The parameters for the new surface.
|
|
|
|
* @param gpu_addr The starting address of the new surface.
|
|
|
|
* @param gpu_addr The starting address of the new surface.
|
|
|
|
* @param preserve_contents Indicates that the new surface should be loaded from memory or left
|
|
|
|
|
|
|
|
* blank.
|
|
|
|
|
|
|
|
* @param untopological Indicates to the recycler that the texture has no way to match the
|
|
|
|
* @param untopological Indicates to the recycler that the texture has no way to match the
|
|
|
|
* overlaps due to topological reasons.
|
|
|
|
* overlaps due to topological reasons.
|
|
|
|
**/
|
|
|
|
**/
|
|
|
|
std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
|
|
|
|
std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
|
|
|
|
const SurfaceParams& params, const GPUVAddr gpu_addr,
|
|
|
|
const SurfaceParams& params, const GPUVAddr gpu_addr,
|
|
|
|
const bool preserve_contents,
|
|
|
|
|
|
|
|
const MatchTopologyResult untopological) {
|
|
|
|
const MatchTopologyResult untopological) {
|
|
|
|
const bool do_load = preserve_contents && Settings::values.use_accurate_gpu_emulation;
|
|
|
|
|
|
|
|
for (auto& surface : overlaps) {
|
|
|
|
for (auto& surface : overlaps) {
|
|
|
|
Unregister(surface);
|
|
|
|
Unregister(surface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (PickStrategy(overlaps, params, gpu_addr, untopological)) {
|
|
|
|
switch (PickStrategy(overlaps, params, gpu_addr, untopological)) {
|
|
|
|
case RecycleStrategy::Ignore: {
|
|
|
|
case RecycleStrategy::Ignore: {
|
|
|
|
return InitializeSurface(gpu_addr, params, do_load);
|
|
|
|
return InitializeSurface(gpu_addr, params, Settings::values.use_accurate_gpu_emulation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case RecycleStrategy::Flush: {
|
|
|
|
case RecycleStrategy::Flush: {
|
|
|
|
std::sort(overlaps.begin(), overlaps.end(),
|
|
|
|
std::sort(overlaps.begin(), overlaps.end(),
|
|
|
@ -476,7 +471,7 @@ private:
|
|
|
|
for (auto& surface : overlaps) {
|
|
|
|
for (auto& surface : overlaps) {
|
|
|
|
FlushSurface(surface);
|
|
|
|
FlushSurface(surface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return InitializeSurface(gpu_addr, params, preserve_contents);
|
|
|
|
return InitializeSurface(gpu_addr, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case RecycleStrategy::BufferCopy: {
|
|
|
|
case RecycleStrategy::BufferCopy: {
|
|
|
|
auto new_surface = GetUncachedSurface(gpu_addr, params);
|
|
|
|
auto new_surface = GetUncachedSurface(gpu_addr, params);
|
|
|
@ -485,7 +480,7 @@ private:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
default: {
|
|
|
|
UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!");
|
|
|
|
UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!");
|
|
|
|
return InitializeSurface(gpu_addr, params, do_load);
|
|
|
|
return InitializeSurface(gpu_addr, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -621,14 +616,11 @@ private:
|
|
|
|
* @param params The parameters on the new surface.
|
|
|
|
* @param params The parameters on the new surface.
|
|
|
|
* @param gpu_addr The starting address of the new surface.
|
|
|
|
* @param gpu_addr The starting address of the new surface.
|
|
|
|
* @param cache_addr The starting address of the new surface on physical memory.
|
|
|
|
* @param cache_addr The starting address of the new surface on physical memory.
|
|
|
|
* @param preserve_contents Indicates that the new surface should be loaded from memory or
|
|
|
|
|
|
|
|
* left blank.
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps,
|
|
|
|
std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps,
|
|
|
|
const SurfaceParams& params,
|
|
|
|
const SurfaceParams& params,
|
|
|
|
const GPUVAddr gpu_addr,
|
|
|
|
const GPUVAddr gpu_addr,
|
|
|
|
const VAddr cpu_addr,
|
|
|
|
const VAddr cpu_addr) {
|
|
|
|
bool preserve_contents) {
|
|
|
|
|
|
|
|
if (params.target == SurfaceTarget::Texture3D) {
|
|
|
|
if (params.target == SurfaceTarget::Texture3D) {
|
|
|
|
bool failed = false;
|
|
|
|
bool failed = false;
|
|
|
|
if (params.num_levels > 1) {
|
|
|
|
if (params.num_levels > 1) {
|
|
|
@ -677,7 +669,7 @@ private:
|
|
|
|
return std::nullopt;
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Unregister(surface);
|
|
|
|
Unregister(surface);
|
|
|
|
return InitializeSurface(gpu_addr, params, preserve_contents);
|
|
|
|
return InitializeSurface(gpu_addr, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -688,7 +680,7 @@ private:
|
|
|
|
return {{surface, surface->GetMainView()}};
|
|
|
|
return {{surface, surface->GetMainView()}};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return InitializeSurface(gpu_addr, params, preserve_contents);
|
|
|
|
return InitializeSurface(gpu_addr, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -711,13 +703,10 @@ private:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param gpu_addr The starting address of the candidate surface.
|
|
|
|
* @param gpu_addr The starting address of the candidate surface.
|
|
|
|
* @param params The parameters on the candidate surface.
|
|
|
|
* @param params The parameters on the candidate surface.
|
|
|
|
* @param preserve_contents Indicates that the new surface should be loaded from memory or
|
|
|
|
|
|
|
|
* left blank.
|
|
|
|
|
|
|
|
* @param is_render Whether or not the surface is a render target.
|
|
|
|
* @param is_render Whether or not the surface is a render target.
|
|
|
|
**/
|
|
|
|
**/
|
|
|
|
std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const VAddr cpu_addr,
|
|
|
|
std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const VAddr cpu_addr,
|
|
|
|
const SurfaceParams& params, bool preserve_contents,
|
|
|
|
const SurfaceParams& params, bool is_render) {
|
|
|
|
bool is_render) {
|
|
|
|
|
|
|
|
// Step 1
|
|
|
|
// Step 1
|
|
|
|
// Check Level 1 Cache for a fast structural match. If candidate surface
|
|
|
|
// Check Level 1 Cache for a fast structural match. If candidate surface
|
|
|
|
// matches at certain level we are pretty much done.
|
|
|
|
// matches at certain level we are pretty much done.
|
|
|
@ -726,8 +715,7 @@ private:
|
|
|
|
const auto topological_result = current_surface->MatchesTopology(params);
|
|
|
|
const auto topological_result = current_surface->MatchesTopology(params);
|
|
|
|
if (topological_result != MatchTopologyResult::FullMatch) {
|
|
|
|
if (topological_result != MatchTopologyResult::FullMatch) {
|
|
|
|
std::vector<TSurface> overlaps{current_surface};
|
|
|
|
std::vector<TSurface> overlaps{current_surface};
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, topological_result);
|
|
|
|
topological_result);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const auto struct_result = current_surface->MatchesStructure(params);
|
|
|
|
const auto struct_result = current_surface->MatchesStructure(params);
|
|
|
@ -752,7 +740,7 @@ private:
|
|
|
|
|
|
|
|
|
|
|
|
// If none are found, we are done. we just load the surface and create it.
|
|
|
|
// If none are found, we are done. we just load the surface and create it.
|
|
|
|
if (overlaps.empty()) {
|
|
|
|
if (overlaps.empty()) {
|
|
|
|
return InitializeSurface(gpu_addr, params, preserve_contents);
|
|
|
|
return InitializeSurface(gpu_addr, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Step 3
|
|
|
|
// Step 3
|
|
|
@ -762,15 +750,13 @@ private:
|
|
|
|
for (const auto& surface : overlaps) {
|
|
|
|
for (const auto& surface : overlaps) {
|
|
|
|
const auto topological_result = surface->MatchesTopology(params);
|
|
|
|
const auto topological_result = surface->MatchesTopology(params);
|
|
|
|
if (topological_result != MatchTopologyResult::FullMatch) {
|
|
|
|
if (topological_result != MatchTopologyResult::FullMatch) {
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, topological_result);
|
|
|
|
topological_result);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check if it's a 3D texture
|
|
|
|
// Check if it's a 3D texture
|
|
|
|
if (params.block_depth > 0) {
|
|
|
|
if (params.block_depth > 0) {
|
|
|
|
auto surface =
|
|
|
|
auto surface = Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr);
|
|
|
|
Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr, preserve_contents);
|
|
|
|
|
|
|
|
if (surface) {
|
|
|
|
if (surface) {
|
|
|
|
return *surface;
|
|
|
|
return *surface;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -790,8 +776,7 @@ private:
|
|
|
|
return *view;
|
|
|
|
return *view;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, MatchTopologyResult::FullMatch);
|
|
|
|
MatchTopologyResult::FullMatch);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Now we check if the candidate is a mipmap/layer of the overlap
|
|
|
|
// Now we check if the candidate is a mipmap/layer of the overlap
|
|
|
|
std::optional<TView> view =
|
|
|
|
std::optional<TView> view =
|
|
|
@ -815,7 +800,7 @@ private:
|
|
|
|
pair.first->EmplaceView(params, gpu_addr, candidate_size);
|
|
|
|
pair.first->EmplaceView(params, gpu_addr, candidate_size);
|
|
|
|
if (mirage_view)
|
|
|
|
if (mirage_view)
|
|
|
|
return {pair.first, *mirage_view};
|
|
|
|
return {pair.first, *mirage_view};
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr,
|
|
|
|
MatchTopologyResult::FullMatch);
|
|
|
|
MatchTopologyResult::FullMatch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {current_surface, *view};
|
|
|
|
return {current_surface, *view};
|
|
|
@ -831,8 +816,7 @@ private:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We failed all the tests, recycle the overlaps into a new texture.
|
|
|
|
// We failed all the tests, recycle the overlaps into a new texture.
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents,
|
|
|
|
return RecycleSurface(overlaps, params, gpu_addr, MatchTopologyResult::FullMatch);
|
|
|
|
MatchTopologyResult::FullMatch);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -990,10 +974,10 @@ private:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
|
|
|
|
std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
|
|
|
|
bool preserve_contents) {
|
|
|
|
bool do_load = true) {
|
|
|
|
auto new_surface{GetUncachedSurface(gpu_addr, params)};
|
|
|
|
auto new_surface{GetUncachedSurface(gpu_addr, params)};
|
|
|
|
Register(new_surface);
|
|
|
|
Register(new_surface);
|
|
|
|
if (preserve_contents) {
|
|
|
|
if (do_load) {
|
|
|
|
LoadSurface(new_surface);
|
|
|
|
LoadSurface(new_surface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {new_surface, new_surface->GetMainView()};
|
|
|
|
return {new_surface, new_surface->GetMainView()};
|
|
|
|