| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- using OpenTK.Graphics.OpenGL;
- using Ryujinx.Graphics.Texture;
- using System;
- namespace Ryujinx.Graphics.Gal.OpenGL
- {
- class OglRenderTarget : IGalRenderTarget
- {
- private const int NativeWidth = 1280;
- private const int NativeHeight = 720;
- private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount;
- private struct Rect
- {
- public int X { get; private set; }
- public int Y { get; private set; }
- public int Width { get; private set; }
- public int Height { get; private set; }
- public Rect(int x, int y, int width, int height)
- {
- X = x;
- Y = y;
- Width = width;
- Height = height;
- }
- }
- private class FrameBufferAttachments
- {
- public int MapCount { get; set; }
- public DrawBuffersEnum[] Map { get; private set; }
- public long[] Colors { get; private set; }
- public long Zeta { get; set; }
- public FrameBufferAttachments()
- {
- Colors = new long[RenderTargetsCount];
- Map = new DrawBuffersEnum[RenderTargetsCount];
- }
- public void Update(FrameBufferAttachments source)
- {
- for (int index = 0; index < RenderTargetsCount; index++)
- {
- Map[index] = source.Map[index];
- Colors[index] = source.Colors[index];
- }
- MapCount = source.MapCount;
- Zeta = source.Zeta;
- }
- }
- private int[] _colorHandles;
- private int _zetaHandle;
- private OglTexture _texture;
- private ImageHandler _readTex;
- private Rect _window;
- private float[] _viewports;
- private bool _flipX;
- private bool _flipY;
- private int _cropTop;
- private int _cropLeft;
- private int _cropRight;
- private int _cropBottom;
- // This framebuffer is used to attach guest rendertargets,
- // think of it as a dummy OpenGL VAO
- private int _dummyFrameBuffer;
- // These framebuffers are used to blit images
- private int _srcFb;
- private int _dstFb;
- private FrameBufferAttachments _attachments;
- private FrameBufferAttachments _oldAttachments;
- private int _copyPbo;
- public bool FramebufferSrgb { get; set; }
- public OglRenderTarget(OglTexture texture)
- {
- _attachments = new FrameBufferAttachments();
- _oldAttachments = new FrameBufferAttachments();
- _colorHandles = new int[RenderTargetsCount];
- _viewports = new float[RenderTargetsCount * 4];
- _texture = texture;
- texture.TextureDeleted += TextureDeletionHandler;
- }
- private void TextureDeletionHandler(object sender, int handle)
- {
- // Texture was deleted, the handle is no longer valid, so
- // reset all uses of this handle on a render target.
- for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
- {
- if (_colorHandles[attachment] == handle)
- {
- _colorHandles[attachment] = 0;
- }
- }
- if (_zetaHandle == handle)
- {
- _zetaHandle = 0;
- }
- }
- public void Bind()
- {
- if (_dummyFrameBuffer == 0)
- {
- _dummyFrameBuffer = GL.GenFramebuffer();
- }
- GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dummyFrameBuffer);
- ImageHandler cachedImage;
- for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
- {
- long key = _attachments.Colors[attachment];
- int handle = 0;
- if (key != 0 && _texture.TryGetImageHandler(key, out cachedImage))
- {
- handle = cachedImage.Handle;
- }
- if (handle == _colorHandles[attachment])
- {
- continue;
- }
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.ColorAttachment0 + attachment,
- handle,
- 0);
- _colorHandles[attachment] = handle;
- }
- if (_attachments.Zeta != 0 && _texture.TryGetImageHandler(_attachments.Zeta, out cachedImage))
- {
- if (cachedImage.Handle != _zetaHandle)
- {
- if (cachedImage.HasDepth && cachedImage.HasStencil)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthStencilAttachment,
- cachedImage.Handle,
- 0);
- }
- else if (cachedImage.HasDepth)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthAttachment,
- cachedImage.Handle,
- 0);
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.StencilAttachment,
- 0,
- 0);
- }
- else
- {
- throw new InvalidOperationException("Invalid image format \"" + cachedImage.Format + "\" used as Zeta!");
- }
- _zetaHandle = cachedImage.Handle;
- }
- }
- else if (_zetaHandle != 0)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthStencilAttachment,
- 0,
- 0);
- _zetaHandle = 0;
- }
- if (OglExtension.ViewportArray)
- {
- GL.ViewportArray(0, RenderTargetsCount, _viewports);
- }
- else
- {
- GL.Viewport(
- (int)_viewports[0],
- (int)_viewports[1],
- (int)_viewports[2],
- (int)_viewports[3]);
- }
- if (_attachments.MapCount > 1)
- {
- GL.DrawBuffers(_attachments.MapCount, _attachments.Map);
- }
- else if (_attachments.MapCount == 1)
- {
- GL.DrawBuffer((DrawBufferMode)_attachments.Map[0]);
- }
- else
- {
- GL.DrawBuffer(DrawBufferMode.None);
- }
- _oldAttachments.Update(_attachments);
- }
- public void BindColor(long key, int attachment)
- {
- _attachments.Colors[attachment] = key;
- }
- public void UnbindColor(int attachment)
- {
- _attachments.Colors[attachment] = 0;
- }
- public void BindZeta(long key)
- {
- _attachments.Zeta = key;
- }
- public void UnbindZeta()
- {
- _attachments.Zeta = 0;
- }
- public void Present(long key)
- {
- _texture.TryGetImageHandler(key, out _readTex);
- }
- public void SetMap(int[] map)
- {
- if (map != null)
- {
- _attachments.MapCount = map.Length;
- for (int attachment = 0; attachment < _attachments.MapCount; attachment++)
- {
- _attachments.Map[attachment] = DrawBuffersEnum.ColorAttachment0 + map[attachment];
- }
- }
- else
- {
- _attachments.MapCount = 0;
- }
- }
- public void SetTransform(bool flipX, bool flipY, int top, int left, int right, int bottom)
- {
- _flipX = flipX;
- _flipY = flipY;
- _cropTop = top;
- _cropLeft = left;
- _cropRight = right;
- _cropBottom = bottom;
- }
- public void SetWindowSize(int width, int height)
- {
- _window = new Rect(0, 0, width, height);
- }
- public void SetViewport(int attachment, int x, int y, int width, int height)
- {
- int offset = attachment * 4;
- _viewports[offset + 0] = x;
- _viewports[offset + 1] = y;
- _viewports[offset + 2] = width;
- _viewports[offset + 3] = height;
- }
- public void Render()
- {
- if (_readTex == null)
- {
- return;
- }
- int srcX0, srcX1, srcY0, srcY1;
- if (_cropLeft == 0 && _cropRight == 0)
- {
- srcX0 = 0;
- srcX1 = _readTex.Width;
- }
- else
- {
- srcX0 = _cropLeft;
- srcX1 = _cropRight;
- }
- if (_cropTop == 0 && _cropBottom == 0)
- {
- srcY0 = 0;
- srcY1 = _readTex.Height;
- }
- else
- {
- srcY0 = _cropTop;
- srcY1 = _cropBottom;
- }
- float ratioX = MathF.Min(1f, (_window.Height * (float)NativeWidth) / ((float)NativeHeight * _window.Width));
- float ratioY = MathF.Min(1f, (_window.Width * (float)NativeHeight) / ((float)NativeWidth * _window.Height));
- int dstWidth = (int)(_window.Width * ratioX);
- int dstHeight = (int)(_window.Height * ratioY);
- int dstPaddingX = (_window.Width - dstWidth) / 2;
- int dstPaddingY = (_window.Height - dstHeight) / 2;
- int dstX0 = _flipX ? _window.Width - dstPaddingX : dstPaddingX;
- int dstX1 = _flipX ? dstPaddingX : _window.Width - dstPaddingX;
- int dstY0 = _flipY ? dstPaddingY : _window.Height - dstPaddingY;
- int dstY1 = _flipY ? _window.Height - dstPaddingY : dstPaddingY;
- 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);
- GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
- GL.Clear(ClearBufferMask.ColorBufferBit);
- GL.Disable(EnableCap.FramebufferSrgb);
- GL.BlitFramebuffer(
- srcX0,
- srcY0,
- srcX1,
- srcY1,
- dstX0,
- dstY0,
- dstX1,
- dstY1,
- ClearBufferMask.ColorBufferBit,
- BlitFramebufferFilter.Linear);
- if (FramebufferSrgb)
- {
- GL.Enable(EnableCap.FramebufferSrgb);
- }
- }
- public void Copy(
- GalImage srcImage,
- GalImage dstImage,
- long srcKey,
- long dstKey,
- int srcLayer,
- int dstLayer,
- int srcX0,
- int srcY0,
- int srcX1,
- int srcY1,
- int dstX0,
- int dstY0,
- int dstX1,
- int dstY1)
- {
- if (_texture.TryGetImageHandler(srcKey, out ImageHandler srcTex) &&
- _texture.TryGetImageHandler(dstKey, out ImageHandler dstTex))
- {
- 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);
- if (ImageUtils.IsArray(srcImage.TextureTarget) && srcLayer > 0)
- {
- GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0, srcLayer);
- }
- else
- {
- GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0);
- }
- if (ImageUtils.IsArray(dstImage.TextureTarget) && dstLayer > 0)
- {
- GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0, dstLayer);
- }
- else
- {
- GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0);
- }
- BlitFramebufferFilter filter = BlitFramebufferFilter.Nearest;
- if (srcTex.HasColor)
- {
- GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
- filter = BlitFramebufferFilter.Linear;
- }
- ClearBufferMask mask = GetClearMask(srcTex);
- GL.BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
- }
- }
- public void Reinterpret(long key, GalImage newImage)
- {
- if (!_texture.TryGetImage(key, out GalImage oldImage))
- {
- return;
- }
- if (newImage.Format == oldImage.Format &&
- newImage.Width == oldImage.Width &&
- newImage.Height == oldImage.Height &&
- newImage.Depth == oldImage.Depth &&
- newImage.LayerCount == oldImage.LayerCount &&
- newImage.TextureTarget == oldImage.TextureTarget)
- {
- return;
- }
- if (_copyPbo == 0)
- {
- _copyPbo = GL.GenBuffer();
- }
- GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPbo);
- // The buffer should be large enough to hold the largest texture.
- int bufferSize = Math.Max(ImageUtils.GetSize(oldImage),
- ImageUtils.GetSize(newImage));
- GL.BufferData(BufferTarget.PixelPackBuffer, bufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
- if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage))
- {
- throw new InvalidOperationException();
- }
- (_, PixelFormat format, PixelType type) = OglEnumConverter.GetImageFormat(cachedImage.Format);
- TextureTarget target = ImageUtils.GetTextureTarget(newImage.TextureTarget);
- GL.BindTexture(target, cachedImage.Handle);
- GL.GetTexImage(target, 0, format, type, IntPtr.Zero);
- GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
- GL.BindBuffer(BufferTarget.PixelUnpackBuffer, _copyPbo);
- GL.PixelStore(PixelStoreParameter.UnpackRowLength, oldImage.Width);
- _texture.Create(key, ImageUtils.GetSize(newImage), newImage);
- GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
- GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
- }
- 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();
- }
- }
- private static ClearBufferMask GetClearMask(ImageHandler cachedImage)
- {
- return (cachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
- (cachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
- (cachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
- }
- }
- }
|