Esempio n. 1
0
        /// <summary>
        /// Gets a compute shader from the cache.
        /// </summary>
        /// <remarks>
        /// This automatically translates, compiles and adds the code to the cache if not present.
        /// </remarks>
        /// <param name="state">Current GPU state</param>
        /// <param name="gpuVa">GPU virtual address of the binary shader code</param>
        /// <param name="localSizeX">Local group size X of the computer shader</param>
        /// <param name="localSizeY">Local group size Y of the computer shader</param>
        /// <param name="localSizeZ">Local group size Z of the computer shader</param>
        /// <param name="localMemorySize">Local memory size of the compute shader</param>
        /// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
        /// <returns>Compiled compute shader code</returns>
        public ShaderBundle GetComputeShader(
            GpuState state,
            ulong gpuVa,
            int localSizeX,
            int localSizeY,
            int localSizeZ,
            int localMemorySize,
            int sharedMemorySize)
        {
            bool isCached = _cpPrograms.TryGetValue(gpuVa, out List <ShaderBundle> list);

            if (isCached)
            {
                foreach (ShaderBundle cachedCpShader in list)
                {
                    if (IsShaderEqual(cachedCpShader, gpuVa))
                    {
                        return(cachedCpShader);
                    }
                }
            }

            TranslatorContext[] shaderContexts = new TranslatorContext[1];

            shaderContexts[0] = DecodeComputeShader(
                state,
                gpuVa,
                localSizeX,
                localSizeY,
                localSizeZ,
                localMemorySize,
                sharedMemorySize);

            bool isShaderCacheEnabled  = _cacheManager != null;
            bool isShaderCacheReadOnly = false;

            Hash128 programCodeHash = default;

            GuestShaderCacheEntry[] shaderCacheEntries = null;

            // Current shader cache doesn't support bindless textures
            if (shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless))
            {
                isShaderCacheEnabled = false;
            }

            if (isShaderCacheEnabled)
            {
                isShaderCacheReadOnly = _cacheManager.IsReadOnly;

                // Compute hash and prepare data for shader disk cache comparison.
                shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts);
                programCodeHash    = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries);
            }

            ShaderBundle cpShader;

            // Search for the program hash in loaded shaders.
            if (!isShaderCacheEnabled || !_cpProgramsDiskCache.TryGetValue(programCodeHash, out cpShader))
            {
                if (isShaderCacheEnabled)
                {
                    Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!");
                }

                // The shader isn't currently cached, translate it and compile it.
                ShaderCodeHolder shader = TranslateShader(shaderContexts[0]);

                shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);

                IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);

                hostProgram.CheckProgramLink(true);

                byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), new ShaderCodeHolder[] { shader });

                cpShader = new ShaderBundle(hostProgram, shader);

                if (isShaderCacheEnabled)
                {
                    _cpProgramsDiskCache.Add(programCodeHash, cpShader);

                    if (!isShaderCacheReadOnly)
                    {
                        _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries), hostProgramBinary);
                    }
                }
            }

            if (!isCached)
            {
                list = new List <ShaderBundle>();

                _cpPrograms.Add(gpuVa, list);
            }

            list.Add(cpShader);

            return(cpShader);
        }
Esempio n. 2
0
 /// <summary>
 /// Invalidates all modified textures on the cache.
 /// </summary>
 /// <param name="state">Current GPU state (unused)</param>
 /// <param name="argument">Method call argument (unused)</param>
 private void InvalidateTextures(GpuState state, int argument)
 {
     TextureManager.Flush();
 }
Esempio n. 3
0
 /// <summary>
 /// Sets the index buffer count.
 /// This also sets internal state that indicates that the next draw is an indexed draw.
 /// </summary>
 /// <param name="state">Current GPU state</param>
 /// <param name="argument">Method call argument</param>
 private void SetIndexBufferCount(GpuState state, int argument)
 {
     _drawIndexed = true;
 }
Esempio n. 4
0
        /// <summary>
        /// Dispatches compute work.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        public void Dispatch(GpuState state, int argument)
        {
            uint qmdAddress = (uint)state.Get <int>(MethodOffset.DispatchParamsAddress);

            var qmd = _context.MemoryAccessor.Read <ComputeQmd>((ulong)qmdAddress << 8);

            GpuVa shaderBaseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress);

            ulong shaderGpuVa = shaderBaseAddress.Pack() + (uint)qmd.ProgramOffset;

            int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;

            int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);

            ComputeShader cs = ShaderCache.GetComputeShader(
                shaderGpuVa,
                qmd.CtaThreadDimension0,
                qmd.CtaThreadDimension1,
                qmd.CtaThreadDimension2,
                localMemorySize,
                sharedMemorySize);

            _context.Renderer.Pipeline.SetProgram(cs.HostProgram);

            var samplerPool = state.Get <PoolState>(MethodOffset.SamplerPoolState);

            TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);

            var texturePool = state.Get <PoolState>(MethodOffset.TexturePoolState);

            TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);

            TextureManager.SetComputeTextureBufferIndex(state.Get <int>(MethodOffset.TextureBufferIndex));

            ShaderProgramInfo info = cs.Shader.Program.Info;

            uint sbEnableMask = 0;
            uint ubEnableMask = 0;

            for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
            {
                if (!qmd.ConstantBufferValid(index))
                {
                    continue;
                }

                ubEnableMask |= 1u << index;

                ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
                ulong size  = (ulong)qmd.ConstantBufferSize(index);

                BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
            }

            for (int index = 0; index < info.SBuffers.Count; index++)
            {
                BufferDescriptor sb = info.SBuffers[index];

                sbEnableMask |= 1u << sb.Slot;

                ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int sbDescOffset = 0x310 + sb.Slot * 0x10;

                sbDescAddress += (ulong)sbDescOffset;

                ReadOnlySpan <byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);

                SbDescriptor sbDescriptor = MemoryMarshal.Cast <byte, SbDescriptor>(sbDescriptorData)[0];

                BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
            }

            ubEnableMask = 0;

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                ubEnableMask |= 1u << info.CBuffers[index].Slot;
            }

            BufferManager.SetComputeStorageBufferEnableMask(sbEnableMask);
            BufferManager.SetComputeUniformBufferEnableMask(ubEnableMask);

            var textureBindings = new TextureBindingInfo[info.Textures.Count];

            for (int index = 0; index < info.Textures.Count; index++)
            {
                var descriptor = info.Textures[index];

                Target target = GetTarget(descriptor.Type);

                if (descriptor.IsBindless)
                {
                    textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufOffset, descriptor.CbufSlot);
                }
                else
                {
                    textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
                }
            }

            TextureManager.SetComputeTextures(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.SetComputeImages(imageBindings);

            BufferManager.CommitComputeBindings();
            TextureManager.CommitComputeBindings();

            _context.Renderer.Pipeline.DispatchCompute(
                qmd.CtaRasterWidth,
                qmd.CtaRasterHeight,
                qmd.CtaRasterDepth);

            UpdateShaderState(state);
        }
Esempio n. 5
0
        /// <summary>
        /// Updates host point size based on guest GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdatePointSizeState(GpuState state)
        {
            float size = state.Get <float>(MethodOffset.PointSize);

            _context.Renderer.Pipeline.SetPointSize(size);
        }
Esempio n. 6
0
        /// <summary>
        /// Updates host viewport transform and clipping state based on current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateViewportTransform(GpuState state)
        {
            DepthMode depthMode = state.Get <DepthMode>(MethodOffset.DepthMode);

            _context.Renderer.Pipeline.SetDepthMode(depthMode);

            YControl yControl = state.Get <YControl>(MethodOffset.YControl);

            bool   flipY  = yControl.HasFlag(YControl.NegateY);
            Origin origin = yControl.HasFlag(YControl.TriangleRastFlip) ? Origin.LowerLeft : Origin.UpperLeft;

            _context.Renderer.Pipeline.SetOrigin(origin);

            // The triangle rast flip flag only affects rasterization, the viewport is not flipped.
            // Setting the origin mode to upper left on the host, however, not only affects rasterization,
            // but also flips the viewport.
            // We negate the effects of flipping the viewport by flipping it again using the viewport swizzle.
            if (origin == Origin.UpperLeft)
            {
                flipY = !flipY;
            }

            Span <Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];

            for (int index = 0; index < Constants.TotalViewports; index++)
            {
                var transform = state.Get <ViewportTransform>(MethodOffset.ViewportTransform, index);
                var extents   = state.Get <ViewportExtents>  (MethodOffset.ViewportExtents, index);

                float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
                float y = transform.TranslateY - MathF.Abs(transform.ScaleY);

                float width  = MathF.Abs(transform.ScaleX) * 2;
                float height = MathF.Abs(transform.ScaleY) * 2;

                float scale = TextureManager.RenderTargetScale;
                if (scale != 1f)
                {
                    x      *= scale;
                    y      *= scale;
                    width  *= scale;
                    height *= scale;
                }

                RectangleF region = new RectangleF(x, y, width, height);

                ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
                ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
                ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
                ViewportSwizzle swizzleW = transform.UnpackSwizzleW();

                if (transform.ScaleX < 0)
                {
                    swizzleX ^= ViewportSwizzle.NegativeFlag;
                }

                if (flipY)
                {
                    swizzleY ^= ViewportSwizzle.NegativeFlag;
                }

                if (transform.ScaleY < 0)
                {
                    swizzleY ^= ViewportSwizzle.NegativeFlag;
                }

                if (transform.ScaleZ < 0)
                {
                    swizzleZ ^= ViewportSwizzle.NegativeFlag;
                }

                viewports[index] = new Viewport(
                    region,
                    swizzleX,
                    swizzleY,
                    swizzleZ,
                    swizzleW,
                    extents.DepthNear,
                    extents.DepthFar);
            }

            _context.Renderer.Pipeline.SetViewports(0, viewports);
        }
Esempio n. 7
0
 /// <summary>
 /// Gets a texture descriptor used on the compute pipeline.
 /// </summary>
 /// <param name="state">Current GPU state</param>
 /// <param name="handle">Shader "fake" handle of the texture</param>
 /// <returns>The texture descriptor</returns>
 public TextureDescriptor GetComputeTextureDescriptor(GpuState state, int handle)
 {
     return(_cpBindingsManager.GetTextureDescriptor(state, 0, handle));
 }
Esempio n. 8
0
        /// <summary>
        /// Finishes the draw call.
        /// This draws geometry on the bound buffers based on the current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        private void DrawEnd(GpuState state, int argument)
        {
            var indexBuffer = state.Get <IndexBufferState>(MethodOffset.IndexBufferState);

            DrawEnd(state, indexBuffer.First, indexBuffer.Count);
        }
Esempio n. 9
0
        /// <summary>
        /// Finishes the draw call.
        /// This draws geometry on the bound buffers based on the current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
        /// <param name="indexCount">Number of index buffer elements used on the draw</param>
        private void DrawEnd(GpuState state, int firstIndex, int indexCount)
        {
            ConditionalRenderEnabled renderEnable = GetRenderEnable(state);

            if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
            {
                if (renderEnable == ConditionalRenderEnabled.False)
                {
                    PerformDeferredDraws();
                }

                _drawIndexed = false;

                if (renderEnable == ConditionalRenderEnabled.Host)
                {
                    _context.Renderer.Pipeline.EndHostConditionalRendering();
                }

                return;
            }

            UpdateState(state, firstIndex, indexCount);

            bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;

            if (instanced)
            {
                _instancedDrawPending = true;

                _instancedIndexed = _drawIndexed;

                _instancedFirstIndex    = firstIndex;
                _instancedFirstVertex   = state.Get <int>(MethodOffset.FirstVertex);
                _instancedFirstInstance = state.Get <int>(MethodOffset.FirstInstance);

                _instancedIndexCount = indexCount;

                var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);

                _instancedDrawStateFirst = drawState.First;
                _instancedDrawStateCount = drawState.Count;

                _drawIndexed = false;

                if (renderEnable == ConditionalRenderEnabled.Host)
                {
                    _context.Renderer.Pipeline.EndHostConditionalRendering();
                }

                return;
            }

            int firstInstance = state.Get <int>(MethodOffset.FirstInstance);

            int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount();

            if (inlineIndexCount != 0)
            {
                int firstVertex = state.Get <int>(MethodOffset.FirstVertex);

                BufferRange br = new BufferRange(_ibStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);

                state.Channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);

                _context.Renderer.Pipeline.DrawIndexed(
                    inlineIndexCount,
                    1,
                    firstIndex,
                    firstVertex,
                    firstInstance);
            }
            else if (_drawIndexed)
            {
                int firstVertex = state.Get <int>(MethodOffset.FirstVertex);

                _context.Renderer.Pipeline.DrawIndexed(
                    indexCount,
                    1,
                    firstIndex,
                    firstVertex,
                    firstInstance);
            }
            else
            {
                var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);

                _context.Renderer.Pipeline.Draw(
                    drawState.Count,
                    1,
                    drawState.First,
                    firstInstance);
            }

            _drawIndexed = false;

            if (renderEnable == ConditionalRenderEnabled.Host)
            {
                _context.Renderer.Pipeline.EndHostConditionalRendering();
            }
        }
Esempio n. 10
0
 /// <summary>
 /// Performs a indexed draw with a low number of index buffer elements,
 /// while also pre-incrementing the current instance value.
 /// </summary>
 /// <param name="state">Current GPU state</param>
 /// <param name="argument">Method call argument</param>
 private void DrawIndexedSmallIncInstance2(GpuState state, int argument)
 {
     DrawIndexedSmallIncInstance(state, argument);
 }
Esempio n. 11
0
 /// <summary>
 /// Pushes one 32-bit index buffer element.
 /// </summary>
 /// <param name="state">Current GPU state</param>
 /// <param name="argument">Method call argument</param>
 private void VbElementU32(GpuState state, int argument)
 {
     _ibStreamer.VbElementU32(_context.Renderer, argument);
 }
Esempio n. 12
0
        /// <summary>
        /// Clears the current color and depth-stencil buffers.
        /// Which buffers should be cleared is also specified on the argument.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        private void Clear(GpuState state, int argument)
        {
            ConditionalRenderEnabled renderEnable = GetRenderEnable(state);

            if (renderEnable == ConditionalRenderEnabled.False)
            {
                return;
            }

            // Scissor and rasterizer discard also affect clears.
            if (state.QueryModified(MethodOffset.ScissorState))
            {
                UpdateScissorState(state);
            }

            if (state.QueryModified(MethodOffset.RasterizeEnable))
            {
                UpdateRasterizerState(state);
            }

            int index = (argument >> 6) & 0xf;

            UpdateRenderTargetState(state, useControl: false, singleUse: index);

            state.Channel.TextureManager.UpdateRenderTargets();

            bool clearDepth   = (argument & 1) != 0;
            bool clearStencil = (argument & 2) != 0;

            uint componentMask = (uint)((argument >> 2) & 0xf);

            if (componentMask != 0)
            {
                var clearColor = state.Get <ClearColors>(MethodOffset.ClearColors);

                ColorF color = new ColorF(
                    clearColor.Red,
                    clearColor.Green,
                    clearColor.Blue,
                    clearColor.Alpha);

                _context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
            }

            if (clearDepth || clearStencil)
            {
                float depthValue   = state.Get <float>(MethodOffset.ClearDepthValue);
                int   stencilValue = state.Get <int>  (MethodOffset.ClearStencilValue);

                int stencilMask = 0;

                if (clearStencil)
                {
                    stencilMask = state.Get <StencilTestState>(MethodOffset.StencilTestState).FrontMask;
                }

                _context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
                    depthValue,
                    clearDepth,
                    stencilValue,
                    stencilMask);
            }

            UpdateRenderTargetState(state, useControl: true);

            if (renderEnable == ConditionalRenderEnabled.Host)
            {
                _context.Renderer.Pipeline.EndHostConditionalRendering();
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Finishes draw call.
        /// This draws geometry on the bound buffers based on the current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        private void DrawEnd(GpuState state, int argument)
        {
            ConditionalRenderEnabled renderEnable = GetRenderEnable(state);

            if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
            {
                if (renderEnable == ConditionalRenderEnabled.False)
                {
                    PerformDeferredDraws();
                }

                _drawIndexed = false;

                if (renderEnable == ConditionalRenderEnabled.Host)
                {
                    _context.Renderer.Pipeline.EndHostConditionalRendering();
                }

                return;
            }

            UpdateState(state);

            bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;

            if (instanced)
            {
                _instancedDrawPending = true;

                _instancedIndexed = _drawIndexed;

                _instancedFirstIndex    = _firstIndex;
                _instancedFirstVertex   = state.Get <int>(MethodOffset.FirstVertex);
                _instancedFirstInstance = state.Get <int>(MethodOffset.FirstInstance);

                _instancedIndexCount = _indexCount;

                var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);

                _instancedDrawStateFirst = drawState.First;
                _instancedDrawStateCount = drawState.Count;

                _drawIndexed = false;

                if (renderEnable == ConditionalRenderEnabled.Host)
                {
                    _context.Renderer.Pipeline.EndHostConditionalRendering();
                }

                return;
            }

            int firstInstance = state.Get <int>(MethodOffset.FirstInstance);

            if (_drawIndexed)
            {
                _drawIndexed = false;

                int firstVertex = state.Get <int>(MethodOffset.FirstVertex);

                _context.Renderer.Pipeline.DrawIndexed(
                    _indexCount,
                    1,
                    _firstIndex,
                    firstVertex,
                    firstInstance);
            }
            else
            {
                var drawState = state.Get <VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);

                _context.Renderer.Pipeline.Draw(
                    drawState.Count,
                    1,
                    drawState.First,
                    firstInstance);
            }

            if (renderEnable == ConditionalRenderEnabled.Host)
            {
                _context.Renderer.Pipeline.EndHostConditionalRendering();
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Gets a graphics shader program from the shader cache.
        /// This includes all the specified shader stages.
        /// </summary>
        /// <remarks>
        /// This automatically translates, compiles and adds the code to the cache if not present.
        /// </remarks>
        /// <param name="state">Current GPU state</param>
        /// <param name="addresses">Addresses of the shaders for each stage</param>
        /// <returns>Compiled graphics shader code</returns>
        public ShaderBundle GetGraphicsShader(GpuState state, ShaderAddresses addresses)
        {
            bool isCached = _gpPrograms.TryGetValue(addresses, out List <ShaderBundle> list);

            if (isCached)
            {
                foreach (ShaderBundle cachedGpShaders in list)
                {
                    if (IsShaderEqual(cachedGpShaders, addresses))
                    {
                        return(cachedGpShaders);
                    }
                }
            }

            TranslatorContext[] shaderContexts = new TranslatorContext[Constants.ShaderStages + 1];

            TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(state);

            TranslationFlags flags = DefaultFlags;

            if (tfd != null)
            {
                flags |= TranslationFlags.Feedback;
            }

            TranslationCounts counts = new TranslationCounts();

            if (addresses.VertexA != 0)
            {
                shaderContexts[0] = DecodeGraphicsShader(state, counts, flags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA);
            }

            shaderContexts[1] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex);
            shaderContexts[2] = DecodeGraphicsShader(state, counts, flags, ShaderStage.TessellationControl, addresses.TessControl);
            shaderContexts[3] = DecodeGraphicsShader(state, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
            shaderContexts[4] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Geometry, addresses.Geometry);
            shaderContexts[5] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Fragment, addresses.Fragment);

            bool isShaderCacheEnabled  = _cacheManager != null;
            bool isShaderCacheReadOnly = false;

            Hash128 programCodeHash = default;

            GuestShaderCacheEntry[] shaderCacheEntries = null;

            // Current shader cache doesn't support bindless textures
            for (int i = 0; i < shaderContexts.Length; i++)
            {
                if (shaderContexts[i] != null && shaderContexts[i].UsedFeatures.HasFlag(FeatureFlags.Bindless))
                {
                    isShaderCacheEnabled = false;
                    break;
                }
            }

            if (isShaderCacheEnabled)
            {
                isShaderCacheReadOnly = _cacheManager.IsReadOnly;

                // Compute hash and prepare data for shader disk cache comparison.
                shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(_context.MemoryManager, shaderContexts);
                programCodeHash    = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd);
            }

            ShaderBundle gpShaders;

            // Search for the program hash in loaded shaders.
            if (!isShaderCacheEnabled || !_gpProgramsDiskCache.TryGetValue(programCodeHash, out gpShaders))
            {
                if (isShaderCacheEnabled)
                {
                    Logger.Debug?.Print(LogClass.Gpu, $"Shader {programCodeHash} not in cache, compiling!");
                }

                // The shader isn't currently cached, translate it and compile it.
                ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages];

                shaders[0] = TranslateShader(shaderContexts[1], shaderContexts[0]);
                shaders[1] = TranslateShader(shaderContexts[2]);
                shaders[2] = TranslateShader(shaderContexts[3]);
                shaders[3] = TranslateShader(shaderContexts[4]);
                shaders[4] = TranslateShader(shaderContexts[5]);

                List <IShader> hostShaders = new List <IShader>();

                for (int stage = 0; stage < Constants.ShaderStages; stage++)
                {
                    ShaderProgram program = shaders[stage]?.Program;

                    if (program == null)
                    {
                        continue;
                    }

                    IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code);

                    shaders[stage].HostShader = hostShader;

                    hostShaders.Add(hostShader);
                }

                IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd);

                hostProgram.CheckProgramLink(true);

                byte[] hostProgramBinary = HostShaderCacheEntry.Create(hostProgram.GetBinary(), shaders);

                gpShaders = new ShaderBundle(hostProgram, shaders);

                if (isShaderCacheEnabled)
                {
                    _gpProgramsDiskCache.Add(programCodeHash, gpShaders);

                    if (!isShaderCacheReadOnly)
                    {
                        _cacheManager.SaveProgram(ref programCodeHash, CacheHelper.CreateGuestProgramDump(shaderCacheEntries, tfd), hostProgramBinary);
                    }
                }
            }

            if (!isCached)
            {
                list = new List <ShaderBundle>();

                _gpPrograms.Add(addresses, list);
            }

            list.Add(gpShaders);

            return(gpShaders);
        }
Esempio n. 15
0
        /// <summary>
        /// Updates render targets (color and depth-stencil buffers) based on current render target state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="useControl">Use draw buffers information from render target control register</param>
        /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
        private void UpdateRenderTargetState(GpuState state, bool useControl, int singleUse = -1)
        {
            var rtControl = state.Get <RtControl>(MethodOffset.RtControl);

            int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;

            var msaaMode = state.Get <TextureMsaaMode>(MethodOffset.RtMsaaMode);

            int samplesInX = msaaMode.SamplesInX();
            int samplesInY = msaaMode.SamplesInY();

            bool changedScale = false;

            for (int index = 0; index < Constants.TotalRenderTargets; index++)
            {
                int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;

                var colorState = state.Get <RtColorState>(MethodOffset.RtColorState, rtIndex);

                if (index >= count || !IsRtEnabled(colorState))
                {
                    changedScale |= TextureManager.SetRenderTargetColor(index, null);

                    continue;
                }

                Texture color = TextureManager.FindOrCreateTexture(colorState, samplesInX, samplesInY);

                changedScale |= TextureManager.SetRenderTargetColor(index, color);

                if (color != null)
                {
                    color.SignalModified();
                }
            }

            bool dsEnable = state.Get <Boolean32>(MethodOffset.RtDepthStencilEnable);

            Texture depthStencil = null;

            if (dsEnable)
            {
                var dsState = state.Get <RtDepthStencilState>(MethodOffset.RtDepthStencilState);
                var dsSize  = state.Get <Size3D>             (MethodOffset.RtDepthStencilSize);

                depthStencil = TextureManager.FindOrCreateTexture(dsState, dsSize, samplesInX, samplesInY);
            }

            changedScale |= TextureManager.SetRenderTargetDepthStencil(depthStencil);

            if (changedScale)
            {
                TextureManager.UpdateRenderTargetScale(singleUse);
                _context.Renderer.Pipeline.SetRenderTargetScale(TextureManager.RenderTargetScale);

                UpdateViewportTransform(state);
                UpdateScissorState(state);
            }

            if (depthStencil != null)
            {
                depthStencil.SignalModified();
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Dispatches compute work.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        public void Dispatch(GpuState state, int argument)
        {
            uint qmdAddress = (uint)state.Get <int>(MethodOffset.DispatchParamsAddress);

            var qmd = _context.MemoryManager.Read <ComputeQmd>((ulong)qmdAddress << 8);

            GpuVa shaderBaseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress);

            ulong shaderGpuVa = shaderBaseAddress.Pack() + (uint)qmd.ProgramOffset;

            int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;

            int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);

            for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
            {
                if (!qmd.ConstantBufferValid(index))
                {
                    continue;
                }

                ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
                ulong size  = (ulong)qmd.ConstantBufferSize(index);

                BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
            }

            ShaderBundle cs = ShaderCache.GetComputeShader(
                state,
                shaderGpuVa,
                qmd.CtaThreadDimension0,
                qmd.CtaThreadDimension1,
                qmd.CtaThreadDimension2,
                localMemorySize,
                sharedMemorySize);

            _context.Renderer.Pipeline.SetProgram(cs.HostProgram);

            var samplerPool = state.Get <PoolState>(MethodOffset.SamplerPoolState);
            var texturePool = state.Get <PoolState>(MethodOffset.TexturePoolState);

            TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);
            TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
            TextureManager.SetComputeTextureBufferIndex(state.Get <int>(MethodOffset.TextureBufferIndex));

            ShaderProgramInfo info = cs.Shaders[0].Info;

            for (int index = 0; index < info.CBuffers.Count; index++)
            {
                BufferDescriptor cb = info.CBuffers[index];

                // NVN uses the "hardware" constant buffer for anything that is less than 8,
                // and those are already bound above.
                // Anything greater than or equal to 8 uses the emulated constant buffers.
                // They are emulated using global memory loads.
                if (cb.Slot < 8)
                {
                    continue;
                }

                ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10;

                cbDescAddress += (ulong)cbDescOffset;

                SbDescriptor cbDescriptor = _context.PhysicalMemory.Read <SbDescriptor>(cbDescAddress);

                BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
            }

            for (int index = 0; index < info.SBuffers.Count; index++)
            {
                BufferDescriptor sb = info.SBuffers[index];

                ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);

                int sbDescOffset = 0x310 + sb.Slot * 0x10;

                sbDescAddress += (ulong)sbDescOffset;

                SbDescriptor sbDescriptor = _context.PhysicalMemory.Read <SbDescriptor>(sbDescAddress);

                BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
            }

            BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
            BufferManager.SetComputeUniformBufferBindings(info.CBuffers);

            var textureBindings = new TextureBindingInfo[info.Textures.Count];

            for (int index = 0; index < info.Textures.Count; index++)
            {
                var descriptor = info.Textures[index];

                Target target = ShaderTexture.GetTarget(descriptor.Type);

                textureBindings[index] = new TextureBindingInfo(
                    target,
                    descriptor.Binding,
                    descriptor.CbufSlot,
                    descriptor.HandleIndex,
                    descriptor.Flags);
            }

            TextureManager.SetComputeTextures(textureBindings);

            var imageBindings = new TextureBindingInfo[info.Images.Count];

            for (int index = 0; index < info.Images.Count; index++)
            {
                var descriptor = info.Images[index];

                Target target = ShaderTexture.GetTarget(descriptor.Type);
                Format format = ShaderTexture.GetFormat(descriptor.Format);

                imageBindings[index] = new TextureBindingInfo(
                    target,
                    format,
                    descriptor.Binding,
                    descriptor.CbufSlot,
                    descriptor.HandleIndex,
                    descriptor.Flags);
            }

            TextureManager.SetComputeImages(imageBindings);

            TextureManager.CommitComputeBindings();
            BufferManager.CommitComputeBindings();

            _context.Renderer.Pipeline.DispatchCompute(
                qmd.CtaRasterWidth,
                qmd.CtaRasterHeight,
                qmd.CtaRasterDepth);

            _forceShaderUpdate = true;
        }
Esempio n. 17
0
        /// <summary>
        /// Updates host depth clamp state based on current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateDepthClampState(GpuState state)
        {
            ViewVolumeClipControl clip = state.Get <ViewVolumeClipControl>(MethodOffset.ViewVolumeClipControl);

            _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0);
        }
Esempio n. 18
0
 /// <summary>
 /// Executes a macro.
 /// </summary>
 /// <param name="index">Index of the macro</param>
 /// <param name="state">Current GPU state</param>
 public void CallMme(int index, GpuState state)
 {
     _macros[index].Execute(_macroCode, state);
 }
Esempio n. 19
0
        /// <summary>
        /// Updates host logical operation state, based on guest state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        public void UpdateLogicOpState(GpuState state)
        {
            LogicalOpState logicOpState = state.Get <LogicalOpState>(MethodOffset.LogicOpState);

            _context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
        }
Esempio n. 20
0
        /// <summary>
        /// Performs a buffer to buffer, or buffer to texture copy.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        /// <param name="argument">Method call argument</param>
        private void CopyBuffer(GpuState state, int argument)
        {
            var cbp = state.Get <CopyBufferParams>(MethodOffset.CopyBufferParams);

            var swizzle = state.Get <CopyBufferSwizzle>(MethodOffset.CopyBufferSwizzle);

            CopyFlags copyFlags = (CopyFlags)argument;

            bool srcLinear = copyFlags.HasFlag(CopyFlags.SrcLinear);
            bool dstLinear = copyFlags.HasFlag(CopyFlags.DstLinear);
            bool copy2D    = copyFlags.HasFlag(CopyFlags.MultiLineEnable);
            bool remap     = copyFlags.HasFlag(CopyFlags.RemapEnable);

            int size = cbp.XCount;

            if (size == 0)
            {
                return;
            }

            FlushUboUpdate();

            if (copy2D)
            {
                // Buffer to texture copy.
                int srcBpp = remap ? swizzle.UnpackSrcComponentsCount() * swizzle.UnpackComponentSize() : 1;
                int dstBpp = remap ? swizzle.UnpackDstComponentsCount() * swizzle.UnpackComponentSize() : 1;

                var dst = state.Get <CopyBufferTexture>(MethodOffset.CopyBufferDstTexture);
                var src = state.Get <CopyBufferTexture>(MethodOffset.CopyBufferSrcTexture);

                var srcCalculator = new OffsetCalculator(
                    src.Width,
                    src.Height,
                    cbp.SrcStride,
                    srcLinear,
                    src.MemoryLayout.UnpackGobBlocksInY(),
                    src.MemoryLayout.UnpackGobBlocksInZ(),
                    srcBpp);

                var dstCalculator = new OffsetCalculator(
                    dst.Width,
                    dst.Height,
                    cbp.DstStride,
                    dstLinear,
                    dst.MemoryLayout.UnpackGobBlocksInY(),
                    dst.MemoryLayout.UnpackGobBlocksInZ(),
                    dstBpp);

                ulong srcBaseAddress = _context.MemoryManager.Translate(cbp.SrcAddress.Pack());
                ulong dstBaseAddress = _context.MemoryManager.Translate(cbp.DstAddress.Pack());

                (int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, cbp.XCount, cbp.YCount);
                (int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, cbp.XCount, cbp.YCount);

                ReadOnlySpan <byte> srcSpan = _context.PhysicalMemory.GetSpan(srcBaseAddress + (ulong)srcBaseOffset, srcSize, true);
                Span <byte>         dstSpan = _context.PhysicalMemory.GetSpan(dstBaseAddress + (ulong)dstBaseOffset, dstSize).ToArray();

                bool completeSource = IsTextureCopyComplete(cbp, src, srcLinear, srcBpp, cbp.SrcStride);
                bool completeDest   = IsTextureCopyComplete(cbp, dst, dstLinear, dstBpp, cbp.DstStride);

                if (completeSource && completeDest)
                {
                    Image.Texture target = TextureManager.FindTexture(dst, cbp, swizzle, dstLinear);
                    if (target != null)
                    {
                        ReadOnlySpan <byte> data;
                        if (srcLinear)
                        {
                            data = LayoutConverter.ConvertLinearStridedToLinear(
                                target.Info.Width,
                                target.Info.Height,
                                1,
                                1,
                                cbp.SrcStride,
                                target.Info.FormatInfo.BytesPerPixel,
                                srcSpan);
                        }
                        else
                        {
                            data = LayoutConverter.ConvertBlockLinearToLinear(
                                src.Width,
                                src.Height,
                                1,
                                target.Info.Levels,
                                1,
                                1,
                                1,
                                srcBpp,
                                src.MemoryLayout.UnpackGobBlocksInY(),
                                src.MemoryLayout.UnpackGobBlocksInZ(),
                                1,
                                new SizeInfo((int)target.Size),
                                srcSpan);
                        }

                        target.SetData(data);
                        target.SignalModified();

                        return;
                    }
                    else if (srcCalculator.LayoutMatches(dstCalculator))
                    {
                        srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely.

                        _context.PhysicalMemory.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);

                        return;
                    }
                }

                unsafe bool Convert <T>(Span <byte> dstSpan, ReadOnlySpan <byte> srcSpan) where T : unmanaged
                {
                    fixed(byte *dstPtr = dstSpan, srcPtr = srcSpan)
                    {
                        byte *dstBase = dstPtr - dstBaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
                        byte *srcBase = srcPtr - srcBaseOffset;

                        for (int y = 0; y < cbp.YCount; y++)
                        {
                            srcCalculator.SetY(src.RegionY + y);
                            dstCalculator.SetY(dst.RegionY + y);

                            for (int x = 0; x < cbp.XCount; x++)
                            {
                                int srcOffset = srcCalculator.GetOffset(src.RegionX + x);
                                int dstOffset = dstCalculator.GetOffset(dst.RegionX + x);

                                *(T *)(dstBase + dstOffset) = *(T *)(srcBase + srcOffset);
                            }
                        }
                    }

                    return(true);
                }

                bool _ = srcBpp switch
                {
                    1 => Convert <byte>(dstSpan, srcSpan),
                    2 => Convert <ushort>(dstSpan, srcSpan),
                    4 => Convert <uint>(dstSpan, srcSpan),
                    8 => Convert <ulong>(dstSpan, srcSpan),
                    12 => Convert <Bpp12Pixel>(dstSpan, srcSpan),
                    16 => Convert <Vector128 <byte> >(dstSpan, srcSpan),
                    _ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.")
                };

                _context.PhysicalMemory.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
            }
            else
            {
                if (remap &&
                    swizzle.UnpackDstX() == BufferSwizzleComponent.ConstA &&
                    swizzle.UnpackDstY() == BufferSwizzleComponent.ConstA &&
                    swizzle.UnpackDstZ() == BufferSwizzleComponent.ConstA &&
                    swizzle.UnpackDstW() == BufferSwizzleComponent.ConstA &&
                    swizzle.UnpackSrcComponentsCount() == 1 &&
                    swizzle.UnpackDstComponentsCount() == 1 &&
                    swizzle.UnpackComponentSize() == 4)
                {
                    // Fast path for clears when remap is enabled.
                    BufferManager.ClearBuffer(cbp.DstAddress, (uint)size * 4, state.Get <uint>(MethodOffset.CopyBufferConstA));
                }
                else
                {
                    // TODO: Implement remap functionality.
                    // Buffer to buffer copy.
                    BufferManager.CopyBuffer(cbp.SrcAddress, cbp.DstAddress, (uint)size);
                }
            }
        }
Esempio n. 21
0
 /// <summary>
 /// Gets a texture descriptor used on the graphics pipeline.
 /// </summary>
 /// <param name="state">Current GPU state</param>
 /// <param name="stageIndex">Index of the shader stage where the texture is bound</param>
 /// <param name="handle">Shader "fake" handle of the texture</param>
 /// <returns>The texture descriptor</returns>
 public TextureDescriptor GetGraphicsTextureDescriptor(GpuState state, int stageIndex, int handle)
 {
     return(_gpBindingsManager.GetTextureDescriptor(state, stageIndex, handle));
 }
Esempio n. 22
0
 /// <summary>
 /// Creates a new instance of the GPU state accessor for graphics shader translation.
 /// </summary>
 /// <param name="context">GPU context</param>
 /// <param name="state">Current GPU state</param>
 /// <param name="stageIndex">Graphics shader stage index (0 = Vertex, 4 = Fragment)</param>
 public GpuAccessor(GpuContext context, GpuState state, int stageIndex)
 {
     _context    = context;
     _state      = state;
     _stageIndex = stageIndex;
 }
Esempio n. 23
0
        /// <summary>
        /// Updates host state based on the current guest GPU state.
        /// </summary>
        /// <param name="state">Guest GPU state</param>
        private void UpdateState(GpuState state)
        {
            // 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.
            if (state.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState))
            {
                UpdateShaderState(state);
            }

            if (state.QueryModified(MethodOffset.RtColorState,
                                    MethodOffset.RtDepthStencilState,
                                    MethodOffset.RtControl,
                                    MethodOffset.RtDepthStencilSize,
                                    MethodOffset.RtDepthStencilEnable))
            {
                UpdateRenderTargetState(state, useControl: true);
            }

            if (state.QueryModified(MethodOffset.ScissorState))
            {
                UpdateScissorState(state);
            }

            if (state.QueryModified(MethodOffset.DepthTestEnable,
                                    MethodOffset.DepthWriteEnable,
                                    MethodOffset.DepthTestFunc))
            {
                UpdateDepthTestState(state);
            }

            if (state.QueryModified(MethodOffset.DepthMode, MethodOffset.ViewportTransform, MethodOffset.ViewportExtents))
            {
                UpdateViewportTransform(state);
            }

            if (state.QueryModified(MethodOffset.DepthBiasState,
                                    MethodOffset.DepthBiasFactor,
                                    MethodOffset.DepthBiasUnits,
                                    MethodOffset.DepthBiasClamp))
            {
                UpdateDepthBiasState(state);
            }

            if (state.QueryModified(MethodOffset.StencilBackMasks,
                                    MethodOffset.StencilTestState,
                                    MethodOffset.StencilBackTestState))
            {
                UpdateStencilTestState(state);
            }

            // Pools.
            if (state.QueryModified(MethodOffset.SamplerPoolState, MethodOffset.SamplerIndex))
            {
                UpdateSamplerPoolState(state);
            }

            if (state.QueryModified(MethodOffset.TexturePoolState))
            {
                UpdateTexturePoolState(state);
            }

            // Input assembler state.
            if (state.QueryModified(MethodOffset.VertexAttribState))
            {
                UpdateVertexAttribState(state);
            }

            if (state.QueryModified(MethodOffset.PointSize))
            {
                UpdatePointSizeState(state);
            }

            if (state.QueryModified(MethodOffset.PrimitiveRestartState))
            {
                UpdatePrimitiveRestartState(state);
            }

            if (state.QueryModified(MethodOffset.IndexBufferState))
            {
                UpdateIndexBufferState(state);
            }

            if (state.QueryModified(MethodOffset.VertexBufferDrawState,
                                    MethodOffset.VertexBufferInstanced,
                                    MethodOffset.VertexBufferState,
                                    MethodOffset.VertexBufferEndAddress))
            {
                UpdateVertexBufferState(state);
            }

            if (state.QueryModified(MethodOffset.FaceState))
            {
                UpdateFaceState(state);
            }

            if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
            {
                UpdateRtColorMask(state);
            }

            if (state.QueryModified(MethodOffset.BlendIndependent,
                                    MethodOffset.BlendStateCommon,
                                    MethodOffset.BlendEnableCommon,
                                    MethodOffset.BlendEnable,
                                    MethodOffset.BlendState))
            {
                UpdateBlendState(state);
            }

            CommitBindings();
        }
Esempio n. 24
0
        /// <summary>
        /// Gets a graphics shader program from the shader cache.
        /// This includes all the specified shader stages.
        /// </summary>
        /// <remarks>
        /// This automatically translates, compiles and adds the code to the cache if not present.
        /// </remarks>
        /// <param name="state">Current GPU state</param>
        /// <param name="addresses">Addresses of the shaders for each stage</param>
        /// <returns>Compiled graphics shader code</returns>
        public ShaderBundle GetGraphicsShader(GpuState state, ShaderAddresses addresses)
        {
            bool isCached = _gpPrograms.TryGetValue(addresses, out List <ShaderBundle> list);

            if (isCached)
            {
                foreach (ShaderBundle cachedGpShaders in list)
                {
                    if (IsShaderEqual(cachedGpShaders, addresses))
                    {
                        return(cachedGpShaders);
                    }
                }
            }

            ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages];

            var tfd = GetTransformFeedbackDescriptors(state);

            TranslationFlags flags = DefaultFlags;

            if (tfd != null)
            {
                flags |= TranslationFlags.Feedback;
            }

            if (addresses.VertexA != 0)
            {
                shaders[0] = TranslateGraphicsShader(state, flags, ShaderStage.Vertex, addresses.Vertex, addresses.VertexA);
            }
            else
            {
                shaders[0] = TranslateGraphicsShader(state, flags, ShaderStage.Vertex, addresses.Vertex);
            }

            shaders[1] = TranslateGraphicsShader(state, flags, ShaderStage.TessellationControl, addresses.TessControl);
            shaders[2] = TranslateGraphicsShader(state, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
            shaders[3] = TranslateGraphicsShader(state, flags, ShaderStage.Geometry, addresses.Geometry);
            shaders[4] = TranslateGraphicsShader(state, flags, ShaderStage.Fragment, addresses.Fragment);

            List <IShader> hostShaders = new List <IShader>();

            for (int stage = 0; stage < Constants.ShaderStages; stage++)
            {
                ShaderProgram program = shaders[stage]?.Program;

                if (program == null)
                {
                    continue;
                }

                IShader hostShader = _context.Renderer.CompileShader(program);

                shaders[stage].HostShader = hostShader;

                hostShaders.Add(hostShader);
            }

            IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), tfd);

            ShaderBundle gpShaders = new ShaderBundle(hostProgram, shaders);

            if (!isCached)
            {
                list = new List <ShaderBundle>();

                _gpPrograms.Add(addresses, list);
            }

            list.Add(gpShaders);

            return(gpShaders);
        }
Esempio n. 25
0
        /// <summary>
        /// Updates host shaders based on the guest GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateShaderState(GpuState state)
        {
            ShaderAddresses addresses = new ShaderAddresses();

            Span <ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);

            Span <ulong> addressesArray = MemoryMarshal.Cast <ShaderAddresses, ulong>(addressesSpan);

            ulong baseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress).Pack();

            for (int index = 0; index < 6; index++)
            {
                var shader = state.Get <ShaderState>(MethodOffset.ShaderState, index);

                if (!shader.UnpackEnable() && index != 1)
                {
                    continue;
                }

                addressesArray[index] = baseAddress + shader.Offset;
            }

            GraphicsShader gs = ShaderCache.GetGraphicsShader(state, addresses);

            _vsUsesInstanceId = gs.Shaders[0]?.Program.Info.UsesInstanceId ?? false;

            for (int stage = 0; stage < Constants.ShaderStages; stage++)
            {
                ShaderProgramInfo info = gs.Shaders[stage]?.Program.Info;

                _currentProgramInfo[stage] = info;

                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];

                    Target target = GetTarget(descriptor.Type);

                    if (descriptor.IsBindless)
                    {
                        textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufSlot, descriptor.CbufOffset);
                    }
                    else
                    {
                        textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
                    }
                }

                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);

                uint sbEnableMask = 0;
                uint ubEnableMask = 0;

                for (int index = 0; index < info.SBuffers.Count; index++)
                {
                    sbEnableMask |= 1u << info.SBuffers[index].Slot;
                }

                for (int index = 0; index < info.CBuffers.Count; index++)
                {
                    ubEnableMask |= 1u << info.CBuffers[index].Slot;
                }

                BufferManager.SetGraphicsStorageBufferEnableMask(stage, sbEnableMask);
                BufferManager.SetGraphicsUniformBufferEnableMask(stage, ubEnableMask);
            }

            _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
        }
Esempio n. 26
0
        /// <summary>
        /// Updates host state based on the current guest GPU state.
        /// </summary>
        /// <param name="state">Guest GPU state</param>
        private void UpdateState(GpuState state)
        {
            bool tfEnable = state.Get <Boolean32>(MethodOffset.TfEnable);

            if (!tfEnable && _prevTfEnable)
            {
                _context.Renderer.Pipeline.EndTransformFeedback();
                _prevTfEnable = false;
            }

            // 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.
            if (state.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState) || _forceShaderUpdate)
            {
                _forceShaderUpdate = false;

                UpdateShaderState(state);
            }

            if (state.QueryModified(MethodOffset.TfBufferState))
            {
                UpdateTfBufferState(state);
            }

            if (state.QueryModified(MethodOffset.ClipDistanceEnable))
            {
                UpdateUserClipState(state);
            }

            if (state.QueryModified(MethodOffset.RasterizeEnable))
            {
                UpdateRasterizerState(state);
            }

            if (state.QueryModified(MethodOffset.RtColorState,
                                    MethodOffset.RtDepthStencilState,
                                    MethodOffset.RtControl,
                                    MethodOffset.RtDepthStencilSize,
                                    MethodOffset.RtDepthStencilEnable))
            {
                UpdateRenderTargetState(state, useControl: true);
            }

            if (state.QueryModified(MethodOffset.ScissorState))
            {
                UpdateScissorState(state);
            }

            if (state.QueryModified(MethodOffset.ViewVolumeClipControl))
            {
                UpdateDepthClampState(state);
            }

            if (state.QueryModified(MethodOffset.DepthTestEnable,
                                    MethodOffset.DepthWriteEnable,
                                    MethodOffset.DepthTestFunc))
            {
                UpdateDepthTestState(state);
            }

            if (state.QueryModified(MethodOffset.DepthMode,
                                    MethodOffset.ViewportTransform,
                                    MethodOffset.ViewportExtents))
            {
                UpdateViewportTransform(state);
            }

            if (state.QueryModified(MethodOffset.DepthBiasState,
                                    MethodOffset.DepthBiasFactor,
                                    MethodOffset.DepthBiasUnits,
                                    MethodOffset.DepthBiasClamp))
            {
                UpdateDepthBiasState(state);
            }

            if (state.QueryModified(MethodOffset.StencilBackMasks,
                                    MethodOffset.StencilTestState,
                                    MethodOffset.StencilBackTestState))
            {
                UpdateStencilTestState(state);
            }

            // Pools.
            if (state.QueryModified(MethodOffset.SamplerPoolState, MethodOffset.SamplerIndex))
            {
                UpdateSamplerPoolState(state);
            }

            if (state.QueryModified(MethodOffset.TexturePoolState))
            {
                UpdateTexturePoolState(state);
            }

            // Input assembler state.
            if (state.QueryModified(MethodOffset.VertexAttribState))
            {
                UpdateVertexAttribState(state);
            }

            if (state.QueryModified(MethodOffset.PointSize,
                                    MethodOffset.VertexProgramPointSize,
                                    MethodOffset.PointSpriteEnable,
                                    MethodOffset.PointCoordReplace))
            {
                UpdatePointState(state);
            }

            if (state.QueryModified(MethodOffset.PrimitiveRestartState))
            {
                UpdatePrimitiveRestartState(state);
            }

            if (state.QueryModified(MethodOffset.IndexBufferState))
            {
                UpdateIndexBufferState(state);
            }

            if (state.QueryModified(MethodOffset.VertexBufferDrawState,
                                    MethodOffset.VertexBufferInstanced,
                                    MethodOffset.VertexBufferState,
                                    MethodOffset.VertexBufferEndAddress))
            {
                UpdateVertexBufferState(state);
            }

            if (state.QueryModified(MethodOffset.FaceState))
            {
                UpdateFaceState(state);
            }

            if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
            {
                UpdateRtColorMask(state);
            }

            if (state.QueryModified(MethodOffset.BlendIndependent,
                                    MethodOffset.BlendConstant,
                                    MethodOffset.BlendStateCommon,
                                    MethodOffset.BlendEnableCommon,
                                    MethodOffset.BlendEnable,
                                    MethodOffset.BlendState))
            {
                UpdateBlendState(state);
            }

            if (state.QueryModified(MethodOffset.LogicOpState))
            {
                UpdateLogicOpState(state);
            }

            CommitBindings();

            if (tfEnable && !_prevTfEnable)
            {
                _context.Renderer.Pipeline.BeginTransformFeedback(PrimitiveType.Convert());
                _prevTfEnable = true;
            }
        }
Esempio n. 27
0
 /// <summary>
 /// Issues a texture barrier.
 /// This waits until previous texture writes from the GPU to finish, before
 /// performing new operations with said textures.
 /// This performs a per-tile wait, it is only valid if both the previous write
 /// and current access has the same access patterns.
 /// This may be faster than the regular barrier on tile-based rasterizers.
 /// </summary>
 /// <param name="state">Current GPU state (unused)</param>
 /// <param name="argument">Method call argument (unused)</param>
 private void TextureBarrierTiled(GpuState state, int argument)
 {
     _context.Renderer.Pipeline.TextureBarrierTiled();
 }
Esempio n. 28
0
        /// <summary>
        /// Updates Rasterizer primitive discard state based on guest gpu state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateRasterizerState(GpuState state)
        {
            Boolean32 enable = state.Get <Boolean32>(MethodOffset.RasterizeEnable);

            _context.Renderer.Pipeline.SetRasterizerDiscard(!enable);
        }
Esempio n. 29
0
 /// <summary>
 /// Performs a indexed draw with a low number of index buffer elements.
 /// </summary>
 /// <param name="state">Current GPU state</param>
 /// <param name="argument">Method call argument</param>
 private void DrawIndexedSmall2(GpuState state, int argument)
 {
     DrawIndexedSmall(state, argument);
 }
Esempio n. 30
0
        /// <summary>
        /// Updates host shaders based on the guest GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateShaderState(GpuState state)
        {
            ShaderAddresses addresses = new ShaderAddresses();

            Span <ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);

            Span <ulong> addressesArray = MemoryMarshal.Cast <ShaderAddresses, ulong>(addressesSpan);

            ulong baseAddress = state.Get <GpuVa>(MethodOffset.ShaderBaseAddress).Pack();

            for (int index = 0; index < 6; index++)
            {
                var shader = state.Get <ShaderState>(MethodOffset.ShaderState, index);

                if (!shader.UnpackEnable() && index != 1)
                {
                    continue;
                }

                addressesArray[index] = baseAddress + shader.Offset;
            }

            ShaderBundle gs = state.Channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(state, addresses);

            byte oldVsClipDistancesWritten = _vsClipDistancesWritten;

            _vsUsesInstanceId       = gs.Shaders[0]?.Info.UsesInstanceId ?? false;
            _vsClipDistancesWritten = gs.Shaders[0]?.Info.ClipDistancesWritten ?? 0;

            if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
            {
                UpdateUserClipState(state);
            }

            int storageBufferBindingsCount = 0;
            int uniformBufferBindingsCount = 0;

            for (int stage = 0; stage < Constants.ShaderStages; stage++)
            {
                ShaderProgramInfo info = gs.Shaders[stage]?.Info;

                _currentProgramInfo[stage] = info;

                if (info == null)
                {
                    state.Channel.TextureManager.SetGraphicsTextures(stage, Array.Empty <TextureBindingInfo>());
                    state.Channel.TextureManager.SetGraphicsImages(stage, Array.Empty <TextureBindingInfo>());
                    state.Channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
                    state.Channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
                    continue;
                }

                var textureBindings = new TextureBindingInfo[info.Textures.Count];

                for (int index = 0; index < info.Textures.Count; index++)
                {
                    var descriptor = info.Textures[index];

                    Target target = ShaderTexture.GetTarget(descriptor.Type);

                    textureBindings[index] = new TextureBindingInfo(
                        target,
                        descriptor.Binding,
                        descriptor.CbufSlot,
                        descriptor.HandleIndex,
                        descriptor.Flags);
                }

                state.Channel.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 = ShaderTexture.GetTarget(descriptor.Type);
                    Format format = ShaderTexture.GetFormat(descriptor.Format);

                    imageBindings[index] = new TextureBindingInfo(
                        target,
                        format,
                        descriptor.Binding,
                        descriptor.CbufSlot,
                        descriptor.HandleIndex,
                        descriptor.Flags);
                }

                state.Channel.TextureManager.SetGraphicsImages(stage, imageBindings);

                state.Channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
                state.Channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);

                if (info.SBuffers.Count != 0)
                {
                    storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
                }

                if (info.CBuffers.Count != 0)
                {
                    uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
                }
            }

            state.Channel.BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
            state.Channel.BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);

            _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
        }