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
|
|
|
|
{
|
2018-08-20 03:25:26 +02:00
|
|
|
public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl
* More work on NvHostCtrl
* Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind
* Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb)
* Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks
* Remove now unused code, add comment about probably wrong result codes
2018-05-07 20:53:23 +02:00
|
|
|
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2018-09-08 19:51:50 +02:00
|
|
|
GalImageFormat Format = GetImageFormat(Tic);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
GalTextureTarget TextureTarget = (GalTextureTarget)((Tic[4] >> 23) & 0xF);
|
|
|
|
|
2018-05-17 20:25:42 +02: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-04-08 21:17:35 +02:00
|
|
|
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
int MaxMipmapLevel = (Tic[3] >> 28) & 0xF + 1;
|
|
|
|
|
2018-09-18 06:30:35 +02:00
|
|
|
GalMemoryLayout Layout;
|
|
|
|
|
2018-06-23 07:00:44 +02:00
|
|
|
if (Swizzle == TextureSwizzle.BlockLinear ||
|
|
|
|
Swizzle == TextureSwizzle.BlockLinearColorKey)
|
|
|
|
{
|
2018-09-18 06:30:35 +02: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
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
Layout = GalMemoryLayout.Pitch;
|
2018-06-23 07:00:44 +02:00
|
|
|
}
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
int GobBlockHeightLog2 = (Tic[3] >> 3) & 7;
|
|
|
|
int GobBlockDepthLog2 = (Tic[3] >> 6) & 7;
|
|
|
|
int TileWidthLog2 = (Tic[3] >> 10) & 7;
|
|
|
|
|
|
|
|
int GobBlockHeight = 1 << GobBlockHeightLog2;
|
|
|
|
int GobBlockDepth = 1 << GobBlockDepthLog2;
|
|
|
|
int TileWidth = 1 << TileWidthLog2;
|
|
|
|
|
|
|
|
int Width = ((Tic[4] >> 0) & 0xffff) + 1;
|
|
|
|
int Height = ((Tic[5] >> 0) & 0xffff) + 1;
|
|
|
|
int Depth = ((Tic[5] >> 16) & 0x3fff) + 1;
|
|
|
|
|
|
|
|
int LayoutCount = 1;
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
// TODO: check this
|
|
|
|
if (ImageUtils.IsArray(TextureTarget))
|
|
|
|
{
|
|
|
|
LayoutCount = Depth;
|
|
|
|
Depth = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TextureTarget == GalTextureTarget.OneD)
|
|
|
|
{
|
|
|
|
Height = 1;
|
|
|
|
}
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
if (TextureTarget == GalTextureTarget.TwoD || TextureTarget == GalTextureTarget.OneD)
|
|
|
|
{
|
|
|
|
Depth = 1;
|
|
|
|
}
|
|
|
|
else if (TextureTarget == GalTextureTarget.CubeMap)
|
|
|
|
{
|
|
|
|
// FIXME: This is a bit hacky but I guess it's fine for now
|
|
|
|
LayoutCount = 6;
|
|
|
|
Depth = 1;
|
|
|
|
}
|
|
|
|
else if (TextureTarget == GalTextureTarget.CubeArray)
|
|
|
|
{
|
|
|
|
// FIXME: This is a really really hacky but I guess it's fine for now
|
|
|
|
LayoutCount *= 6;
|
|
|
|
Depth = 1;
|
|
|
|
}
|
2018-04-08 21:17:35 +02:00
|
|
|
|
2018-10-13 03:37:01 +02:00
|
|
|
GalImage Image = new GalImage(
|
2018-04-08 21:17:35 +02:00
|
|
|
Width,
|
|
|
|
Height,
|
2019-02-28 02:12:24 +01:00
|
|
|
Depth,
|
|
|
|
LayoutCount,
|
2018-07-19 07:30:21 +02:00
|
|
|
TileWidth,
|
2019-02-28 02:12:24 +01:00
|
|
|
GobBlockHeight,
|
|
|
|
GobBlockDepth,
|
2018-09-18 06:30:35 +02:00
|
|
|
Layout,
|
|
|
|
Format,
|
2019-02-28 02:12:24 +01:00
|
|
|
TextureTarget,
|
|
|
|
MaxMipmapLevel,
|
2018-09-18 06:30:35 +02:00
|
|
|
XSource,
|
|
|
|
YSource,
|
|
|
|
ZSource,
|
|
|
|
WSource);
|
2018-10-13 03:37:01 +02:00
|
|
|
|
|
|
|
if (Layout == GalMemoryLayout.Pitch)
|
|
|
|
{
|
|
|
|
Image.Pitch = (Tic[3] & 0xffff) << 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Image;
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl
* More work on NvHostCtrl
* Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind
* Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb)
* Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks
* Remove now unused code, add comment about probably wrong result codes
2018-05-07 20:53:23 +02:00
|
|
|
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl
* More work on NvHostCtrl
* Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind
* Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb)
* Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks
* Remove now unused code, add comment about probably wrong result codes
2018-05-07 20:53:23 +02:00
|
|
|
int[] Tsc = ReadWords(Vmm, TscPosition, 8);
|
2018-04-08 21:17:35 +02:00
|
|
|
|
|
|
|
GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7);
|
|
|
|
GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
|
|
|
|
GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7);
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1;
|
|
|
|
|
|
|
|
DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7);
|
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3);
|
|
|
|
GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3);
|
|
|
|
GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3);
|
|
|
|
|
|
|
|
GalColorF BorderColor = new GalColorF(
|
|
|
|
BitConverter.Int32BitsToSingle(Tsc[4]),
|
|
|
|
BitConverter.Int32BitsToSingle(Tsc[5]),
|
|
|
|
BitConverter.Int32BitsToSingle(Tsc[6]),
|
|
|
|
BitConverter.Int32BitsToSingle(Tsc[7]));
|
|
|
|
|
|
|
|
return new GalTextureSampler(
|
|
|
|
AddressU,
|
|
|
|
AddressV,
|
|
|
|
AddressP,
|
|
|
|
MinFilter,
|
|
|
|
MagFilter,
|
|
|
|
MipFilter,
|
2019-02-28 02:12:24 +01:00
|
|
|
BorderColor,
|
|
|
|
DepthCompare,
|
|
|
|
DepthCompareFunc);
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
2018-09-08 19:51:50 +02:00
|
|
|
private static GalImageFormat GetImageFormat(int[] Tic)
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
2018-09-08 19:51:50 +02:00
|
|
|
GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
|
|
|
|
GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
|
|
|
|
GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);
|
|
|
|
|
|
|
|
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
bool ConvSrgb = ((Tic[4] >> 22) & 1) != 0;
|
|
|
|
|
|
|
|
return ImageUtils.ConvertTexture(Format, RType, GType, BType, AType, ConvSrgb);
|
2018-09-08 19:51:50 +02:00
|
|
|
}
|
|
|
|
|
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl
* More work on NvHostCtrl
* Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind
* Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb)
* Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks
* Remove now unused code, add comment about probably wrong result codes
2018-05-07 20:53:23 +02:00
|
|
|
private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
|
|
|
int[] Words = new int[Count];
|
|
|
|
|
|
|
|
for (int Index = 0; Index < Count; Index++, Position += 4)
|
|
|
|
{
|
NvServices refactoring (#120)
* Initial implementation of NvMap/NvHostCtrl
* More work on NvHostCtrl
* Refactoring of nvservices, move GPU Vmm, make Vmm per-process, refactor most gpu devices, move Gpu to Core, fix CbBind
* Implement GetGpuTime, support CancelSynchronization, fix issue on InsertWaitingMutex, proper double buffering support (again, not working properly for commercial games, only hb)
* Try to fix perf regression reading/writing textures, moved syncpts and events to a UserCtx class, delete global state when the process exits, other minor tweaks
* Remove now unused code, add comment about probably wrong result codes
2018-05-07 20:53:23 +02:00
|
|
|
Words[Index] = Vmm.ReadInt32(Position);
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Words;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|