Methods.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu.Image;
  4. using Ryujinx.Graphics.Gpu.Memory;
  5. using Ryujinx.Graphics.Gpu.Shader;
  6. using Ryujinx.Graphics.Gpu.State;
  7. using Ryujinx.Graphics.Shader;
  8. using System;
  9. using System.Runtime.InteropServices;
  10. namespace Ryujinx.Graphics.Gpu.Engine
  11. {
  12. using Texture = Image.Texture;
  13. /// <summary>
  14. /// GPU method implementations.
  15. /// </summary>
  16. partial class Methods
  17. {
  18. private readonly GpuContext _context;
  19. private readonly ShaderCache _shaderCache;
  20. private readonly ShaderProgramInfo[] _currentProgramInfo;
  21. /// <summary>
  22. /// GPU buffer manager.
  23. /// </summary>
  24. public BufferManager BufferManager { get; }
  25. /// <summary>
  26. /// GPU texture manager.
  27. /// </summary>
  28. public TextureManager TextureManager { get; }
  29. private bool _isAnyVbInstanced;
  30. private bool _vsUsesInstanceId;
  31. /// <summary>
  32. /// Creates a new instance of the GPU methods class.
  33. /// </summary>
  34. /// <param name="context">GPU context</param>
  35. public Methods(GpuContext context)
  36. {
  37. _context = context;
  38. _shaderCache = new ShaderCache(_context);
  39. _currentProgramInfo = new ShaderProgramInfo[Constants.TotalShaderStages];
  40. BufferManager = new BufferManager(context);
  41. TextureManager = new TextureManager(context);
  42. }
  43. /// <summary>
  44. /// Register callback for GPU method calls that triggers an action on the GPU.
  45. /// </summary>
  46. /// <param name="state">GPU state where the triggers will be registered</param>
  47. public void RegisterCallbacks(GpuState state)
  48. {
  49. state.RegisterCallback(MethodOffset.LaunchDma, LaunchDma);
  50. state.RegisterCallback(MethodOffset.LoadInlineData, LoadInlineData);
  51. state.RegisterCallback(MethodOffset.Dispatch, Dispatch);
  52. state.RegisterCallback(MethodOffset.CopyBuffer, CopyBuffer);
  53. state.RegisterCallback(MethodOffset.CopyTexture, CopyTexture);
  54. state.RegisterCallback(MethodOffset.TextureBarrier, TextureBarrier);
  55. state.RegisterCallback(MethodOffset.InvalidateTextures, InvalidateTextures);
  56. state.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
  57. state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
  58. state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
  59. state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
  60. state.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
  61. state.RegisterCallback(MethodOffset.Clear, Clear);
  62. state.RegisterCallback(MethodOffset.Report, Report);
  63. state.RegisterCallback(MethodOffset.UniformBufferUpdateData, 16, UniformBufferUpdate);
  64. state.RegisterCallback(MethodOffset.UniformBufferBindVertex, UniformBufferBindVertex);
  65. state.RegisterCallback(MethodOffset.UniformBufferBindTessControl, UniformBufferBindTessControl);
  66. state.RegisterCallback(MethodOffset.UniformBufferBindTessEvaluation, UniformBufferBindTessEvaluation);
  67. state.RegisterCallback(MethodOffset.UniformBufferBindGeometry, UniformBufferBindGeometry);
  68. state.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment);
  69. }
  70. /// <summary>
  71. /// Updates host state based on the current guest GPU state.
  72. /// </summary>
  73. /// <param name="state">Guest GPU state</param>
  74. private void UpdateState(GpuState state)
  75. {
  76. // Shaders must be the first one to be updated if modified, because
  77. // some of the other state depends on information from the currently
  78. // bound shaders.
  79. if (state.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState))
  80. {
  81. UpdateShaderState(state);
  82. }
  83. if (state.QueryModified(MethodOffset.RtColorState,
  84. MethodOffset.RtDepthStencilState,
  85. MethodOffset.RtControl,
  86. MethodOffset.RtDepthStencilSize,
  87. MethodOffset.RtDepthStencilEnable))
  88. {
  89. UpdateRenderTargetState(state, useControl: true);
  90. }
  91. if (state.QueryModified(MethodOffset.DepthTestEnable,
  92. MethodOffset.DepthWriteEnable,
  93. MethodOffset.DepthTestFunc))
  94. {
  95. UpdateDepthTestState(state);
  96. }
  97. if (state.QueryModified(MethodOffset.DepthMode, MethodOffset.ViewportTransform, MethodOffset.ViewportExtents))
  98. {
  99. UpdateViewportTransform(state);
  100. }
  101. if (state.QueryModified(MethodOffset.DepthBiasState,
  102. MethodOffset.DepthBiasFactor,
  103. MethodOffset.DepthBiasUnits,
  104. MethodOffset.DepthBiasClamp))
  105. {
  106. UpdateDepthBiasState(state);
  107. }
  108. if (state.QueryModified(MethodOffset.StencilBackMasks,
  109. MethodOffset.StencilTestState,
  110. MethodOffset.StencilBackTestState))
  111. {
  112. UpdateStencilTestState(state);
  113. }
  114. // Pools.
  115. if (state.QueryModified(MethodOffset.SamplerPoolState, MethodOffset.SamplerIndex))
  116. {
  117. UpdateSamplerPoolState(state);
  118. }
  119. if (state.QueryModified(MethodOffset.TexturePoolState))
  120. {
  121. UpdateTexturePoolState(state);
  122. }
  123. // Input assembler state.
  124. if (state.QueryModified(MethodOffset.VertexAttribState))
  125. {
  126. UpdateVertexAttribState(state);
  127. }
  128. if (state.QueryModified(MethodOffset.PrimitiveRestartState))
  129. {
  130. UpdatePrimitiveRestartState(state);
  131. }
  132. if (state.QueryModified(MethodOffset.IndexBufferState))
  133. {
  134. UpdateIndexBufferState(state);
  135. }
  136. if (state.QueryModified(MethodOffset.VertexBufferDrawState,
  137. MethodOffset.VertexBufferInstanced,
  138. MethodOffset.VertexBufferState,
  139. MethodOffset.VertexBufferEndAddress))
  140. {
  141. UpdateVertexBufferState(state);
  142. }
  143. if (state.QueryModified(MethodOffset.FaceState))
  144. {
  145. UpdateFaceState(state);
  146. }
  147. if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
  148. {
  149. UpdateRtColorMask(state);
  150. }
  151. if (state.QueryModified(MethodOffset.BlendIndependent,
  152. MethodOffset.BlendStateCommon,
  153. MethodOffset.BlendEnableCommon,
  154. MethodOffset.BlendEnable,
  155. MethodOffset.BlendState))
  156. {
  157. UpdateBlendState(state);
  158. }
  159. CommitBindings();
  160. }
  161. /// <summary>
  162. /// Ensures that the bindings are visible to the host GPU.
  163. /// This actually performs the binding using the host graphics API.
  164. /// </summary>
  165. private void CommitBindings()
  166. {
  167. UpdateStorageBuffers();
  168. BufferManager.CommitBindings();
  169. TextureManager.CommitGraphicsBindings();
  170. }
  171. /// <summary>
  172. /// Updates storage buffer bindings.
  173. /// </summary>
  174. private void UpdateStorageBuffers()
  175. {
  176. for (int stage = 0; stage < _currentProgramInfo.Length; stage++)
  177. {
  178. ShaderProgramInfo info = _currentProgramInfo[stage];
  179. if (info == null)
  180. {
  181. continue;
  182. }
  183. for (int index = 0; index < info.SBuffers.Count; index++)
  184. {
  185. BufferDescriptor sb = info.SBuffers[index];
  186. ulong sbDescAddress = BufferManager.GetGraphicsUniformBufferAddress(stage, 0);
  187. int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
  188. sbDescAddress += (ulong)sbDescOffset;
  189. Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
  190. SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
  191. BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
  192. }
  193. }
  194. }
  195. /// <summary>
  196. /// Updates render targets (color and depth-stencil buffers) based on current render target state.
  197. /// </summary>
  198. /// <param name="state">Current GPU state</param>
  199. /// <param name="useControl">Use draw buffers information from render target control register</param>
  200. private void UpdateRenderTargetState(GpuState state, bool useControl)
  201. {
  202. var rtControl = state.Get<RtControl>(MethodOffset.RtControl);
  203. int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
  204. var msaaMode = state.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
  205. int samplesInX = msaaMode.SamplesInX();
  206. int samplesInY = msaaMode.SamplesInY();
  207. for (int index = 0; index < Constants.TotalRenderTargets; index++)
  208. {
  209. int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
  210. var colorState = state.Get<RtColorState>(MethodOffset.RtColorState, rtIndex);
  211. if (index >= count || !IsRtEnabled(colorState))
  212. {
  213. TextureManager.SetRenderTargetColor(index, null);
  214. continue;
  215. }
  216. Texture color = TextureManager.FindOrCreateTexture(colorState, samplesInX, samplesInY);
  217. TextureManager.SetRenderTargetColor(index, color);
  218. if (color != null)
  219. {
  220. color.Modified = true;
  221. }
  222. }
  223. bool dsEnable = state.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
  224. Texture depthStencil = null;
  225. if (dsEnable)
  226. {
  227. var dsState = state.Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
  228. var dsSize = state.Get<Size3D> (MethodOffset.RtDepthStencilSize);
  229. depthStencil = TextureManager.FindOrCreateTexture(dsState, dsSize, samplesInX, samplesInY);
  230. }
  231. TextureManager.SetRenderTargetDepthStencil(depthStencil);
  232. if (depthStencil != null)
  233. {
  234. depthStencil.Modified = true;
  235. }
  236. }
  237. /// <summary>
  238. /// Checks if a render target color buffer is used.
  239. /// </summary>
  240. /// <param name="colorState">Color buffer information</param>
  241. /// <returns>True if the specified buffer is enabled/used, false otherwise</returns>
  242. private static bool IsRtEnabled(RtColorState colorState)
  243. {
  244. // Colors are disabled by writing 0 to the format.
  245. return colorState.Format != 0 && colorState.WidthOrStride != 0;
  246. }
  247. /// <summary>
  248. /// Updates host depth test state based on current GPU state.
  249. /// </summary>
  250. /// <param name="state">Current GPU state</param>
  251. private void UpdateDepthTestState(GpuState state)
  252. {
  253. _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
  254. state.Get<Boolean32>(MethodOffset.DepthTestEnable),
  255. state.Get<Boolean32>(MethodOffset.DepthWriteEnable),
  256. state.Get<CompareOp>(MethodOffset.DepthTestFunc)));
  257. }
  258. /// <summary>
  259. /// Updates host viewport transform and clipping state based on current GPU state.
  260. /// </summary>
  261. /// <param name="state">Current GPU state</param>
  262. private void UpdateViewportTransform(GpuState state)
  263. {
  264. DepthMode depthMode = state.Get<DepthMode>(MethodOffset.DepthMode);
  265. _context.Renderer.Pipeline.SetDepthMode(depthMode);
  266. bool transformEnable = GetViewportTransformEnable(state);
  267. bool flipY = (state.Get<int>(MethodOffset.YControl) & 1) != 0;
  268. float yFlip = flipY ? -1 : 1;
  269. Viewport[] viewports = new Viewport[Constants.TotalViewports];
  270. for (int index = 0; index < Constants.TotalViewports; index++)
  271. {
  272. var transform = state.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
  273. var extents = state.Get<ViewportExtents> (MethodOffset.ViewportExtents, index);
  274. RectangleF region;
  275. if (transformEnable)
  276. {
  277. float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
  278. float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
  279. float width = transform.ScaleX * 2;
  280. float height = transform.ScaleY * 2 * yFlip;
  281. region = new RectangleF(x, y, width, height);
  282. }
  283. else
  284. {
  285. // It's not possible to fully disable viewport transform, at least with the most
  286. // common graphics APIs, but we can effectively disable it with a dummy transform.
  287. // The transform is defined as: xw = (width / 2) * xndc + x + (width / 2)
  288. // By setting x to -(width / 2), we effectively remove the translation.
  289. // By setting the width to 2, we remove the scale since 2 / 2 = 1.
  290. // Now, the only problem is the viewport clipping, that we also can't disable.
  291. // To prevent the values from being clipped, we multiply (-1, -1, 2, 2) by
  292. // the maximum supported viewport dimensions.
  293. // This must be compensated on the shader, by dividing the vertex position
  294. // by the maximum viewport dimensions.
  295. float maxSize = _context.Capabilities.MaximumViewportDimensions;
  296. float halfMaxSize = _context.Capabilities.MaximumViewportDimensions * 0.5f;
  297. region = new RectangleF(-halfMaxSize, -halfMaxSize, maxSize, maxSize * yFlip);
  298. }
  299. viewports[index] = new Viewport(
  300. region,
  301. transform.UnpackSwizzleX(),
  302. transform.UnpackSwizzleY(),
  303. transform.UnpackSwizzleZ(),
  304. transform.UnpackSwizzleW(),
  305. extents.DepthNear,
  306. extents.DepthFar);
  307. }
  308. _context.Renderer.Pipeline.SetViewports(0, viewports);
  309. }
  310. /// <summary>
  311. /// Updates host depth bias (also called polygon offset) state based on current GPU state.
  312. /// </summary>
  313. /// <param name="state">Current GPU state</param>
  314. private void UpdateDepthBiasState(GpuState state)
  315. {
  316. var depthBias = state.Get<DepthBiasState>(MethodOffset.DepthBiasState);
  317. float factor = state.Get<float>(MethodOffset.DepthBiasFactor);
  318. float units = state.Get<float>(MethodOffset.DepthBiasUnits);
  319. float clamp = state.Get<float>(MethodOffset.DepthBiasClamp);
  320. PolygonModeMask enables;
  321. enables = (depthBias.PointEnable ? PolygonModeMask.Point : 0);
  322. enables |= (depthBias.LineEnable ? PolygonModeMask.Line : 0);
  323. enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
  324. _context.Renderer.Pipeline.SetDepthBias(enables, factor, units, clamp);
  325. }
  326. /// <summary>
  327. /// Updates host stencil test state based on current GPU state.
  328. /// </summary>
  329. /// <param name="state">Current GPU state</param>
  330. private void UpdateStencilTestState(GpuState state)
  331. {
  332. var backMasks = state.Get<StencilBackMasks> (MethodOffset.StencilBackMasks);
  333. var test = state.Get<StencilTestState> (MethodOffset.StencilTestState);
  334. var backTest = state.Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
  335. CompareOp backFunc;
  336. StencilOp backSFail;
  337. StencilOp backDpPass;
  338. StencilOp backDpFail;
  339. int backFuncRef;
  340. int backFuncMask;
  341. int backMask;
  342. if (backTest.TwoSided)
  343. {
  344. backFunc = backTest.BackFunc;
  345. backSFail = backTest.BackSFail;
  346. backDpPass = backTest.BackDpPass;
  347. backDpFail = backTest.BackDpFail;
  348. backFuncRef = backMasks.FuncRef;
  349. backFuncMask = backMasks.FuncMask;
  350. backMask = backMasks.Mask;
  351. }
  352. else
  353. {
  354. backFunc = test.FrontFunc;
  355. backSFail = test.FrontSFail;
  356. backDpPass = test.FrontDpPass;
  357. backDpFail = test.FrontDpFail;
  358. backFuncRef = test.FrontFuncRef;
  359. backFuncMask = test.FrontFuncMask;
  360. backMask = test.FrontMask;
  361. }
  362. _context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
  363. test.Enable,
  364. test.FrontFunc,
  365. test.FrontSFail,
  366. test.FrontDpPass,
  367. test.FrontDpFail,
  368. test.FrontFuncRef,
  369. test.FrontFuncMask,
  370. test.FrontMask,
  371. backFunc,
  372. backSFail,
  373. backDpPass,
  374. backDpFail,
  375. backFuncRef,
  376. backFuncMask,
  377. backMask));
  378. }
  379. /// <summary>
  380. /// Updates current sampler pool address and size based on guest GPU state.
  381. /// </summary>
  382. /// <param name="state">Current GPU state</param>
  383. private void UpdateSamplerPoolState(GpuState state)
  384. {
  385. var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
  386. var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState);
  387. var samplerIndex = state.Get<SamplerIndex>(MethodOffset.SamplerIndex);
  388. int maximumId = samplerIndex == SamplerIndex.ViaHeaderIndex
  389. ? texturePool.MaximumId
  390. : samplerPool.MaximumId;
  391. TextureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), maximumId, samplerIndex);
  392. }
  393. /// <summary>
  394. /// Updates current texture pool address and size based on guest GPU state.
  395. /// </summary>
  396. /// <param name="state">Current GPU state</param>
  397. private void UpdateTexturePoolState(GpuState state)
  398. {
  399. var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
  400. TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
  401. TextureManager.SetGraphicsTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
  402. }
  403. /// <summary>
  404. /// Updates host vertex attributes based on guest GPU state.
  405. /// </summary>
  406. /// <param name="state">Current GPU state</param>
  407. private void UpdateVertexAttribState(GpuState state)
  408. {
  409. VertexAttribDescriptor[] vertexAttribs = new VertexAttribDescriptor[16];
  410. for (int index = 0; index < 16; index++)
  411. {
  412. var vertexAttrib = state.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
  413. if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
  414. {
  415. Logger.PrintDebug(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
  416. format = Format.R32G32B32A32Float;
  417. }
  418. vertexAttribs[index] = new VertexAttribDescriptor(
  419. vertexAttrib.UnpackBufferIndex(),
  420. vertexAttrib.UnpackOffset(),
  421. format);
  422. }
  423. _context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
  424. }
  425. /// <summary>
  426. /// Updates host primitive restart based on guest GPU state.
  427. /// </summary>
  428. /// <param name="state">Current GPU state</param>
  429. private void UpdatePrimitiveRestartState(GpuState state)
  430. {
  431. PrimitiveRestartState primitiveRestart = state.Get<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState);
  432. _context.Renderer.Pipeline.SetPrimitiveRestart(
  433. primitiveRestart.Enable,
  434. primitiveRestart.Index);
  435. }
  436. /// <summary>
  437. /// Updates host index buffer binding based on guest GPU state.
  438. /// </summary>
  439. /// <param name="state">Current GPU state</param>
  440. private void UpdateIndexBufferState(GpuState state)
  441. {
  442. var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
  443. _firstIndex = indexBuffer.First;
  444. _indexCount = indexBuffer.Count;
  445. if (_indexCount == 0)
  446. {
  447. return;
  448. }
  449. ulong gpuVa = indexBuffer.Address.Pack();
  450. // Do not use the end address to calculate the size, because
  451. // the result may be much larger than the real size of the index buffer.
  452. ulong size = (ulong)(_firstIndex + _indexCount);
  453. switch (indexBuffer.Type)
  454. {
  455. case IndexType.UShort: size *= 2; break;
  456. case IndexType.UInt: size *= 4; break;
  457. }
  458. BufferManager.SetIndexBuffer(gpuVa, size, indexBuffer.Type);
  459. // The index buffer affects the vertex buffer size calculation, we
  460. // need to ensure that they are updated.
  461. UpdateVertexBufferState(state);
  462. }
  463. /// <summary>
  464. /// Updates host vertex buffer bindings based on guest GPU state.
  465. /// </summary>
  466. /// <param name="state">Current GPU state</param>
  467. private void UpdateVertexBufferState(GpuState state)
  468. {
  469. _isAnyVbInstanced = false;
  470. for (int index = 0; index < 16; index++)
  471. {
  472. var vertexBuffer = state.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
  473. if (!vertexBuffer.UnpackEnable())
  474. {
  475. BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
  476. continue;
  477. }
  478. GpuVa endAddress = state.Get<GpuVa>(MethodOffset.VertexBufferEndAddress, index);
  479. ulong address = vertexBuffer.Address.Pack();
  480. int stride = vertexBuffer.UnpackStride();
  481. bool instanced = state.Get<Boolean32>(MethodOffset.VertexBufferInstanced + index);
  482. int divisor = instanced ? vertexBuffer.Divisor : 0;
  483. _isAnyVbInstanced |= divisor != 0;
  484. ulong size;
  485. if (_drawIndexed || stride == 0 || instanced)
  486. {
  487. // This size may be (much) larger than the real vertex buffer size.
  488. // Avoid calculating it this way, unless we don't have any other option.
  489. size = endAddress.Pack() - address + 1;
  490. }
  491. else
  492. {
  493. // For non-indexed draws, we can guess the size from the vertex count
  494. // and stride.
  495. int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
  496. var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
  497. size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
  498. }
  499. BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
  500. }
  501. }
  502. /// <summary>
  503. /// Updates host face culling and orientation based on guest GPU state.
  504. /// </summary>
  505. /// <param name="state">Current GPU state</param>
  506. private void UpdateFaceState(GpuState state)
  507. {
  508. var face = state.Get<FaceState>(MethodOffset.FaceState);
  509. _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
  510. _context.Renderer.Pipeline.SetFrontFace(face.FrontFace);
  511. }
  512. /// <summary>
  513. /// Updates host render target color masks, based on guest GPU state.
  514. /// This defines with color channels are written to each color buffer.
  515. /// </summary>
  516. /// <param name="state">Current GPU state</param>
  517. private void UpdateRtColorMask(GpuState state)
  518. {
  519. bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared);
  520. uint[] componentMasks = new uint[Constants.TotalRenderTargets];
  521. for (int index = 0; index < Constants.TotalRenderTargets; index++)
  522. {
  523. var colorMask = state.Get<RtColorMask>(MethodOffset.RtColorMask, rtColorMaskShared ? 0 : index);
  524. uint componentMask;
  525. componentMask = (colorMask.UnpackRed() ? 1u : 0u);
  526. componentMask |= (colorMask.UnpackGreen() ? 2u : 0u);
  527. componentMask |= (colorMask.UnpackBlue() ? 4u : 0u);
  528. componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
  529. componentMasks[index] = componentMask;
  530. }
  531. _context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
  532. }
  533. /// <summary>
  534. /// Updates host render target color buffer blending state, based on guest state.
  535. /// </summary>
  536. /// <param name="state">Current GPU state</param>
  537. private void UpdateBlendState(GpuState state)
  538. {
  539. bool blendIndependent = state.Get<Boolean32>(MethodOffset.BlendIndependent);
  540. for (int index = 0; index < 8; index++)
  541. {
  542. BlendDescriptor descriptor;
  543. if (blendIndependent)
  544. {
  545. bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, index);
  546. var blend = state.Get<BlendState>(MethodOffset.BlendState, index);
  547. descriptor = new BlendDescriptor(
  548. enable,
  549. blend.ColorOp,
  550. blend.ColorSrcFactor,
  551. blend.ColorDstFactor,
  552. blend.AlphaOp,
  553. blend.AlphaSrcFactor,
  554. blend.AlphaDstFactor);
  555. }
  556. else
  557. {
  558. bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, 0);
  559. var blend = state.Get<BlendStateCommon>(MethodOffset.BlendStateCommon);
  560. descriptor = new BlendDescriptor(
  561. enable,
  562. blend.ColorOp,
  563. blend.ColorSrcFactor,
  564. blend.ColorDstFactor,
  565. blend.AlphaOp,
  566. blend.AlphaSrcFactor,
  567. blend.AlphaDstFactor);
  568. }
  569. _context.Renderer.Pipeline.SetBlendState(index, descriptor);
  570. }
  571. }
  572. /// <summary>
  573. /// Storage buffer address and size information.
  574. /// </summary>
  575. private struct SbDescriptor
  576. {
  577. public uint AddressLow;
  578. public uint AddressHigh;
  579. public int Size;
  580. public int Padding;
  581. public ulong PackAddress()
  582. {
  583. return AddressLow | ((ulong)AddressHigh << 32);
  584. }
  585. }
  586. /// <summary>
  587. /// Updates host shaders based on the guest GPU state.
  588. /// </summary>
  589. /// <param name="state">Current GPU state</param>
  590. private void UpdateShaderState(GpuState state)
  591. {
  592. ShaderAddresses addresses = new ShaderAddresses();
  593. Span<ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);
  594. Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
  595. ulong baseAddress = state.Get<GpuVa>(MethodOffset.ShaderBaseAddress).Pack();
  596. for (int index = 0; index < 6; index++)
  597. {
  598. var shader = state.Get<ShaderState>(MethodOffset.ShaderState, index);
  599. if (!shader.UnpackEnable() && index != 1)
  600. {
  601. continue;
  602. }
  603. addressesArray[index] = baseAddress + shader.Offset;
  604. }
  605. GraphicsShader gs = _shaderCache.GetGraphicsShader(state, addresses);
  606. _vsUsesInstanceId = gs.Shader[0].Program.Info.UsesInstanceId;
  607. for (int stage = 0; stage < Constants.TotalShaderStages; stage++)
  608. {
  609. ShaderProgramInfo info = gs.Shader[stage].Program?.Info;
  610. _currentProgramInfo[stage] = info;
  611. if (info == null)
  612. {
  613. continue;
  614. }
  615. var textureBindings = new TextureBindingInfo[info.Textures.Count];
  616. for (int index = 0; index < info.Textures.Count; index++)
  617. {
  618. var descriptor = info.Textures[index];
  619. Target target = GetTarget(descriptor.Type);
  620. if (descriptor.IsBindless)
  621. {
  622. textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufSlot, descriptor.CbufOffset);
  623. }
  624. else
  625. {
  626. textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
  627. }
  628. }
  629. TextureManager.SetGraphicsTextures(stage, textureBindings);
  630. var imageBindings = new TextureBindingInfo[info.Images.Count];
  631. for (int index = 0; index < info.Images.Count; index++)
  632. {
  633. var descriptor = info.Images[index];
  634. Target target = GetTarget(descriptor.Type);
  635. imageBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
  636. }
  637. TextureManager.SetGraphicsImages(stage, imageBindings);
  638. uint sbEnableMask = 0;
  639. uint ubEnableMask = 0;
  640. for (int index = 0; index < info.SBuffers.Count; index++)
  641. {
  642. sbEnableMask |= 1u << info.SBuffers[index].Slot;
  643. }
  644. for (int index = 0; index < info.CBuffers.Count; index++)
  645. {
  646. ubEnableMask |= 1u << info.CBuffers[index].Slot;
  647. }
  648. BufferManager.SetGraphicsStorageBufferEnableMask(stage, sbEnableMask);
  649. BufferManager.SetGraphicsUniformBufferEnableMask(stage, ubEnableMask);
  650. }
  651. _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
  652. }
  653. /// <summary>
  654. /// Gets viewport transform enable.
  655. /// </summary>
  656. /// <param name="state">Current GPU state</param>
  657. /// <returns>Viewport transform enable</returns>
  658. public bool GetViewportTransformEnable(GpuState state)
  659. {
  660. // FIXME: We should read ViewportTransformEnable, but it seems that some games writes 0 there?
  661. // return state.Get<Boolean32>(MethodOffset.ViewportTransformEnable) != 0;
  662. return true;
  663. }
  664. /// <summary>
  665. /// Gets texture target from a sampler type.
  666. /// </summary>
  667. /// <param name="type">Sampler type</param>
  668. /// <returns>Texture target value</returns>
  669. private static Target GetTarget(SamplerType type)
  670. {
  671. type &= ~(SamplerType.Indexed | SamplerType.Shadow);
  672. switch (type)
  673. {
  674. case SamplerType.Texture1D:
  675. return Target.Texture1D;
  676. case SamplerType.TextureBuffer:
  677. return Target.TextureBuffer;
  678. case SamplerType.Texture1D | SamplerType.Array:
  679. return Target.Texture1DArray;
  680. case SamplerType.Texture2D:
  681. return Target.Texture2D;
  682. case SamplerType.Texture2D | SamplerType.Array:
  683. return Target.Texture2DArray;
  684. case SamplerType.Texture2D | SamplerType.Multisample:
  685. return Target.Texture2DMultisample;
  686. case SamplerType.Texture2D | SamplerType.Multisample | SamplerType.Array:
  687. return Target.Texture2DMultisampleArray;
  688. case SamplerType.Texture3D:
  689. return Target.Texture3D;
  690. case SamplerType.TextureCube:
  691. return Target.Cubemap;
  692. case SamplerType.TextureCube | SamplerType.Array:
  693. return Target.CubemapArray;
  694. }
  695. // TODO: Warning.
  696. return Target.Texture2D;
  697. }
  698. /// <summary>
  699. /// Issues a texture barrier.
  700. /// This waits until previous texture writes from the GPU to finish, before
  701. /// performing new operations with said textures.
  702. /// </summary>
  703. /// <param name="state">Current GPU state</param>
  704. /// <param name="argument">Method call argument</param>
  705. private void TextureBarrier(GpuState state, int argument)
  706. {
  707. _context.Renderer.Pipeline.TextureBarrier();
  708. }
  709. /// <summary>
  710. /// Invalidates all modified textures on the cache.
  711. /// </summary>
  712. /// <param name="state">Current GPU state</param>
  713. /// <param name="argument">Method call argument</param>
  714. private void InvalidateTextures(GpuState state, int argument)
  715. {
  716. TextureManager.Flush();
  717. }
  718. /// <summary>
  719. /// Issues a texture barrier.
  720. /// This waits until previous texture writes from the GPU to finish, before
  721. /// performing new operations with said textures.
  722. /// This performs a per-tile wait, it is only valid if both the previous write
  723. /// and current access has the same access patterns.
  724. /// This may be faster than the regular barrier on tile-based rasterizers.
  725. /// </summary>
  726. /// <param name="state"></param>
  727. /// <param name="argument"></param>
  728. private void TextureBarrierTiled(GpuState state, int argument)
  729. {
  730. _context.Renderer.Pipeline.TextureBarrierTiled();
  731. }
  732. }
  733. }