/// <summary> /// Gets the texture descriptor for a given texture handle. /// </summary> /// <param name="poolGpuVa">GPU virtual address of the texture pool</param> /// <param name="bufferIndex">Index of the constant buffer with texture handles</param> /// <param name="maximumId">Maximum ID of the texture pool</param> /// <param name="stageIndex">The stage number where the texture is bound</param> /// <param name="handle">The texture handle</param> /// <param name="cbufSlot">The texture handle's constant buffer slot</param> /// <returns>The texture descriptor for the specified texture</returns> public TextureDescriptor GetTextureDescriptor( ulong poolGpuVa, int bufferIndex, int maximumId, int stageIndex, int handle, int cbufSlot) { (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(cbufSlot, bufferIndex); int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, samplerBufferIndex); int textureId = UnpackTextureId(packedId); ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa); TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId); return(texturePool.GetDescriptor(textureId)); }
/// <summary> /// Ensures that the texture bindings are visible to the host GPU. /// Note: this actually performs the binding using the host graphics API. /// </summary> /// <param name="pool">The current texture pool</param> /// <param name="stage">The shader stage using the textures to be bound</param> /// <param name="stageIndex">The stage number of the specified shader stage</param> private void CommitTextureBindings(TexturePool pool, ShaderStage stage, int stageIndex) { int textureCount = _textureBindingsCount[stageIndex]; if (textureCount == 0) { return; } var samplerPool = _samplerPool; if (pool == null) { Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses textures, but texture pool was not set."); return; } for (int index = 0; index < textureCount; index++) { TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex); int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex, samplerBufferIndex); int textureId = UnpackTextureId(packedId); int samplerId; if (_samplerIndex == SamplerIndex.ViaHeaderIndex) { samplerId = textureId; } else { samplerId = UnpackSamplerId(packedId); } Texture texture = pool.Get(textureId); ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); if (hostTexture != null && texture.Target == Target.TextureBuffer) { // Ensure that the buffer texture is using the correct buffer as storage. // Buffers are frequently re-created to accomodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. _channel.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false); } else { if (_textureState[stageIndex][index].Texture != hostTexture || _rebind) { if (UpdateScale(texture, bindingInfo, index, stage)) { hostTexture = texture?.GetTargetTexture(bindingInfo.Target); } _textureState[stageIndex][index].Texture = hostTexture; _context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTexture); } Sampler sampler = samplerPool?.Get(samplerId); ISampler hostSampler = sampler?.GetHostSampler(texture); if (_textureState[stageIndex][index].Sampler != hostSampler || _rebind) { _textureState[stageIndex][index].Sampler = hostSampler; _context.Renderer.Pipeline.SetSampler(bindingInfo.Binding, hostSampler); } } } }
/// <summary> /// Ensures that the image bindings are visible to the host GPU. /// Note: this actually performs the binding using the host graphics API. /// </summary> /// <param name="pool">The current texture pool</param> /// <param name="stage">The shader stage using the textures to be bound</param> /// <param name="stageIndex">The stage number of the specified shader stage</param> private void CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex) { int imageCount = _imageBindingsCount[stageIndex]; if (imageCount == 0) { return; } if (pool == null) { Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses images, but texture pool was not set."); return; } // Scales for images appear after the texture ones. int baseScaleIndex = _textureBindingsCount[stageIndex]; for (int index = 0; index < imageCount; index++) { TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index]; (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex); int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex, samplerBufferIndex); int textureId = UnpackTextureId(packedId); Texture texture = pool.Get(textureId); ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore); if (hostTexture != null && texture.Target == Target.TextureBuffer) { // Ensure that the buffer texture is using the correct buffer as storage. // Buffers are frequently re-created to accomodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. Format format = bindingInfo.Format; if (format == 0 && texture != null) { format = texture.Format; } _channel.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true); } else { if (isStore) { texture?.SignalModified(); } if (_imageState[stageIndex][index].Texture != hostTexture || _rebind) { if (UpdateScale(texture, bindingInfo, baseScaleIndex + index, stage)) { hostTexture = texture?.GetTargetTexture(bindingInfo.Target); } _imageState[stageIndex][index].Texture = hostTexture; Format format = bindingInfo.Format; if (format == 0 && texture != null) { format = texture.Format; } _context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format); } } } }
/// <summary> /// Checks if the recorded state matches the current GPU state. /// </summary> /// <param name="channel">GPU channel</param> /// <param name="poolState">Texture pool state</param> /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param> /// <returns>True if the state matches, false otherwise</returns> private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool isCompute) { int constantBufferUsePerStageMask = _constantBufferUsePerStage; while (constantBufferUsePerStageMask != 0) { int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask); uint useMask = isCompute ? channel.BufferManager.GetComputeUniformBufferUseMask() : channel.BufferManager.GetGraphicsUniformBufferUseMask(index); if (ConstantBufferUse[index] != useMask) { return(false); } constantBufferUsePerStageMask &= ~(1 << index); } foreach (var kv in _textureSpecialization) { TextureKey textureKey = kv.Key; (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex); ulong textureCbAddress; ulong samplerCbAddress; if (isCompute) { textureCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex); samplerCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex); } else { textureCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, textureBufferIndex); samplerCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, samplerBufferIndex); } if (!channel.MemoryManager.Physical.IsMapped(textureCbAddress) || !channel.MemoryManager.Physical.IsMapped(samplerCbAddress)) { continue; } Image.TextureDescriptor descriptor; if (isCompute) { descriptor = channel.TextureManager.GetComputeTextureDescriptor( poolState.TexturePoolGpuVa, poolState.TextureBufferIndex, poolState.TexturePoolMaximumId, textureKey.Handle, textureKey.CbufSlot); } else { descriptor = channel.TextureManager.GetGraphicsTextureDescriptor( poolState.TexturePoolGpuVa, poolState.TextureBufferIndex, poolState.TexturePoolMaximumId, textureKey.StageIndex, textureKey.Handle, textureKey.CbufSlot); } Box <TextureSpecializationState> specializationState = kv.Value; if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) && specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized()) { return(false); } } return(true); }