|
|
|
@ -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); |
|
|
|
|