For some reason, when I try to add textures to my app, it crashes saying “Incorrect parameter.” - I comment out the texture part, and it works fine.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GraphicsPlatform;
using SharpDX;
using SharpDX.Direct3D12;
using SharpDX.DXGI;
using DX12Plat.DataTypes;
using System.Runtime.InteropServices;
namespace DX12Plat
{
public class DX12Platform : GraphicsPlatform.GraphicsPlatform
{
public D3DApp D3D = null;
private int _wW, _wH;
public static DX12Platform ThisPlatform = null;
public override void InitWindow(string title, int width, int height, bool fullscreen)
{
ThisPlatform = this;
_wW = width;
_wH = height;
D3D = new D3DApp();
D3D.SetMetrics(width, height, title, false);
D3D.Initialize();
D3D.CommandList.Reset(D3D.DirectCmdListAlloc, null);
BuildRectHeap();
BuildRectConstantBuffers();
BuildRectRootSignature();
BuildRectShadersAndInputLayout();
// BuildRectGeo(20, 20, 200, 200);
RectBuildPSO();
D3D.CommandList.Close();
D3D.CommandQueue.ExecuteCommandList(D3D.CommandList);
D3D.FlushCommandQueue();
base.InitWindow(title, width, height, fullscreen);
}
// - 2D drawing props.
private RootSignature _RectrootSignature;
private DescriptorHeap _cbvHeap;
private DescriptorHeap[] _descriptorHeaps;
private UploadBuffer<DataTypes.ObjectConstant2D> _RectobjectCB;
private ShaderBytecode _rectVSByteCode;
private ShaderBytecode _mrectPSByteCode;
private InputLayoutDescription _inputLayout;
private PipelineState _RectPSO;
private Matrix _proj = Matrix.Identity;
private Matrix _view = Matrix.Identity;
private float _theta = 1.5f * MathUtil.Pi;
private float _phi = MathUtil.PiOverFour;
private float _radius = 5.0f;
private Point _lastMousePos;
private DescriptorHeap _tvHeap;
public void BuildRectHeap()
{
var cbvHeapDesc = new DescriptorHeapDescription
{
DescriptorCount = 1,
Type = DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView,
Flags = DescriptorHeapFlags.ShaderVisible,
NodeMask = 0
};
var svHeapDesc = new DescriptorHeapDescription
{
DescriptorCount = 1,
Type = DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView,
Flags = DescriptorHeapFlags.ShaderVisible,
NodeMask = 0
};
_cbvHeap = D3D.Device.CreateDescriptorHeap(cbvHeapDesc);
_tvHeap = D3D.Device.CreateDescriptorHeap(svHeapDesc);
}
private void BuildRectConstantBuffers()
{
int sizeInBytes = D3DUtil.CalcConstantBufferByteSize<DataTypes.ObjectConstant2D>();
_RectobjectCB = new UploadBuffer<DataTypes.ObjectConstant2D>(D3D.Device, 1, true);
var cbvDesc = new ConstantBufferViewDescription
{
BufferLocation = _RectobjectCB.Resource.GPUVirtualAddress,
SizeInBytes = sizeInBytes
};
CpuDescriptorHandle cbvHeapHandle = _cbvHeap.CPUDescriptorHandleForHeapStart;
D3D.Device.CreateConstantBufferView(cbvDesc, cbvHeapHandle);
}
private void BuildRectRootSignature()
{
// Shader programs typically require resources as input (constant buffers,
// textures, samplers). The root signature defines the resources the shader
// programs expect. If we think of the shader programs as a function, and
// the input resources as function parameters, then the root signature can be
// thought of as defining the function signature.
// Root parameter can be a table, root descriptor or root constants.
// Create a single descriptor table of CBVs.
var cbvTable = new DescriptorRange(DescriptorRangeType.ConstantBufferView, 1, 0);
var svTable = new DescriptorRange
{
RangeType = DescriptorRangeType.ShaderResourceView,
DescriptorCount = 1,
// OffsetInDescriptorsFromTableStart = int.MinValue,
BaseShaderRegister = 0
};
// A root signature is an array of root parameters.
var rootSigDesc = new RootSignatureDescription(RootSignatureFlags.AllowInputAssemblerInputLayout, new[]
{
new RootParameter(ShaderVisibility.Vertex,cbvTable),
new RootParameter(ShaderVisibility.Pixel,svTable)
},
new[]
{
new StaticSamplerDescription(ShaderVisibility.Pixel,0,0)
{
Filter = Filter.MinimumMinMagMipPoint,
AddressUVW = TextureAddressMode.Border
}
}
) ;
_RectrootSignature = D3D.Device.CreateRootSignature(rootSigDesc.Serialize());
}
private void BuildRectShadersAndInputLayout()
{
_rectVSByteCode = D3DUtil.CompileShader("data/platform/dx12/shader/rect2d.hlsl", "VS", "vs_5_0");
_mrectPSByteCode = D3DUtil.CompileShader("data/platform/dx12/shader/rect2d.hlsl", "PS", "ps_5_0");
_inputLayout = new InputLayoutDescription(new[] // TODO: API suggestion: Add params overload
{
new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 12, 0),
new InputElement("TEXCOORD",0,Format.R32G32B32A32_Float,28,0)
});
}
private MeshGeometry _RectGeo;
private long GetRequiredIntermediateSize(SharpDX.Direct3D12.Resource destinationResource, int firstSubresource, int NumSubresources)
{
var desc = destinationResource.Description;
long requiredSize;
D3D.Device.GetCopyableFootprints(ref desc, firstSubresource, NumSubresources, 0, null, null, null, out requiredSize);
return requiredSize;
}
public override Texture2D LoadTexture2D(string path)
{
System.Drawing.Bitmap bits = new System.Drawing.Bitmap(path);
int w = bits.Width;
int h = bits.Height;
byte[] pix = new byte[w * h * 4];
int loc = 0;
for(int y = 0; y < h; y++)
{
for(int x = 0; x < w; x++)
{
var col = bits.GetPixel(x, y);
pix[loc++] = col.R;
pix[loc++] = col.G;
pix[loc++] = col.B;
pix[loc++] = col.A;
}
}
return CreateTexture2D(w, h, pix);
}
public Texture2D CreateTexture2D(int w, int h,byte[] data)
{
D3D.DirectCmdListAlloc.Reset();
D3D.CommandList.Reset(D3D.DirectCmdListAlloc,null);
var tex = new Texture2DDX12();
var textureDesc = ResourceDescription.Texture2D(Format.R8G8B8A8_UNorm, w, h);
SharpDX.Direct3D12.Resource texture = D3D.Device.CreateCommittedResource(new HeapProperties(HeapType.Default), HeapFlags.None, textureDesc, ResourceStates.CopyDestination);
tex.texture = texture;
tex.textureDesc = textureDesc;
tex.Width = w;
tex.Height = h;
long uploadSize = GetRequiredIntermediateSize(texture, 0, 1);
var textureUploadHeap = D3D.Device.CreateCommittedResource(new HeapProperties(CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None, ResourceDescription.Texture2D(Format.R8G8B8A8_UNorm,w,h), ResourceStates.GenericRead);
var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var ptr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
textureUploadHeap.WriteToSubresource(0, null, ptr, 4 * w, data.Length);
handle.Free();
D3D.CommandList.CopyTextureRegion(new TextureCopyLocation(texture, 0), 0, 0, 0, new TextureCopyLocation(textureUploadHeap, 0), null);
D3D.CommandList.ResourceBarrierTransition(texture, ResourceStates.CopyDestination, ResourceStates.PixelShaderResource);
var srvDesc = new ShaderResourceViewDescription
{
Shader4ComponentMapping = D3DXUtilities.DefaultComponentMapping(),
Format = textureDesc.Format,
Dimension = ShaderResourceViewDimension.Texture2D,
};
srvDesc.Texture2D.MipLevels = 1;
D3D.Device.CreateShaderResourceView(texture, srvDesc, _tvHeap.CPUDescriptorHandleForHeapStart);
D3D.CommandList.Close();
D3D.CommandQueue.ExecuteCommandList(D3D.CommandList);
D3D.FlushCommandQueue();
return tex;
}
private void RectBuildPSO()
{
var psoDesc = new GraphicsPipelineStateDescription
{
InputLayout = _inputLayout,
RootSignature = _RectrootSignature,
VertexShader = _rectVSByteCode,
PixelShader = _mrectPSByteCode,
RasterizerState = RasterizerStateDescription.Default(),
BlendState = BlendStateDescription.Default(),
DepthStencilState = DepthStencilStateDescription.Default(),
SampleMask = int.MaxValue,
PrimitiveTopologyType = PrimitiveTopologyType.Triangle,
RenderTargetCount = 1,
SampleDescription = new SampleDescription(D3D.MsaaCount, D3D.MsaaQuality),
DepthStencilFormat = D3D.DepthStencilFormat,
StreamOutput = new StreamOutputDescription(),
Flags = PipelineStateFlags.None
};
psoDesc.RenderTargetFormats[0] = D3D.BackBufferFormat;
_RectPSO = D3D.Device.CreateGraphicsPipelineState(psoDesc);
}
public override void BeginRun()
{
D3D.BeginRun();
}
public override void UpdateRun()
{
D3D.UpdateRun();
}
public override void BeginFrame()
{
//D3D.BeginFrame();
}
public override void Present()
{
// Indicate a state transition on the resource usage.
D3D.CommandList.ResourceBarrierTransition(D3D.CurrentBackBuffer, ResourceStates.RenderTarget, ResourceStates.Present);
// Done recording commands.
D3D.CommandList.Close();
// Add the command list to the queue for execution.
D3D.CommandQueue.ExecuteCommandList(D3D.CommandList);
// Present the buffer to the screen. Presenting will automatically swap the back and front buffers.
D3D.SwapChain.Present(0, PresentFlags.None);
// Wait until frame commands are complete. This waiting is inefficient and is
// done for simplicity. Later we will show how to organize our rendering code
// so we do not have to wait per frame.
D3D.FlushCommandQueue();
}
public List<DXRect> Rects = new List<DXRect>();
private float drawZ = 0.01f;
public override void BeginDrawing()
{
Rects.Clear();
drawZ = 0.99f;
}
public override void EndDrawing()
{
_proj = Matrix.OrthoLH(_wW, -_wH, 0, 1);
//_proj = Matrix.Identity;
var cb = new DataTypes.ObjectConstant2D
{
Proj = _proj
};
_RectobjectCB.CopyData(0, ref cb);
D3D.BeginRender(_RectPSO);
_descriptorHeaps = new DescriptorHeap[2];
_descriptorHeaps[0] = _cbvHeap;
_descriptorHeaps[1] = _tvHeap;
// TODO: Make requiring explicit length optional.
D3D.CommandList.SetDescriptorHeaps(_descriptorHeaps.Length, _descriptorHeaps);
D3D.CommandList.SetGraphicsRootSignature(_RectrootSignature);
D3D.CommandList.SetGraphicsRootDescriptorTable(1, _cbvHeap.GPUDescriptorHandleForHeapStart);
D3D.CommandList.SetGraphicsRootDescriptorTable(0, _tvHeap.GPUDescriptorHandleForHeapStart);
D3D.CommandList.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;
foreach (var rect in Rects)
{
D3D.CommandList.SetVertexBuffer(0, rect._Geo.VertexBufferView);
D3D.CommandList.SetIndexBuffer(rect._Geo.IndexBufferView);
D3D.CommandList.DrawIndexedInstanced(rect._Geo.IndexCount, 1, 0, 0, 0);
}
}
float xi = -0.5f;
bool first = true;
public override void DrawRect(int x, int y, int w, int h, float r, float g, float b, float a,Texture2D tex)
{
// x = x - _wW / 2;
x = x - _wW / 2;
y = y - _wH / 2;
xi = xi + 0.001f;
DXRect rect = new DXRect(D3D, x, y, w, h, r, g, b, a, drawZ, tex as Texture2DDX12);
//rect.DrawZ = drawZ;
drawZ -= 0.001f;
Rects.Add(rect);
// _proj = Matrix.OrthoOffCenterLH(_wW,0, _wH,0, 0, 1);
}
}
public class D3DXUtilities
{
public const int ComponentMappingMask = 0x7;
public const int ComponentMappingShift = 3;
public const int ComponentMappingAlwaysSetBitAvoidingZeromemMistakes = (1 << (ComponentMappingShift * 4));
public static int ComponentMapping(int src0, int src1, int src2, int src3)
{
return ((((src0) & ComponentMappingMask) |
(((src1) & ComponentMappingMask) << ComponentMappingShift) |
(((src2) & ComponentMappingMask) << (ComponentMappingShift * 2)) |
(((src3) & ComponentMappingMask) << (ComponentMappingShift * 3)) |
ComponentMappingAlwaysSetBitAvoidingZeromemMistakes));
}
public static int DefaultComponentMapping()
{
return ComponentMapping(0, 1, 2, 3);
}
public static int ComponentMapping(int ComponentToExtract, int Mapping)
{
return ((Mapping >> (ComponentMappingShift * ComponentToExtract) & ComponentMappingMask));
}
}
}