2018-09-18 06:30:35 +02:00
|
|
|
|
using ChocolArm64.Memory;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
|
using Ryujinx.Common;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
using Ryujinx.Graphics.Gal;
|
|
|
|
|
using Ryujinx.Graphics.Memory;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Texture
|
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
public static class ImageUtils
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
[Flags]
|
|
|
|
|
private enum TargetBuffer
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
Color = 1 << 0,
|
|
|
|
|
Depth = 1 << 1,
|
|
|
|
|
Stencil = 1 << 2,
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
2018-09-18 06:30:35 +02:00
|
|
|
|
DepthStencil = Depth | Stencil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private struct ImageDescriptor
|
|
|
|
|
{
|
|
|
|
|
public int BytesPerPixel { get; private set; }
|
|
|
|
|
public int BlockWidth { get; private set; }
|
|
|
|
|
public int BlockHeight { get; private set; }
|
2019-02-28 02:12:24 +01:00
|
|
|
|
public int BlockDepth { get; private set; }
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
2018-09-18 06:30:35 +02:00
|
|
|
|
public TargetBuffer Target { get; private set; }
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target)
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
this.BytesPerPixel = BytesPerPixel;
|
|
|
|
|
this.BlockWidth = BlockWidth;
|
|
|
|
|
this.BlockHeight = BlockHeight;
|
2019-02-28 02:12:24 +01:00
|
|
|
|
this.BlockDepth = BlockDepth;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
this.Target = Target;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
|
private const GalImageFormat Snorm = GalImageFormat.Snorm;
|
|
|
|
|
private const GalImageFormat Unorm = GalImageFormat.Unorm;
|
|
|
|
|
private const GalImageFormat Sint = GalImageFormat.Sint;
|
|
|
|
|
private const GalImageFormat Uint = GalImageFormat.Uint;
|
|
|
|
|
private const GalImageFormat Float = GalImageFormat.Float;
|
|
|
|
|
private const GalImageFormat Srgb = GalImageFormat.Srgb;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
|
|
|
|
private static readonly Dictionary<GalTextureFormat, GalImageFormat> s_TextureTable =
|
|
|
|
|
new Dictionary<GalTextureFormat, GalImageFormat>()
|
2018-10-17 23:02:23 +02:00
|
|
|
|
{
|
|
|
|
|
{ GalTextureFormat.RGBA32, GalImageFormat.RGBA32 | Sint | Uint | Float },
|
|
|
|
|
{ GalTextureFormat.RGBA16, GalImageFormat.RGBA16 | Snorm | Unorm | Sint | Uint | Float },
|
|
|
|
|
{ GalTextureFormat.RG32, GalImageFormat.RG32 | Sint | Uint | Float },
|
|
|
|
|
{ GalTextureFormat.RGBA8, GalImageFormat.RGBA8 | Snorm | Unorm | Sint | Uint | Srgb },
|
|
|
|
|
{ GalTextureFormat.RGB10A2, GalImageFormat.RGB10A2 | Snorm | Unorm | Sint | Uint },
|
|
|
|
|
{ GalTextureFormat.RG8, GalImageFormat.RG8 | Snorm | Unorm | Sint | Uint },
|
|
|
|
|
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float },
|
|
|
|
|
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
2018-12-27 12:05:54 +01:00
|
|
|
|
{ GalTextureFormat.RG16, GalImageFormat.RG16 | Snorm | Unorm | Sint | Float },
|
2018-10-17 23:02:23 +02:00
|
|
|
|
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Float },
|
|
|
|
|
{ GalTextureFormat.RGBA4, GalImageFormat.RGBA4 | Unorm },
|
|
|
|
|
{ GalTextureFormat.RGB5A1, GalImageFormat.RGB5A1 | Unorm },
|
|
|
|
|
{ GalTextureFormat.RGB565, GalImageFormat.RGB565 | Unorm },
|
|
|
|
|
{ GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float },
|
|
|
|
|
{ GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint },
|
|
|
|
|
{ GalTextureFormat.D32F, GalImageFormat.D32 | Float },
|
2018-11-09 19:41:40 +01:00
|
|
|
|
{ GalTextureFormat.D32FX24S8, GalImageFormat.D32S8 | Float },
|
2018-10-17 23:02:23 +02:00
|
|
|
|
{ GalTextureFormat.D16, GalImageFormat.D16 | Unorm },
|
|
|
|
|
|
|
|
|
|
//Compressed formats
|
|
|
|
|
{ GalTextureFormat.BptcSfloat, GalImageFormat.BptcSfloat | Float },
|
|
|
|
|
{ GalTextureFormat.BptcUfloat, GalImageFormat.BptcUfloat | Float },
|
|
|
|
|
{ GalTextureFormat.BptcUnorm, GalImageFormat.BptcUnorm | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.BC1, GalImageFormat.BC1 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
|
|
|
|
|
{ GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
|
|
|
|
|
{ GalTextureFormat.Astc2D4x4, GalImageFormat.Astc2D4x4 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D5x5, GalImageFormat.Astc2D5x5 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D6x6, GalImageFormat.Astc2D6x6 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D8x8, GalImageFormat.Astc2D8x8 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D10x10, GalImageFormat.Astc2D10x10 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D12x12, GalImageFormat.Astc2D12x12 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D5x4, GalImageFormat.Astc2D5x4 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D6x5, GalImageFormat.Astc2D6x5 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D8x6, GalImageFormat.Astc2D8x6 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D10x8, GalImageFormat.Astc2D10x8 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D12x10, GalImageFormat.Astc2D12x10 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D8x5, GalImageFormat.Astc2D8x5 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D10x5, GalImageFormat.Astc2D10x5 | Unorm | Srgb },
|
|
|
|
|
{ GalTextureFormat.Astc2D10x6, GalImageFormat.Astc2D10x6 | Unorm | Srgb }
|
|
|
|
|
};
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
|
|
|
|
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
|
|
|
|
new Dictionary<GalImageFormat, ImageDescriptor>()
|
2018-09-18 06:30:35 +02:00
|
|
|
|
{
|
2019-02-28 02:12:24 +01:00
|
|
|
|
{ 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) }
|
2018-09-18 06:30:35 +02:00
|
|
|
|
};
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
|
|
|
|
public static GalImageFormat ConvertTexture(
|
|
|
|
|
GalTextureFormat Format,
|
2018-09-18 06:30:35 +02:00
|
|
|
|
GalTextureType RType,
|
|
|
|
|
GalTextureType GType,
|
|
|
|
|
GalTextureType BType,
|
2018-10-17 23:02:23 +02:00
|
|
|
|
GalTextureType AType,
|
|
|
|
|
bool ConvSrgb)
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-11-21 07:27:33 +01:00
|
|
|
|
if (!s_TextureTable.TryGetValue(Format, out GalImageFormat ImageFormat))
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-11-21 07:27:33 +01:00
|
|
|
|
throw new NotImplementedException($"Format 0x{((int)Format):x} not implemented!");
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-21 07:27:33 +01:00
|
|
|
|
if (!HasDepth(ImageFormat) && (RType != GType || RType != BType || RType != AType))
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-11-21 07:27:33 +01:00
|
|
|
|
throw new NotImplementedException($"Per component types are not implemented!");
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
|
GalImageFormat FormatType = ConvSrgb ? Srgb : GetFormatType(RType);
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
|
GalImageFormat CombinedFormat = (ImageFormat & GalImageFormat.FormatMask) | FormatType;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
|
if (!ImageFormat.HasFlag(FormatType))
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-10-17 23:02:23 +02:00
|
|
|
|
throw new NotImplementedException($"Format \"{CombinedFormat}\" not implemented!");
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
2018-10-17 23:02:23 +02:00
|
|
|
|
|
|
|
|
|
return CombinedFormat;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static GalImageFormat ConvertSurface(GalSurfaceFormat Format)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
2018-10-17 23:02:23 +02:00
|
|
|
|
case GalSurfaceFormat.RGBA32Float: return GalImageFormat.RGBA32 | Float;
|
|
|
|
|
case GalSurfaceFormat.RGBA32Uint: return GalImageFormat.RGBA32 | Uint;
|
|
|
|
|
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.RGBA16 | Float;
|
2018-11-23 15:21:45 +01:00
|
|
|
|
case GalSurfaceFormat.RGBA16Unorm: return GalImageFormat.RGBA16 | Unorm;
|
2018-10-17 23:02:23 +02:00
|
|
|
|
case GalSurfaceFormat.RG32Float: return GalImageFormat.RG32 | Float;
|
|
|
|
|
case GalSurfaceFormat.RG32Sint: return GalImageFormat.RG32 | Sint;
|
|
|
|
|
case GalSurfaceFormat.RG32Uint: return GalImageFormat.RG32 | Uint;
|
|
|
|
|
case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.BGRA8 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.BGRA8 | Srgb;
|
|
|
|
|
case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.RGB10A2 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.RGBA8 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.RGBA8 | Srgb;
|
|
|
|
|
case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.RGBA8 | Snorm;
|
|
|
|
|
case GalSurfaceFormat.RG16Snorm: return GalImageFormat.RG16 | Snorm;
|
|
|
|
|
case GalSurfaceFormat.RG16Unorm: return GalImageFormat.RG16 | Unorm;
|
2018-12-27 12:05:54 +01:00
|
|
|
|
case GalSurfaceFormat.RG16Sint: return GalImageFormat.RG16 | Sint;
|
2018-10-17 23:02:23 +02:00
|
|
|
|
case GalSurfaceFormat.RG16Float: return GalImageFormat.RG16 | Float;
|
|
|
|
|
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float;
|
|
|
|
|
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float;
|
|
|
|
|
case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint;
|
|
|
|
|
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.RG8 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.RG8 | Snorm;
|
|
|
|
|
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float;
|
|
|
|
|
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint;
|
|
|
|
|
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint;
|
|
|
|
|
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.RGB565 | Unorm;
|
|
|
|
|
case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.BGR5A1 | Unorm;
|
2018-11-17 05:01:31 +01:00
|
|
|
|
case GalSurfaceFormat.RGBX8Unorm: return GalImageFormat.RGBX8 | Unorm;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new NotImplementedException(Format.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static GalImageFormat ConvertZeta(GalZetaFormat Format)
|
|
|
|
|
{
|
|
|
|
|
switch (Format)
|
|
|
|
|
{
|
2018-10-17 23:02:23 +02:00
|
|
|
|
case GalZetaFormat.D32Float: return GalImageFormat.D32 | Float;
|
|
|
|
|
case GalZetaFormat.S8D24Unorm: return GalImageFormat.D24S8 | Unorm;
|
|
|
|
|
case GalZetaFormat.D16Unorm: return GalImageFormat.D16 | Unorm;
|
2018-11-17 05:01:31 +01:00
|
|
|
|
case GalZetaFormat.D24X8Unorm: return GalImageFormat.D24 | Unorm;
|
2018-10-17 23:02:23 +02:00
|
|
|
|
case GalZetaFormat.D24S8Unorm: return GalImageFormat.D24S8 | Unorm;
|
|
|
|
|
case GalZetaFormat.D32S8X24Float: return GalImageFormat.D32S8 | Float;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new NotImplementedException(Format.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-31 02:43:02 +01:00
|
|
|
|
public static byte[] ReadTexture(IMemory Memory, GalImage Image, long Position)
|
2018-09-18 06:30:35 +02:00
|
|
|
|
{
|
2018-10-31 02:43:02 +01:00
|
|
|
|
MemoryManager CpuMemory;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
|
|
|
|
if (Memory is NvGpuVmm Vmm)
|
|
|
|
|
{
|
|
|
|
|
CpuMemory = Vmm.Memory;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-10-31 02:43:02 +01:00
|
|
|
|
CpuMemory = (MemoryManager)Memory;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
|
|
|
|
|
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
(int Width, int Height, int Depth) = GetImageSizeInBlocks(Image);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
|
|
|
|
int BytesPerPixel = Desc.BytesPerPixel;
|
|
|
|
|
|
2018-10-14 04:54:14 +02:00
|
|
|
|
//Note: Each row of the texture needs to be aligned to 4 bytes.
|
|
|
|
|
int Pitch = (Width * BytesPerPixel + 3) & ~3;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
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);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
for (int Layer = 0; Layer < Image.LayerCount; Layer++)
|
|
|
|
|
{
|
|
|
|
|
for (int Z = 0; Z < Depth; Z++)
|
2018-10-14 04:54:14 +02:00
|
|
|
|
{
|
2019-02-28 02:12:24 +01:00
|
|
|
|
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);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel);
|
2018-10-14 04:54:14 +02:00
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
OutOffs += BytesPerPixel;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-14 04:54:14 +02:00
|
|
|
|
}
|
2018-09-18 06:30:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data)
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
|
|
|
|
|
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
(int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
|
|
|
|
int BytesPerPixel = Desc.BytesPerPixel;
|
|
|
|
|
|
|
|
|
|
int InOffs = 0;
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
for (int Z = 0; Z < Depth; Z++)
|
2018-09-18 06:30:35 +02:00
|
|
|
|
for (int Y = 0; Y < Height; Y++)
|
|
|
|
|
for (int X = 0; X < Width; X++)
|
|
|
|
|
{
|
2019-02-28 02:12:24 +01:00
|
|
|
|
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
|
|
|
|
Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
InOffs += BytesPerPixel;
|
|
|
|
|
}
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
// TODO: Support non 2D
|
2018-11-17 05:01:31 +01:00
|
|
|
|
public static bool CopyTexture(
|
|
|
|
|
NvGpuVmm Vmm,
|
|
|
|
|
GalImage SrcImage,
|
|
|
|
|
GalImage DstImage,
|
|
|
|
|
long SrcAddress,
|
|
|
|
|
long DstAddress,
|
|
|
|
|
int SrcX,
|
|
|
|
|
int SrcY,
|
|
|
|
|
int DstX,
|
|
|
|
|
int DstY,
|
|
|
|
|
int Width,
|
|
|
|
|
int Height)
|
|
|
|
|
{
|
|
|
|
|
ISwizzle SrcSwizzle = TextureHelper.GetSwizzle(SrcImage);
|
|
|
|
|
ISwizzle DstSwizzle = TextureHelper.GetSwizzle(DstImage);
|
|
|
|
|
|
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(SrcImage.Format);
|
|
|
|
|
|
|
|
|
|
if (GetImageDescriptor(DstImage.Format).BytesPerPixel != Desc.BytesPerPixel)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int BytesPerPixel = Desc.BytesPerPixel;
|
|
|
|
|
|
|
|
|
|
for (int Y = 0; Y < Height; Y++)
|
|
|
|
|
for (int X = 0; X < Width; X++)
|
|
|
|
|
{
|
2019-02-28 02:12:24 +01:00
|
|
|
|
long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0);
|
|
|
|
|
long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0);
|
2018-11-17 05:01:31 +01:00
|
|
|
|
|
|
|
|
|
byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
Vmm.WriteBytes(DstAddress + DstOffset, Texel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-08 19:51:50 +02:00
|
|
|
|
public static int GetSize(GalImage Image)
|
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget);
|
|
|
|
|
|
|
|
|
|
if (IsArray(Image.TextureTarget))
|
|
|
|
|
ComponentCount--;
|
|
|
|
|
|
2018-09-18 06:30:35 +02:00
|
|
|
|
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
|
|
|
|
|
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
|
2019-02-28 02:12:24 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
2018-09-18 06:30:35 +02:00
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel);
|
2018-09-18 06:30:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int GetPitch(GalImageFormat Format, int Width)
|
|
|
|
|
{
|
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Format);
|
|
|
|
|
|
2018-10-13 03:37:01 +02:00
|
|
|
|
int Pitch = Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
|
|
|
|
|
|
|
|
|
Pitch = (Pitch + 0x1f) & ~0x1f;
|
|
|
|
|
|
|
|
|
|
return Pitch;
|
2018-09-18 06:30:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int GetBlockWidth(GalImageFormat Format)
|
|
|
|
|
{
|
|
|
|
|
return GetImageDescriptor(Format).BlockWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int GetBlockHeight(GalImageFormat Format)
|
|
|
|
|
{
|
|
|
|
|
return GetImageDescriptor(Format).BlockHeight;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
public static int GetBlockDepth(GalImageFormat Format)
|
|
|
|
|
{
|
|
|
|
|
return GetImageDescriptor(Format).BlockDepth;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 06:30:35 +02:00
|
|
|
|
public static int GetAlignedWidth(GalImage Image)
|
|
|
|
|
{
|
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
|
|
|
|
|
|
|
|
|
int AlignMask;
|
|
|
|
|
|
|
|
|
|
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
AlignMask = Image.TileWidth * (64 / Desc.BytesPerPixel) - 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AlignMask = (32 / Desc.BytesPerPixel) - 1;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 06:30:35 +02:00
|
|
|
|
return (Image.Width + AlignMask) & ~AlignMask;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-28 02:12:24 +01:00
|
|
|
|
public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image)
|
2018-09-18 06:30:35 +02:00
|
|
|
|
{
|
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
|
|
|
|
|
|
|
|
|
return (DivRoundUp(Image.Width, Desc.BlockWidth),
|
2019-02-28 02:12:24 +01:00
|
|
|
|
DivRoundUp(Image.Height, Desc.BlockHeight),
|
|
|
|
|
DivRoundUp(Image.Depth, Desc.BlockDepth));
|
2018-09-18 06:30:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int GetBytesPerPixel(GalImageFormat Format)
|
|
|
|
|
{
|
|
|
|
|
return GetImageDescriptor(Format).BytesPerPixel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int DivRoundUp(int LHS, int RHS)
|
|
|
|
|
{
|
|
|
|
|
return (LHS + (RHS - 1)) / RHS;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool HasColor(GalImageFormat Format)
|
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
return (GetImageDescriptor(Format).Target & TargetBuffer.Color) != 0;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool HasDepth(GalImageFormat Format)
|
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
return (GetImageDescriptor(Format).Target & TargetBuffer.Depth) != 0;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool HasStencil(GalImageFormat Format)
|
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
return (GetImageDescriptor(Format).Target & TargetBuffer.Stencil) != 0;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool IsCompressed(GalImageFormat Format)
|
|
|
|
|
{
|
2018-09-18 06:30:35 +02:00
|
|
|
|
ImageDescriptor Desc = GetImageDescriptor(Format);
|
|
|
|
|
|
|
|
|
|
return (Desc.BlockWidth | Desc.BlockHeight) != 1;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
|
|
|
|
{
|
2018-10-17 23:02:23 +02:00
|
|
|
|
GalImageFormat PixelFormat = Format & GalImageFormat.FormatMask;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
|
if (s_ImageTable.TryGetValue(PixelFormat, out ImageDescriptor Descriptor))
|
2018-09-08 19:51:50 +02:00
|
|
|
|
{
|
|
|
|
|
return Descriptor;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 23:02:23 +02:00
|
|
|
|
throw new NotImplementedException($"Format \"{PixelFormat}\" not implemented!");
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static GalImageFormat GetFormatType(GalTextureType Type)
|
|
|
|
|
{
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
case GalTextureType.Snorm: return Snorm;
|
|
|
|
|
case GalTextureType.Unorm: return Unorm;
|
|
|
|
|
case GalTextureType.Sint: return Sint;
|
|
|
|
|
case GalTextureType.Uint: return Uint;
|
2018-10-17 23:02:23 +02:00
|
|
|
|
case GalTextureType.Float: return Float;
|
2018-09-08 19:51:50 +02:00
|
|
|
|
|
|
|
|
|
default: throw new NotImplementedException(((int)Type).ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-28 02:12:24 +01:00
|
|
|
|
|
|
|
|
|
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.");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-08 19:51:50 +02:00
|
|
|
|
}
|
2018-11-09 19:41:40 +01:00
|
|
|
|
}
|