Initial support for using frame buffer as texture
This commit is contained in:
parent
9227b0ea59
commit
f39ced70c1
8 changed files with 151 additions and 68 deletions
|
@ -244,6 +244,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
Context.Memory.WriteInt64(Position + 0x20, Offset);
|
||||
|
||||
Map.GpuAddress = Offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,5 +8,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
public int Align;
|
||||
public int Kind;
|
||||
public long CpuAddress;
|
||||
public long GpuAddress;
|
||||
}
|
||||
}
|
|
@ -296,6 +296,8 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
NvMapFb MapFb = (NvMapFb)INvDrvServices.NvMapsFb.GetData(Context.Process, 0);
|
||||
|
||||
Renderer.SetFrameBuffer(Map.GpuAddress);
|
||||
|
||||
long Address = Map.CpuAddress;
|
||||
|
||||
if (MapFb.HasBufferOffset(Slot))
|
||||
|
|
|
@ -39,11 +39,13 @@ namespace Ryujinx.Graphics.Gal
|
|||
GalBlendFactor FuncDstAlpha);
|
||||
|
||||
//Frame Buffer
|
||||
void SetFb(int FbIndex, int Width, int Height);
|
||||
void CreateFrameBuffer(long Tag, int Width, int Height);
|
||||
|
||||
void BindFrameBuffer(int FbIndex);
|
||||
void BindFrameBuffer(long Tag);
|
||||
|
||||
void DrawFrameBuffer(int FbIndex);
|
||||
void BindFrameBufferTexture(long Tag, int Index);
|
||||
|
||||
void SetFrameBuffer(long Tag);
|
||||
|
||||
//Rasterizer
|
||||
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||
|
@ -72,6 +74,8 @@ namespace Ryujinx.Graphics.Gal
|
|||
//Texture
|
||||
void SetTexture(int Index, GalTexture Tex);
|
||||
|
||||
void SetSampler(int Index, GalTextureSampler Sampler);
|
||||
void BindTexture(int Index);
|
||||
|
||||
void SetSampler(GalTextureSampler Sampler);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
|
@ -8,7 +9,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
private struct FrameBuffer
|
||||
{
|
||||
public int FbHandle;
|
||||
public int Handle;
|
||||
public int RbHandle;
|
||||
public int TexHandle;
|
||||
}
|
||||
|
@ -20,83 +21,121 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
public int FpHandle;
|
||||
}
|
||||
|
||||
private FrameBuffer[] Fbs;
|
||||
private Dictionary<long, FrameBuffer> Fbs;
|
||||
|
||||
private FrameBuffer CurrentFb;
|
||||
|
||||
private ShaderProgram Shader;
|
||||
|
||||
private bool IsInitialized;
|
||||
|
||||
private int FbHandle;
|
||||
private int VaoHandle;
|
||||
private int VboHandle;
|
||||
|
||||
public OGLFrameBuffer()
|
||||
{
|
||||
Fbs = new FrameBuffer[16];
|
||||
Fbs = new Dictionary<long, FrameBuffer>();
|
||||
|
||||
Shader = new ShaderProgram();
|
||||
}
|
||||
|
||||
public void Set(int Index, int Width, int Height)
|
||||
public void Create(long Tag, int Width, int Height)
|
||||
{
|
||||
if (Fbs[Index].FbHandle != 0)
|
||||
if (Fbs.ContainsKey(Tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Fbs[Index].FbHandle = GL.GenFramebuffer();
|
||||
Fbs[Index].RbHandle = GL.GenRenderbuffer();
|
||||
Fbs[Index].TexHandle = GL.GenTexture();
|
||||
FrameBuffer Fb = new FrameBuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fbs[Index].FbHandle);
|
||||
Fb.Handle = GL.GenFramebuffer();
|
||||
Fb.RbHandle = GL.GenRenderbuffer();
|
||||
Fb.TexHandle = GL.GenTexture();
|
||||
|
||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fbs[Index].RbHandle);
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||
|
||||
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, 1280, 720);
|
||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle);
|
||||
|
||||
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, Fbs[Index].RbHandle);
|
||||
GL.RenderbufferStorage(
|
||||
RenderbufferTarget.Renderbuffer,
|
||||
RenderbufferStorage.Depth24Stencil8,
|
||||
1280,
|
||||
720);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fbs[Index].TexHandle);
|
||||
GL.FramebufferRenderbuffer(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
RenderbufferTarget.Renderbuffer,
|
||||
Fb.RbHandle);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, 1280, 720, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, Fbs[Index].TexHandle, 0);
|
||||
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, Fb.TexHandle, 0);
|
||||
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
Fbs.Add(Tag, Fb);
|
||||
}
|
||||
|
||||
public void Bind(int Index)
|
||||
public void Bind(long Tag)
|
||||
{
|
||||
if (Fbs[Index].FbHandle == 0)
|
||||
if (Fbs.TryGetValue(Tag, out FrameBuffer Fb))
|
||||
{
|
||||
return;
|
||||
}
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fbs[Index].FbHandle);
|
||||
FbHandle = Fb.Handle;
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(int Index)
|
||||
public void BindTexture(long Tag, int Index)
|
||||
{
|
||||
if (Fbs[Index].FbHandle == 0)
|
||||
if (Fbs.TryGetValue(Tag, out FrameBuffer Fb))
|
||||
{
|
||||
return;
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
||||
}
|
||||
}
|
||||
|
||||
EnsureInitialized();
|
||||
public void Set(long Tag)
|
||||
{
|
||||
if (Fbs.TryGetValue(Tag, out FrameBuffer Fb))
|
||||
{
|
||||
CurrentFb = Fb;
|
||||
}
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
public void Render()
|
||||
{
|
||||
if (CurrentFb.TexHandle != 0)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fbs[Index].TexHandle);
|
||||
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.UseProgram(Shader.Handle);
|
||||
GL.BindTexture(TextureTarget.Texture2D, CurrentFb.TexHandle);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.UseProgram(Shader.Handle);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
||||
|
||||
//Restore the original state.
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FbHandle);
|
||||
|
||||
GL.UseProgram(CurrentProgram);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
|
|
|
@ -15,9 +15,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
int Handle = EnsureTextureInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
Bind(Index);
|
||||
|
||||
const int Border = 0;
|
||||
|
||||
|
@ -54,12 +52,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public void Set(int Index, GalTextureSampler Sampler)
|
||||
public void Bind(int Index)
|
||||
{
|
||||
int Handle = EnsureTextureInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
}
|
||||
|
||||
public void Set(GalTextureSampler Sampler)
|
||||
{
|
||||
int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
|
||||
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
|
||||
|
||||
|
|
|
@ -63,7 +63,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Render()
|
||||
{
|
||||
FbRenderer.Render();
|
||||
//FbRenderer.Render();
|
||||
FrameBuffer.Render();
|
||||
}
|
||||
|
||||
public void SetWindowSize(int Width, int Height)
|
||||
|
@ -132,19 +133,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
});
|
||||
}
|
||||
|
||||
public void SetFb(int FbIndex, int Width, int Height)
|
||||
public void CreateFrameBuffer(long Tag, int Width, int Height)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Set(FbIndex, Width, Height));
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Create(Tag, Width, Height));
|
||||
}
|
||||
|
||||
public void BindFrameBuffer(int FbIndex)
|
||||
public void BindFrameBuffer(long Tag)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Bind(FbIndex));
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Bind(Tag));
|
||||
}
|
||||
|
||||
public void DrawFrameBuffer(int FbIndex)
|
||||
public void BindFrameBufferTexture(long Tag, int Index)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Draw(FbIndex));
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.BindTexture(Tag, Index));
|
||||
}
|
||||
|
||||
public void SetFrameBuffer(long Tag)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Set(Tag));
|
||||
}
|
||||
|
||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||
|
@ -239,14 +245,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
||||
}
|
||||
|
||||
public void SetTexture(int Index, GalTexture Tex)
|
||||
public void SetTexture(int Index, GalTexture Texture)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Texture.Set(Index, Tex));
|
||||
ActionsQueue.Enqueue(() => this.Texture.Set(Index, Texture));
|
||||
}
|
||||
|
||||
public void SetSampler(int Index, GalTextureSampler Sampler)
|
||||
public void BindTexture(int Index)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Texture.Set(Index, Sampler));
|
||||
ActionsQueue.Enqueue(() => Texture.Bind(Index));
|
||||
}
|
||||
|
||||
public void SetSampler(GalTextureSampler Sampler)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Texture.Set(Sampler));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,9 @@ namespace Ryujinx.Graphics.Gpu
|
|||
public int Size;
|
||||
}
|
||||
|
||||
private ConstBuffer[] Cbs;
|
||||
private ConstBuffer[] ConstBuffers;
|
||||
|
||||
private HashSet<long> FrameBuffers;
|
||||
|
||||
private bool HasDataToRender;
|
||||
|
||||
|
@ -48,7 +50,9 @@ namespace Ryujinx.Graphics.Gpu
|
|||
AddMethod(0x8e4, 16, 1, CbData);
|
||||
AddMethod(0x904, 1, 1, CbBind);
|
||||
|
||||
Cbs = new ConstBuffer[18];
|
||||
ConstBuffers = new ConstBuffer[18];
|
||||
|
||||
FrameBuffers = new HashSet<long>();
|
||||
}
|
||||
|
||||
public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||
|
@ -85,8 +89,6 @@ namespace Ryujinx.Graphics.Gpu
|
|||
if (HasDataToRender)
|
||||
{
|
||||
HasDataToRender = false;
|
||||
|
||||
Gpu.Renderer.DrawFrameBuffer(0);
|
||||
}
|
||||
|
||||
int Arg0 = PBEntry.Arguments[0];
|
||||
|
@ -99,16 +101,20 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
SetFrameBuffer(0);
|
||||
|
||||
Gpu.Renderer.ClearBuffers(Layer, Flags);
|
||||
//Gpu.Renderer.ClearBuffers(Layer, Flags);
|
||||
}
|
||||
|
||||
private void SetFrameBuffer(int FbIndex)
|
||||
{
|
||||
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||
long Address = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
||||
|
||||
Gpu.Renderer.SetFb(FbIndex, Width, Height);
|
||||
Gpu.Renderer.BindFrameBuffer(FbIndex);
|
||||
FrameBuffers.Add(Address);
|
||||
|
||||
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||
|
||||
Gpu.Renderer.CreateFrameBuffer(Address, Width, Height);
|
||||
Gpu.Renderer.BindFrameBuffer(Address);
|
||||
}
|
||||
|
||||
private long[] UploadShaders(AMemory Memory)
|
||||
|
@ -205,11 +211,13 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||
|
||||
long BasePosition = Cbs[TextureCbIndex].Position;
|
||||
long BasePosition = ConstBuffers[TextureCbIndex].Position;
|
||||
|
||||
long Size = (uint)Cbs[TextureCbIndex].Size;
|
||||
long Size = (uint)ConstBuffers[TextureCbIndex].Size;
|
||||
|
||||
int TexIndex = 0;
|
||||
//Note: On the emulator renderer, Texture Unit 0 is
|
||||
//reserved for drawing the frame buffer.
|
||||
int TexIndex = 1;
|
||||
|
||||
for (int Index = 0; Index < Tags.Length; Index++)
|
||||
{
|
||||
|
@ -241,8 +249,23 @@ namespace Ryujinx.Graphics.Gpu
|
|||
TicPosition += TicIndex * 0x20;
|
||||
TscPosition += TscIndex * 0x20;
|
||||
|
||||
Gpu.Renderer.SetTexture(TexIndex, TextureFactory.MakeTexture(Gpu, Memory, TicPosition));
|
||||
Gpu.Renderer.SetSampler(TexIndex, TextureFactory.MakeSampler(Gpu, Memory, TscPosition));
|
||||
long TextureAddress = Memory.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
||||
|
||||
if (FrameBuffers.Contains(TextureAddress))
|
||||
{
|
||||
//This texture is a frame buffer texture,
|
||||
//we shouldn't read anything from memory and bind
|
||||
//the frame buffer texture instead, since we're not
|
||||
//really writing anything to memory.
|
||||
Gpu.Renderer.BindFrameBufferTexture(TextureAddress, TexIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Gpu.Renderer.SetTexture(TexIndex, TextureFactory.MakeTexture(Gpu, Memory, TicPosition));
|
||||
Gpu.Renderer.BindTexture(TexIndex);
|
||||
}
|
||||
|
||||
Gpu.Renderer.SetSampler(TextureFactory.MakeSampler(Gpu, Memory, TscPosition));
|
||||
}
|
||||
|
||||
private void UploadUniforms(AMemory Memory)
|
||||
|
@ -262,9 +285,9 @@ namespace Ryujinx.Graphics.Gpu
|
|||
continue;
|
||||
}
|
||||
|
||||
for (int Cbuf = 0; Cbuf < Cbs.Length; Cbuf++)
|
||||
for (int Cbuf = 0; Cbuf < ConstBuffers.Length; Cbuf++)
|
||||
{
|
||||
ConstBuffer Cb = Cbs[Cbuf];
|
||||
ConstBuffer Cb = ConstBuffers[Cbuf];
|
||||
|
||||
if (Cb.Enabled)
|
||||
{
|
||||
|
@ -414,16 +437,16 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position))
|
||||
{
|
||||
Cbs[Index].Position = Position;
|
||||
Cbs[Index].Enabled = Enabled;
|
||||
ConstBuffers[Index].Position = Position;
|
||||
ConstBuffers[Index].Enabled = Enabled;
|
||||
|
||||
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
|
||||
ConstBuffers[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadCb(AMemory Memory, int Cbuf, int Offset)
|
||||
{
|
||||
long Position = Cbs[Cbuf].Position;
|
||||
long Position = ConstBuffers[Cbuf].Position;
|
||||
|
||||
int Value = Memory.ReadInt32(Position + Offset);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue