2018-04-08 21:17:35 +02:00
|
|
|
using Ryujinx.Graphics.Gal;
|
2018-09-08 19:51:50 +02:00
|
|
|
using Ryujinx.Graphics.Memory;
|
2018-04-08 21:17:35 +02:00
|
|
|
using System;
|
|
|
|
|
2018-09-08 19:51:50 +02:00
|
|
|
namespace Ryujinx.Graphics.Texture
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
|
|
|
static class TextureFactory
|
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
public static GalImage MakeTexture(NvGpuVmm vmm, long ticPosition)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
int[] tic = ReadWords(vmm, ticPosition, 8);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalImageFormat format = GetImageFormat(tic);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureTarget textureTarget = (GalTextureTarget)((tic[4] >> 23) & 0xF);
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureSource xSource = (GalTextureSource)((tic[0] >> 19) & 7);
|
|
|
|
GalTextureSource ySource = (GalTextureSource)((tic[0] >> 22) & 7);
|
|
|
|
GalTextureSource zSource = (GalTextureSource)((tic[0] >> 25) & 7);
|
|
|
|
GalTextureSource wSource = (GalTextureSource)((tic[0] >> 28) & 7);
|
2018-05-17 20:25:42 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
TextureSwizzle swizzle = (TextureSwizzle)((tic[2] >> 21) & 7);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int maxMipmapLevel = (tic[3] >> 28) & 0xF + 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalMemoryLayout layout;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (swizzle == TextureSwizzle.BlockLinear ||
|
|
|
|
swizzle == TextureSwizzle.BlockLinearColorKey)
|
2018-06-23 07:00:44 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
layout = GalMemoryLayout.BlockLinear;
|
2018-06-23 07:00:44 +02:00
|
|
|
}
|
2018-09-18 06:30:35 +02:00
|
|
|
else
|
2018-06-23 07:00:44 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
layout = GalMemoryLayout.Pitch;
|
2018-06-23 07:00:44 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int gobBlockHeightLog2 = (tic[3] >> 3) & 7;
|
|
|
|
int gobBlockDepthLog2 = (tic[3] >> 6) & 7;
|
|
|
|
int tileWidthLog2 = (tic[3] >> 10) & 7;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int gobBlockHeight = 1 << gobBlockHeightLog2;
|
|
|
|
int gobBlockDepth = 1 << gobBlockDepthLog2;
|
|
|
|
int tileWidth = 1 << tileWidthLog2;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int width = ((tic[4] >> 0) & 0xffff) + 1;
|
|
|
|
int height = ((tic[5] >> 0) & 0xffff) + 1;
|
|
|
|
int depth = ((tic[5] >> 16) & 0x3fff) + 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
int layoutCount = 1;
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
// TODO: check this
|
2019-03-04 02:45:25 +01:00
|
|
|
if (ImageUtils.IsArray(textureTarget))
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
layoutCount = depth;
|
|
|
|
depth = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (textureTarget == GalTextureTarget.OneD)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
height = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
if (textureTarget == GalTextureTarget.TwoD || textureTarget == GalTextureTarget.OneD)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
depth = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
2019-03-04 02:45:25 +01:00
|
|
|
else if (textureTarget == GalTextureTarget.CubeMap)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
|
|
|
// FIXME: This is a bit hacky but I guess it's fine for now
|
2019-03-04 02:45:25 +01:00
|
|
|
layoutCount = 6;
|
|
|
|
depth = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
2019-03-04 02:45:25 +01:00
|
|
|
else if (textureTarget == GalTextureTarget.CubeArray)
|
2019-02-28 02:12:24 +01:00
|
|
|
{
|
|
|
|
// FIXME: This is a really really hacky but I guess it's fine for now
|
2019-03-04 02:45:25 +01:00
|
|
|
layoutCount *= 6;
|
|
|
|
depth = 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
}
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalImage image = new GalImage(
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
depth,
|
|
|
|
layoutCount,
|
|
|
|
tileWidth,
|
|
|
|
gobBlockHeight,
|
|
|
|
gobBlockDepth,
|
|
|
|
layout,
|
|
|
|
format,
|
|
|
|
textureTarget,
|
|
|
|
maxMipmapLevel,
|
|
|
|
xSource,
|
|
|
|
ySource,
|
|
|
|
zSource,
|
|
|
|
wSource);
|
|
|
|
|
|
|
|
if (layout == GalMemoryLayout.Pitch)
|
2018-10-13 03:37:01 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
image.Pitch = (tic[3] & 0xffff) << 5;
|
2018-10-13 03:37:01 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
return image;
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
public static GalTextureSampler MakeSampler(NvGpu gpu, NvGpuVmm vmm, long tscPosition)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
int[] tsc = ReadWords(vmm, tscPosition, 8);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureWrap addressU = (GalTextureWrap)((tsc[0] >> 0) & 7);
|
|
|
|
GalTextureWrap addressV = (GalTextureWrap)((tsc[0] >> 3) & 7);
|
|
|
|
GalTextureWrap addressP = (GalTextureWrap)((tsc[0] >> 6) & 7);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
bool depthCompare = ((tsc[0] >> 9) & 1) == 1;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
DepthCompareFunc depthCompareFunc = (DepthCompareFunc)((tsc[0] >> 10) & 7);
|
2019-02-28 02:12:24 +01:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureFilter magFilter = (GalTextureFilter) ((tsc[1] >> 0) & 3);
|
|
|
|
GalTextureFilter minFilter = (GalTextureFilter) ((tsc[1] >> 4) & 3);
|
|
|
|
GalTextureMipFilter mipFilter = (GalTextureMipFilter)((tsc[1] >> 6) & 3);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalColorF borderColor = new GalColorF(
|
|
|
|
BitConverter.Int32BitsToSingle(tsc[4]),
|
|
|
|
BitConverter.Int32BitsToSingle(tsc[5]),
|
|
|
|
BitConverter.Int32BitsToSingle(tsc[6]),
|
|
|
|
BitConverter.Int32BitsToSingle(tsc[7]));
|
2018-04-08 21:17:35 +02:00
|
|
|
|
|
|
|
return new GalTextureSampler(
|
2019-03-04 02:45:25 +01:00
|
|
|
addressU,
|
|
|
|
addressV,
|
|
|
|
addressP,
|
|
|
|
minFilter,
|
|
|
|
magFilter,
|
|
|
|
mipFilter,
|
|
|
|
borderColor,
|
|
|
|
depthCompare,
|
|
|
|
depthCompareFunc);
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private static GalImageFormat GetImageFormat(int[] tic)
|
2018-09-08 19:51:50 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureType rType = (GalTextureType)((tic[0] >> 7) & 7);
|
|
|
|
GalTextureType gType = (GalTextureType)((tic[0] >> 10) & 7);
|
|
|
|
GalTextureType bType = (GalTextureType)((tic[0] >> 13) & 7);
|
|
|
|
GalTextureType aType = (GalTextureType)((tic[0] >> 16) & 7);
|
2018-09-08 19:51:50 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
GalTextureFormat format = (GalTextureFormat)(tic[0] & 0x7f);
|
2018-09-08 19:51:50 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
bool convSrgb = ((tic[4] >> 22) & 1) != 0;
|
2018-10-17 23:02:23 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
return ImageUtils.ConvertTexture(format, rType, gType, bType, aType, convSrgb);
|
2018-09-08 19:51:50 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
private static int[] ReadWords(NvGpuVmm vmm, long position, int count)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
int[] words = new int[count];
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
for (int index = 0; index < count; index++, position += 4)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2019-03-04 02:45:25 +01:00
|
|
|
words[index] = vmm.ReadInt32(position);
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-04 02:45:25 +01:00
|
|
|
return words;
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|