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