Allow "reinterpretation" of framebuffer/zeta formats (#418)

* (Re)Implement format reinterpretation, other changes

* Implement writeback to guest memory, some refactoring

* More refactoring, implement reinterpretation the old way again

* Clean up

* Some fixes on M2MF (old Dma engine), added partial support for P2MF, fix conditional ssy, add Z24S8 zeta format, other fixes

* nit: Formatting

* Address PR feedback
This commit is contained in:
gdkchan 2018-09-18 01:30:35 -03:00 committed by GitHub
parent bec95cacc1
commit d4187aaa9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 1594 additions and 1979 deletions

View file

@ -1,14 +1,9 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.Texture;
using System;
using Ryujinx.Graphics.Texture;
namespace Ryujinx.Graphics.Gal.OpenGL
{
class ImageHandler
{
private static int CopyBuffer = 0;
private static int CopyBufferSize = 0;
public GalImage Image { get; private set; }
public int Width => Image.Width;
@ -16,144 +11,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public GalImageFormat Format => Image.Format;
public PixelInternalFormat InternalFormat { get; private set; }
public PixelFormat PixelFormat { get; private set; }
public PixelType PixelType { get; private set; }
public int Handle { get; private set; }
private bool Initialized;
public ImageHandler()
{
Handle = GL.GenTexture();
}
public ImageHandler(int Handle, GalImage Image)
{
this.Handle = Handle;
this.Image = Image;
}
public void EnsureSetup(GalImage NewImage)
{
if (Width == NewImage.Width &&
Height == NewImage.Height &&
Format == NewImage.Format &&
Initialized)
{
return;
}
PixelInternalFormat InternalFmt;
PixelFormat PixelFormat;
PixelType PixelType;
if (ImageUtils.IsCompressed(NewImage.Format))
{
InternalFmt = (PixelInternalFormat)OGLEnumConverter.GetCompressedImageFormat(NewImage.Format);
PixelFormat = default(PixelFormat);
PixelType = default(PixelType);
}
else
{
(InternalFmt, PixelFormat, PixelType) = OGLEnumConverter.GetImageFormat(NewImage.Format);
}
GL.BindTexture(TextureTarget.Texture2D, Handle);
if (Initialized)
{
if (CopyBuffer == 0)
{
CopyBuffer = GL.GenBuffer();
}
int CurrentSize = Math.Max(ImageUtils.GetSize(NewImage),
ImageUtils.GetSize(Image));
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer);
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer);
if (CopyBufferSize < CurrentSize)
{
CopyBufferSize = CurrentSize;
GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
}
if (ImageUtils.IsCompressed(Image.Format))
{
GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, IntPtr.Zero);
}
else
{
GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
}
GL.DeleteTexture(Handle);
Handle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, Handle);
}
const int MinFilter = (int)TextureMinFilter.Linear;
const int MagFilter = (int)TextureMagFilter.Linear;
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
const int Level = 0;
const int Border = 0;
if (ImageUtils.IsCompressed(NewImage.Format))
{
Console.WriteLine("Hit");
GL.CompressedTexImage2D(
TextureTarget.Texture2D,
Level,
(InternalFormat)InternalFmt,
NewImage.Width,
NewImage.Height,
Border,
ImageUtils.GetSize(NewImage),
IntPtr.Zero);
}
else
{
GL.TexImage2D(
TextureTarget.Texture2D,
Level,
InternalFmt,
NewImage.Width,
NewImage.Height,
Border,
PixelFormat,
PixelType,
IntPtr.Zero);
}
if (Initialized)
{
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
}
Image = NewImage;
this.InternalFormat = InternalFmt;
this.PixelFormat = PixelFormat;
this.PixelType = PixelType;
Initialized = true;
}
public bool HasColor => ImageUtils.HasColor(Image.Format);
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
public ImageHandler(int Handle, GalImage Image)
{
this.Handle = Handle;
this.Image = Image;
}
}
}

View file

@ -22,9 +22,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
{
this.Value = Value;
this.DataSize = DataSize;
this.Node = Node;
this.Value = Value;
this.DataSize = DataSize;
this.Node = Node;
Timestamp = Environment.TickCount;
}

View file

@ -149,8 +149,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);

View file

@ -126,6 +126,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
BindVertexLayout(New);
if (New.FramebufferSrgb != Old.FramebufferSrgb)
{
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
}
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
{
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
@ -337,6 +342,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
foreach (GalVertexAttrib Attrib in Binding.Attribs)
{
//Skip uninitialized attributes.
if (Attrib.Size == 0)
{
continue;
}
GL.EnableVertexAttribArray(Attrib.Index);
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);

View file

@ -113,14 +113,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
IndexBuffer.ElemSizeLog2 = (int)Format;
}
public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType)
public void DrawArrays(int First, int Count, GalPrimitiveType PrimType)
{
if (PrimCount == 0)
if (Count == 0)
{
return;
}
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount);
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
}
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)

View file

@ -15,9 +15,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public Rect(int X, int Y, int Width, int Height)
{
this.X = X;
this.Y = Y;
this.Width = Width;
this.X = X;
this.Y = Y;
this.Width = Width;
this.Height = Height;
}
}
@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private OGLTexture Texture;
private ImageHandler RawTex;
private ImageHandler ReadTex;
private Rect Viewport;
@ -64,13 +63,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
this.Texture = Texture;
}
public void BindColor(long Key, int Attachment)
public void BindColor(long Key, int Attachment, GalImage Image)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
{
EnsureFrameBuffer();
Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
}
else
{
@ -84,40 +83,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
}
public void BindZeta(long Key)
public void BindZeta(long Key, GalImage Image)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
{
EnsureFrameBuffer();
if (Tex.HasDepth && Tex.HasStencil)
if (CachedImage.HasDepth && CachedImage.HasStencil)
{
if (DepthAttachment != Tex.Handle ||
StencilAttachment != Tex.Handle)
if (DepthAttachment != CachedImage.Handle ||
StencilAttachment != CachedImage.Handle)
{
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
FramebufferAttachment.DepthStencilAttachment,
Tex.Handle,
CachedImage.Handle,
0);
DepthAttachment = Tex.Handle;
StencilAttachment = Tex.Handle;
DepthAttachment = CachedImage.Handle;
StencilAttachment = CachedImage.Handle;
}
}
else if (Tex.HasDepth)
else if (CachedImage.HasDepth)
{
Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment);
Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
}
else if (Tex.HasStencil)
else if (CachedImage.HasStencil)
{
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment);
Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
}
else
{
@ -130,12 +128,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
{
if (OldHandle != NewHandle)
{
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
FbAttachment,
NewHandle,
0);
OldHandle = NewHandle;
}
}
public void UnbindZeta()
{
EnsureFrameBuffer();
if (DepthAttachment != 0 ||
StencilAttachment != 0)
if (DepthAttachment != 0 || StencilAttachment != 0)
{
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
@ -143,44 +154,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
0,
0);
DepthAttachment = 0;
DepthAttachment = 0;
StencilAttachment = 0;
}
}
public void BindTexture(long Key, int Index)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
{
GL.ActiveTexture(TextureUnit.Texture0 + Index);
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
}
}
public void Set(long Key)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
{
ReadTex = Tex;
}
}
public void Set(byte[] Data, int Width, int Height)
{
if (RawTex == null)
{
RawTex = new ImageHandler();
}
RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data);
ReadTex = RawTex;
Texture.TryGetImageHandler(Key, out ReadTex);
}
public void SetMap(int[] Map)
@ -280,13 +261,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
GL.Viewport(0, 0, Window.Width, Window.Height);
if (SrcFb == 0)
{
SrcFb = GL.GenFramebuffer();
}
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
@ -298,7 +281,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.BlitFramebuffer(
SrcX0, SrcY0, SrcX1, SrcY1,
DstX0, DstY0, DstX1, DstY1,
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
ClearBufferMask.ColorBufferBit,
BlitFramebufferFilter.Linear);
EnsureFrameBuffer();
}
@ -315,110 +299,135 @@ namespace Ryujinx.Graphics.Gal.OpenGL
int DstX1,
int DstY1)
{
if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) &&
Texture.TryGetImage(DstKey, out ImageHandler DstTex))
if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
{
if (SrcTex.HasColor != DstTex.HasColor ||
SrcTex.HasDepth != DstTex.HasDepth ||
if (SrcTex.HasColor != DstTex.HasColor ||
SrcTex.HasDepth != DstTex.HasDepth ||
SrcTex.HasStencil != DstTex.HasStencil)
{
throw new NotImplementedException();
}
if (SrcFb == 0)
{
SrcFb = GL.GenFramebuffer();
}
if (DstFb == 0)
{
DstFb = GL.GenFramebuffer();
}
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
FramebufferAttachment Attachment = GetAttachment(SrcTex);
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
if (SrcTex.HasColor)
{
CopyTextures(
SrcX0, SrcY0, SrcX1, SrcY1,
DstX0, DstY0, DstX1, DstY1,
SrcTex.Handle,
DstTex.Handle,
FramebufferAttachment.ColorAttachment0,
ClearBufferMask.ColorBufferBit,
true);
}
else if (SrcTex.HasDepth && SrcTex.HasStencil)
{
CopyTextures(
SrcX0, SrcY0, SrcX1, SrcY1,
DstX0, DstY0, DstX1, DstY1,
SrcTex.Handle,
DstTex.Handle,
FramebufferAttachment.DepthStencilAttachment,
ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
false);
}
else if (SrcTex.HasDepth)
{
CopyTextures(
SrcX0, SrcY0, SrcX1, SrcY1,
DstX0, DstY0, DstX1, DstY1,
SrcTex.Handle,
DstTex.Handle,
FramebufferAttachment.DepthAttachment,
ClearBufferMask.DepthBufferBit,
false);
}
else if (SrcTex.HasStencil)
{
CopyTextures(
SrcX0, SrcY0, SrcX1, SrcY1,
DstX0, DstY0, DstX1, DstY1,
SrcTex.Handle,
DstTex.Handle,
FramebufferAttachment.StencilAttachment,
ClearBufferMask.StencilBufferBit,
false);
}
else
{
throw new InvalidOperationException();
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
Filter = BlitFramebufferFilter.Linear;
}
ClearBufferMask Mask = GetClearMask(SrcTex);
GL.Clear(Mask);
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
EnsureFrameBuffer();
}
}
public void GetBufferData(long Key, Action<byte[]> Callback)
public void Reinterpret(long Key, GalImage NewImage)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
if (!Texture.TryGetImage(Key, out GalImage OldImage))
{
byte[] Data = new byte[ImageUtils.GetSize(Tex.Image)];
return;
}
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
if (NewImage.Format == OldImage.Format)
{
return;
}
GL.GetTexImage(
TextureTarget.Texture2D,
0,
Tex.PixelFormat,
Tex.PixelType,
Data);
byte[] Data = GetData(Key);
Callback(Data);
GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width);
Texture.Create(Key, Data, NewImage);
GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
}
public byte[] GetData(long Key)
{
if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
{
return null;
}
if (SrcFb == 0)
{
SrcFb = GL.GenFramebuffer();
}
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
FramebufferAttachment Attachment = GetAttachment(CachedImage);
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, CachedImage.Handle, 0);
int Size = ImageUtils.GetSize(CachedImage.Image);
byte[] Data = new byte[Size];
int Width = CachedImage.Width;
int Height = CachedImage.Height;
(_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
GL.ReadPixels(0, 0, Width, Height, Format, Type, Data);
return Data;
}
private static FramebufferAttachment GetAttachment(ImageHandler CachedImage)
{
if (CachedImage.HasColor)
{
return FramebufferAttachment.ColorAttachment0;
}
else if (CachedImage.HasDepth && CachedImage.HasStencil)
{
return FramebufferAttachment.DepthStencilAttachment;
}
else if (CachedImage.HasDepth)
{
return FramebufferAttachment.DepthAttachment;
}
else if (CachedImage.HasStencil)
{
return FramebufferAttachment.StencilAttachment;
}
else
{
throw new InvalidOperationException();
}
}
public void SetBufferData(
long Key,
int Width,
int Height,
byte[] Buffer)
private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
{
if (Texture.TryGetImage(Key, out ImageHandler Tex))
{
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
const int Level = 0;
const int Border = 0;
GL.TexImage2D(
TextureTarget.Texture2D,
Level,
Tex.InternalFormat,
Width,
Height,
Border,
Tex.PixelFormat,
Tex.PixelType,
Buffer);
}
return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
}
private void EnsureFrameBuffer()
@ -430,68 +439,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
}
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
{
if (OldHandle != NewHandle)
{
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
FbAttachment,
NewHandle,
0);
OldHandle = NewHandle;
}
}
private void CopyTextures(
int SrcX0,
int SrcY0,
int SrcX1,
int SrcY1,
int DstX0,
int DstY0,
int DstX1,
int DstY1,
int SrcTexture,
int DstTexture,
FramebufferAttachment Attachment,
ClearBufferMask Mask,
bool Color)
{
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
if (DstFb == 0) DstFb = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
GL.FramebufferTexture(
FramebufferTarget.ReadFramebuffer,
Attachment,
SrcTexture,
0);
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
Attachment,
DstTexture,
0);
if (Color)
{
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
}
GL.Clear(Mask);
GL.BlitFramebuffer(
SrcX0, SrcY0, SrcX1, SrcY1,
DstX0, DstY0, DstX1, DstY1,
Mask,
Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
EnsureFrameBuffer();
}
}
}

View file

@ -28,17 +28,65 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.DeleteTexture(CachedImage.Handle);
}
public void Create(long Key, byte[] Data, GalImage Image)
public void Create(long Key, int Size, GalImage Image)
{
int Handle = GL.GenTexture();
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
GL.BindTexture(TextureTarget.Texture2D, Handle);
const int Level = 0; //TODO: Support mipmap textures.
const int Border = 0;
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
{
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
GL.CompressedTexImage2D(
TextureTarget.Texture2D,
Level,
InternalFmt,
Image.Width,
Image.Height,
Border,
Size,
IntPtr.Zero);
}
else
{
(PixelInternalFormat InternalFmt,
PixelFormat Format,
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
GL.TexImage2D(
TextureTarget.Texture2D,
Level,
InternalFmt,
Image.Width,
Image.Height,
Border,
Format,
Type,
IntPtr.Zero);
}
}
public void Create(long Key, byte[] Data, GalImage Image)
{
int Handle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, Handle);
const int Level = 0; //TODO: Support mipmap textures.
const int Border = 0;
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
@ -62,8 +110,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
//TODO: Use KHR_texture_compression_astc_hdr when available
if (IsASTC)
{
int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
Data = ASTCDecoder.DecodeToRGBA8888(
Data,
@ -85,12 +133,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
}
(PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
(PixelInternalFormat InternalFmt,
PixelFormat Format,
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
GL.TexImage2D(
TextureTarget.Texture2D,
Level,
InternalFormat,
InternalFmt,
Image.Width,
Image.Height,
Border,
@ -98,31 +148,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Type,
Data);
}
int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource);
int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource);
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
}
public void CreateFb(long Key, long Size, GalImage Image)
public bool TryGetImage(long Key, out GalImage Image)
{
if (!TryGetImage(Key, out ImageHandler CachedImage))
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
{
CachedImage = new ImageHandler();
Image = CachedImage.Image;
TextureCache.AddOrUpdate(Key, CachedImage, Size);
return true;
}
CachedImage.EnsureSetup(Image);
Image = default(GalImage);
return false;
}
public bool TryGetImage(long Key, out ImageHandler CachedImage)
public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
{
if (TextureCache.TryGetValue(Key, out CachedImage))
{
@ -134,76 +176,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
private static int GetAstcBlockWidth(GalImageFormat Format)
{
switch (Format)
{
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5;
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6;
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8;
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10;
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12;
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8;
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10;
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10;
}
throw new ArgumentException(nameof(Format));
}
private static int GetAstcBlockHeight(GalImageFormat Format)
{
switch (Format)
{
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4;
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5;
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6;
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8;
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10;
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5;
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5;
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6;
}
throw new ArgumentException(nameof(Format));
}
public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image)
{
if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
{
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
{
Image = CachedImage.Image;
return true;
}
}
Image = default(GalImage);
return false;
}
public void Bind(long Key, int Index)
public void Bind(long Key, int Index, GalImage Image)
{
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
{
GL.ActiveTexture(TextureUnit.Texture0 + Index);
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
int[] SwizzleRgba = new int[]
{
(int)OGLEnumConverter.GetTextureSwizzle(Image.XSource),
(int)OGLEnumConverter.GetTextureSwizzle(Image.YSource),
(int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource),
(int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
};
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
}
}