diff options
| author | Thomas Guillemard <thog@protonmail.com> | 2019-02-28 02:12:24 +0100 |
|---|---|---|
| committer | jduncanator <1518948+jduncanator@users.noreply.github.com> | 2019-02-28 12:12:24 +1100 |
| commit | 884b4e5fd3c2a54ebb796b7f995c0eda9c4d0038 (patch) | |
| tree | 35838aba68da07fda992510fede8a3920c60ccb3 /Ryujinx.Graphics/Graphics3d | |
| parent | 81aa50feb0899e73ee62e5113b786efe0ff6b7a9 (diff) | |
Initial non 2D textures support (#525)
* Initial non 2D textures support
- Shaders still need to be changed
- Some types aren't yet implemented
* Start implementing texture instructions suffixes
Fix wrong texture type with cube and TEXS
Also support array textures in TEX and TEX.B
Clean up TEX and TEXS coords managment
Fix TEXS.LL with non-2d textures
Implement TEX.AOFFI
Get the right arguments for TEX, TEXS and TLDS
Also, store suffix operands in appropriate values to support multiple
suffix combinaisons
* Support depth in read/writeTexture
Also support WrapR and detect mipmap
* Proper cube map textures support + fix TEXS.LZ
* Implement depth compare
* some code clean up
* Implement CubeMap textures in OGLTexture.Create
* Implement TLD4 and TLD4S
* Add Texture 1D support
* updates comments
* fix some code style issues
* Fix some nits + rename some things to be less confusing
* Remove GetSuffix local functions
* AOFFI => AOffI
* TextureType => GalTextureTarget
* finish renaming TextureType to TextureTarget
* Disable LL, LZ and LB support in the decompiler
This needs more work at the GL level (GLSL implementation should be
right)
* Revert "Disable LL, LZ and LB support in the decompiler"
This reverts commit 64536c3d9f673645faff3152838d1413c3203395.
* Fix TEXS ARRAY_2D index
* ImageFormat depth should be 1 for all image format
* Fix shader build issues with sampler1DShadow and texture
* Fix DC & AOFFI combinaison with TEX/TEXS
* Support AOFFI with TLD4 and TLD4S
* Fix shader compilation error for TLD4.AOFFI with no DC
* Fix binding isuses on the 2d copy engine
TODO: support 2d array copy
* Support 2D array copy operation in the 2D engine
This make every copy right in the GPU side.
Thie CPU copy probably needs to be updated
* Implement GetGpuSize + fix somes issues with 2d engine copies
TODO: mipmap level in it
* Don't throw an exception in the layer handling
* Fix because of rebase
* Reject 2d layers of non textures in 2d copy engine
* Add 3D textures and mipmap support on BlockLinearSwizzle
* Fix naming on new BitUtils methods
* gpu cache: Make sure to invalidate textures that doesn't have the same target
* Add the concept of layer count for array instead of using depth
Also cleanup GetGpuSize as Swizzle can compute the size with mipmap
* Support multi layer with mip map in ReadTexture
* Add more check for cache invalidation & remove cubemap and cubemap array code for now
Also fix compressed 2d array
* Fix texelFetchOffset shader build error
* Start looking into cube map again
Also add some way to log write in register in engines
* fix write register log levles
* Remove debug logs in WriteRegister
* Disable AOFFI support on non NVIDIA drivers
* Fix code align
Diffstat (limited to 'Ryujinx.Graphics/Graphics3d')
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs | 96 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs | 2 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 14 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs | 217 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs | 21 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs | 8 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs | 1 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs | 165 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs | 8 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs | 241 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs | 36 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs | 65 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs | 17 |
13 files changed, 667 insertions, 224 deletions
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs index 55e3ebd4..3295f6da 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; @@ -46,6 +47,8 @@ namespace Ryujinx.Graphics.Graphics3d 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); @@ -53,6 +56,8 @@ namespace Ryujinx.Graphics.Graphics3d 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); @@ -82,26 +87,99 @@ namespace Ryujinx.Graphics.Graphics3d long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); long DstKey = Vmm.GetPhysicalAddress(DstAddress); + bool IsSrcLayered = false; + bool IsDstLayered = false; + + GalTextureTarget SrcTarget = GalTextureTarget.TwoD; + + if (SrcDepth != 0) + { + SrcTarget = GalTextureTarget.TwoDArray; + SrcDepth++; + IsSrcLayered = true; + } + else + { + SrcDepth = 1; + } + + GalTextureTarget DstTarget = GalTextureTarget.TwoD; + + if (DstDepth != 0) + { + DstTarget = GalTextureTarget.TwoDArray; + DstDepth++; + IsDstLayered = true; + } + else + { + DstDepth = 1; + } + GalImage SrcTexture = new GalImage( SrcWidth, - SrcHeight, 1, - SrcBlockHeight, + SrcHeight, + 1, SrcDepth, 1, + SrcBlockHeight, 1, SrcLayout, - SrcImgFormat); + SrcImgFormat, + SrcTarget); GalImage DstTexture = new GalImage( DstWidth, - DstHeight, 1, - DstBlockHeight, + DstHeight, + 1, DstDepth, 1, + DstBlockHeight, 1, DstLayout, - DstImgFormat); + DstImgFormat, + DstTarget); SrcTexture.Pitch = SrcPitch; DstTexture.Pitch = DstPitch; + long GetLayerOffset(GalImage Image, int Layer) + { + int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1; + return ImageUtils.GetLayerOffset(Image, TargetMipLevel) * Layer; + } + + int SrcLayerIndex = -1; + + if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureLayer(SrcKey, out SrcLayerIndex) && SrcLayerIndex != 0) + { + SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex); + } + + int DstLayerIndex = -1; + + if (IsDstLayered && Gpu.ResourceManager.TryGetTextureLayer(DstKey, out DstLayerIndex) && DstLayerIndex != 0) + { + DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex); + } + Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture); Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture); + if (IsSrcLayered && SrcLayerIndex == -1) + { + for (int Layer = 0; Layer < SrcTexture.LayerCount; Layer++) + { + Gpu.ResourceManager.SetTextureArrayLayer(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer); + } + + SrcLayerIndex = 0; + } + + if (IsDstLayered && DstLayerIndex == -1) + { + for (int Layer = 0; Layer < DstTexture.LayerCount; Layer++) + { + Gpu.ResourceManager.SetTextureArrayLayer(DstKey + GetLayerOffset(DstTexture, Layer), Layer); + } + + DstLayerIndex = 0; + } + int SrcBlitX1 = (int)(SrcBlitX >> 32); int SrcBlitY1 = (int)(SrcBlitY >> 32); @@ -109,8 +187,12 @@ namespace Ryujinx.Graphics.Graphics3d int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32); Gpu.Renderer.RenderTarget.Copy( + SrcTexture, + DstTexture, SrcKey, DstKey, + SrcLayerIndex, + DstLayerIndex, SrcBlitX1, SrcBlitY1, SrcBlitX2, @@ -124,6 +206,8 @@ namespace Ryujinx.Graphics.Graphics3d //the texture is modified by the guest, however it doesn't //work when resources that the gpu can write to are copied, //like framebuffers. + + // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer) ImageUtils.CopyTexture( Vmm, SrcTexture, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs index c1c0dba2..7747b5a3 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs @@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Graphics3d DstWidth = 0x86, DstHeight = 0x87, DstAddress = 0x88, + DstAddressLow = 0x89, SrcFormat = 0x8c, SrcLinear = 0x8d, SrcBlockDimensions = 0x8e, @@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Graphics3d SrcWidth = 0x92, SrcHeight = 0x93, SrcAddress = 0x94, + SrcAddressLow = 0x95, ClipEnable = 0xa4, CopyOperation = 0xab, BlitControl = 0x223, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index 6120053d..eb6289fb 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; @@ -190,7 +191,11 @@ namespace Ryujinx.Graphics.Graphics3d int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); - int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10); + int ArrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + FbIndex * 0x10); + int LayerCount = ArrayMode & 0xFFFF; + int LayerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + FbIndex * 0x10); + int BaseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + FbIndex * 0x10); + int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10); int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); @@ -210,7 +215,7 @@ namespace Ryujinx.Graphics.Graphics3d GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat); - GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); + GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD); Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image); @@ -264,7 +269,8 @@ namespace Ryujinx.Graphics.Graphics3d GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat); - GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); + // TODO: Support non 2D? + GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD); Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image); } @@ -600,7 +606,7 @@ namespace Ryujinx.Graphics.Graphics3d } Gpu.Renderer.Texture.Bind(Key, Index, Image); - Gpu.Renderer.Texture.SetSampler(Sampler); + Gpu.Renderer.Texture.SetSampler(Image, Sampler); } } diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs index 026b0cd1..91346464 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs @@ -2,112 +2,115 @@ namespace Ryujinx.Graphics.Graphics3d { enum NvGpuEngine3dReg { - FrameBufferNAddress = 0x200, - FrameBufferNWidth = 0x202, - FrameBufferNHeight = 0x203, - FrameBufferNFormat = 0x204, - FrameBufferNBlockDim = 0x205, - ViewportNScaleX = 0x280, - ViewportNScaleY = 0x281, - ViewportNScaleZ = 0x282, - ViewportNTranslateX = 0x283, - ViewportNTranslateY = 0x284, - ViewportNTranslateZ = 0x285, - ViewportNHoriz = 0x300, - ViewportNVert = 0x301, - DepthRangeNNear = 0x302, - DepthRangeNFar = 0x303, - VertexArrayFirst = 0x35d, - VertexArrayCount = 0x35e, - ClearNColor = 0x360, - ClearDepth = 0x364, - ClearStencil = 0x368, - ScissorEnable = 0x380, - ScissorHorizontal = 0x381, - ScissorVertical = 0x382, - StencilBackFuncRef = 0x3d5, - StencilBackMask = 0x3d6, - StencilBackFuncMask = 0x3d7, - ColorMaskCommon = 0x3e4, - RTSeparateFragData = 0x3eb, - ZetaAddress = 0x3f8, - ZetaFormat = 0x3fa, - ZetaBlockDimensions = 0x3fb, - ZetaLayerStride = 0x3fc, - VertexAttribNFormat = 0x458, - RTControl = 0x487, - ZetaHoriz = 0x48a, - ZetaVert = 0x48b, - ZetaArrayMode = 0x48c, - LinkedTsc = 0x48d, - DepthTestEnable = 0x4b3, - BlendIndependent = 0x4b9, - DepthWriteEnable = 0x4ba, - DepthTestFunction = 0x4c3, - BlendSeparateAlpha = 0x4cf, - BlendEquationRgb = 0x4d0, - BlendFuncSrcRgb = 0x4d1, - BlendFuncDstRgb = 0x4d2, - BlendEquationAlpha = 0x4d3, - BlendFuncSrcAlpha = 0x4d4, - BlendFuncDstAlpha = 0x4d6, - BlendEnable = 0x4d7, - IBlendNEnable = 0x4d8, - StencilEnable = 0x4e0, - StencilFrontOpFail = 0x4e1, - StencilFrontOpZFail = 0x4e2, - StencilFrontOpZPass = 0x4e3, - StencilFrontFuncFunc = 0x4e4, - StencilFrontFuncRef = 0x4e5, - StencilFrontFuncMask = 0x4e6, - StencilFrontMask = 0x4e7, - ScreenYControl = 0x4eb, - VertexArrayElemBase = 0x50d, - VertexArrayInstBase = 0x50e, - ZetaEnable = 0x54e, - TexHeaderPoolOffset = 0x55d, - TexSamplerPoolOffset = 0x557, - StencilTwoSideEnable = 0x565, - StencilBackOpFail = 0x566, - StencilBackOpZFail = 0x567, - StencilBackOpZPass = 0x568, - StencilBackFuncFunc = 0x569, - FrameBufferSrgb = 0x56e, - ShaderAddress = 0x582, - VertexBeginGl = 0x586, - PrimRestartEnable = 0x591, - PrimRestartIndex = 0x592, - IndexArrayAddress = 0x5f2, - IndexArrayEndAddr = 0x5f4, - IndexArrayFormat = 0x5f6, - IndexBatchFirst = 0x5f7, - IndexBatchCount = 0x5f8, - VertexArrayNInstance = 0x620, - CullFaceEnable = 0x646, - FrontFace = 0x647, - CullFace = 0x648, - ColorMaskN = 0x680, - QueryAddress = 0x6c0, - QuerySequence = 0x6c2, - QueryControl = 0x6c3, - VertexArrayNControl = 0x700, - VertexArrayNAddress = 0x701, - VertexArrayNDivisor = 0x703, - IBlendNSeparateAlpha = 0x780, - IBlendNEquationRgb = 0x781, - IBlendNFuncSrcRgb = 0x782, - IBlendNFuncDstRgb = 0x783, - IBlendNEquationAlpha = 0x784, - IBlendNFuncSrcAlpha = 0x785, - IBlendNFuncDstAlpha = 0x786, - VertexArrayNEndAddr = 0x7c0, - ShaderNControl = 0x800, - ShaderNOffset = 0x801, - ShaderNMaxGprs = 0x803, - ShaderNType = 0x804, - ConstBufferSize = 0x8e0, - ConstBufferAddress = 0x8e1, - ConstBufferOffset = 0x8e3, - TextureCbIndex = 0x982 + FrameBufferNAddress = 0x200, + FrameBufferNWidth = 0x202, + FrameBufferNHeight = 0x203, + FrameBufferNFormat = 0x204, + FrameBufferNBlockDim = 0x205, + FrameBufferNArrayMode = 0x206, + FrameBufferNLayerStride = 0x207, + FrameBufferNBaseLayer = 0x208, + ViewportNScaleX = 0x280, + ViewportNScaleY = 0x281, + ViewportNScaleZ = 0x282, + ViewportNTranslateX = 0x283, + ViewportNTranslateY = 0x284, + ViewportNTranslateZ = 0x285, + ViewportNHoriz = 0x300, + ViewportNVert = 0x301, + DepthRangeNNear = 0x302, + DepthRangeNFar = 0x303, + VertexArrayFirst = 0x35d, + VertexArrayCount = 0x35e, + ClearNColor = 0x360, + ClearDepth = 0x364, + ClearStencil = 0x368, + ScissorEnable = 0x380, + ScissorHorizontal = 0x381, + ScissorVertical = 0x382, + StencilBackFuncRef = 0x3d5, + StencilBackMask = 0x3d6, + StencilBackFuncMask = 0x3d7, + ColorMaskCommon = 0x3e4, + RTSeparateFragData = 0x3eb, + ZetaAddress = 0x3f8, + ZetaFormat = 0x3fa, + ZetaBlockDimensions = 0x3fb, + ZetaLayerStride = 0x3fc, + VertexAttribNFormat = 0x458, + RTControl = 0x487, + ZetaHoriz = 0x48a, + ZetaVert = 0x48b, + ZetaArrayMode = 0x48c, + LinkedTsc = 0x48d, + DepthTestEnable = 0x4b3, + BlendIndependent = 0x4b9, + DepthWriteEnable = 0x4ba, + DepthTestFunction = 0x4c3, + BlendSeparateAlpha = 0x4cf, + BlendEquationRgb = 0x4d0, + BlendFuncSrcRgb = 0x4d1, + BlendFuncDstRgb = 0x4d2, + BlendEquationAlpha = 0x4d3, + BlendFuncSrcAlpha = 0x4d4, + BlendFuncDstAlpha = 0x4d6, + BlendEnable = 0x4d7, + IBlendNEnable = 0x4d8, + StencilEnable = 0x4e0, + StencilFrontOpFail = 0x4e1, + StencilFrontOpZFail = 0x4e2, + StencilFrontOpZPass = 0x4e3, + StencilFrontFuncFunc = 0x4e4, + StencilFrontFuncRef = 0x4e5, + StencilFrontFuncMask = 0x4e6, + StencilFrontMask = 0x4e7, + ScreenYControl = 0x4eb, + VertexArrayElemBase = 0x50d, + VertexArrayInstBase = 0x50e, + ZetaEnable = 0x54e, + TexHeaderPoolOffset = 0x55d, + TexSamplerPoolOffset = 0x557, + StencilTwoSideEnable = 0x565, + StencilBackOpFail = 0x566, + StencilBackOpZFail = 0x567, + StencilBackOpZPass = 0x568, + StencilBackFuncFunc = 0x569, + FrameBufferSrgb = 0x56e, + ShaderAddress = 0x582, + VertexBeginGl = 0x586, + PrimRestartEnable = 0x591, + PrimRestartIndex = 0x592, + IndexArrayAddress = 0x5f2, + IndexArrayEndAddr = 0x5f4, + IndexArrayFormat = 0x5f6, + IndexBatchFirst = 0x5f7, + IndexBatchCount = 0x5f8, + VertexArrayNInstance = 0x620, + CullFaceEnable = 0x646, + FrontFace = 0x647, + CullFace = 0x648, + ColorMaskN = 0x680, + QueryAddress = 0x6c0, + QuerySequence = 0x6c2, + QueryControl = 0x6c3, + VertexArrayNControl = 0x700, + VertexArrayNAddress = 0x701, + VertexArrayNDivisor = 0x703, + IBlendNSeparateAlpha = 0x780, + IBlendNEquationRgb = 0x781, + IBlendNFuncSrcRgb = 0x782, + IBlendNFuncDstRgb = 0x783, + IBlendNEquationAlpha = 0x784, + IBlendNFuncSrcAlpha = 0x785, + IBlendNFuncDstAlpha = 0x786, + VertexArrayNEndAddr = 0x7c0, + ShaderNControl = 0x800, + ShaderNOffset = 0x801, + ShaderNMaxGprs = 0x803, + ShaderNType = 0x804, + ConstBufferSize = 0x8e0, + ConstBufferAddress = 0x8e1, + ConstBufferOffset = 0x8e3, + TextureCbIndex = 0x982 } }
\ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs index d89059c0..2f1df3d3 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; using System.Collections.Generic; @@ -125,29 +126,37 @@ namespace Ryujinx.Graphics.Graphics3d if (SrcLinear) { - SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp); + SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY); } else { - SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight); + SrcSwizzle = new BlockLinearSwizzle( + SrcSizeX, + SrcSizeY, 1, + SrcBlockHeight, 1, + SrcCpp); } ISwizzle DstSwizzle; if (DstLinear) { - DstSwizzle = new LinearSwizzle(DstPitch, DstCpp); + DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY); } else { - DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight); + DstSwizzle = new BlockLinearSwizzle( + DstSizeX, + DstSizeY, 1, + DstBlockHeight, 1, + DstCpp); } for (int Y = 0; Y < YCount; Y++) for (int X = 0; X < XCount; X++) { - int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y); - int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y); + int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0); + int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0); long Src = SrcPA + (uint)SrcOffset; long Dst = DstPA + (uint)DstOffset; diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs index 68155255..62872ba1 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; using System.Collections.Generic; @@ -119,14 +120,17 @@ namespace Ryujinx.Graphics.Graphics3d } else { - BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(CopyWidth, 1, CopyGobBlockHeight); + BlockLinearSwizzle Swizzle = new BlockLinearSwizzle( + CopyWidth, + CopyHeight, 1, + CopyGobBlockHeight, 1, 1); int SrcOffset = 0; for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++) for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++) { - int DstOffset = Swizzle.GetSwizzleOffset(X, Y); + int DstOffset = Swizzle.GetSwizzleOffset(X, Y, 0); Vmm.WriteByte(CopyAddress + DstOffset, Buffer[SrcOffset++]); } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs index 1efa0255..00158dc1 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs @@ -72,6 +72,7 @@ namespace Ryujinx.Graphics.Texture if (BlockZ != 1 || Z != 1) { + // TODO: Support 3D textures? throw new ASTCDecoderException("3D compressed textures unsupported!"); } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs index 9451291e..1be06442 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs @@ -1,51 +1,178 @@ +using Ryujinx.Common; using System; namespace Ryujinx.Graphics.Texture { class BlockLinearSwizzle : ISwizzle { + private const int GobWidth = 64; + private const int GobHeight = 8; + + private const int GobSize = GobWidth * GobHeight; + + private int TexWidth; + private int TexHeight; + private int TexDepth; + private int TexGobBlockHeight; + private int TexGobBlockDepth; + private int TexBpp; + + private int BhMask; + private int BdMask; + private int BhShift; + private int BdShift; private int BppShift; - private int BhMask; private int XShift; - private int GobStride; - public BlockLinearSwizzle(int Width, int Bpp, int BlockHeight = 16) + private int RobSize; + private int SliceSize; + + private int BaseOffset; + + public BlockLinearSwizzle( + int Width, + int Height, + int Depth, + int GobBlockHeight, + int GobBlockDepth, + int Bpp) { - BhMask = (BlockHeight * 8) - 1; + TexWidth = Width; + TexHeight = Height; + TexDepth = Depth; + TexGobBlockHeight = GobBlockHeight; + TexGobBlockDepth = GobBlockDepth; + TexBpp = Bpp; + + BppShift = BitUtils.CountTrailingZeros32(Bpp); + + SetMipLevel(0); + } + + public void SetMipLevel(int Level) + { + BaseOffset = GetMipOffset(Level); + + int Width = Math.Max(1, TexWidth >> Level); + int Height = Math.Max(1, TexHeight >> Level); + int Depth = Math.Max(1, TexDepth >> Level); - BhShift = CountLsbZeros(BlockHeight * 8); - BppShift = CountLsbZeros(Bpp); + GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth); - int WidthInGobs = (int)MathF.Ceiling(Width * Bpp / 64f); + BhMask = GbSizes.Height - 1; + BdMask = GbSizes.Depth - 1; - GobStride = 512 * BlockHeight * WidthInGobs; + BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height); + BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth); - XShift = CountLsbZeros(512 * BlockHeight); + XShift = BitUtils.CountTrailingZeros32(GobSize * GbSizes.Height * GbSizes.Depth); + + RobAndSliceSizes GsSizes = GetRobAndSliceSizes(Width, Height, GbSizes); + + RobSize = GsSizes.RobSize; + SliceSize = GsSizes.SliceSize; + } + + public int GetImageSize(int MipsCount) + { + int Size = GetMipOffset(MipsCount); + + Size = (Size + 0x1fff) & ~0x1fff; + + return Size; } - private int CountLsbZeros(int Value) + public int GetMipOffset(int Level) { - int Count = 0; + int TotalSize = 0; - while (((Value >> Count) & 1) == 0) + for (int Index = 0; Index < Level; Index++) { - Count++; + int Width = Math.Max(1, TexWidth >> Index); + int Height = Math.Max(1, TexHeight >> Index); + int Depth = Math.Max(1, TexDepth >> Index); + + GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth); + + RobAndSliceSizes RsSizes = GetRobAndSliceSizes(Width, Height, GbSizes); + + TotalSize += BitUtils.DivRoundUp(Depth, GbSizes.Depth) * RsSizes.SliceSize; } - return Count; + return TotalSize; } - public int GetSwizzleOffset(int X, int Y) + private struct GobBlockSizes + { + public int Height; + public int Depth; + + public GobBlockSizes(int GobBlockHeight, int GobBlockDepth) + { + this.Height = GobBlockHeight; + this.Depth = GobBlockDepth; + } + } + + private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth) + { + int GobBlockHeight = TexGobBlockHeight; + int GobBlockDepth = TexGobBlockDepth; + + int Pow2Height = BitUtils.Pow2RoundUp(Height); + int Pow2Depth = BitUtils.Pow2RoundUp(Depth); + + while (GobBlockHeight * GobHeight > Pow2Height && GobBlockHeight > 1) + { + GobBlockHeight >>= 1; + } + + while (GobBlockDepth > Pow2Depth && GobBlockDepth > 1) + { + GobBlockDepth >>= 1; + } + + return new GobBlockSizes(GobBlockHeight, GobBlockDepth); + } + + private struct RobAndSliceSizes + { + public int RobSize; + public int SliceSize; + + public RobAndSliceSizes(int RobSize, int SliceSize) + { + this.RobSize = RobSize; + this.SliceSize = SliceSize; + } + } + + private RobAndSliceSizes GetRobAndSliceSizes(int Width, int Height, GobBlockSizes GbSizes) + { + int WidthInGobs = BitUtils.DivRoundUp(Width * TexBpp, GobWidth); + + int RobSize = GobSize * GbSizes.Height * GbSizes.Depth * WidthInGobs; + + int SliceSize = BitUtils.DivRoundUp(Height, GbSizes.Height * GobHeight) * RobSize; + + return new RobAndSliceSizes(RobSize, SliceSize); + } + + public int GetSwizzleOffset(int X, int Y, int Z) { X <<= BppShift; - int Position = (Y >> BhShift) * GobStride; + int YH = Y / GobHeight; + + int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize; + + Position += (X / GobWidth) << XShift; - Position += (X >> 6) << XShift; + Position += (YH & BhMask) * GobSize; - Position += ((Y & BhMask) >> 3) << 9; + Position += ((Z & BdMask) * GobSize) << BhShift; Position += ((X & 0x3f) >> 5) << 8; Position += ((Y & 0x07) >> 1) << 6; @@ -53,7 +180,7 @@ namespace Ryujinx.Graphics.Texture Position += ((Y & 0x01) >> 0) << 4; Position += ((X & 0x0f) >> 0) << 0; - return Position; + return BaseOffset + Position; } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs index 583fc20c..2e0e8aed 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs @@ -2,6 +2,12 @@ namespace Ryujinx.Graphics.Texture { interface ISwizzle { - int GetSwizzleOffset(int X, int Y); + int GetSwizzleOffset(int X, int Y, int Z); + + void SetMipLevel(int Level); + + int GetMipOffset(int Level); + + int GetImageSize(int MipsCount); } }
\ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs index f958e1de..c4208935 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs @@ -1,4 +1,6 @@ using ChocolArm64.Memory; +using OpenTK.Graphics.OpenGL; +using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using System; @@ -23,14 +25,16 @@ namespace Ryujinx.Graphics.Texture public int BytesPerPixel { get; private set; } public int BlockWidth { get; private set; } public int BlockHeight { get; private set; } + public int BlockDepth { get; private set; } public TargetBuffer Target { get; private set; } - public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target) + public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target) { this.BytesPerPixel = BytesPerPixel; this.BlockWidth = BlockWidth; this.BlockHeight = BlockHeight; + this.BlockDepth = BlockDepth; this.Target = Target; } } @@ -92,52 +96,52 @@ namespace Ryujinx.Graphics.Texture private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable = new Dictionary<GalImageFormat, ImageDescriptor>() { - { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) }, - { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) }, - { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) }, - { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) }, - { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) }, - { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) }, - { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) }, - - { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) }, - { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) }, - { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) }, - { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) }, - { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) } + { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, 1, TargetBuffer.Color) }, + + { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.DepthStencil) }, + { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.DepthStencil) } }; public static GalImageFormat ConvertTexture( @@ -241,26 +245,37 @@ namespace Ryujinx.Graphics.Texture ImageDescriptor Desc = GetImageDescriptor(Image.Format); - (int Width, int Height) = GetImageSizeInBlocks(Image); + (int Width, int Height, int Depth) = GetImageSizeInBlocks(Image); int BytesPerPixel = Desc.BytesPerPixel; //Note: Each row of the texture needs to be aligned to 4 bytes. int Pitch = (Width * BytesPerPixel + 3) & ~3; - byte[] Data = new byte[Height * Pitch]; - for (int Y = 0; Y < Height; Y++) - { - int OutOffs = Y * Pitch; + int DataLayerSize = Height * Pitch * Depth; + byte[] Data = new byte[DataLayerSize * Image.LayerCount]; + + int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1; + int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel); - for (int X = 0; X < Width; X++) + for (int Layer = 0; Layer < Image.LayerCount; Layer++) + { + for (int Z = 0; Z < Depth; Z++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + for (int Y = 0; Y < Height; Y++) + { + int OutOffs = (DataLayerSize * Layer) + Y * Pitch + (Z * Width * Height * BytesPerPixel); + + for (int X = 0; X < Width; X++) + { + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); - CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel); + CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel); - OutOffs += BytesPerPixel; + OutOffs += BytesPerPixel; + } + } } } @@ -273,16 +288,17 @@ namespace Ryujinx.Graphics.Texture ImageDescriptor Desc = GetImageDescriptor(Image.Format); - (int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image); + (int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image); int BytesPerPixel = Desc.BytesPerPixel; int InOffs = 0; + for (int Z = 0; Z < Depth; Z++) for (int Y = 0; Y < Height; Y++) for (int X = 0; X < Width; X++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel); @@ -290,6 +306,7 @@ namespace Ryujinx.Graphics.Texture } } + // TODO: Support non 2D public static bool CopyTexture( NvGpuVmm Vmm, GalImage SrcImage, @@ -318,8 +335,8 @@ namespace Ryujinx.Graphics.Texture for (int Y = 0; Y < Height; Y++) for (int X = 0; X < Width; X++) { - long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y); - long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y); + long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0); + long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0); byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel); @@ -333,10 +350,41 @@ namespace Ryujinx.Graphics.Texture { ImageDescriptor Desc = GetImageDescriptor(Image.Format); + int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget); + + if (IsArray(Image.TextureTarget)) + ComponentCount--; + int Width = DivRoundUp(Image.Width, Desc.BlockWidth); int Height = DivRoundUp(Image.Height, Desc.BlockHeight); + int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth); + + switch (ComponentCount) + { + case 1: + return Desc.BytesPerPixel * Width * Image.LayerCount; + case 2: + return Desc.BytesPerPixel * Width * Height * Image.LayerCount; + case 3: + return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount; + default: + throw new InvalidOperationException($"Invalid component count: {ComponentCount}"); + } + } + + public static int GetGpuSize(GalImage Image, bool forcePitch = false) + { + return TextureHelper.GetSwizzle(Image).GetImageSize(Image.MaxMipmapLevel) * Image.LayerCount; + } + + public static int GetLayerOffset(GalImage Image, int MipLevel) + { + if (MipLevel <= 0) + { + MipLevel = 1; + } - return Desc.BytesPerPixel * Width * Height; + return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel); } public static int GetPitch(GalImageFormat Format, int Width) @@ -360,6 +408,11 @@ namespace Ryujinx.Graphics.Texture return GetImageDescriptor(Format).BlockHeight; } + public static int GetBlockDepth(GalImageFormat Format) + { + return GetImageDescriptor(Format).BlockDepth; + } + public static int GetAlignedWidth(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); @@ -378,12 +431,13 @@ namespace Ryujinx.Graphics.Texture return (Image.Width + AlignMask) & ~AlignMask; } - public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image) + public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); return (DivRoundUp(Image.Width, Desc.BlockWidth), - DivRoundUp(Image.Height, Desc.BlockHeight)); + DivRoundUp(Image.Height, Desc.BlockHeight), + DivRoundUp(Image.Depth, Desc.BlockDepth)); } public static int GetBytesPerPixel(GalImageFormat Format) @@ -443,5 +497,66 @@ namespace Ryujinx.Graphics.Texture default: throw new NotImplementedException(((int)Type).ToString()); } } + + public static TextureTarget GetTextureTarget(GalTextureTarget GalTextureTarget) + { + switch (GalTextureTarget) + { + case GalTextureTarget.OneD: + return TextureTarget.Texture1D; + case GalTextureTarget.TwoD: + case GalTextureTarget.TwoDNoMipMap: + return TextureTarget.Texture2D; + case GalTextureTarget.ThreeD: + return TextureTarget.Texture3D; + case GalTextureTarget.OneDArray: + return TextureTarget.Texture1DArray; + case GalTextureTarget.OneDBuffer: + return TextureTarget.TextureBuffer; + case GalTextureTarget.TwoDArray: + return TextureTarget.Texture2DArray; + case GalTextureTarget.CubeMap: + return TextureTarget.TextureCubeMap; + case GalTextureTarget.CubeArray: + return TextureTarget.TextureCubeMapArray; + default: + throw new NotSupportedException($"Texture target {GalTextureTarget} currently not supported!"); + } + } + + public static bool IsArray(GalTextureTarget TextureTarget) + { + switch (TextureTarget) + { + case GalTextureTarget.OneDArray: + case GalTextureTarget.TwoDArray: + case GalTextureTarget.CubeArray: + return true; + default: + return false; + } + } + + public static int GetCoordsCountTextureTarget(GalTextureTarget TextureTarget) + { + switch (TextureTarget) + { + case GalTextureTarget.OneD: + return 1; + case GalTextureTarget.OneDArray: + case GalTextureTarget.OneDBuffer: + case GalTextureTarget.TwoD: + case GalTextureTarget.TwoDNoMipMap: + return 2; + case GalTextureTarget.ThreeD: + case GalTextureTarget.TwoDArray: + case GalTextureTarget.CubeMap: + return 3; + case GalTextureTarget.CubeArray: + return 4; + default: + throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet."); + } + } } } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs index ef468e27..e6509baa 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs @@ -1,3 +1,5 @@ +using System; + namespace Ryujinx.Graphics.Texture { class LinearSwizzle : ISwizzle @@ -5,15 +7,39 @@ namespace Ryujinx.Graphics.Texture private int Pitch; private int Bpp; - public LinearSwizzle(int Pitch, int Bpp) + private int SliceSize; + + public LinearSwizzle(int Pitch, int Bpp, int Width, int Height) { - this.Pitch = Pitch; - this.Bpp = Bpp; + this.Pitch = Pitch; + this.Bpp = Bpp; + SliceSize = Width * Height * Bpp; + } + + public void SetMipLevel(int Level) + { + throw new NotImplementedException(); + } + + public int GetMipOffset(int Level) + { + if (Level == 1) + return SliceSize; + throw new NotImplementedException(); + } + + public int GetImageSize(int MipsCount) + { + int Size = GetMipOffset(MipsCount); + + Size = (Size + 0x1fff) & ~0x1fff; + + return Size; } - public int GetSwizzleOffset(int X, int Y) + public int GetSwizzleOffset(int X, int Y, int Z) { - return X * Bpp + Y * Pitch; + return Z * SliceSize + X * Bpp + Y * Pitch; } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs index 1f2d625e..a2ce86f5 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs @@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Texture GalImageFormat Format = GetImageFormat(Tic); + GalTextureTarget TextureTarget = (GalTextureTarget)((Tic[4] >> 23) & 0xF); + GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7); GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7); GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7); @@ -19,6 +21,8 @@ namespace Ryujinx.Graphics.Texture TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); + int MaxMipmapLevel = (Tic[3] >> 28) & 0xF + 1; + GalMemoryLayout Layout; if (Swizzle == TextureSwizzle.BlockLinear || @@ -31,22 +35,61 @@ namespace Ryujinx.Graphics.Texture Layout = GalMemoryLayout.Pitch; } - int BlockHeightLog2 = (Tic[3] >> 3) & 7; - int TileWidthLog2 = (Tic[3] >> 10) & 7; + 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; - int BlockHeight = 1 << BlockHeightLog2; - int TileWidth = 1 << TileWidthLog2; + // TODO: check this + if (ImageUtils.IsArray(TextureTarget)) + { + LayoutCount = Depth; + Depth = 1; + } + + if (TextureTarget == GalTextureTarget.OneD) + { + Height = 1; + } - int Width = (Tic[4] & 0xffff) + 1; - int Height = (Tic[5] & 0xffff) + 1; + 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; + } GalImage Image = new GalImage( Width, Height, + Depth, + LayoutCount, TileWidth, - BlockHeight, + GobBlockHeight, + GobBlockDepth, Layout, Format, + TextureTarget, + MaxMipmapLevel, XSource, YSource, ZSource, @@ -68,6 +111,10 @@ namespace Ryujinx.Graphics.Texture GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7); GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7); + bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1; + + DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7); + GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3); GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3); GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3); @@ -85,7 +132,9 @@ namespace Ryujinx.Graphics.Texture MinFilter, MagFilter, MipFilter, - BorderColor); + BorderColor, + DepthCompare, + DepthCompareFunc); } private static GalImageFormat GetImageFormat(int[] Tic) diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs index 6ac91d8b..33ccb0aa 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; @@ -9,9 +10,13 @@ namespace Ryujinx.Graphics.Texture public static ISwizzle GetSwizzle(GalImage Image) { int BlockWidth = ImageUtils.GetBlockWidth (Image.Format); + int BlockHeight = ImageUtils.GetBlockHeight (Image.Format); + int BlockDepth = ImageUtils.GetBlockDepth (Image.Format); int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format); - int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth; + int Width = BitUtils.DivRoundUp(Image.Width, BlockWidth); + int Height = BitUtils.DivRoundUp(Image.Height, BlockHeight); + int Depth = BitUtils.DivRoundUp(Image.Depth, BlockDepth); if (Image.Layout == GalMemoryLayout.BlockLinear) { @@ -19,11 +24,17 @@ namespace Ryujinx.Graphics.Texture Width = (Width + AlignMask) & ~AlignMask; - return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight); + return new BlockLinearSwizzle( + Width, + Height, + Depth, + Image.GobBlockHeight, + Image.GobBlockDepth, + BytesPerPixel); } else { - return new LinearSwizzle(Image.Pitch, BytesPerPixel); + return new LinearSwizzle(Image.Pitch, BytesPerPixel, Width, Height); } } |
