1524 lines
56 KiB
Plaintext
1524 lines
56 KiB
Plaintext
#import "d3d11";
|
|
#import "d3d_compiler";
|
|
#import "dxgi";
|
|
#import "File";
|
|
#import "Windows";
|
|
#load "../imgui/imgui_dx11.jai";
|
|
|
|
Graphics_Backend :: D3D11_Backend;
|
|
Backend_Vertex_Input :: *ID3D11InputLayout;
|
|
Backend_Sampler :: *ID3D11SamplerState;
|
|
Backend_Blend_State :: *ID3D11BlendState;
|
|
|
|
Backend_Render_Target :: struct {
|
|
render_target_view : *ID3D11RenderTargetView;
|
|
|
|
texture: Backend_Texture;
|
|
};
|
|
|
|
Backend_Depth_Stencil_Buffer :: struct {
|
|
texture : *ID3D11Texture2D;
|
|
depth_stencil_view : *ID3D11DepthStencilView;
|
|
shader_resource_view : *ID3D11ShaderResourceView;
|
|
};
|
|
|
|
Backend_Buffer :: struct {
|
|
buffer : *ID3D11Buffer;
|
|
view : *ID3D11ShaderResourceView;
|
|
}
|
|
|
|
Backend_Texture :: struct {
|
|
texture : *ID3D11Texture2D;
|
|
view : *ID3D11ShaderResourceView;
|
|
}
|
|
|
|
Backend_Shader :: struct {
|
|
bytecode : string;
|
|
blob : *ID3DBlob;
|
|
|
|
union {
|
|
vertex_shader : *ID3D11VertexShader;
|
|
pixel_shader : *ID3D11PixelShader;
|
|
}
|
|
}
|
|
|
|
Rasterizer_State :: struct {
|
|
fill: bool;
|
|
cull_face: Cull_Face;
|
|
scissor_test: bool;
|
|
state: *ID3D11RasterizerState;
|
|
}
|
|
|
|
D3D11_Backend :: struct {
|
|
driver_type := D3D_DRIVER_TYPE.NULL;
|
|
feature_level := D3D_FEATURE_LEVEL._11_0;
|
|
|
|
d3d_device : *ID3D11Device;
|
|
d3d_context : *ID3D11DeviceContext;
|
|
factory : *IDXGIFactory1;
|
|
swap_chain : *IDXGISwapChain;
|
|
render_target_view : *ID3D11RenderTargetView;
|
|
|
|
rasterizer_states: [..] Rasterizer_State;
|
|
|
|
ds_state : *ID3D11DepthStencilState;
|
|
no_depth_ds_state : *ID3D11DepthStencilState;
|
|
|
|
fill: bool = true;
|
|
cull_face: Cull_Face = .BACK;
|
|
scissor_test: bool = false;
|
|
}
|
|
|
|
create_backend :: (w: *Window) -> *D3D11_Backend {
|
|
backend := New(D3D11_Backend);
|
|
hwnd := cast(HWND)get_hwnd(w);
|
|
if !init_device(hwnd, backend) {
|
|
print ("init_device failed!\n");
|
|
cleanup_device(backend);
|
|
return null;
|
|
}
|
|
|
|
imgui_impldx11_init(backend.d3d_device, backend.d3d_context);
|
|
|
|
return backend;
|
|
}
|
|
|
|
deinit_backend :: (backend: *Graphics_Backend) {
|
|
cleanup_device(backend);
|
|
}
|
|
|
|
destroy_shader :: (using shader: Shader) {
|
|
if type == {
|
|
case .VERTEX;
|
|
if backend_shader.vertex_shader IUnknown_Release(backend_shader.vertex_shader);
|
|
case .PIXEL;
|
|
if backend_shader.pixel_shader IUnknown_Release(backend_shader.pixel_shader);
|
|
}
|
|
}
|
|
|
|
destroy_buffer :: (using buffer: Buffer) {
|
|
IUnknown_Release(backend_buffer.buffer);
|
|
}
|
|
|
|
cleanup_device :: (using backend: *Graphics_Backend) {
|
|
if d3d_context ID3D11DeviceContext_ClearState(d3d_context);
|
|
|
|
//if vertex_layout IUnknown_Release(vertex_layout);
|
|
|
|
if render_target_view IUnknown_Release(render_target_view);
|
|
if swap_chain IUnknown_Release(swap_chain);
|
|
if d3d_context IUnknown_Release(d3d_context);
|
|
if d3d_device IUnknown_Release(d3d_device);
|
|
}
|
|
|
|
init_device :: (hwnd: HWND, using renderer: *D3D11_Backend) -> bool {
|
|
hr : HRESULT = S_OK;
|
|
|
|
flags : D3D11_CREATE_DEVICE_FLAG;
|
|
#if DEBUG flags |= .DEBUG;
|
|
|
|
driver_types := D3D_DRIVER_TYPE.[.HARDWARE, .WARP, .REFERENCE];
|
|
feature_levels := D3D_FEATURE_LEVEL.[._11_1, ._11_0, ._10_1, ._10_0];
|
|
|
|
for 0..driver_types.count-1 {
|
|
|
|
driver_type = driver_types[it];
|
|
hr = D3D11CreateDevice(null, driver_type, null, flags, feature_levels.data, feature_levels.count, D3D11_SDK_VERSION, *d3d_device, *feature_level, *d3d_context);
|
|
|
|
if hr == E_INVALIDARG {
|
|
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it.
|
|
hr = D3D11CreateDevice(null, driver_type, null, flags, feature_levels.data + 1, feature_levels.count - 1, D3D11_SDK_VERSION, *d3d_device, *feature_level, *d3d_context);
|
|
}
|
|
|
|
if SUCCEEDED(hr) break;
|
|
}
|
|
if FAILED(hr) {
|
|
print("D3D11CreateDevice failed.\n");
|
|
return false;
|
|
}
|
|
|
|
assert(d3d_device != null);
|
|
|
|
// Obtain DXGI factory from device (since we used null for pAdapter above)
|
|
dxgi_factory : *IDXGIFactory1;
|
|
{
|
|
dxgi_device : *IDXGIDevice;
|
|
hr = IUnknown_QueryInterface(d3d_device, *uid(IDXGIDevice_UUID), xx *dxgi_device);
|
|
// You could also use the vtable helper instead of the C api:
|
|
// hr = vtable(d3d_device).QueryInterface(d3d_device, *uid(IDXGIDevice_UUID), xx *dxgi_device);
|
|
if SUCCEEDED(hr) {
|
|
adapter : *IDXGIAdapter;
|
|
hr = IDXGIDevice_GetAdapter(dxgi_device, *adapter);
|
|
if SUCCEEDED(hr) {
|
|
hr = IDXGIObject_GetParent(adapter, *uid(IDXGIFactory1_UUID), xx *dxgi_factory);
|
|
IUnknown_Release(adapter);
|
|
}
|
|
IUnknown_Release(dxgi_device);
|
|
} else {
|
|
print("QueryInterface FAILED\n");
|
|
}
|
|
}
|
|
|
|
factory = dxgi_factory;
|
|
|
|
if FAILED(hr) {
|
|
print("GetAdapter failed.\n");
|
|
return false;
|
|
}
|
|
|
|
rc : RECT;
|
|
GetClientRect(hwnd, *rc);
|
|
width := rc.right - rc.left;
|
|
height := rc.bottom - rc.top;
|
|
|
|
// Create swap chain
|
|
sd : DXGI_SWAP_CHAIN_DESC;
|
|
sd.SwapEffect = .SEQUENTIAL;
|
|
sd.BufferCount = 2;
|
|
sd.BufferDesc.Width = xx width;
|
|
sd.BufferDesc.Height = xx height;
|
|
sd.BufferDesc.Format = .R8G8B8A8_UNORM;
|
|
sd.BufferDesc.RefreshRate.Numerator = 60;
|
|
sd.BufferDesc.RefreshRate.Denominator = 1;
|
|
sd.BufferUsage = .RENDER_TARGET_OUTPUT;
|
|
sd.OutputWindow = hwnd;
|
|
sd.SampleDesc.Count = 1;
|
|
sd.SampleDesc.Quality = 0;
|
|
sd.Windowed = BOOL.TRUE;
|
|
|
|
hr = IDXGIFactory_CreateSwapChain(dxgi_factory, d3d_device, *sd, *swap_chain);
|
|
if FAILED(hr) {
|
|
log_error("CreateSwapChain failed: %", hr);
|
|
}
|
|
|
|
// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut
|
|
IDXGIFactory_MakeWindowAssociation(dxgi_factory, hwnd, cast (u32) DXGI_MWA.NO_ALT_ENTER);
|
|
IUnknown_Release(dxgi_factory);
|
|
|
|
if FAILED(hr) return false;
|
|
|
|
|
|
back_buffer : *ID3D11Texture2D;
|
|
hr = IDXGISwapChain_GetBuffer(swap_chain, 0, *uid(ID3D11Texture2D_UUID), xx *back_buffer);
|
|
if FAILED(hr) {
|
|
log_error("GetBuffer failed: %", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = ID3D11Device_CreateRenderTargetView(d3d_device, back_buffer, null, *render_target_view);
|
|
IUnknown_Release(back_buffer);
|
|
if FAILED(hr) {
|
|
log_error("CreateRenderTargetView failed: %", hr);
|
|
return false;
|
|
}
|
|
|
|
|
|
// Depth stencil
|
|
ds_desc : D3D11_DEPTH_STENCIL_DESC;
|
|
|
|
// Depth test parameters
|
|
ds_desc.DepthEnable = .TRUE;
|
|
ds_desc.DepthWriteMask = .D3D11_DEPTH_WRITE_MASK_ALL;
|
|
ds_desc.DepthFunc = .D3D11_COMPARISON_LESS_EQUAL;
|
|
|
|
// Stencil test parameters
|
|
ds_desc.StencilEnable = .FALSE;
|
|
ds_desc.StencilReadMask = 0xFF;
|
|
ds_desc.StencilWriteMask = 0xFF;
|
|
|
|
// Stencil operations if pixel is front-facing
|
|
ds_desc.FrontFace.StencilFailOp = .D3D11_STENCIL_OP_KEEP;
|
|
ds_desc.FrontFace.StencilDepthFailOp = .D3D11_STENCIL_OP_INCR;
|
|
ds_desc.FrontFace.StencilPassOp = .D3D11_STENCIL_OP_KEEP;
|
|
ds_desc.FrontFace.StencilFunc = .D3D11_COMPARISON_ALWAYS;
|
|
|
|
// Stencil operations if pixel is back-facing
|
|
ds_desc.BackFace.StencilFailOp = .D3D11_STENCIL_OP_KEEP;
|
|
ds_desc.BackFace.StencilDepthFailOp = .D3D11_STENCIL_OP_DECR;
|
|
ds_desc.BackFace.StencilPassOp = .D3D11_STENCIL_OP_KEEP;
|
|
ds_desc.BackFace.StencilFunc = .D3D11_COMPARISON_ALWAYS;
|
|
|
|
// Create depth stencil state
|
|
ID3D11Device_CreateDepthStencilState(d3d_device, *ds_desc, *ds_state);
|
|
ID3D11DeviceContext_OMSetDepthStencilState(d3d_context, ds_state, 1);
|
|
|
|
ds_desc.DepthEnable = .FALSE;
|
|
ID3D11Device_CreateDepthStencilState(d3d_device, *ds_desc, *no_depth_ds_state);
|
|
|
|
vp : D3D11_VIEWPORT;
|
|
vp.Width = xx width;
|
|
vp.Height = xx height;
|
|
vp.MinDepth = 0.0;
|
|
vp.MaxDepth = 1.0;
|
|
vp.TopLeftX = 0;
|
|
vp.TopLeftY = 0;
|
|
ID3D11DeviceContext_RSSetViewports(d3d_context, 1, *vp);
|
|
|
|
array_reserve(*renderer.rasterizer_states, 8);
|
|
|
|
create_rasterizer_state(renderer, true, .BACK, false);
|
|
create_rasterizer_state(renderer, false, .BACK, false);
|
|
create_rasterizer_state(renderer, true, .FRONT, false);
|
|
create_rasterizer_state(renderer, false, .FRONT, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
get :: (array: [..]$T, handle: $S) -> *T {
|
|
assert(handle > 0 && handle <= xx array.count);
|
|
return *array[handle - 1];
|
|
}
|
|
|
|
// @Note(Daniel): Taken from the module to convert defines to D3D_SHADER_MACRO structs, since we need that for our engine
|
|
d3d_compile :: (shader: string, source_name: string, pDefines: []string, pInclude: *ID3DInclude, entry_point: string, target: string, Flags1: u32, Flags2: u32) -> bytecode:string, *ID3DBlob, errors:string, HRESULT {
|
|
pSourceName := temp_c_string(source_name);
|
|
pEntrypoint := temp_c_string(entry_point);
|
|
pTarget := temp_c_string(target);
|
|
|
|
defines : [..] D3D_SHADER_MACRO;
|
|
defines.allocator = temp;
|
|
|
|
for pDefines {
|
|
macro : D3D_SHADER_MACRO;
|
|
macro.Name = to_c_string(it);
|
|
array_add(*defines, macro);
|
|
}
|
|
|
|
null_macro : D3D_SHADER_MACRO;
|
|
null_macro.Name = null;
|
|
null_macro.Definition = null;
|
|
array_add(*defines, null_macro);
|
|
|
|
pCode: *ID3DBlob;
|
|
pErrorMsgs: *ID3DBlob;
|
|
|
|
hr := D3DCompile(shader.data, cast(u64)shader.count, pSourceName, defines.data, pInclude, pEntrypoint, pTarget, Flags1, Flags2, *pCode, *pErrorMsgs);
|
|
|
|
for defines {
|
|
free(it.Name);
|
|
}
|
|
|
|
bytecode : string;
|
|
errors : string;
|
|
|
|
if pCode {
|
|
bytecode = copy_string(to_string(ID3D10Blob_GetBufferPointer(pCode), cast(s64) ID3D10Blob_GetBufferSize(pCode)));
|
|
}
|
|
|
|
if pErrorMsgs {
|
|
errors = copy_string(to_string(ID3D10Blob_GetBufferPointer(pErrorMsgs), cast(s64) ID3D10Blob_GetBufferSize(pErrorMsgs)));
|
|
}
|
|
|
|
//safe_release(pCode);
|
|
safe_release(pErrorMsgs);
|
|
return bytecode, pCode, errors, hr;
|
|
}
|
|
|
|
compile_shader :: (name: string, source: string, entry_point: string, shader_model: string, defines: [] string = string.[]) -> string, *ID3DBlob, HRESULT {
|
|
flags := D3DCOMPILE.ENABLE_STRICTNESS;
|
|
|
|
#if DEBUG {
|
|
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
|
|
// Setting this flag improves the shader debugging experience, but still allows
|
|
// the shaders to be optimized and to run exactly the way they will run in
|
|
// the release configuration of this program.
|
|
flags |= .DEBUG;
|
|
|
|
// Disable optimizations to further improve shader debugging
|
|
flags |= .SKIP_OPTIMIZATION;
|
|
}
|
|
|
|
|
|
bytecode, blob, errors, hr := d3d_compile(source, "source", defines, null, entry_point, shader_model, xx flags, 0);
|
|
defer free(errors);
|
|
|
|
if FAILED(hr) {
|
|
free(bytecode);
|
|
if errors print("Shader compilation error in shader '%': %", name, errors);
|
|
return "", null, hr;
|
|
}
|
|
|
|
return bytecode, blob, hr;
|
|
}
|
|
|
|
variable_type_to_property_type :: (type_desc: D3D11_SHADER_TYPE_DESC) -> Shader_Property_Type {
|
|
if type_desc.Type == {
|
|
case .SVT_BOOL;
|
|
return .BOOL;
|
|
case .SVT_INT;
|
|
return .INTEGER;
|
|
case .SVT_FLOAT;
|
|
if type_desc.Class == {
|
|
case .SVC_SCALAR;
|
|
return .FLOAT;
|
|
case .SVC_VECTOR; {
|
|
if type_desc.Columns == {
|
|
case 2;
|
|
return .FLOAT2;
|
|
case 3;
|
|
return .FLOAT3;
|
|
case 4;
|
|
return .FLOAT4;
|
|
}
|
|
}
|
|
case .SVC_MATRIX_COLUMNS; #through;
|
|
case .SVC_MATRIX_ROWS; {
|
|
if type_desc.Columns == {
|
|
case 3;
|
|
return .MATRIX3;
|
|
case 4;
|
|
return .MATRIX4;
|
|
}
|
|
}
|
|
}
|
|
return .FLOAT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// @Incomplete: Move this out of the DX11 backend code
|
|
look_for_mapping :: (name: string) -> Shader_Parameter_Mapping, string {
|
|
mapping_strs := split(name, "__");
|
|
if mapping_strs.count < 2 {
|
|
return .NONE, "";
|
|
}
|
|
|
|
if mapping_strs[1] == {
|
|
case "MODEL_MATRIX";
|
|
return .MODEL_MATRIX, "";
|
|
case "TIME";
|
|
return .TIME, "";
|
|
case "CAMERA_DATA";
|
|
return .CAMERA_DATA, "";
|
|
case "MATERIAL";
|
|
return .MATERIAL, "";
|
|
case "DIRECTIONAL_LIGHT";
|
|
return .DIRECTIONAL_LIGHT, "";
|
|
case "POINT_LIGHTS";
|
|
return .POINT_LIGHTS, "";
|
|
case "BONE_MATRICES";
|
|
return .BONE_MATRICES, "";
|
|
case "SCREEN_DATA";
|
|
return .SCREEN_DATA, "";
|
|
case "BASE_COLOR_TEXTURE";
|
|
return .BASE_COLOR_TEXTURE, "";
|
|
case "NORMAL_MAP";
|
|
return .NORMAL_MAP, "";
|
|
case "ATT0";
|
|
return .SHADER_ATTACHMENT0, "";
|
|
case "ATT1";
|
|
return .SHADER_ATTACHMENT1, "";
|
|
case "ATT2";
|
|
return .SHADER_ATTACHMENT2, "";
|
|
case "ATT3";
|
|
return .SHADER_ATTACHMENT3, "";
|
|
case "ATT4";
|
|
return .SHADER_ATTACHMENT4, "";
|
|
case "ATT5";
|
|
return .SHADER_ATTACHMENT5, "";
|
|
case "ATT6";
|
|
return .SHADER_ATTACHMENT6, "";
|
|
case "REPEAT_SAMPLER";
|
|
return .REPEAT_SAMPLER, "";
|
|
case "CLAMP_SAMPLER";
|
|
return .CLAMP_SAMPLER, "";
|
|
}
|
|
|
|
return .CUSTOM, copy_string(mapping_strs[1]);
|
|
}
|
|
|
|
get_shader_info_from_blob :: (blob: *ID3DBlob, shader_type: Shader_Type) -> Shader_Info {
|
|
shader_info : Shader_Info;
|
|
|
|
reflection : *ID3D11ShaderReflection;
|
|
reflection_result := D3DReflect(ID3D10Blob_GetBufferPointer(blob), ID3D10Blob_GetBufferSize(blob), uid("8d536ca1-0cca-4956-a837-786963755584"), cast(**void)*reflection);
|
|
|
|
if !FAILED(reflection_result) {
|
|
defer safe_release(reflection);
|
|
|
|
// Input layout
|
|
desc : D3D11_SHADER_DESC;
|
|
ID3D11ShaderReflection_GetDesc(reflection, *desc);
|
|
|
|
param_index : u32 = 0;
|
|
while param_index < desc.InputParameters {
|
|
defer param_index += 1;
|
|
param_desc : D3D11_SIGNATURE_PARAMETER_DESC;
|
|
ID3D11ShaderReflection_GetInputParameterDesc(reflection, param_index, *param_desc);
|
|
|
|
input : Vertex_Input;
|
|
input.semantic_name = copy_string(to_string(param_desc.SemanticName));
|
|
input.semantic_index = param_desc.SemanticIndex;
|
|
input.slot = 0; // @Incomplete: this might have to change
|
|
|
|
if param_desc.Mask == 1 {
|
|
if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_UINT32
|
|
input.format = .R32_UINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_SINT32
|
|
input.format = .R32_SINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_FLOAT32
|
|
input.format = .R32_FLOAT;
|
|
} else if param_desc.Mask <= 3 {
|
|
if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_UINT32
|
|
input.format = .R32G32_UINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_SINT32
|
|
input.format = .R32G32_SINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_FLOAT32
|
|
input.format = .R32G32_FLOAT;
|
|
} else if param_desc.Mask <= 7 {
|
|
if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_UINT32
|
|
input.format = .R32G32B32_UINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_SINT32
|
|
input.format = .R32G32B32_SINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_FLOAT32
|
|
input.format = .R32G32B32_FLOAT;
|
|
} else if param_desc.Mask <= 15 {
|
|
if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_UINT32
|
|
input.format = .R32G32B32A32_UINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_SINT32
|
|
input.format = .R32G32B32A32_SINT;
|
|
else if param_desc.ComponentType == .D3D_REGISTER_COMPONENT_FLOAT32
|
|
input.format = .R32G32B32A32_FLOAT;
|
|
}
|
|
|
|
array_add(*shader_info.input, input);
|
|
}
|
|
|
|
// Constant buffers
|
|
buffer_index : u32 = 0;
|
|
while buffer_index < desc.ConstantBuffers {
|
|
defer buffer_index += 1;
|
|
ptr := ID3D11ShaderReflection_GetConstantBufferByIndex(reflection, buffer_index);
|
|
buffer_desc : D3D11_SHADER_BUFFER_DESC;
|
|
if FAILED(ID3D11ShaderReflectionConstantBuffer_GetDesc(ptr, *buffer_desc)) assert(false);
|
|
|
|
param : Shader_Parameter;
|
|
param.type = .BUFFER;
|
|
param.shader = shader_type;
|
|
param.name = copy_string(to_string(buffer_desc.Name));
|
|
|
|
param.size = buffer_desc.Size;
|
|
|
|
input_desc : D3D11_SHADER_INPUT_BIND_DESC;
|
|
if FAILED(ID3D11ShaderReflection_GetResourceBindingDescByName(reflection, buffer_desc.Name, *input_desc)) assert(false);
|
|
param.slot = input_desc.BindPoint;
|
|
|
|
param.mapping, param.mapping_str = look_for_mapping(param.name);
|
|
if param.mapping == .CUSTOM {
|
|
log("CUSTOM MAPPING FOUND %\n", param.mapping_str);
|
|
}
|
|
|
|
var_index : u32 = 0;
|
|
while var_index < buffer_desc.Variables {
|
|
defer var_index += 1;
|
|
pvar := ID3D11ShaderReflectionConstantBuffer_GetVariableByIndex(ptr, var_index);
|
|
var_desc : D3D11_SHADER_VARIABLE_DESC;
|
|
if FAILED(ID3D11ShaderReflectionVariable_GetDesc(pvar, *var_desc)) assert(false);
|
|
ptype := ID3D11ShaderReflectionVariable_GetType(pvar);
|
|
var_type_desc : D3D11_SHADER_TYPE_DESC;
|
|
if FAILED(ID3D11ShaderReflectionType_GetDesc(ptype, *var_type_desc)) assert(false);
|
|
|
|
prop : Shader_Property;
|
|
prop.name = copy_string(to_string(var_desc.Name));
|
|
prop.type = variable_type_to_property_type(var_type_desc);
|
|
prop.buffer_offset = xx var_desc.StartOffset;
|
|
|
|
if prop.type == .INVALID continue;
|
|
|
|
param.properties[param.num_properties] = prop;
|
|
param.num_properties += 1;
|
|
}
|
|
|
|
array_add(*shader_info.parameters, param);
|
|
}
|
|
|
|
res_index : u32 = 0;
|
|
while res_index < desc.BoundResources {
|
|
defer res_index += 1;
|
|
|
|
bind_desc : D3D11_SHADER_INPUT_BIND_DESC;
|
|
if FAILED(ID3D11ShaderReflection_GetResourceBindingDesc(reflection, res_index, *bind_desc)) assert(false);
|
|
param : Shader_Parameter;
|
|
|
|
// @Incomplete: Maybe put the constant buffer stuff here and use the ByName function?
|
|
|
|
if bind_desc.Type == {
|
|
case .SIT_SAMPLER; {
|
|
param.type = .SAMPLER;
|
|
}
|
|
case .SIT_TEXTURE; {
|
|
param.type = .TEXTURE;
|
|
prop : Shader_Property;
|
|
prop.name = copy_string(to_string(bind_desc.Name));
|
|
prop.type = .TEXTURE;
|
|
param.properties[param.num_properties] = prop;
|
|
param.num_properties += 1;
|
|
}
|
|
case .SIT_CBUFFER; continue;
|
|
}
|
|
|
|
param.shader = shader_type;
|
|
param.name = copy_string(to_string(bind_desc.Name));
|
|
param.slot = bind_desc.BindPoint;
|
|
param.mapping, param.mapping_str = look_for_mapping(param.name);
|
|
|
|
array_add(*shader_info.parameters, param);
|
|
}
|
|
|
|
}
|
|
|
|
return shader_info;
|
|
}
|
|
|
|
create_backend_shader_from_source :: (using renderer: *D3D11_Backend, name: string, source: string, entry_point: string, shader_type: Shader_Type, defines: [] string = string.[]) -> Backend_Shader, Shader_Info, bool {
|
|
shader_model : string;
|
|
|
|
if shader_type == .VERTEX shader_model = "vs_4_0";
|
|
else shader_model = "ps_4_0";
|
|
|
|
bytecode, blob, hr := compile_shader(name, source, entry_point, shader_model, defines);
|
|
|
|
if FAILED(hr) return .{}, .{}, false;
|
|
|
|
shader : Backend_Shader;
|
|
shader.bytecode = bytecode;
|
|
shader.blob = blob;
|
|
|
|
shader_info := get_shader_info_from_blob(blob, shader_type);
|
|
|
|
if shader_type == {
|
|
case .VERTEX;
|
|
hr = ID3D11Device_CreateVertexShader(d3d_device, bytecode.data, cast(u64)bytecode.count, null, *shader.vertex_shader);
|
|
|
|
if FAILED(hr) {
|
|
log_error("CreateVertexShader failed: %", hr);
|
|
return .{}, .{}, false;
|
|
}
|
|
|
|
case .PIXEL;
|
|
hr = ID3D11Device_CreatePixelShader(d3d_device, bytecode.data, cast(u64)bytecode.count, null, *shader.pixel_shader);
|
|
|
|
if FAILED(hr) {
|
|
log_error("CreatePixelShader failed: %", hr);
|
|
return .{}, .{}, false;
|
|
}
|
|
}
|
|
|
|
return shader, shader_info, true;
|
|
}
|
|
|
|
create_backend_shader :: (using renderer: *D3D11_Backend, path: string, entry_point: string, shader_type: Shader_Type, defines: [] string = string.[]) -> Backend_Shader, Shader_Info, bool {
|
|
content := read_entire_file(path);
|
|
if !content return .{}, .{}, false;
|
|
defer free(content);
|
|
|
|
shader, info, success := create_backend_shader_from_source(renderer, path, content, entry_point, shader_type, defines);
|
|
|
|
return shader, info, success;
|
|
}
|
|
|
|
reload_backend_shader :: (using renderer: *D3D11_Backend, path: string, entry_point: string, shader_type: Shader_Type, defines: [] string = string.[]) -> Backend_Shader, bool {
|
|
content := read_entire_file(path);
|
|
if !content return .{}, false;
|
|
defer free(content);
|
|
|
|
shader, success := reload_backend_shader_from_source(renderer, path, content, entry_point, shader_type, defines);
|
|
|
|
return shader, success;
|
|
}
|
|
|
|
reload_backend_shader_from_source :: (using renderer: *D3D11_Backend, name: string, source: string, entry_point: string, shader_type: Shader_Type, defines: [] string = string.[]) -> Backend_Shader, bool {
|
|
shader_model : string;
|
|
|
|
if shader_type == .VERTEX shader_model = "vs_4_0";
|
|
else shader_model = "ps_4_0";
|
|
|
|
bytecode, blob, hr := compile_shader(name, source, entry_point, shader_model, defines);
|
|
|
|
if FAILED(hr) return .{}, false;
|
|
|
|
shader : Backend_Shader;
|
|
shader.bytecode = bytecode;
|
|
shader.blob = blob;
|
|
|
|
if shader_type == {
|
|
case .VERTEX;
|
|
hr = ID3D11Device_CreateVertexShader(d3d_device, bytecode.data, cast(u64)bytecode.count, null, *shader.vertex_shader);
|
|
|
|
if FAILED(hr) {
|
|
log_error("CreateVertexShader failed: %", hr);
|
|
return .{}, false;
|
|
}
|
|
|
|
case .PIXEL;
|
|
hr = ID3D11Device_CreatePixelShader(d3d_device, bytecode.data, cast(u64)bytecode.count, null, *shader.pixel_shader);
|
|
|
|
if FAILED(hr) {
|
|
log_error("CreatePixelShader failed: %", hr);
|
|
return .{}, false;
|
|
}
|
|
}
|
|
|
|
return shader, true;
|
|
}
|
|
|
|
create_backend_blend_state :: (using renderer: *D3D11_Backend, type: Blend_Type) -> Backend_Blend_State, bool {
|
|
blend_state : Backend_Blend_State;
|
|
|
|
if type == {
|
|
case .OPAQUE;
|
|
// We don't have to create a blend state for opaque objects...
|
|
assert(false);
|
|
case .TRANSPARENT;
|
|
blend_desc : D3D11_BLEND_DESC;
|
|
rtbd : D3D11_RENDER_TARGET_BLEND_DESC;
|
|
|
|
rtbd.BlendEnable = .TRUE;
|
|
rtbd.SrcBlend = .D3D11_BLEND_SRC_ALPHA;
|
|
rtbd.DestBlend = .D3D11_BLEND_INV_SRC_ALPHA;
|
|
rtbd.BlendOp = .D3D11_BLEND_OP_ADD;
|
|
rtbd.SrcBlendAlpha = .D3D11_BLEND_ONE;
|
|
rtbd.DestBlendAlpha = .D3D11_BLEND_DEST_ALPHA;
|
|
rtbd.BlendOpAlpha = .D3D11_BLEND_OP_MAX;
|
|
rtbd.RenderTargetWriteMask = xx D3D11_COLOR_WRITE_ENABLE.ALL;
|
|
|
|
blend_desc.AlphaToCoverageEnable = .FALSE;
|
|
blend_desc.IndependentBlendEnable = .FALSE;
|
|
blend_desc.RenderTarget[0] = rtbd;
|
|
|
|
success := !FAILED(ID3D11Device_CreateBlendState(d3d_device, *blend_desc, *blend_state));
|
|
return blend_state, success;
|
|
}
|
|
|
|
return null, false;
|
|
}
|
|
|
|
semantic_index_for_vertex_data_type :: (type: Vertex_Data_Type) -> u32 {
|
|
if #complete type == {
|
|
case .POSITION;
|
|
#through;
|
|
case .POSITION2D;
|
|
#through;
|
|
case .NORMAL;
|
|
#through;
|
|
case .TANGENT0;
|
|
#through;
|
|
case .COLOR0;
|
|
#through;
|
|
case .COLOR;
|
|
#through;
|
|
case .COLOR_WITH_ALPHA;
|
|
#through;
|
|
case .COLOR_WITH_ALPHA8;
|
|
#through;
|
|
case .TEXCOORD0;
|
|
return 0;
|
|
case .TANGENT1; #through;
|
|
case .POSITION1; #through;
|
|
case .POSITION1_2D;
|
|
return 1;
|
|
case .TEXCOORD1;
|
|
return 1;
|
|
case .TEXCOORD2;
|
|
return 2;
|
|
case .TEXCOORD3;
|
|
return 3;
|
|
case .TEXCOORD4;
|
|
return 4;
|
|
case .INSTANCED_MAT0;
|
|
return 0;
|
|
case .INSTANCED_MAT1;
|
|
return 1;
|
|
case .INSTANCED_MAT2;
|
|
return 2;
|
|
case .INSTANCED_MAT3;
|
|
return 3;
|
|
case .VERTEX_ID;
|
|
return 0;
|
|
case .INSTANCE_ID;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
semantic_name_for_vertex_data_type :: (type: Vertex_Data_Type) -> *u8 #expand {
|
|
str : string;
|
|
if #complete type == {
|
|
case .POSITION;
|
|
#through;
|
|
case .POSITION2D;
|
|
str = "POSITION";
|
|
case .POSITION1;
|
|
str = "POSITION";
|
|
case .POSITION1_2D;
|
|
str = "POSITION";
|
|
case .NORMAL;
|
|
str = "NORMAL";
|
|
case .TANGENT0;
|
|
str = "TANGENT";
|
|
case .TANGENT1;
|
|
str = "TANGENT";
|
|
case .COLOR0;
|
|
str = "COLOR0";
|
|
case .COLOR;
|
|
#through;
|
|
case .COLOR_WITH_ALPHA;
|
|
#through;
|
|
case .COLOR_WITH_ALPHA8;
|
|
str = "COLOR";
|
|
case .TEXCOORD0;
|
|
str = "TEXCOORD";
|
|
case .TEXCOORD1;
|
|
str = "TEXCOORD";
|
|
case .TEXCOORD2;
|
|
str = "TEXCOORD";
|
|
case .TEXCOORD3;
|
|
str = "TEXCOORD";
|
|
case .TEXCOORD4;
|
|
str = "TEXCOORD";
|
|
case .INSTANCED_MAT0; #through;
|
|
case .INSTANCED_MAT1; #through;
|
|
case .INSTANCED_MAT2; #through;
|
|
case .INSTANCED_MAT3;
|
|
str = "INSTANCED_MAT";
|
|
case .VERTEX_ID; {
|
|
str = "SV_VertexID";
|
|
}
|
|
case .INSTANCE_ID; {
|
|
str = "SV_InstanceID";
|
|
}
|
|
}
|
|
|
|
return temp_c_string(str);
|
|
}
|
|
|
|
format_for_vertex_data_type :: (type: Vertex_Data_Type) -> DXGI_FORMAT {
|
|
if #complete type == {
|
|
case .POSITION; #through;
|
|
case .POSITION1;
|
|
return .R32G32B32_FLOAT;
|
|
case .POSITION2D; #through;
|
|
case .POSITION1_2D;
|
|
return .R32G32_FLOAT;
|
|
case .NORMAL;
|
|
return .R32G32B32_FLOAT;
|
|
case .TANGENT0; #through;
|
|
case .TANGENT1;
|
|
return .R32G32B32_FLOAT;
|
|
case .COLOR;
|
|
return .R32G32B32_FLOAT;
|
|
case .COLOR0; #through;
|
|
case .COLOR_WITH_ALPHA;
|
|
return .R32G32B32A32_FLOAT;
|
|
case .COLOR_WITH_ALPHA8;
|
|
return .R8G8B8A8_UNORM;
|
|
case .TEXCOORD0;
|
|
return .R32G32_FLOAT;
|
|
case .TEXCOORD1;
|
|
return .R32G32B32A32_FLOAT;
|
|
case .TEXCOORD2;
|
|
return .R32G32B32A32_FLOAT;
|
|
case .TEXCOORD3;
|
|
return .R32G32B32A32_FLOAT;
|
|
case .TEXCOORD4;
|
|
return .R32G32B32A32_FLOAT;
|
|
case .INSTANCED_MAT0; #through;
|
|
case .INSTANCED_MAT1; #through;
|
|
case .INSTANCED_MAT2; #through;
|
|
case .INSTANCED_MAT3;
|
|
return .R32G32B32A32_FLOAT;
|
|
case .VERTEX_ID; {
|
|
return .R32_UINT;
|
|
}
|
|
case .INSTANCE_ID; {
|
|
return .R32_UINT;
|
|
}
|
|
}
|
|
}
|
|
|
|
create_backend_input_layout :: (using renderer: *D3D11_Backend, layout: [] Vertex_Data_Info, shader: Backend_Shader) -> *ID3D11InputLayout {
|
|
d3d_layout : [..]D3D11_INPUT_ELEMENT_DESC;
|
|
d3d_layout.allocator = temp;
|
|
|
|
for vl, index: layout {
|
|
semantic_name := semantic_name_for_vertex_data_type(vl.type);
|
|
if semantic_name == "SV_InstanceID" continue;
|
|
|
|
l : D3D11_INPUT_ELEMENT_DESC;
|
|
l.SemanticIndex = semantic_index_for_vertex_data_type(vl.type);
|
|
l.SemanticName = semantic_name;
|
|
l.Format = format_for_vertex_data_type(vl.type);
|
|
l.InputSlot = xx vl.slot;
|
|
l.InstanceDataStepRate = xx vl.instanced_step_rate;
|
|
l.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
|
|
|
|
if vl.instanced_step_rate == 0 {
|
|
l.InputSlotClass = .VERTEX_DATA;
|
|
} else {
|
|
l.InputSlotClass = .INSTANCE_DATA;
|
|
}
|
|
|
|
array_add(*d3d_layout, l);
|
|
}
|
|
|
|
vertex_layout : *ID3D11InputLayout;
|
|
hr := ID3D11Device_CreateInputLayout(d3d_device, d3d_layout.data, cast(u32) d3d_layout.count, shader.bytecode.data, cast(u64) shader.bytecode.count, *vertex_layout);
|
|
|
|
if FAILED(hr) {
|
|
//log_error("CreateInputLayout failed: %", hr);
|
|
return null;
|
|
}
|
|
|
|
return vertex_layout;
|
|
}
|
|
|
|
create_backend_input_layout2 :: (using renderer: *D3D11_Backend, layout: [] Vertex_Input, shader: Backend_Shader) -> *ID3D11InputLayout {
|
|
d3d_layout : [..]D3D11_INPUT_ELEMENT_DESC;
|
|
d3d_layout.allocator = temp;
|
|
|
|
for vl, index: layout {
|
|
if vl.semantic_name == "SV_InstanceID" continue;
|
|
|
|
l : D3D11_INPUT_ELEMENT_DESC;
|
|
l.SemanticIndex = xx vl.semantic_index;
|
|
l.SemanticName = to_temp_c_string(vl.semantic_name);
|
|
l.Format = xx vl.format; // @Robustness: Dangerous, since right now the formats are directly mapped with the integer values of DXGI_FORMAT, but this might change at some point and we wouldn't want weird errors
|
|
l.InputSlot = xx vl.slot;
|
|
l.InstanceDataStepRate = xx vl.instanced_step_rate;
|
|
l.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
|
|
|
|
if vl.instanced_step_rate == 0 {
|
|
l.InputSlotClass = .VERTEX_DATA;
|
|
} else {
|
|
l.InputSlotClass = .INSTANCE_DATA;
|
|
}
|
|
|
|
array_add(*d3d_layout, l);
|
|
}
|
|
|
|
vertex_layout : *ID3D11InputLayout;
|
|
hr := ID3D11Device_CreateInputLayout(d3d_device, d3d_layout.data, cast(u32) d3d_layout.count, shader.bytecode.data, cast(u64) shader.bytecode.count, *vertex_layout);
|
|
|
|
if FAILED(hr) {
|
|
log_error("CreateInputLayout failed: %", hr);
|
|
return null;
|
|
}
|
|
|
|
return vertex_layout;
|
|
}
|
|
|
|
create_backend_buffer :: (using renderer: *D3D11_Backend, data: *void, size: u32, stride: u32, type: Buffer_Type, mappable: bool) -> Backend_Buffer, bool {
|
|
bd : D3D11_BUFFER_DESC;
|
|
|
|
flag : D3D11_BIND_FLAG;
|
|
if type == {
|
|
case .VERTEX; {
|
|
bd.BindFlags = .VERTEX_BUFFER;
|
|
}
|
|
case .INDEX; {
|
|
bd.BindFlags = .INDEX_BUFFER;
|
|
}
|
|
case .CONSTANT; {
|
|
bd.BindFlags = .CONSTANT_BUFFER;
|
|
}
|
|
case .STRUCTURED; {
|
|
bd.MiscFlags = .BUFFER_STRUCTURED;
|
|
bd.BindFlags = .SHADER_RESOURCE;
|
|
bd.StructureByteStride = stride;
|
|
}
|
|
}
|
|
|
|
bd.ByteWidth = size;
|
|
|
|
if mappable {
|
|
bd.Usage = .DYNAMIC;
|
|
bd.CPUAccessFlags = .WRITE;
|
|
} else {
|
|
bd.Usage = .DEFAULT;
|
|
bd.CPUAccessFlags = 0;
|
|
}
|
|
|
|
InitData : D3D11_SUBRESOURCE_DATA;
|
|
InitData.pSysMem = data;
|
|
|
|
data_ptr : *D3D11_SUBRESOURCE_DATA;
|
|
if data {
|
|
data_ptr = *InitData;
|
|
}
|
|
|
|
buffer : Backend_Buffer;
|
|
hr := ID3D11Device_CreateBuffer(d3d_device, *bd, data_ptr, *buffer.buffer);
|
|
|
|
|
|
if FAILED(hr) {
|
|
log_error("CreateBuffer failed: %", hr);
|
|
return .{}, false;
|
|
}
|
|
|
|
// If it's a structured buffer, create the shader resource view as well
|
|
if type == .STRUCTURED {
|
|
srv_desc : D3D11_SHADER_RESOURCE_VIEW_DESC;
|
|
srv_desc.Format = .UNKNOWN;
|
|
srv_desc.ViewDimension = .D3D11_SRV_DIMENSION_BUFFER;
|
|
srv_desc.Buffer.ElementOffset = 0;
|
|
srv_desc.Buffer.ElementWidth = stride;
|
|
srv_desc.Buffer.NumElements = size / stride;
|
|
|
|
hr = ID3D11Device_CreateShaderResourceView(d3d_device, buffer.buffer, *srv_desc, *buffer.view);
|
|
if FAILED(hr) {
|
|
log_error("CreateBuffer failed: %", hr);
|
|
return .{}, false;
|
|
}
|
|
}
|
|
|
|
return buffer, true;
|
|
}
|
|
|
|
destroy_backend_buffer :: (using backend: *D3D11_Backend, buffer: Backend_Buffer) {
|
|
IUnknown_Release(buffer.buffer);
|
|
if buffer.view != null {
|
|
IUnknown_Release(buffer.view);
|
|
}
|
|
}
|
|
|
|
map_backend_buffer :: (using backend: *D3D11_Backend, buffer: Backend_Buffer) -> *void{
|
|
mapped_resource : D3D11_MAPPED_SUBRESOURCE;
|
|
memset(*mapped_resource, 0, size_of(D3D11_MAPPED_SUBRESOURCE));
|
|
ID3D11DeviceContext_Map(d3d_context, buffer.buffer, 0, .D3D11_MAP_WRITE_DISCARD, 0, *mapped_resource);
|
|
|
|
return mapped_resource.pData;
|
|
}
|
|
|
|
unmap_backend_buffer :: (using backend: *D3D11_Backend, buffer: Backend_Buffer) {
|
|
ID3D11DeviceContext_Unmap(d3d_context, buffer.buffer, 0);
|
|
}
|
|
|
|
engine_format_to_dx_format :: (format: Format) -> DXGI_FORMAT {
|
|
return cast(DXGI_FORMAT)format;
|
|
}
|
|
|
|
create_backend_texture :: (using backend: *D3D11_Backend, data: *u8, width: u32, height : u32, channels: u32, generate_mips: bool=true, format: Format) -> Backend_Texture, bool {
|
|
dx_format : DXGI_FORMAT = engine_format_to_dx_format(format);
|
|
|
|
//if channels == 1 {
|
|
// format = .DXGI_FORMAT_R8_UNORM;
|
|
//} else {
|
|
// if srgb {
|
|
// format = .DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
|
// } else {
|
|
// format = .DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
// }
|
|
//}
|
|
|
|
desc : D3D11_TEXTURE2D_DESC;
|
|
desc.Width = width;
|
|
desc.Height = height;
|
|
desc.ArraySize = 1;
|
|
|
|
if generate_mips {
|
|
desc.MipLevels = 0;
|
|
desc.BindFlags = D3D11_BIND_FLAG.SHADER_RESOURCE | D3D11_BIND_FLAG.RENDER_TARGET;
|
|
desc.MiscFlags = .D3D11_RESOURCE_MISC_GENERATE_MIPS;
|
|
} else {
|
|
desc.MipLevels = 1;
|
|
desc.BindFlags = D3D11_BIND_FLAG.SHADER_RESOURCE;
|
|
desc.MiscFlags = 0;
|
|
}
|
|
|
|
desc.Format = dx_format;
|
|
desc.SampleDesc.Count = 1;
|
|
desc.Usage = .D3D11_USAGE_DEFAULT;
|
|
desc.CPUAccessFlags = 0;
|
|
|
|
texture : Backend_Texture;
|
|
|
|
if generate_mips {
|
|
hr := ID3D11Device_CreateTexture2D(backend.d3d_device, *desc, null, *texture.texture);
|
|
ID3D11DeviceContext_UpdateSubresource(backend.d3d_context, texture.texture, 0, null, data, width * channels * size_of(u8), 0);
|
|
|
|
if FAILED(hr) {
|
|
return .{}, false;
|
|
} else {
|
|
srv_desc : D3D11_SHADER_RESOURCE_VIEW_DESC;
|
|
srv_desc.Format = desc.Format;
|
|
srv_desc.ViewDimension = .D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
srv_desc.Texture2D.MostDetailedMip = 0;
|
|
srv_desc.Texture2D.MipLevels = cast,no_check(u32)-1;
|
|
|
|
hr = ID3D11Device_CreateShaderResourceView(backend.d3d_device, texture.texture, *srv_desc, *texture.view);
|
|
|
|
if FAILED(hr) {
|
|
return .{}, false;
|
|
}
|
|
|
|
ID3D11DeviceContext_GenerateMips(backend.d3d_context, texture.view);
|
|
}
|
|
} else {
|
|
image_subresource_data : D3D11_SUBRESOURCE_DATA;
|
|
image_subresource_data.pSysMem = data;
|
|
image_subresource_data.SysMemPitch = width * channels * size_of(u8);
|
|
|
|
data_ptr : *D3D11_SUBRESOURCE_DATA;
|
|
|
|
if data {
|
|
data_ptr = *image_subresource_data;
|
|
}
|
|
|
|
hr := ID3D11Device_CreateTexture2D(backend.d3d_device, *desc, data_ptr, *texture.texture);
|
|
|
|
if FAILED(hr) {
|
|
return .{}, false;
|
|
} else {
|
|
srv_desc : D3D11_SHADER_RESOURCE_VIEW_DESC;
|
|
srv_desc.Format = desc.Format;
|
|
srv_desc.ViewDimension = .D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
srv_desc.Texture2D.MostDetailedMip = 0;
|
|
srv_desc.Texture2D.MipLevels = 1;
|
|
|
|
hr = ID3D11Device_CreateShaderResourceView(backend.d3d_device, texture.texture, *srv_desc, *texture.view);
|
|
|
|
if FAILED(hr) {
|
|
return .{}, false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return texture, true;
|
|
}
|
|
|
|
destroy_backend_texture :: (using backend: *D3D11_Backend, texture: Backend_Texture) {
|
|
IUnknown_Release(texture.view);
|
|
IUnknown_Release(texture.texture);
|
|
}
|
|
|
|
update_backend_texture_region :: (using backend: *D3D11_Backend, texture: Backend_Texture, xoffset: u32, yoffset: u32, width: u32, height: u32, pitch: u32, data: *void) {
|
|
box : D3D11_BOX;
|
|
box.front = 0;
|
|
box.back = 1;
|
|
box.left = xoffset;
|
|
box.right = xoffset + width;
|
|
box.top = yoffset;
|
|
box.bottom = yoffset + height;
|
|
ID3D11DeviceContext_UpdateSubresource(backend.d3d_context, texture.texture, 0, *box, data, width * pitch, width * height * pitch);
|
|
}
|
|
|
|
create_backend_render_target :: (using backend: *D3D11_Backend, width: u32, height: u32, format: Format) -> Backend_Render_Target {
|
|
rt : Backend_Render_Target;
|
|
|
|
texture_desc : D3D11_TEXTURE2D_DESC;
|
|
result : HRESULT;
|
|
render_target_view_desc : D3D11_RENDER_TARGET_VIEW_DESC;
|
|
shader_resource_view_desc : D3D11_SHADER_RESOURCE_VIEW_DESC;
|
|
|
|
// Setup the render target texture description.
|
|
texture_desc.Width = width;
|
|
texture_desc.Height = height;
|
|
texture_desc.MipLevels = 1;
|
|
texture_desc.ArraySize = 1;
|
|
texture_desc.Format = .DXGI_FORMAT_R16G16B16A16_FLOAT; // @Incomplete
|
|
texture_desc.SampleDesc.Count = 1;
|
|
texture_desc.Usage = .D3D11_USAGE_DEFAULT;
|
|
texture_desc.BindFlags = D3D11_BIND_FLAG.RENDER_TARGET | D3D11_BIND_FLAG.SHADER_RESOURCE;
|
|
texture_desc.CPUAccessFlags = 0;
|
|
texture_desc.MiscFlags = 0;
|
|
|
|
// Create the render target texture.
|
|
result = ID3D11Device_CreateTexture2D(backend.d3d_device, *texture_desc, null, *rt.texture.texture);
|
|
assert(!FAILED(result));
|
|
|
|
render_target_view_desc.Format = texture_desc.Format;
|
|
render_target_view_desc.ViewDimension = .D3D11_RTV_DIMENSION_TEXTURE2D;
|
|
render_target_view_desc.Texture2D.MipSlice = 0;
|
|
|
|
result = ID3D11Device_CreateRenderTargetView(backend.d3d_device, rt.texture.texture, *render_target_view_desc, *rt.render_target_view);
|
|
assert(!FAILED(result));
|
|
|
|
shader_resource_view_desc.Format = texture_desc.Format;
|
|
shader_resource_view_desc.ViewDimension = .D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
shader_resource_view_desc.Texture2D.MostDetailedMip = 0;
|
|
shader_resource_view_desc.Texture2D.MipLevels = 1;
|
|
|
|
result = ID3D11Device_CreateShaderResourceView(backend.d3d_device, rt.texture.texture, *shader_resource_view_desc, *rt.texture.view);
|
|
assert(!FAILED(result));
|
|
|
|
return rt;
|
|
}
|
|
|
|
get_backend_texture_from_render_target :: (using backend: *D3D11_Backend, render_target: Backend_Render_Target) -> Backend_Texture {
|
|
return render_target.texture;
|
|
}
|
|
|
|
create_backend_depth_stencil_buffer :: (using backend: *D3D11_Backend, width: u32, height: u32) -> Backend_Depth_Stencil_Buffer {
|
|
ds : Backend_Depth_Stencil_Buffer;
|
|
|
|
result : HRESULT;
|
|
|
|
// Setup the render target texture description.
|
|
texture_desc : D3D11_TEXTURE2D_DESC;
|
|
texture_desc.Width = width;
|
|
texture_desc.Height = height;
|
|
texture_desc.MipLevels = 1;
|
|
texture_desc.ArraySize = 1;
|
|
texture_desc.Format = .DXGI_FORMAT_R32_TYPELESS;
|
|
texture_desc.SampleDesc.Count = 1;
|
|
texture_desc.Usage = .D3D11_USAGE_DEFAULT;
|
|
texture_desc.BindFlags = D3D11_BIND_FLAG.DEPTH_STENCIL | D3D11_BIND_FLAG.SHADER_RESOURCE;
|
|
texture_desc.CPUAccessFlags = 0;
|
|
texture_desc.MiscFlags = 0;
|
|
|
|
// Create the render target texture.
|
|
result = ID3D11Device_CreateTexture2D(backend.d3d_device, *texture_desc, null, *ds.texture);
|
|
assert(!FAILED(result));
|
|
|
|
depth_stencil_view_desc : D3D11_DEPTH_STENCIL_VIEW_DESC;
|
|
depth_stencil_view_desc.Format = .DXGI_FORMAT_D32_FLOAT;
|
|
depth_stencil_view_desc.ViewDimension = .D3D11_DSV_DIMENSION_TEXTURE2D;
|
|
depth_stencil_view_desc.Texture2D.MipSlice = 0;
|
|
|
|
result = ID3D11Device_CreateDepthStencilView(backend.d3d_device, ds.texture, *depth_stencil_view_desc, *ds.depth_stencil_view);
|
|
assert(!FAILED(result));
|
|
|
|
shader_resource_view_desc : D3D11_SHADER_RESOURCE_VIEW_DESC;
|
|
shader_resource_view_desc.Format = .DXGI_FORMAT_R32_FLOAT;
|
|
shader_resource_view_desc.ViewDimension = .D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
shader_resource_view_desc.Texture2D.MostDetailedMip = 0;
|
|
shader_resource_view_desc.Texture2D.MipLevels = 1;
|
|
|
|
result = ID3D11Device_CreateShaderResourceView(backend.d3d_device, ds.texture, *shader_resource_view_desc, *ds.shader_resource_view);
|
|
assert(!FAILED(result));
|
|
|
|
return ds;
|
|
}
|
|
|
|
create_backend_sampler :: (using backend: *D3D11_Backend, filter: Sampling_Filter, wrap_mode: Wrap_Mode) -> Backend_Sampler, bool {
|
|
samp_desc : D3D11_SAMPLER_DESC;
|
|
//samp_desc.Filter = .D3D11_FILTER_ANISOTROPIC;
|
|
//samp_desc.AddressU = .D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
//samp_desc.AddressV = .D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
//samp_desc.AddressW = .D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
//samp_desc.MaxAnisotropy = D3D11_REQ_MAXANISOTROPY;
|
|
//samp_desc.ComparisonFunc = .D3D11_COMPARISON_NEVER;
|
|
//samp_desc.MinLOD = 0;
|
|
//samp_desc.MaxLOD = xx D3D11_FLOAT32_MAX;
|
|
//samp_desc.BorderColor[0] = 0.0;
|
|
//samp_desc.BorderColor[1] = 0.0;
|
|
//samp_desc.BorderColor[2] = 0.0;
|
|
//samp_desc.BorderColor[3] = 0.0;
|
|
|
|
//samp_desc.Filter = .D3D11_FILTER_MIN_MAG_MIP_POINT;//.D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;//.D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
|
if filter == {
|
|
case .POINT;
|
|
samp_desc.Filter = .D3D11_FILTER_MIN_MAG_MIP_POINT;
|
|
case .LINEAR;
|
|
samp_desc.Filter = .D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
|
|
|
case .ANISOTROPIC;
|
|
assert(false);
|
|
}
|
|
|
|
if wrap_mode == {
|
|
case .CLAMP;
|
|
samp_desc.AddressU = .D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
samp_desc.AddressV = .D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
samp_desc.AddressW = .D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
case .REPEAT;
|
|
samp_desc.AddressU = .D3D11_TEXTURE_ADDRESS_WRAP;
|
|
samp_desc.AddressV = .D3D11_TEXTURE_ADDRESS_WRAP;
|
|
samp_desc.AddressW = .D3D11_TEXTURE_ADDRESS_WRAP;
|
|
}
|
|
|
|
samp_desc.MipLODBias = 0;
|
|
samp_desc.MaxAnisotropy = 1;
|
|
samp_desc.ComparisonFunc = .D3D11_COMPARISON_NEVER;
|
|
samp_desc.MinLOD = xx -D3D11_FLOAT32_MAX;
|
|
samp_desc.MaxLOD = xx D3D11_FLOAT32_MAX;
|
|
|
|
sampler : Backend_Sampler;
|
|
hr := ID3D11Device_CreateSamplerState(backend.d3d_device, *samp_desc, *sampler);
|
|
|
|
if FAILED(hr) return null, false;
|
|
|
|
return sampler, true;
|
|
}
|
|
|
|
render :: (backend: *D3D11_Backend, command_buffer: *Render_Command_Buffer) {
|
|
time := seconds_since_init();
|
|
|
|
d3d_renderer := cast(*D3D11_Backend)backend;
|
|
using d3d_renderer;
|
|
|
|
for command_buffer.commands {
|
|
if #complete it.type == {
|
|
case .CLEAR_BACKBUFFER;
|
|
clear_color : [4] float;
|
|
clear_color[0] = it.clear_backbuffer.color.x;
|
|
clear_color[1] = it.clear_backbuffer.color.y;
|
|
clear_color[2] = it.clear_backbuffer.color.z;
|
|
clear_color[3] = it.clear_backbuffer.color.w;
|
|
ID3D11DeviceContext_ClearRenderTargetView(d3d_context, render_target_view, *clear_color);
|
|
case .CLEAR_RENDER_TARGET;
|
|
clear_color : [4] float;
|
|
clear_color[0] = it.clear_render_target.color.x;
|
|
clear_color[1] = it.clear_render_target.color.y;
|
|
clear_color[2] = it.clear_render_target.color.z;
|
|
clear_color[3] = it.clear_render_target.color.w;
|
|
ID3D11DeviceContext_ClearRenderTargetView(d3d_context, it.clear_render_target.rt.render_target_view, *clear_color);
|
|
case .CLEAR_DEPTH_STENCIL;
|
|
ID3D11DeviceContext_ClearDepthStencilView(d3d_context, it.clear_depth_stencil.ds.depth_stencil_view, xx D3D11_CLEAR_FLAG.DEPTH, it.clear_depth_stencil.depth, 0);
|
|
case .SET_DRAW_MODE;
|
|
if it.set_draw_mode.draw_mode == {
|
|
case .FILL;
|
|
{
|
|
state := get_or_create_rasterizer_state(d3d_renderer, true, d3d_renderer.cull_face, d3d_renderer.scissor_test);
|
|
d3d_renderer.fill = true;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
}
|
|
case .WIREFRAME;
|
|
{
|
|
state := get_or_create_rasterizer_state(d3d_renderer, false, d3d_renderer.cull_face, d3d_renderer.scissor_test);
|
|
d3d_renderer.fill = false;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
}
|
|
}
|
|
case .SET_CULL_FACE;
|
|
{
|
|
if it.set_cull_face.cull_face == {
|
|
case .FRONT;
|
|
{
|
|
state := get_or_create_rasterizer_state(d3d_renderer, d3d_renderer.fill, .FRONT, d3d_renderer.scissor_test);
|
|
d3d_renderer.cull_face = .FRONT;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
}
|
|
case .BACK;
|
|
{
|
|
state := get_or_create_rasterizer_state(d3d_renderer, d3d_renderer.fill, .BACK, d3d_renderer.scissor_test);
|
|
d3d_renderer.cull_face = .BACK;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
}
|
|
case .NONE;
|
|
{
|
|
state := get_or_create_rasterizer_state(d3d_renderer, d3d_renderer.fill, .NONE, d3d_renderer.scissor_test);
|
|
d3d_renderer.cull_face = .NONE;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
}
|
|
}
|
|
}
|
|
case .SET_DEPTH_WRITE;
|
|
if it.set_depth_write.enabled {
|
|
ID3D11DeviceContext_OMSetDepthStencilState(d3d_context, ds_state, 1);
|
|
} else {
|
|
ID3D11DeviceContext_OMSetDepthStencilState(d3d_context, no_depth_ds_state, 1);
|
|
}
|
|
case .SET_PIPELINE_STATE;
|
|
ID3D11DeviceContext_VSSetShader(d3d_context, it.set_pipeline_state.vs.vertex_shader, null, 0);
|
|
ID3D11DeviceContext_PSSetShader(d3d_context, it.set_pipeline_state.ps.pixel_shader, null, 0);
|
|
ID3D11DeviceContext_IASetInputLayout(d3d_context, it.set_pipeline_state.vertex_layout);
|
|
|
|
if it.set_pipeline_state.blend_type == {
|
|
case .OPAQUE;
|
|
ID3D11DeviceContext_OMSetBlendState(d3d_context, null, null, 0xffffffff);
|
|
case .TRANSPARENT;
|
|
ID3D11DeviceContext_OMSetBlendState(d3d_context, it.set_pipeline_state.blend_state, null, 0xffffffff);
|
|
}
|
|
case .SET_VERTEX_BUFFER;
|
|
offset : u32 = 0;
|
|
ID3D11DeviceContext_IASetVertexBuffers(d3d_context, it.set_vertex_buffer.start_slot, 1, *it.set_vertex_buffer.buffer.buffer, *it.set_vertex_buffer.stride, *offset);
|
|
case .SET_INDEX_BUFFER; {
|
|
ID3D11DeviceContext_IASetIndexBuffer(d3d_context, it.set_index_buffer.buffer.buffer, .R32_UINT, 0);
|
|
}
|
|
case .SET_CONSTANT_BUFFER; {
|
|
if it.set_constant_buffer.shader_type == {
|
|
case .VERTEX;
|
|
ID3D11DeviceContext_VSSetConstantBuffers(d3d_context, it.set_constant_buffer.slot, 1, *it.set_constant_buffer.buffer.buffer);
|
|
case .PIXEL;
|
|
ID3D11DeviceContext_PSSetConstantBuffers(d3d_context, it.set_constant_buffer.slot, 1, *it.set_constant_buffer.buffer.buffer);
|
|
}
|
|
}
|
|
case .SET_STRUCTURED_BUFFER; {
|
|
ID3D11DeviceContext_VSSetShaderResources(d3d_context, xx it.set_structured_buffer.slot, 1, *it.set_structured_buffer.buffer.view);
|
|
}
|
|
case .SET_TEXTURE;
|
|
ID3D11DeviceContext_PSSetShaderResources(d3d_context, xx it.set_texture.slot, 1, *it.set_texture.texture.view);
|
|
case .SET_TEXTURE_FROM_RENDER_TARGET;
|
|
view := it.set_texture_from_rt.rt.texture.view;
|
|
ID3D11DeviceContext_PSSetShaderResources(d3d_context, xx it.set_texture_from_rt.slot, 1, *view);
|
|
case .SET_TEXTURE_FROM_DEPTH_STENCIL;
|
|
view := it.set_texture_from_ds.ds.shader_resource_view;
|
|
ID3D11DeviceContext_PSSetShaderResources(d3d_context, xx it.set_texture_from_ds.slot, 1, *view);
|
|
case .SET_RENDER_TARGETS;
|
|
|
|
views : [..] *ID3D11RenderTargetView;
|
|
views.allocator = temp;
|
|
|
|
render_targets := it.set_render_targets.render_targets;
|
|
for rt, index: render_targets {
|
|
array_add(*views, rt.render_target_view);
|
|
}
|
|
depth_stencil_view : *ID3D11DepthStencilView;
|
|
if it.set_render_targets.depth_stencil_enabled {
|
|
depth_stencil_view = it.set_render_targets.depth_stencil_buffer.depth_stencil_view;
|
|
}
|
|
|
|
ID3D11DeviceContext_OMSetRenderTargets(d3d_context, xx views.count, views.data, depth_stencil_view);
|
|
case .SET_BACKBUFFER;
|
|
ID3D11DeviceContext_OMSetRenderTargets(d3d_context, 1, *render_target_view, null);
|
|
case .SET_SAMPLER;
|
|
ID3D11DeviceContext_PSSetSamplers(d3d_context, xx it.set_sampler.slot, 1, *it.set_sampler.sampler);
|
|
case .SET_VIEWPORT;
|
|
vp : D3D11_VIEWPORT;
|
|
vp.Width = xx it.set_viewport.width;
|
|
vp.Height = xx it.set_viewport.height;
|
|
vp.MinDepth = it.set_viewport.min_depth;
|
|
vp.MaxDepth = it.set_viewport.max_depth;
|
|
vp.TopLeftX = xx it.set_viewport.x;
|
|
vp.TopLeftY = xx it.set_viewport.y;
|
|
ID3D11DeviceContext_RSSetViewports(d3d_context, 1, *vp);
|
|
case .SET_SCISSOR;
|
|
rect : D3D11_RECT;
|
|
rect.left = xx it.set_scissor.x;
|
|
rect.right = xx (it.set_scissor.x + it.set_scissor.width);
|
|
rect.top = xx it.set_scissor.y;
|
|
rect.bottom = xx (it.set_scissor.y + it.set_scissor.height);
|
|
ID3D11DeviceContext_RSSetScissorRects(d3d_context, 1, *rect);
|
|
state := get_or_create_rasterizer_state(d3d_renderer, true, d3d_renderer.cull_face, true);
|
|
d3d_renderer.scissor_test = true;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
case .CLEAR_SCISSOR;
|
|
state := get_or_create_rasterizer_state(d3d_renderer, true, d3d_renderer.cull_face, false);
|
|
d3d_renderer.scissor_test = false;
|
|
ID3D11DeviceContext_RSSetState(d3d_context, state.state);
|
|
case .DRAW;
|
|
if it.draw.topology == {
|
|
case .TRIANGLE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLELIST);
|
|
case .LINE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINELIST);
|
|
case .TRIANGLE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLESTRIP);
|
|
case .LINE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINESTRIP);
|
|
}
|
|
|
|
ID3D11DeviceContext_Draw(d3d_context, xx it.draw.vertex_count, xx it.draw.start_vertex_index);
|
|
case .DRAW_INDEXED;
|
|
if it.draw.topology == {
|
|
case .TRIANGLE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLELIST);
|
|
case .LINE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINELIST);
|
|
case .TRIANGLE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLESTRIP);
|
|
case .LINE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINESTRIP);
|
|
}
|
|
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLELIST);
|
|
ID3D11DeviceContext_DrawIndexed(d3d_context, xx it.draw_indexed.index_count, xx it.draw_indexed.start_index, xx it.draw_indexed.base_vertex);
|
|
case .DRAW_INSTANCED;
|
|
if it.draw.topology == {
|
|
case .TRIANGLE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLELIST);
|
|
case .LINE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINELIST);
|
|
case .TRIANGLE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLESTRIP);
|
|
case .LINE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINESTRIP);
|
|
}
|
|
|
|
ID3D11DeviceContext_DrawInstanced(d3d_context, xx it.draw_instanced.vertex_count, xx it.draw_instanced.instance_count, xx it.draw_instanced.start_vertex_index, xx it.draw_instanced.start_instance_index);
|
|
case .DRAW_INDEXED_INSTANCED;
|
|
if it.draw.topology == {
|
|
case .TRIANGLE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLELIST);
|
|
case .LINE_LIST;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINELIST);
|
|
case .TRIANGLE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.TRIANGLESTRIP);
|
|
case .LINE_STRIP;
|
|
ID3D11DeviceContext_IASetPrimitiveTopology(d3d_context, D3D11_PRIMITIVE_TOPOLOGY.LINESTRIP);
|
|
}
|
|
|
|
ID3D11DeviceContext_DrawIndexedInstanced(d3d_context, xx it.draw_indexed_instanced.index_count, xx it.draw_indexed_instanced.instance_count, xx it.draw_indexed_instanced.start_index, xx it.draw_indexed_instanced.base_vertex, 0);
|
|
case .RENDER_IMGUI; {
|
|
ImGui.Render();
|
|
imgui_impldx11_render_draw_data(ImGui.GetDrawData());
|
|
}
|
|
}
|
|
}
|
|
|
|
d3d_renderer.scissor_test = false;
|
|
|
|
now := seconds_since_init();
|
|
engine.renderer.last_render_time_cpu = cast(float)(now - time) * 1000.0;
|
|
time = now;
|
|
|
|
// Present the information rendered to the back buffer to the front buffer (the screen)
|
|
before_swap := seconds_since_init();
|
|
hr := IDXGISwapChain_Present(swap_chain, xx ifx engine.renderer.vsync then 1 else 0, 0);
|
|
after_swap := seconds_since_init();
|
|
//print("RENDERING: It took % sec to present the final image\n", after_swap - before_swap);
|
|
engine.renderer.last_render_time_gpu = cast(float)(now - time) * 1000.0;
|
|
|
|
if FAILED(hr) {
|
|
log_error("Present failed: %", hr);
|
|
removed_reason := ID3D11Device_GetDeviceRemovedReason(d3d_device);
|
|
log_error("Removed reason: %", removed_reason);
|
|
}
|
|
}
|
|
|
|
#scope_file
|
|
get_or_create_rasterizer_state :: (backend: *D3D11_Backend, fill: bool, cull_face: Cull_Face, scissor_test: bool) -> *Rasterizer_State {
|
|
for * backend.rasterizer_states {
|
|
if it.fill == fill && it.cull_face == cull_face && it.scissor_test == scissor_test {
|
|
return it;
|
|
}
|
|
}
|
|
|
|
return create_rasterizer_state(backend, fill, cull_face, scissor_test);
|
|
}
|
|
|
|
create_rasterizer_state :: (backend: *D3D11_Backend, fill: bool, cull_face: Cull_Face, scissor_test: bool) -> *Rasterizer_State {
|
|
raster_desc : D3D11_RASTERIZER_DESC;
|
|
raster_desc.AntialiasedLineEnable = .FALSE;
|
|
|
|
if cull_face == {
|
|
case .FRONT;
|
|
raster_desc.CullMode = .D3D11_CULL_FRONT;
|
|
case .BACK;
|
|
raster_desc.CullMode = .D3D11_CULL_BACK;
|
|
case .NONE;
|
|
raster_desc.CullMode = .D3D11_CULL_NONE;
|
|
}
|
|
|
|
raster_desc.DepthBias = 0;
|
|
raster_desc.DepthBiasClamp = 0.0;
|
|
raster_desc.DepthClipEnable = .TRUE;
|
|
|
|
if fill {
|
|
raster_desc.FillMode = .D3D11_FILL_SOLID;
|
|
} else {
|
|
raster_desc.FillMode = .D3D11_FILL_WIREFRAME;
|
|
}
|
|
|
|
raster_desc.FrontCounterClockwise = .FALSE;
|
|
raster_desc.MultisampleEnable = .FALSE;
|
|
raster_desc.ScissorEnable = ifx scissor_test then .TRUE else .FALSE;
|
|
raster_desc.SlopeScaledDepthBias = 0.0;
|
|
|
|
state : *ID3D11RasterizerState;
|
|
result := ID3D11Device_CreateRasterizerState(backend.d3d_device, *raster_desc, *state);
|
|
assert(!FAILED(result));
|
|
|
|
rasterizer_info : Rasterizer_State;
|
|
rasterizer_info.fill = fill;
|
|
rasterizer_info.cull_face = cull_face;
|
|
rasterizer_info.state = state;
|
|
|
|
array_add(*backend.rasterizer_states, rasterizer_info);
|
|
|
|
return *backend.rasterizer_states[backend.rasterizer_states.count-1];
|
|
}
|
|
|
|
//#import "shader_parsing";
|