2019-10-13 08:02:07 +02:00
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
|
using Ryujinx.Graphics.GAL.Blend;
|
|
|
|
using Ryujinx.Graphics.GAL.DepthStencil;
|
|
|
|
using Ryujinx.Graphics.GAL.InputAssembler;
|
|
|
|
using Ryujinx.Graphics.GAL.Texture;
|
|
|
|
using Ryujinx.Graphics.Gpu.Image;
|
|
|
|
using Ryujinx.Graphics.Gpu.Memory;
|
|
|
|
using Ryujinx.Graphics.Gpu.State;
|
|
|
|
using Ryujinx.Graphics.Shader;
|
|
|
|
using System;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
|
{
|
|
|
|
partial class Methods
|
|
|
|
{
|
|
|
|
private GpuContext _context;
|
|
|
|
|
|
|
|
private ShaderCache _shaderCache;
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
private ShaderProgramInfo[] _currentProgramInfo;
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
private BufferManager _bufferManager;
|
|
|
|
private TextureManager _textureManager;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
public BufferManager BufferManager => _bufferManager;
|
2019-10-13 08:02:07 +02:00
|
|
|
public TextureManager TextureManager => _textureManager;
|
|
|
|
|
|
|
|
private bool _isAnyVbInstanced;
|
|
|
|
private bool _vsUsesInstanceId;
|
|
|
|
|
|
|
|
public Methods(GpuContext context)
|
|
|
|
{
|
|
|
|
_context = context;
|
|
|
|
|
|
|
|
_shaderCache = new ShaderCache(_context);
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_currentProgramInfo = new ShaderProgramInfo[Constants.TotalShaderStages];
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
_bufferManager = new BufferManager(context);
|
2019-10-18 04:41:18 +02:00
|
|
|
_textureManager = new TextureManager(context);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
RegisterCallbacks();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void RegisterCallbacks()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.LaunchDma, LaunchDma);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.LoadInlineData, LoadInlineData);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.Dispatch, Dispatch);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.CopyBuffer, CopyBuffer);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.CopyTexture, CopyTexture);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.TextureBarrier, TextureBarrier);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.InvalidateTextures, InvalidateTextures);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.State.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
|
|
|
|
|
|
|
|
_context.State.RegisterCallback(MethodOffset.Clear, Clear);
|
|
|
|
|
|
|
|
_context.State.RegisterCallback(MethodOffset.Report, Report);
|
|
|
|
|
|
|
|
_context.State.RegisterCallback(MethodOffset.UniformBufferUpdateData, 16, UniformBufferUpdate);
|
|
|
|
|
|
|
|
_context.State.RegisterCallback(MethodOffset.UniformBufferBindVertex, UniformBufferBindVertex);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.UniformBufferBindTessControl, UniformBufferBindTessControl);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.UniformBufferBindTessEvaluation, UniformBufferBindTessEvaluation);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.UniformBufferBindGeometry, UniformBufferBindGeometry);
|
|
|
|
_context.State.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public Image.Texture GetTexture(ulong address) => _textureManager.Find2(address);
|
|
|
|
|
|
|
|
private void UpdateState()
|
|
|
|
{
|
|
|
|
// Shaders must be the first one to be updated if modified, because
|
|
|
|
// some of the other state depends on information from the currently
|
|
|
|
// bound shaders.
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateShaderState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
UpdateRenderTargetStateIfNeeded();
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.DepthTestEnable,
|
|
|
|
MethodOffset.DepthWriteEnable,
|
|
|
|
MethodOffset.DepthTestFunc))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateDepthTestState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.ViewportTransform, MethodOffset.ViewportExtents))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateViewportTransform();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.DepthBiasState,
|
|
|
|
MethodOffset.DepthBiasFactor,
|
|
|
|
MethodOffset.DepthBiasUnits,
|
|
|
|
MethodOffset.DepthBiasClamp))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateDepthBiasState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.StencilBackMasks,
|
|
|
|
MethodOffset.StencilTestState,
|
|
|
|
MethodOffset.StencilBackTestState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateStencilTestState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
// Pools.
|
|
|
|
if (_context.State.QueryModified(MethodOffset.SamplerPoolState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateSamplerPoolState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.TexturePoolState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateTexturePoolState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
// Input assembler state.
|
|
|
|
if (_context.State.QueryModified(MethodOffset.VertexAttribState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
UpdateVertexAttribState();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_context.State.QueryModified(MethodOffset.PrimitiveRestartState))
|
|
|
|
{
|
|
|
|
UpdatePrimitiveRestartState();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_context.State.QueryModified(MethodOffset.IndexBufferState))
|
|
|
|
{
|
|
|
|
UpdateIndexBufferState();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_context.State.QueryModified(MethodOffset.VertexBufferDrawState,
|
|
|
|
MethodOffset.VertexBufferInstanced,
|
|
|
|
MethodOffset.VertexBufferState,
|
|
|
|
MethodOffset.VertexBufferEndAddress))
|
|
|
|
{
|
|
|
|
UpdateVertexBufferState();
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.FaceState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateFaceState();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.RtColorMask))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateRtColorMask();
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (_context.State.QueryModified(MethodOffset.BlendEnable, MethodOffset.BlendState))
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
UpdateBlendState();
|
|
|
|
}
|
|
|
|
|
|
|
|
CommitBindings();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void CommitBindings()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
UpdateStorageBuffers();
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
_bufferManager.CommitBindings();
|
2019-10-18 04:41:18 +02:00
|
|
|
_textureManager.CommitGraphicsBindings();
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
private void UpdateStorageBuffers()
|
|
|
|
{
|
|
|
|
for (int stage = 0; stage < _currentProgramInfo.Length; stage++)
|
|
|
|
{
|
|
|
|
ShaderProgramInfo info = _currentProgramInfo[stage];
|
|
|
|
|
|
|
|
if (info == null)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < info.SBuffers.Count; index++)
|
|
|
|
{
|
|
|
|
BufferDescriptor sb = info.SBuffers[index];
|
|
|
|
|
|
|
|
ulong sbDescAddress = _bufferManager.GetGraphicsUniformBufferAddress(stage, 0);
|
|
|
|
|
|
|
|
int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
|
|
|
|
|
|
|
|
sbDescAddress += (ulong)sbDescOffset;
|
|
|
|
|
|
|
|
Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
|
|
|
|
|
|
|
|
SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
|
|
|
|
|
|
|
|
_bufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateRenderTargetStateIfNeeded()
|
|
|
|
{
|
|
|
|
if (_context.State.QueryModified(MethodOffset.RtColorState,
|
|
|
|
MethodOffset.RtDepthStencilState,
|
|
|
|
MethodOffset.RtDepthStencilSize,
|
|
|
|
MethodOffset.RtDepthStencilEnable))
|
|
|
|
{
|
|
|
|
UpdateRenderTargetState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateRenderTargetState()
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var msaaMode = _context.State.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
int samplesInX = msaaMode.SamplesInX();
|
|
|
|
int samplesInY = msaaMode.SamplesInY();
|
|
|
|
|
|
|
|
Image.Texture color3D = Get3DRenderTarget(samplesInX, samplesInY);
|
|
|
|
|
|
|
|
if (color3D == null)
|
|
|
|
{
|
|
|
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
if (!IsRtEnabled(colorState))
|
|
|
|
{
|
|
|
|
_textureManager.SetRenderTargetColor(index, null);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Image.Texture color = _textureManager.FindOrCreateTexture(
|
|
|
|
colorState,
|
|
|
|
samplesInX,
|
|
|
|
samplesInY);
|
|
|
|
|
|
|
|
_textureManager.SetRenderTargetColor(index, color);
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (color != null)
|
|
|
|
{
|
|
|
|
color.Modified = true;
|
|
|
|
}
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_textureManager.SetRenderTargetColor3D(color3D);
|
|
|
|
|
|
|
|
color3D.Modified = true;
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
bool dsEnable = _context.State.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
Image.Texture depthStencil = null;
|
|
|
|
|
|
|
|
if (dsEnable)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var dsState = _context.State.Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
|
|
|
|
var dsSize = _context.State.Get<Size3D> (MethodOffset.RtDepthStencilSize);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
depthStencil = _textureManager.FindOrCreateTexture(
|
|
|
|
dsState,
|
|
|
|
dsSize,
|
|
|
|
samplesInX,
|
|
|
|
samplesInY);
|
|
|
|
}
|
|
|
|
|
|
|
|
_textureManager.SetRenderTargetDepthStencil(depthStencil);
|
2019-10-26 19:50:52 +02:00
|
|
|
|
|
|
|
if (depthStencil != null)
|
|
|
|
{
|
|
|
|
depthStencil.Modified = true;
|
|
|
|
}
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private Image.Texture Get3DRenderTarget(int samplesInX, int samplesInY)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var colorState0 = _context.State.Get<RtColorState>(MethodOffset.RtColorState, 0);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
if (!IsRtEnabled(colorState0) || !colorState0.MemoryLayout.UnpackIsTarget3D() || colorState0.Depth != 1)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
int slices = 1;
|
|
|
|
int unused = 0;
|
|
|
|
|
|
|
|
for (int index = 1; index < Constants.TotalRenderTargets; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
if (!IsRtEnabled(colorState))
|
|
|
|
{
|
|
|
|
unused++;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colorState.MemoryLayout.UnpackIsTarget3D() && colorState.Depth == 1)
|
|
|
|
{
|
|
|
|
slices++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slices + unused == Constants.TotalRenderTargets)
|
|
|
|
{
|
|
|
|
colorState0.Depth = slices;
|
|
|
|
|
|
|
|
return _textureManager.FindOrCreateTexture(colorState0, samplesInX, samplesInY);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool IsRtEnabled(RtColorState colorState)
|
|
|
|
{
|
|
|
|
// Colors are disabled by writing 0 to the format.
|
|
|
|
return colorState.Format != 0 && colorState.WidthOrStride != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateDepthTestState()
|
|
|
|
{
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.State.Get<Boolean32>(MethodOffset.DepthTestEnable),
|
|
|
|
_context.State.Get<Boolean32>(MethodOffset.DepthWriteEnable),
|
|
|
|
_context.State.Get<CompareOp>(MethodOffset.DepthTestFunc)));
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateViewportTransform()
|
|
|
|
{
|
|
|
|
Viewport[] viewports = new Viewport[Constants.TotalViewports];
|
|
|
|
|
|
|
|
for (int index = 0; index < Constants.TotalViewports; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var transform = _context.State.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
|
|
|
|
var extents = _context.State.Get<ViewportExtents> (MethodOffset.ViewportExtents, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
|
|
|
|
float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
|
|
|
|
|
|
|
|
float width = transform.ScaleX * 2;
|
|
|
|
float height = transform.ScaleY * 2;
|
|
|
|
|
|
|
|
RectangleF region = new RectangleF(x, y, width, height);
|
|
|
|
|
|
|
|
viewports[index] = new Viewport(
|
|
|
|
region,
|
|
|
|
transform.UnpackSwizzleX(),
|
|
|
|
transform.UnpackSwizzleY(),
|
|
|
|
transform.UnpackSwizzleZ(),
|
|
|
|
transform.UnpackSwizzleW(),
|
|
|
|
extents.DepthNear,
|
|
|
|
extents.DepthFar);
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetViewports(0, viewports);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateDepthBiasState()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var depthBias = _context.State.Get<DepthBiasState>(MethodOffset.DepthBiasState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
float factor = _context.State.Get<float>(MethodOffset.DepthBiasFactor);
|
|
|
|
float units = _context.State.Get<float>(MethodOffset.DepthBiasUnits);
|
|
|
|
float clamp = _context.State.Get<float>(MethodOffset.DepthBiasClamp);
|
|
|
|
|
|
|
|
PolygonModeMask enables = 0;
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
enables = (depthBias.PointEnable ? PolygonModeMask.Point : 0);
|
|
|
|
enables |= (depthBias.LineEnable ? PolygonModeMask.Line : 0);
|
|
|
|
enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetDepthBias(enables, factor, units, clamp);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateStencilTestState()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var backMasks = _context.State.Get<StencilBackMasks> (MethodOffset.StencilBackMasks);
|
|
|
|
var test = _context.State.Get<StencilTestState> (MethodOffset.StencilTestState);
|
|
|
|
var backTest = _context.State.Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
CompareOp backFunc;
|
|
|
|
StencilOp backSFail;
|
|
|
|
StencilOp backDpPass;
|
|
|
|
StencilOp backDpFail;
|
|
|
|
int backFuncRef;
|
|
|
|
int backFuncMask;
|
|
|
|
int backMask;
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
if (backTest.TwoSided)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
|
|
|
backFunc = backTest.BackFunc;
|
|
|
|
backSFail = backTest.BackSFail;
|
|
|
|
backDpPass = backTest.BackDpPass;
|
|
|
|
backDpFail = backTest.BackDpFail;
|
|
|
|
backFuncRef = backMasks.FuncRef;
|
|
|
|
backFuncMask = backMasks.FuncMask;
|
|
|
|
backMask = backMasks.Mask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
backFunc = test.FrontFunc;
|
|
|
|
backSFail = test.FrontSFail;
|
|
|
|
backDpPass = test.FrontDpPass;
|
|
|
|
backDpFail = test.FrontDpFail;
|
|
|
|
backFuncRef = test.FrontFuncRef;
|
|
|
|
backFuncMask = test.FrontFuncMask;
|
|
|
|
backMask = test.FrontMask;
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
|
2019-10-26 19:50:52 +02:00
|
|
|
test.Enable,
|
2019-10-13 08:02:07 +02:00
|
|
|
test.FrontFunc,
|
|
|
|
test.FrontSFail,
|
|
|
|
test.FrontDpPass,
|
|
|
|
test.FrontDpFail,
|
|
|
|
test.FrontFuncRef,
|
|
|
|
test.FrontFuncMask,
|
|
|
|
test.FrontMask,
|
|
|
|
backFunc,
|
|
|
|
backSFail,
|
|
|
|
backDpPass,
|
|
|
|
backDpFail,
|
|
|
|
backFuncRef,
|
|
|
|
backFuncMask,
|
|
|
|
backMask));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateSamplerPoolState()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var samplerPool = _context.State.Get<PoolState>(MethodOffset.SamplerPoolState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_textureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateTexturePoolState()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var texturePool = _context.State.Get<PoolState>(MethodOffset.TexturePoolState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_textureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_textureManager.SetGraphicsTextureBufferIndex(_context.State.Get<int>(MethodOffset.TextureBufferIndex));
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateVertexAttribState()
|
|
|
|
{
|
|
|
|
VertexAttribDescriptor[] vertexAttribs = new VertexAttribDescriptor[16];
|
|
|
|
|
|
|
|
for (int index = 0; index < 16; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var vertexAttrib = _context.State.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
|
|
|
|
{
|
|
|
|
// TODO: warning.
|
|
|
|
|
|
|
|
format = Format.R32G32B32A32Float;
|
|
|
|
}
|
|
|
|
|
|
|
|
vertexAttribs[index] = new VertexAttribDescriptor(
|
|
|
|
vertexAttrib.UnpackBufferIndex(),
|
|
|
|
vertexAttrib.UnpackOffset(),
|
|
|
|
format);
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.BindVertexAttribs(vertexAttribs);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdatePrimitiveRestartState()
|
|
|
|
{
|
|
|
|
PrimitiveRestartState primitiveRestart = _context.State.Get<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState);
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetPrimitiveRestart(
|
2019-10-13 08:02:07 +02:00
|
|
|
primitiveRestart.Enable,
|
|
|
|
primitiveRestart.Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateIndexBufferState()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var indexBuffer = _context.State.Get<IndexBufferState>(MethodOffset.IndexBufferState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
_firstIndex = indexBuffer.First;
|
|
|
|
_indexCount = indexBuffer.Count;
|
|
|
|
|
|
|
|
if (_indexCount == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ulong gpuVa = indexBuffer.Address.Pack();
|
|
|
|
|
|
|
|
// Do not use the end address to calculate the size, because
|
|
|
|
// the result may be much larger than the real size of the index buffer.
|
|
|
|
ulong size = (ulong)(_firstIndex + _indexCount);
|
|
|
|
|
|
|
|
switch (indexBuffer.Type)
|
|
|
|
{
|
|
|
|
case IndexType.UShort: size *= 2; break;
|
|
|
|
case IndexType.UInt: size *= 4; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_bufferManager.SetIndexBuffer(gpuVa, size, indexBuffer.Type);
|
|
|
|
|
|
|
|
// The index buffer affects the vertex buffer size calculation, we
|
|
|
|
// need to ensure that they are updated.
|
|
|
|
UpdateVertexBufferState();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateVertexBufferState()
|
|
|
|
{
|
|
|
|
_isAnyVbInstanced = false;
|
|
|
|
|
|
|
|
for (int index = 0; index < 16; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var vertexBuffer = _context.State.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
if (!vertexBuffer.UnpackEnable())
|
|
|
|
{
|
|
|
|
_bufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
GpuVa endAddress = _context.State.Get<GpuVa>(MethodOffset.VertexBufferEndAddress, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
ulong address = vertexBuffer.Address.Pack();
|
|
|
|
|
|
|
|
int stride = vertexBuffer.UnpackStride();
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
bool instanced = _context.State.Get<Boolean32>(MethodOffset.VertexBufferInstanced + index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
int divisor = instanced ? vertexBuffer.Divisor : 0;
|
|
|
|
|
|
|
|
_isAnyVbInstanced |= divisor != 0;
|
|
|
|
|
|
|
|
ulong size;
|
|
|
|
|
|
|
|
if (_drawIndexed || stride == 0 || instanced)
|
|
|
|
{
|
|
|
|
// This size may be (much) larger than the real vertex buffer size.
|
|
|
|
// Avoid calculating it this way, unless we don't have any other option.
|
|
|
|
size = endAddress.Pack() - address + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// For non-indexed draws, we can guess the size from the vertex count
|
|
|
|
// and stride.
|
2019-10-26 19:50:52 +02:00
|
|
|
int firstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
|
|
|
|
}
|
|
|
|
|
|
|
|
_bufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateFaceState()
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var face = _context.State.Get<FaceState>(MethodOffset.FaceState);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetFrontFace(face.FrontFace);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateRtColorMask()
|
|
|
|
{
|
|
|
|
uint[] componentMasks = new uint[Constants.TotalRenderTargets];
|
|
|
|
|
|
|
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var colorMask = _context.State.Get<RtColorMask>(MethodOffset.RtColorMask, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
uint componentMask = 0;
|
|
|
|
|
|
|
|
componentMask = (colorMask.UnpackRed() ? 1u : 0u);
|
|
|
|
componentMask |= (colorMask.UnpackGreen() ? 2u : 0u);
|
|
|
|
componentMask |= (colorMask.UnpackBlue() ? 4u : 0u);
|
|
|
|
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
|
|
|
|
|
|
|
componentMasks[index] = componentMask;
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateBlendState()
|
|
|
|
{
|
|
|
|
BlendState[] blends = new BlendState[8];
|
|
|
|
|
|
|
|
for (int index = 0; index < 8; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
bool enable = _context.State.Get<Boolean32>(MethodOffset.BlendEnable, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
var blend = _context.State.Get<BlendState>(MethodOffset.BlendState, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
BlendDescriptor descriptor = new BlendDescriptor(
|
2019-10-26 19:50:52 +02:00
|
|
|
enable,
|
2019-10-13 08:02:07 +02:00
|
|
|
blend.ColorOp,
|
|
|
|
blend.ColorSrcFactor,
|
|
|
|
blend.ColorDstFactor,
|
|
|
|
blend.AlphaOp,
|
|
|
|
blend.AlphaSrcFactor,
|
|
|
|
blend.AlphaDstFactor);
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.BindBlendState(index, descriptor);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private struct SbDescriptor
|
|
|
|
{
|
|
|
|
public uint AddressLow;
|
|
|
|
public uint AddressHigh;
|
|
|
|
public int Size;
|
|
|
|
public int Padding;
|
|
|
|
|
|
|
|
public ulong PackAddress()
|
|
|
|
{
|
|
|
|
return AddressLow | ((ulong)AddressHigh << 32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateShaderState()
|
|
|
|
{
|
|
|
|
ShaderAddresses addresses = new ShaderAddresses();
|
|
|
|
|
|
|
|
Span<ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);
|
|
|
|
|
|
|
|
Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
ulong baseAddress = _context.State.Get<GpuVa>(MethodOffset.ShaderBaseAddress).Pack();
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
for (int index = 0; index < 6; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
var shader = _context.State.Get<ShaderState>(MethodOffset.ShaderState, index);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
if (!shader.UnpackEnable() && index != 1)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addressesArray[index] = baseAddress + shader.Offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
GraphicsShader gs = _shaderCache.GetGraphicsShader(addresses);
|
|
|
|
|
|
|
|
_vsUsesInstanceId = gs.Shader[0].Info.UsesInstanceId;
|
|
|
|
|
|
|
|
for (int stage = 0; stage < Constants.TotalShaderStages; stage++)
|
|
|
|
{
|
|
|
|
ShaderProgramInfo info = gs.Shader[stage]?.Info;
|
|
|
|
|
2019-10-26 19:50:52 +02:00
|
|
|
_currentProgramInfo[stage] = info;
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
if (info == null)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
var textureBindings = new TextureBindingInfo[info.Textures.Count];
|
|
|
|
|
|
|
|
for (int index = 0; index < info.Textures.Count; index++)
|
|
|
|
{
|
|
|
|
var descriptor = info.Textures[index];
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
Target target = GetTarget(descriptor.Type);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_textureManager.SetGraphicsTextures(stage, textureBindings);
|
|
|
|
|
|
|
|
var imageBindings = new TextureBindingInfo[info.Images.Count];
|
|
|
|
|
|
|
|
for (int index = 0; index < info.Images.Count; index++)
|
|
|
|
{
|
|
|
|
var descriptor = info.Images[index];
|
|
|
|
|
|
|
|
Target target = GetTarget(descriptor.Type);
|
|
|
|
|
|
|
|
imageBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
_textureManager.SetGraphicsImages(stage, imageBindings);
|
2019-10-13 08:02:07 +02:00
|
|
|
|
|
|
|
uint sbEnableMask = 0;
|
|
|
|
uint ubEnableMask = 0;
|
|
|
|
|
|
|
|
for (int index = 0; index < info.SBuffers.Count; index++)
|
|
|
|
{
|
2019-10-26 19:50:52 +02:00
|
|
|
sbEnableMask |= 1u << info.SBuffers[index].Slot;
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < info.CBuffers.Count; index++)
|
|
|
|
{
|
|
|
|
ubEnableMask |= 1u << info.CBuffers[index].Slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
_bufferManager.SetGraphicsStorageBufferEnableMask(stage, sbEnableMask);
|
|
|
|
_bufferManager.SetGraphicsUniformBufferEnableMask(stage, ubEnableMask);
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
_context.Renderer.Pipeline.BindProgram(gs.Interface);
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
private static Target GetTarget(SamplerType type)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2019-10-18 04:41:18 +02:00
|
|
|
type &= ~SamplerType.Shadow;
|
2019-10-13 08:02:07 +02:00
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
switch (type)
|
2019-10-13 08:02:07 +02:00
|
|
|
{
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.Texture1D:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture1D;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.TextureBuffer:
|
|
|
|
return Target.TextureBuffer;
|
|
|
|
|
|
|
|
case SamplerType.Texture1D | SamplerType.Array:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture1DArray;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.Texture2D:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture2D;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.Texture2D | SamplerType.Array:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture2DArray;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.Texture2D | SamplerType.Multisample:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture2DMultisample;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.Texture2D | SamplerType.Multisample | SamplerType.Array:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture2DMultisampleArray;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.Texture3D:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Texture3D;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.TextureCube:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.Cubemap;
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
case SamplerType.TextureCube | SamplerType.Array:
|
2019-10-13 08:02:07 +02:00
|
|
|
return Target.CubemapArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Warning.
|
|
|
|
|
|
|
|
return Target.Texture2D;
|
|
|
|
}
|
|
|
|
|
2019-10-18 04:41:18 +02:00
|
|
|
private void TextureBarrier(int argument)
|
|
|
|
{
|
|
|
|
_context.Renderer.Pipeline.TextureBarrier();
|
|
|
|
}
|
|
|
|
|
2019-10-13 08:02:07 +02:00
|
|
|
private void InvalidateTextures(int argument)
|
|
|
|
{
|
|
|
|
_textureManager.Flush();
|
|
|
|
}
|
2019-10-18 04:41:18 +02:00
|
|
|
|
|
|
|
private void TextureBarrierTiled(int argument)
|
|
|
|
{
|
|
|
|
_context.Renderer.Pipeline.TextureBarrierTiled();
|
|
|
|
}
|
2019-10-13 08:02:07 +02:00
|
|
|
}
|
|
|
|
}
|