2018-04-26 04:11:26 +02:00
|
|
|
using Ryujinx.Graphics.Gal;
|
2018-09-08 19:51:50 +02:00
|
|
|
using Ryujinx.Graphics.Memory;
|
|
|
|
using Ryujinx.Graphics.Texture;
|
2019-06-01 02:13:57 +02:00
|
|
|
using Ryujinx.Profiler;
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2018-12-03 03:38:47 +01:00
|
|
|
namespace Ryujinx.Graphics.Graphics3d
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2018-11-17 05:01:31 +01:00
|
|
|
class NvGpuEngine2d : INvGpuEngine
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
|
|
|
private enum CopyOperation
|
|
|
|
{
|
|
|
|
SrcCopyAnd,
|
|
|
|
RopAnd,
|
|
|
|
Blend,
|
|
|
|
SrcCopy,
|
|
|
|
Rop,
|
|
|
|
SrcCopyPremult,
|
|
|
|
BlendPremult
|
|
|
|
}
|
|
|
|
|
|
|
|
public int[] Registers { get; private set; }
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private NvGpu _gpu;
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public NvGpuEngine2d(NvGpu gpu)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu = gpu;
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2018-10-27 20:46:17 +02:00
|
|
|
Registers = new int[0x238];
|
2018-04-26 04:11:26 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
WriteRegister(methCall);
|
2018-10-27 20:46:17 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if ((NvGpuEngine2dReg)methCall.Method == NvGpuEngine2dReg.BlitSrcYInt)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
TextureCopy(vmm);
|
2018-04-26 04:11:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private void TextureCopy(NvGpuVmm vmm)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2019-06-01 02:13:57 +02:00
|
|
|
Profile.Begin(Profiles.GPU.Engine2d.TextureCopy);
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
CopyOperation operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
|
|
|
|
bool dstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
|
|
|
|
int dstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
|
|
|
|
int dstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
|
|
|
|
int dstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
|
|
|
|
int dstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
|
|
|
|
int dstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
|
|
|
|
int dstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
|
2018-11-17 05:01:31 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int srcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
|
|
|
|
bool srcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
|
|
|
|
int srcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
|
|
|
|
int srcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
|
|
|
|
int srcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
|
|
|
|
int srcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
|
|
|
|
int srcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
|
|
|
|
int srcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int dstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX);
|
|
|
|
int dstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY);
|
|
|
|
int dstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW);
|
|
|
|
int dstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH);
|
2018-11-17 05:01:31 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
long blitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract);
|
|
|
|
long blitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract);
|
2018-11-29 00:09:44 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
long srcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract);
|
|
|
|
long srcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract);
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalImageFormat srcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)srcFormat);
|
|
|
|
GalImageFormat dstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)dstFormat);
|
2018-07-19 07:30:21 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalMemoryLayout srcLayout = GetLayout(srcLinear);
|
|
|
|
GalMemoryLayout dstLayout = GetLayout(dstLinear);
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf);
|
|
|
|
int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
long srcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
|
|
|
|
long dstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
|
2018-04-26 04:11:26 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
long srcKey = vmm.GetPhysicalAddress(srcAddress);
|
|
|
|
long dstKey = vmm.GetPhysicalAddress(dstAddress);
|
2018-07-19 07:30:21 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
bool isSrcLayered = false;
|
|
|
|
bool isDstLayered = false;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureTarget srcTarget = GalTextureTarget.TwoD;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (srcDepth != 0)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
srcTarget = GalTextureTarget.TwoDArray;
|
|
|
|
srcDepth++;
|
|
|
|
isSrcLayered = true;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
srcDepth = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureTarget dstTarget = GalTextureTarget.TwoD;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (dstDepth != 0)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
dstTarget = GalTextureTarget.TwoDArray;
|
|
|
|
dstDepth++;
|
|
|
|
isDstLayered = true;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
dstDepth = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalImage srcTexture = new GalImage(
|
|
|
|
srcWidth,
|
|
|
|
srcHeight,
|
|
|
|
1, srcDepth, 1,
|
|
|
|
srcBlockHeight, 1,
|
|
|
|
srcLayout,
|
|
|
|
srcImgFormat,
|
|
|
|
srcTarget);
|
|
|
|
|
|
|
|
GalImage dstTexture = new GalImage(
|
|
|
|
dstWidth,
|
|
|
|
dstHeight,
|
|
|
|
1, dstDepth, 1,
|
|
|
|
dstBlockHeight, 1,
|
|
|
|
dstLayout,
|
|
|
|
dstImgFormat,
|
|
|
|
dstTarget);
|
|
|
|
|
|
|
|
srcTexture.Pitch = srcPitch;
|
|
|
|
dstTexture.Pitch = dstPitch;
|
|
|
|
|
|
|
|
long GetLayerOffset(GalImage image, int layer)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
|
|
|
|
return ImageUtils.GetLayerOffset(image, targetMipLevel) * layer;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int srcLayerIndex = -1;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (isSrcLayered && _gpu.ResourceManager.TryGetTextureLayer(srcKey, out srcLayerIndex) && srcLayerIndex != 0)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
srcKey = srcKey - GetLayerOffset(srcTexture, srcLayerIndex);
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int dstLayerIndex = -1;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (isDstLayered && _gpu.ResourceManager.TryGetTextureLayer(dstKey, out dstLayerIndex) && dstLayerIndex != 0)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
dstKey = dstKey - GetLayerOffset(dstTexture, dstLayerIndex);
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.ResourceManager.SendTexture(vmm, srcKey, srcTexture);
|
|
|
|
_gpu.ResourceManager.SendTexture(vmm, dstKey, dstTexture);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (isSrcLayered && srcLayerIndex == -1)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
for (int layer = 0; layer < srcTexture.LayerCount; layer++)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.ResourceManager.SetTextureArrayLayer(srcKey + GetLayerOffset(srcTexture, layer), layer);
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
srcLayerIndex = 0;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (isDstLayered && dstLayerIndex == -1)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
for (int layer = 0; layer < dstTexture.LayerCount; layer++)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
_gpu.ResourceManager.SetTextureArrayLayer(dstKey + GetLayerOffset(dstTexture, layer), layer);
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
dstLayerIndex = 0;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int srcBlitX1 = (int)(srcBlitX >> 32);
|
|
|
|
int srcBlitY1 = (int)(srcBlitY >> 32);
|
|
|
|
|
|
|
|
int srcBlitX2 = (int)(srcBlitX + dstBlitW * blitDuDx >> 32);
|
|
|
|
int srcBlitY2 = (int)(srcBlitY + dstBlitH * blitDvDy >> 32);
|
|
|
|
|
|
|
|
_gpu.Renderer.RenderTarget.Copy(
|
|
|
|
srcTexture,
|
|
|
|
dstTexture,
|
|
|
|
srcKey,
|
|
|
|
dstKey,
|
|
|
|
srcLayerIndex,
|
|
|
|
dstLayerIndex,
|
|
|
|
srcBlitX1,
|
|
|
|
srcBlitY1,
|
|
|
|
srcBlitX2,
|
|
|
|
srcBlitY2,
|
|
|
|
dstBlitX,
|
|
|
|
dstBlitY,
|
|
|
|
dstBlitX + dstBlitW,
|
|
|
|
dstBlitY + dstBlitH);
|
2018-11-17 05:01:31 +01:00
|
|
|
|
2019-07-02 04:39:22 +02:00
|
|
|
// Do a guest side copy as well. This is necessary when
|
|
|
|
// the texture is modified by the guest, however it doesn't
|
|
|
|
// work when resources that the gpu can write to are copied,
|
|
|
|
// like framebuffers.
|
2019-02-28 02:12:24 +01:00
|
|
|
|
|
|
|
// FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer)
|
2018-11-17 05:01:31 +01:00
|
|
|
ImageUtils.CopyTexture(
|
2019-03-04 02:45:25 +01:00
|
|
|
vmm,
|
|
|
|
srcTexture,
|
|
|
|
dstTexture,
|
|
|
|
srcAddress,
|
|
|
|
dstAddress,
|
|
|
|
srcBlitX1,
|
|
|
|
srcBlitY1,
|
|
|
|
dstBlitX,
|
|
|
|
dstBlitY,
|
|
|
|
dstBlitW,
|
|
|
|
dstBlitH);
|
|
|
|
|
|
|
|
vmm.IsRegionModified(dstKey, ImageUtils.GetSize(dstTexture), NvGpuBufferType.Texture);
|
2019-06-01 02:13:57 +02:00
|
|
|
|
|
|
|
Profile.End(Profiles.GPU.Engine2d.TextureCopy);
|
2018-09-18 06:30:35 +02:00
|
|
|
}
|
2018-07-19 07:30:21 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private static GalMemoryLayout GetLayout(bool linear)
|
2018-09-18 06:30:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
return linear
|
2018-09-18 06:30:35 +02:00
|
|
|
? GalMemoryLayout.Pitch
|
|
|
|
: GalMemoryLayout.BlockLinear;
|
2018-04-26 04:11:26 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private long MakeInt64From2xInt32(NvGpuEngine2dReg reg)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
|
|
|
return
|
2019-03-04 02:45:25 +01:00
|
|
|
(long)Registers[(int)reg + 0] << 32 |
|
|
|
|
(uint)Registers[(int)reg + 1];
|
2018-04-26 04:11:26 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private void WriteRegister(GpuMethodCall methCall)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
Registers[methCall.Method] = methCall.Argument;
|
2018-04-26 04:11:26 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private long ReadRegisterFixed1_31_32(NvGpuEngine2dReg reg)
|
2018-11-29 00:09:44 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
long low = (uint)ReadRegister(reg + 0);
|
|
|
|
long high = (uint)ReadRegister(reg + 1);
|
2018-11-29 00:09:44 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
return low | (high << 32);
|
2018-11-29 00:09:44 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private int ReadRegister(NvGpuEngine2dReg reg)
|
2018-04-26 04:11:26 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
return Registers[(int)reg];
|
2018-04-26 04:11:26 +02:00
|
|
|
}
|
|
|
|
}
|
2019-06-01 02:13:57 +02:00
|
|
|
}
|