2018-09-18 06:30:35 +02:00
|
|
|
using Ryujinx.Graphics.Gal;
|
|
|
|
using Ryujinx.Graphics.Memory;
|
|
|
|
using Ryujinx.Graphics.Texture;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics
|
|
|
|
{
|
|
|
|
public class GpuResourceManager
|
|
|
|
{
|
2018-09-19 23:26:49 +02:00
|
|
|
private enum ImageType
|
|
|
|
{
|
|
|
|
None,
|
|
|
|
Texture,
|
2019-02-28 02:12:24 +01:00
|
|
|
TextureArrayLayer,
|
2018-09-19 23:26:49 +02:00
|
|
|
ColorBuffer,
|
|
|
|
ZetaBuffer
|
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private NvGpu _gpu;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private HashSet<long>[] _uploadedKeys;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private Dictionary<long, ImageType> _imageTypes;
|
|
|
|
private Dictionary<long, int> _mirroredTextures;
|
2018-09-19 23:26:49 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public GpuResourceManager(NvGpu gpu)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu = gpu;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_uploadedKeys = new HashSet<long>[(int)NvGpuBufferType.Count];
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
for (int index = 0; index < _uploadedKeys.Length; index++)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_uploadedKeys[index] = new HashSet<long>();
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
2018-09-19 23:26:49 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_imageTypes = new Dictionary<long, ImageType>();
|
|
|
|
_mirroredTextures = new Dictionary<long, int>();
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public void SendColorBuffer(NvGpuVmm vmm, long position, int attachment, GalImage newImage)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
long size = (uint)ImageUtils.GetSize(newImage);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_imageTypes[position] = ImageType.ColorBuffer;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (!TryReuse(vmm, position, newImage))
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.Renderer.RenderTarget.BindColor(position, attachment);
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public void SendZetaBuffer(NvGpuVmm vmm, long position, GalImage newImage)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
long size = (uint)ImageUtils.GetSize(newImage);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_imageTypes[position] = ImageType.ZetaBuffer;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (!TryReuse(vmm, position, newImage))
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.Renderer.RenderTarget.BindZeta(position);
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public void SendTexture(NvGpuVmm vmm, long position, GalImage newImage)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
PrepareSendTexture(vmm, position, newImage);
|
2018-09-19 23:26:49 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_imageTypes[position] = ImageType.Texture;
|
2018-09-19 23:26:49 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public bool TryGetTextureLayer(long position, out int layerIndex)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
if (_mirroredTextures.TryGetValue(position, out layerIndex))
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
ImageType type = _imageTypes[position];
|
2019-02-28 02:12:24 +01:00
|
|
|
|
|
|
|
// FIXME(thog): I'm actually unsure if we should deny all other image type, gpu testing needs to be done here.
|
2019-03-04 02:45:25 +01:00
|
|
|
if (type != ImageType.Texture && type != ImageType.TextureArrayLayer)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
layerIndex = -1;
|
2019-02-28 02:12:24 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
layerIndex = -1;
|
2019-02-28 02:12:24 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public void SetTextureArrayLayer(long position, int layerIndex)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_imageTypes[position] = ImageType.TextureArrayLayer;
|
|
|
|
_mirroredTextures[position] = layerIndex;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private void PrepareSendTexture(NvGpuVmm vmm, long position, GalImage newImage)
|
2018-09-19 23:26:49 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
long size = ImageUtils.GetSize(newImage);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
bool skipCheck = false;
|
2018-09-19 23:26:49 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (_imageTypes.TryGetValue(position, out ImageType oldType))
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
if (oldType == ImageType.ColorBuffer || oldType == ImageType.ZetaBuffer)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-07-02 04:39:22 +02:00
|
|
|
// Avoid data destruction
|
2019-03-04 02:45:25 +01:00
|
|
|
MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
skipCheck = true;
|
2018-09-19 23:26:49 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (skipCheck || !MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture))
|
2018-09-19 23:26:49 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
if (TryReuse(vmm, position, newImage))
|
2018-09-19 23:26:49 +02:00
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
byte[] data = ImageUtils.ReadTexture(vmm, newImage, position);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.Renderer.Texture.Create(position, data, newImage);
|
2018-09-19 23:26:49 +02:00
|
|
|
}
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private bool TryReuse(NvGpuVmm vmm, long position, GalImage newImage)
|
2018-09-19 23:26:49 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
if (_gpu.Renderer.Texture.TryGetImage(position, out GalImage cachedImage) && cachedImage.TextureTarget == newImage.TextureTarget && cachedImage.SizeMatches(newImage))
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.Renderer.RenderTarget.Reinterpret(position, newImage);
|
2018-09-19 23:26:49 +02:00
|
|
|
|
|
|
|
return true;
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2018-09-19 23:26:49 +02:00
|
|
|
return false;
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public bool MemoryRegionModified(NvGpuVmm vmm, long position, long size, NvGpuBufferType type)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
HashSet<long> uploaded = _uploadedKeys[(int)type];
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (!uploaded.Add(position))
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
return vmm.IsRegionModified(position, size, type);
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ClearPbCache()
|
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
for (int index = 0; index < _uploadedKeys.Length; index++)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_uploadedKeys[index].Clear();
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
}
|
2018-11-17 05:01:31 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public void ClearPbCache(NvGpuBufferType type)
|
2018-11-17 05:01:31 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_uploadedKeys[(int)type].Clear();
|
2018-11-17 05:01:31 +01:00
|
|
|
}
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
|
|
|
}
|