/// <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) { if (_textureBindings[stageIndex] == null || _textureBindings[stageIndex].Length == 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; } if (samplerPool == null) { Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses textures, but sampler pool was not set."); return; } for (int index = 0; index < _textureBindings[stageIndex].Length; index++) { TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; int textureBufferIndex; int samplerBufferIndex; if (bindingInfo.CbufSlot < 0) { textureBufferIndex = _textureBufferIndex; samplerBufferIndex = textureBufferIndex; } else { textureBufferIndex = bindingInfo.CbufSlot & SlotMask; samplerBufferIndex = ((bindingInfo.CbufSlot >> SlotHigh) != 0) ? (bindingInfo.CbufSlot >> SlotHigh) - 1 : 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 (_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); } 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); } Sampler sampler = samplerPool.Get(samplerId); ISampler hostSampler = sampler?.HostSampler; 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) { if (_imageBindings[stageIndex] == null) { return; } // Scales for images appear after the texture ones. int baseScaleIndex = _textureBindings[stageIndex]?.Length ?? 0; for (int index = 0; index < _imageBindings[stageIndex].Length; index++) { TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index]; int textureBufferIndex; int samplerBufferIndex; if (bindingInfo.CbufSlot < 0) { textureBufferIndex = _textureBufferIndex; samplerBufferIndex = textureBufferIndex; } else { textureBufferIndex = bindingInfo.CbufSlot & SlotMask; samplerBufferIndex = ((bindingInfo.CbufSlot >> SlotHigh) != 0) ? (bindingInfo.CbufSlot >> SlotHigh) - 1 : 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> /// 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> /// 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) { if (_textureBindings[stageIndex] == null) { return; } for (int index = 0; index < _textureBindings[stageIndex].Length; index++) { TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; int textureBufferIndex = bindingInfo.CbufSlot < 0 ? _textureBufferIndex : bindingInfo.CbufSlot; int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex); 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 (_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); } if (hostTexture != null && texture.Info.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. _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Address, texture.Size, _isCompute); } Sampler sampler = _samplerPool.Get(samplerId); ISampler hostSampler = sampler?.HostSampler; if (_textureState[stageIndex][index].Sampler != hostSampler || _rebind) { _textureState[stageIndex][index].Sampler = hostSampler; _context.Renderer.Pipeline.SetSampler(bindingInfo.Binding, hostSampler); } } }