Implemented Materials

- Shaders get Textureslots via reflection
- added Textureslots to Effect
This commit is contained in:
Simon Lübeß
2021-08-09 18:03:47 +02:00
parent 2326e69c0c
commit 344accea60
10 changed files with 463 additions and 75 deletions
@@ -174,19 +174,61 @@ namespace GlitchyEngine.Renderer
public override void SetVertexShader(VertexShader vertexShader)
{
//Todo: nativeContext.VertexShader.SetSamplers();
uint32 _firstTexture = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
uint32 _textureCount = 0;
ID3D11ShaderResourceView*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _textures = .();
ID3D11SamplerState*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _samplers = .();
for(let entry in vertexShader.Textures)
{
_textures[entry.Index] = entry.Texture?.nativeView;
_samplers[entry.Index] = entry.Texture?.SamplerState?.nativeSamplerState;
if(entry.Index >= _textureCount)
_textureCount = entry.Index + 1;
if(entry.Index < _firstTexture)
_firstTexture = entry.Index;
}
if(_textureCount > 0)
{
nativeContext.VertexShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]);
nativeContext.VertexShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]);
}
vertexShader.Buffers.PlatformFetchNativeBuffers();
nativeContext.VertexShader.SetConstantBuffers(0, vertexShader.Buffers.nativeBuffers.Count, &vertexShader.Buffers.nativeBuffers);
//Todo: nativeContext.VertexShader.SetShaderResources();
nativeContext.VertexShader.SetShader(vertexShader.nativeShader);
}
public override void SetPixelShader(PixelShader pixelShader)
{
//Todo: nativeContext.PixelShader.SetSamplers();
uint32 _firstTexture = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
uint32 _textureCount = 0;
ID3D11ShaderResourceView*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _textures = .();
ID3D11SamplerState*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _samplers = .();
for(let entry in pixelShader.Textures)
{
_textures[entry.Index] = entry.Texture?.nativeView;
_samplers[entry.Index] = entry.Texture?.SamplerState?.nativeSamplerState;
if(entry.Index >= _textureCount)
_textureCount = entry.Index + 1;
if(entry.Index < _firstTexture)
_firstTexture = entry.Index;
}
if(_textureCount > 0)
{
nativeContext.PixelShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]);
nativeContext.PixelShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]);
}
pixelShader.Buffers.PlatformFetchNativeBuffers();
nativeContext.PixelShader.SetConstantBuffers(0, pixelShader.Buffers.nativeBuffers.Count, &pixelShader.Buffers.nativeBuffers);
//Todo: nativeContext.PixelShader.SetShaderResources();
nativeContext.PixelShader.SetShader(pixelShader.nativeShader);
}
}
@@ -16,7 +16,7 @@ namespace GlitchyEngine.Renderer
*/
internal ID3DBlob* nativeCode ~ _?.Release();
protected const ShaderCompileFlags DefaultCompileFlags =
protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness |
#if DEBUG
.Debug;
#else
@@ -57,56 +57,43 @@ namespace GlitchyEngine.Renderer
}
reflection.GetDescription(let desc);
uint32 cBufferCount = desc.ConstantBuffers;
for(uint32 i < cBufferCount)
uint32 resourceCount = desc.BoundResources;
for (uint32 i < resourceCount)
{
reflection.GetResourceBindingDescription(i, let bindDesc);
var res = reflection.GetResourceBindingDescription(i, let bindDesc);
var bufferReflection = reflection.GetConstantBufferByIndex(i);
bufferReflection.GetDescription(let bufferDesc);
// ConstantBuffer
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
if (res.Failed)
{
let buffer = new ConstantBuffer(_context, bufferReflection);
_buffers.Add(bindDesc.BindPoint, buffer.Name, buffer);
buffer.ReleaseRef();
Log.EngineLogger.Error($"Error({(int)res}) {res}: Failed to get resource binding desc for resource {i}");
continue;
}
/*
bufferReflection.GetDescription(let bufferDesc);
// ConstantBuffer
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
switch(bindDesc.Type)
{
GlitchyEngine.Renderer.BufferDescription cBufferDesc = .(bufferDesc.Size, .Constant, .Dynamic, .Write);
case .ConstantBuffer:
var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name);
let buffer = new Buffer(_context, cBufferDesc);
bufferReflection.GetDescription(let bufferDesc);
_buffers.Add(bindDesc.BindPoint, StringView(bufferDesc.Name), buffer);//, true
buffer.ReleaseRef();
// Buffer for default values
uint8* rawData = new:ScopedAlloc! uint8[bufferDesc.Size]*;
// Get default values
for(uint32 variable < bufferDesc.Variables)
// ConstantBuffer
if(bufferDesc.Type == .D3D11_CT_CBUFFER)
{
let variableReflection = bufferReflection.GetVariableByIndex(variable);
let buffer = new ConstantBuffer(_context, bufferReflection);
variableReflection.GetDescription(let varDesc);
_buffers.Add(bindDesc.BindPoint, buffer.Name, buffer);
if(varDesc.DefaultValue != null)
Internal.MemCpy(rawData + varDesc.StartOffset, varDesc.DefaultValue, varDesc.Size);
buffer.ReleaseRef();
}
buffer.SetData(Span<uint8>(rawData, bufferDesc.Size));
case .Texture:
_textures.Add(scope String(bindDesc.Name), bindDesc.BindPoint, null);
case .Sampler:
// TODO: do we have to do something for samplers?
default:
Log.EngineLogger.Warning($"Unhandled shader resource type: \"{bindDesc.Type}\"");
}
*/
}
reflection.Release();
}
}
+37 -3
View File
@@ -12,10 +12,10 @@ namespace GlitchyEngine.Renderer
private ShaderVariableType _type;
private uint32 _columns;
private uint32 _rows;
internal uint32 _columns;
internal uint32 _rows;
private uint32 _offset;
private uint32 _sizeInBytes;
internal uint32 _sizeInBytes;
private bool _isUsed;
@@ -25,6 +25,8 @@ namespace GlitchyEngine.Renderer
public String Name => _name;
public bool IsUsed => _isUsed;
/**
* Gets a pointer to the start of the variable in the constant buffers backing data.
*/
@@ -58,6 +60,38 @@ namespace GlitchyEngine.Renderer
Log.EngineLogger.Warning($"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\"");
#endif
}
public void EnsureTypeMatch<T>()
{
switch(typeof(T))
{
case typeof(bool):
EnsureTypeMatch(1, 1, .Bool);
case typeof(float):
EnsureTypeMatch(1, 1, .Float);
case typeof(Vector2):
EnsureTypeMatch(1, 2, .Float);
case typeof(Vector3):
EnsureTypeMatch(1, 3, .Float);
case typeof(Vector4):
EnsureTypeMatch(1, 4, .Float);
case typeof(Matrix4x3):
EnsureTypeMatch(4, 3, .Float);
case typeof(Matrix3x3):
EnsureTypeMatch(3, 3, .Float);
case typeof(Matrix):
EnsureTypeMatch(4, 4, .Float);
case typeof(ColorRGB):
EnsureTypeMatch(1, 3, .Float);
case typeof(ColorRGBA):
EnsureTypeMatch(1, 4, .Float);
case typeof(Color):
EnsureTypeMatch(1, 4, .Float);
}
}
public void SetData(bool value)
{
+115 -20
View File
@@ -99,9 +99,14 @@ namespace GlitchyEngine.Renderer
BufferCollection _bufferCollection ~ delete _;
BufferVariableCollection _variables ~ delete _;
typealias TextureEntry = (Texture Texture, ShaderTextureCollection.ResourceEntry* VsSlot, ShaderTextureCollection.ResourceEntry* PsSlot);
Dictionary<String, TextureEntry> _textures ~ delete _;
public GraphicsContext Context => _context;
public Dictionary<String, TextureEntry> Textures => _textures;
public VertexShader VertexShader
{
get => _vs;
@@ -129,25 +134,6 @@ namespace GlitchyEngine.Renderer
public String Name => _name;
public void ApplyChanges()
{
for(let buffer in _bufferCollection)
{
if(let cbuffer = buffer.Buffer as ConstantBuffer)
{
cbuffer.Update();
}
}
}
public void Bind(GraphicsContext context)
{
ApplyChanges();
context.SetVertexShader(_vs);
context.SetPixelShader(_ps);
}
[Obsolete("Will be removed in the future", false)]
public this()
{
@@ -178,6 +164,12 @@ namespace GlitchyEngine.Renderer
String psName = scope String();
ProcessFile(filename, fileContent, vsName, psName);
if(filename.EndsWith("textureShader.hlsl"))
{
NOP!();
}
Compile(fileContent, vsName, psName);
MergeResources();
@@ -199,7 +191,60 @@ namespace GlitchyEngine.Renderer
_name = new String(shaderName);
}
public ~this()
{
for(let entry in _textures)
{
entry.value.Texture?.ReleaseRef();
}
}
public void SetTexture(String name, Texture texture)
{
ref TextureEntry entry = ref _textures[name];
entry.Texture?.ReleaseRef();
entry.Texture = texture;
entry.Texture?.AddRef();
}
private void ApplyTextures()
{
for(let (name, entry) in _textures)
{
entry.VsSlot?.Texture?.ReleaseRef();
entry.VsSlot?.Texture = entry.Texture;
entry.VsSlot?.Texture?.AddRef();
entry.PsSlot?.Texture?.ReleaseRef();
entry.PsSlot?.Texture = entry.Texture;
entry.PsSlot?.Texture?.AddRef();
}
}
private void ApplyChanges()
{
for(let buffer in _bufferCollection)
{
if(let cbuffer = buffer.Buffer as ConstantBuffer)
{
cbuffer.Update();
}
}
}
public void Bind(GraphicsContext context)
{
ApplyTextures();
ApplyChanges();
context.SetVertexShader(_vs);
context.SetPixelShader(_ps);
}
private void CompileFromFile(String filename, String vsEntry, String psEntry)
{
let vs = Shader.FromFile!<VertexShader>(_context, filename, vsEntry);
@@ -293,6 +338,7 @@ namespace GlitchyEngine.Renderer
{
MergeConstantBuffers();
MergeBufferVariables();
MergeTextures();
}
private void MergeConstantBuffers()
@@ -364,5 +410,54 @@ namespace GlitchyEngine.Renderer
}
}
}
/// Merges the texture slots of all shaders into one dictionary.
private void MergeTextures()
{
delete _textures;
_textures = new .();
EnumerateShaderTextures(_vs);
EnumerateShaderTextures(_ps);
}
/** @brief Merges all textures of the given shader into the _textures dictionary.
* @param shader The shader whose textures will be merged into the dictionary.
*/
private void EnumerateShaderTextures<T>(T shader) where T : Shader
{
//for(var (name, index, texture) in shader.Resources)
for(var shaderEntry in ref shader.Textures)
{
TextureEntry entry;
// Get existing entry or create new
if(!_textures.TryGetValue(shaderEntry.Name, out entry))
{
entry = (shaderEntry.Texture, null, null);
entry.Texture?.AddRef();
}
// Set the corresponding shader resource slot
if(typeof(T) == typeof(VertexShader))
{
entry.VsSlot = &shaderEntry;
}
else if(typeof(T) == typeof(PixelShader))
{
entry.PsSlot = &shaderEntry;
}
// If the entry has no texture but the shader has one -> set texture
if(entry.Texture == null && shaderEntry.Texture != null)
{
entry.Texture = shaderEntry.Texture;
entry.Texture?.AddRef();
}
// save entry
_textures[shaderEntry.Name] = entry;
}
}
}
}
+144 -3
View File
@@ -1,15 +1,159 @@
using System;
using System.Collections;
using GlitchyEngine.Math;
using internal GlitchyEngine.Renderer;
namespace GlitchyEngine.Renderer
{
public class Material : RefCounted
{
private Effect _effect ~ _?.ReleaseRef();
private uint8[] _rawVariables ~ delete _;
private Dictionary<String, Texture> _textures = new .();
private Dictionary<String, (uint32 Offset, BufferVariable Variable)> _variables = new .() ~ delete _;
public Effect Effect => _effect;
public this(Effect effect)
{
_effect = effect..AddRef();
// TODO: get variables from effect
for(let (name, entry) in _effect.Textures)
{
var texture = entry.Texture;
texture?.AddRef();
_textures.Add(name, texture);
}
InitRawData();
}
public ~this()
{
for(let (name, texture) in _textures)
{
texture?.ReleaseRef();
}
delete _textures;
}
/** @brief Initializes the raw data array for the variables.
*/
private void InitRawData()
{
uint32 bufferSize = 0;
for(let variable in _effect.Variables)
{
_variables.Add(variable.Name, (bufferSize, variable));
bufferSize += variable._sizeInBytes;
}
_rawVariables = new uint8[bufferSize];
}
/**
* Binds the materials Shaders and Parameters to the given context.
*/
public void Bind(GraphicsContext context)
{
for(let (name, texture) in _textures)
{
_effect.SetTexture(name, texture);
}
for(let (name, variable) in _variables)
{
variable.Variable.SetRawData(&RawPointer!<uint8>(variable.Offset));
}
_effect.Bind(context);
}
/** @brief Sets a texture of the material.
* @param name The name of the texture to set.
* @param texture The texture to bind to the effect.
*/
public void SetTexture(String name, Texture texture)
{
if(_textures.TryGetValue(name, var entry))
{
entry?.ReleaseRef();
_textures[name] = texture;
texture?.AddRef();
}
else
{
Log.EngineLogger.Assert(false);
}
}
private mixin RawPointer<T>(uint32 offset)
{
*(T*)(&_rawVariables[offset])
}
public void SetVariable(String name, float value)
{
if(_variables.TryGetValue(name, let entry))
{
entry.Variable.EnsureTypeMatch(1, 1, .Float);
RawPointer!<float>(entry.Offset) = value;
}
else
{
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
}
}
public void SetVariable(String name, Color value)
{
if(_variables.TryGetValue(name, let entry))
{
entry.Variable.EnsureTypeMatch<Color>();
RawPointer!<ColorRGBA>(entry.Offset) = (ColorRGBA)value;
}
else
{
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
}
}
public void SetVariable(String name, Matrix value)
{
if(_variables.TryGetValue(name, let entry))
{
entry.Variable.EnsureTypeMatch<Matrix>();
RawPointer!<Matrix>(entry.Offset) = value;
}
else
{
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
}
}
/**
* Sets the raw data of the variable.
* @param rawData The pointer to the raw data. If rawData is null the raw data will be set to zero.
*/
internal void SetRawData(uint32 offset, void* rawData, uint32 byteCount)
{
if(rawData != null)
Internal.MemCpy(&_rawVariables + offset, rawData, byteCount);
else
Internal.MemSet(&_rawVariables + offset, 0, byteCount);
}
// public void Set(String name, VALUE)...
@@ -22,8 +166,5 @@ namespace GlitchyEngine.Renderer
// Bool, Bool2, Bool3, Bool4
// Half, Half2, Half3, Half4
// Byte, Byte2, Byte3, Byte4
// Texture
// Sampler
}
}
+11
View File
@@ -77,5 +77,16 @@ namespace GlitchyEngine.Renderer
geometry.Bind();
RenderCommand.DrawIndexed(geometry);
}
public static void Submit(GeometryBinding geometry, Material material, Matrix transform = .Identity)
{
material.SetVariable("ViewProjection", _sceneConstants.ViewProjection);
material.SetVariable("Transform", transform);
material.Bind(_context);
geometry.Bind();
RenderCommand.DrawIndexed(geometry);
}
}
}
+5
View File
@@ -23,17 +23,22 @@ namespace GlitchyEngine.Renderer
protected GraphicsContext _context ~ _?.ReleaseRef();
protected BufferCollection _buffers ~ delete _;//:append _;
protected ShaderTextureCollection _textures ~ delete _;
public GraphicsContext Context => _context;
public BufferCollection Buffers => _buffers;
public ShaderTextureCollection Textures => _textures;
[AllowAppend]
public this(GraphicsContext context, String source, String entryPoint, ShaderDefine[] macros = null)
{
// Todo: append as soon as it's fixed.
//let buffers = new BufferCollection();
_buffers = new BufferCollection();
_textures = new ShaderTextureCollection();
_context = context..AddRef();
CompileFromSource(source, entryPoint);
@@ -0,0 +1,65 @@
using System;
using System.Collections;
namespace GlitchyEngine.Renderer
{
public class ShaderTextureCollection : IEnumerable<(String Name, uint32 Index, Texture Texture)>
{
public typealias ResourceEntry = (String Name, uint32 Index, Texture Texture);
List<ResourceEntry> _textures ~ DeleteTextureEntries!(_);
Dictionary<String, ResourceEntry*> _strToBuf ~ delete _;
Dictionary<int, ResourceEntry*> _idxToBuf ~ delete _;
public this()
{
let textures = new List<ResourceEntry>();
let strToBuf = new Dictionary<String, ResourceEntry*>();
let idxToBuf = new Dictionary<int, ResourceEntry*>();
_textures = textures;
_strToBuf = strToBuf;
_idxToBuf = idxToBuf;
}
mixin DeleteTextureEntries(List<ResourceEntry> entries)
{
if(entries == null)
return;
for(let entry in entries)
{
delete entry.Name;
entry.Texture?.ReleaseRef();
}
delete entries;
}
// TODO: finish implementation (like BufferCollection)
public void Add(String name, uint32 index, Texture texture)
{
Add((name, index, texture));
}
public void Add(ResourceEntry entry)
{
ResourceEntry copy = (new String(entry.Name), entry.Index, entry.Texture);
entry.Texture?.AddRef();
_textures.Add(copy);
ResourceEntry* copyRef = &_textures.Back;
_strToBuf.Add(copy.Name, copyRef);
_idxToBuf.Add(copy.Index, copyRef);
}
public List<ResourceEntry>.Enumerator GetEnumerator()
{
return _textures.GetEnumerator();
}
}
}
+1 -1
View File
@@ -49,7 +49,7 @@ PS_IN VS(VS_IN input)
float4 PS(PS_IN input) : SV_TARGET
{
return input.Color * ColorTexture.Sample(TextureSampler, input.TexCoord);
return input.Color * BaseColor * ColorTexture.Sample(TextureSampler, input.TexCoord);
}
#effect[VS=VS,PS=PS]
+16 -8
View File
@@ -61,7 +61,9 @@ namespace Sandbox
GraphicsContext _context ~ _?.ReleaseRef();
DepthStencilTarget _depthTarget ~ _?.ReleaseRef();
Material _checkerMaterial ~ _?.ReleaseRef();
Material _logoMaterial ~ _?.ReleaseRef();
Texture2D _texture ~ _?.ReleaseRef();
Texture2D _ge_logo ~ _?.ReleaseRef();
@@ -188,6 +190,12 @@ namespace Sandbox
sampler.ReleaseRef();
_logoMaterial = new Material(textureEffect);
_logoMaterial.SetTexture("ColorTexture", _ge_logo);
_checkerMaterial = new Material(textureEffect);
_checkerMaterial.SetTexture("ColorTexture", _texture);
BlendStateDescription blendDesc = .();
blendDesc.RenderTarget[0] = .(true, .SourceAlpha, .InvertedSourceAlpha, .Add, .SourceAlpha, .InvertedSourceAlpha, .Add, .All);
_alphaBlendState = new BlendState(_context, blendDesc);
@@ -289,7 +297,6 @@ namespace Sandbox
_opaqueBlendState.Bind();
var basicEffect = _effectLibrary.Get("basicShader");
var textureEffect = _effectLibrary.Get("textureShader");
// Model test
{
@@ -314,7 +321,7 @@ namespace Sandbox
var transform = _world.GetComponent<TransformComponent>(entity);
transform.Update();
}
int i = 0;
for(var entity in _world.Enumerate(typeof(TransformComponent), typeof(MeshComponent)))
{
@@ -332,19 +339,20 @@ namespace Sandbox
}
basicEffect.Variables["BaseColor"].SetData(_squareColor1);
_checkerMaterial.SetVariable("BaseColor", Color.White);
_texture.Bind();
Renderer.Submit(_quadGeometryBinding, textureEffect, .Scaling(1.5f));
Renderer.Submit(_quadGeometryBinding, _checkerMaterial, .Scaling(1.5f));
_alphaBlendState.Bind();
_logoMaterial.SetVariable("BaseColor", Color.Pink);
_ge_logo.Bind();
Renderer.Submit(_quadGeometryBinding, textureEffect, .Scaling(1.5f));
Renderer.Submit(_quadGeometryBinding, _logoMaterial, .Scaling(2f));
Renderer.EndScene();
basicEffect.ReleaseRef();
textureEffect.ReleaseRef();
}
ColorRGBA _squareColor0 = ColorRGBA.CornflowerBlue;