Files
coven/renderer/dx11_renderer.jai

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";