#if !OOGABOOGA_DEV #include "d3d11_image_shader_bytecode.c" #endif #define D3D11Release(x) x->lpVtbl->Release(x) #define VTABLE(proc, ...) FIRST_ARG(__VA_ARGS__)->lpVtbl->proc(__VA_ARGS__) const Gfx_Handle GFX_INVALID_HANDLE = 0; string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16); typedef struct D3D11_Vertex { Vector4 position; Vector2 uv; Vector4 color; int texture_index; } D3D11_Vertex; ID3D11Debug *d3d11_debug = 0; ID3D11Device* d3d11_device = 0; ID3D11DeviceContext* d3d11_context = 0; ID3D11RenderTargetView *d3d11_window_render_target_view = 0; ID3D11Texture2D *d3d11_back_buffer = 0; D3D_DRIVER_TYPE d3d11_driver_type = 0; D3D_FEATURE_LEVEL d3d11_feature_level = 0; IDXGISwapChain1 *d3d11_swap_chain = 0; DXGI_SWAP_CHAIN_DESC1 d3d11_swap_chain_desc = ZERO(DXGI_SWAP_CHAIN_DESC1); u32 d3d11_swap_chain_width = 0; u32 d3d11_swap_chain_height = 0; ID3D11BlendState *d3d11_blend_state = 0; ID3D11RasterizerState *d3d11_rasterizer = 0; ID3D11SamplerState *d3d11_image_sampler = 0; ID3D11VertexShader *d3d11_image_vertex_shader = 0; ID3D11PixelShader *d3d11_image_pixel_shader = 0; ID3D11InputLayout *d3d11_image_vertex_layout = 0; ID3D11Buffer *d3d11_quad_vbo = 0; u32 d3d11_quad_vbo_size = 0; void *d3d11_staging_quad_buffer = 0; const char* d3d11_stringify_category(D3D11_MESSAGE_CATEGORY category) { switch (category) { case D3D11_MESSAGE_CATEGORY_APPLICATION_DEFINED: return "Application Defined"; case D3D11_MESSAGE_CATEGORY_MISCELLANEOUS: return "Miscellaneous"; case D3D11_MESSAGE_CATEGORY_INITIALIZATION: return "Initialization"; case D3D11_MESSAGE_CATEGORY_CLEANUP: return "Cleanup"; case D3D11_MESSAGE_CATEGORY_COMPILATION: return "Compilation"; case D3D11_MESSAGE_CATEGORY_STATE_CREATION: return "State Creation"; case D3D11_MESSAGE_CATEGORY_STATE_SETTING: return "State Setting"; case D3D11_MESSAGE_CATEGORY_STATE_GETTING: return "State Getting"; case D3D11_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: return "Resource Manipulation"; case D3D11_MESSAGE_CATEGORY_EXECUTION: return "Execution"; default: return "Unknown"; } } const char* d3d11_stringify_severity(D3D11_MESSAGE_SEVERITY severity) { switch (severity) { case D3D11_MESSAGE_SEVERITY_CORRUPTION: return "Corruption"; case D3D11_MESSAGE_SEVERITY_ERROR: return "Error"; case D3D11_MESSAGE_SEVERITY_WARNING: return "Warning"; case D3D11_MESSAGE_SEVERITY_INFO: return "Info"; case D3D11_MESSAGE_SEVERITY_MESSAGE: return "Message"; default: return "Unknown"; } } void CALLBACK d3d11_debug_callback(D3D11_MESSAGE_CATEGORY category, D3D11_MESSAGE_SEVERITY severity, D3D11_MESSAGE_ID id, const char* description) { string msg = tprint("D3D11 MESSAGE [Category: %cs, Severity: %cs, id: %d]: %cs", d3d11_stringify_category(category), d3d11_stringify_severity(severity), id, description); switch (severity) { case D3D11_MESSAGE_SEVERITY_CORRUPTION: case D3D11_MESSAGE_SEVERITY_ERROR: log_error(msg); case D3D11_MESSAGE_SEVERITY_WARNING: log_warning(msg); case D3D11_MESSAGE_SEVERITY_INFO: log_info(msg); case D3D11_MESSAGE_SEVERITY_MESSAGE: log_verbose(msg); default: log("Ligma"); } } #define win32_check_hr(hr) win32_check_hr_impl(hr, __LINE__, __FILE__); void win32_check_hr_impl(HRESULT hr, u32 line, const char* file_name) { if (FAILED(hr)) { LPVOID errorMsg; DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; DWORD messageLength = FormatMessage( dwFlags, NULL, hr, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR) &errorMsg, 0, NULL ); if (messageLength > 0) { MessageBox(NULL, (LPCTSTR)errorMsg, TEXT("Error"), MB_OK | MB_ICONERROR); } else { MessageBox(NULL, TEXT("Failed to retrieve error message."), TEXT("Error"), MB_OK | MB_ICONERROR); } panic("win32 hr failed in file %cs on line %d", file_name, line); } } void d3d11_update_swapchain() { HRESULT hr; bool create = !d3d11_swap_chain; if (create) { DXGI_SWAP_CHAIN_DESC1 scd = ZERO(DXGI_SWAP_CHAIN_DESC1); scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; //scd.BufferDesc.RefreshRate.Numerator = xx st.refresh_rate; //scd.BufferDesc.RefreshRate.Denominator = 1; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.SampleDesc.Count = 1; scd.SampleDesc.Quality = 0; if (d3d11_feature_level < D3D_FEATURE_LEVEL_11_0) { scd.Scaling = DXGI_SCALING_STRETCH; // for compatability with 7 } // Windows 10 allows to use DXGI_SWAP_EFFECT_FLIP_DISCARD // for Windows 8 compatibility use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL // for Windows 7 compatibility use DXGI_SWAP_EFFECT_DISCARD if (d3d11_feature_level >= D3D_FEATURE_LEVEL_11_0) { // this is supported only on FLIP presentation model scd.Scaling = DXGI_SCALING_NONE; scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; scd.BufferCount = 3; gfx._can_vsync = false; log_verbose("Present mode is flip discard, 3 buffers"); } else { scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; scd.BufferCount = 2; gfx._can_vsync = true; log_verbose("Present mode is discard, 2 buffers"); } // Obtain DXGI factory from device IDXGIDevice *dxgi_device; hr = VTABLE(QueryInterface, d3d11_device, &IID_IDXGIDevice, cast(void**)&dxgi_device); win32_check_hr(hr); IDXGIAdapter *adapter; hr = VTABLE(GetAdapter, dxgi_device, &adapter); win32_check_hr(hr); IDXGIFactory2 *dxgi_factory; hr = VTABLE(GetParent, adapter, &IID_IDXGIFactory2, cast(void**)&dxgi_factory); win32_check_hr(hr); hr = VTABLE(CreateSwapChainForHwnd, dxgi_factory, (IUnknown*)d3d11_device, window._os_handle, &scd, 0, 0, &d3d11_swap_chain); win32_check_hr(hr); RECT client_rect; bool ok = GetClientRect(window._os_handle, &client_rect); assert(ok, "GetClientRect failed with error code %lu", GetLastError()); d3d11_swap_chain_width = client_rect.right-client_rect.left; d3d11_swap_chain_height = client_rect.bottom-client_rect.top; // store the swap chain description, as created by CreateSwapChainForHwnd hr = VTABLE(GetDesc1, d3d11_swap_chain, &d3d11_swap_chain_desc); win32_check_hr(hr); // disable alt enter VTABLE(MakeWindowAssociation, dxgi_factory, window._os_handle, cast (u32) DXGI_MWA_NO_ALT_ENTER); D3D11Release(dxgi_device); D3D11Release(adapter); D3D11Release(dxgi_factory); log("Created swap chain of size %dx%d", d3d11_swap_chain_width, d3d11_swap_chain_height); } else { if (d3d11_window_render_target_view) D3D11Release(d3d11_window_render_target_view); if (d3d11_back_buffer) D3D11Release(d3d11_back_buffer); RECT client_rect; bool ok = GetClientRect(window._os_handle, &client_rect); assert(ok, "GetClientRect failed with error code %lu", GetLastError()); u32 window_width = client_rect.right-client_rect.left; u32 window_height = client_rect.bottom-client_rect.top; hr = VTABLE(ResizeBuffers, d3d11_swap_chain, d3d11_swap_chain_desc.BufferCount, window_width, window_height, d3d11_swap_chain_desc.Format, d3d11_swap_chain_desc.Flags); win32_check_hr(hr); // update swap chain description hr = VTABLE(GetDesc1, d3d11_swap_chain, &d3d11_swap_chain_desc); win32_check_hr(hr); log("Resized swap chain from %dx%d to %dx%d", d3d11_swap_chain_width, d3d11_swap_chain_height, window_width, window_height); d3d11_swap_chain_width = window_width; d3d11_swap_chain_height = window_height; } hr = VTABLE(GetBuffer, d3d11_swap_chain, 0, &IID_ID3D11Texture2D, (void**)&d3d11_back_buffer); win32_check_hr(hr); hr = VTABLE(CreateRenderTargetView, d3d11_device, (ID3D11Resource*)d3d11_back_buffer, 0, &d3d11_window_render_target_view); win32_check_hr(hr); } void gfx_init() { gfx.enable_vsync = false; log_verbose("d3d11 gfx_init"); HWND hwnd = window._os_handle; HRESULT hr = S_OK; D3D11_CREATE_DEVICE_FLAG flags = 0; #if CONFIGURATION == DEBUG flags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_DRIVER_TYPE driver_types[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE }; s64 num_drivers = sizeof(driver_types)/sizeof(D3D_DRIVER_TYPE); D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 }; s64 num_feature_levels = sizeof(feature_levels)/sizeof(D3D_FEATURE_LEVEL); for (s64 i = 0; i < num_drivers; i++) { d3d11_driver_type = driver_types[i]; hr = D3D11CreateDevice(0, d3d11_driver_type, 0, flags, feature_levels, num_feature_levels, D3D11_SDK_VERSION, &d3d11_device, &d3d11_feature_level, &d3d11_context); if (hr == E_INVALIDARG) { // 11_1 not recognized in 11.0 hr = D3D11CreateDevice(0, d3d11_driver_type, 0, flags, feature_levels+1, num_feature_levels-1, D3D11_SDK_VERSION, &d3d11_device, &d3d11_feature_level, &d3d11_context); } if (SUCCEEDED(hr)) break; log_verbose("Failed driver type number %d (%d)", i, driver_types[i]); } win32_check_hr(hr); assert(d3d11_device != 0, "D3D11CreateDevice failed"); #if CONFIGURATION == DEBUG hr = VTABLE(QueryInterface, d3d11_device, &IID_ID3D11Debug, (void**)&d3d11_debug); if (SUCCEEDED(hr)) { log_verbose("D3D11 debug is active"); } #endif log_verbose("Created D3D11 device"); IDXGIDevice *dxgi_device = 0; IDXGIAdapter *target_adapter = 0; hr = VTABLE(QueryInterface, d3d11_device, &IID_IDXGIDevice, (void **)&dxgi_device); hr = VTABLE(GetAdapter, dxgi_device, &target_adapter); if (SUCCEEDED(hr)) { DXGI_ADAPTER_DESC adapter_desc = ZERO(DXGI_ADAPTER_DESC); hr = VTABLE(GetDesc, target_adapter, &adapter_desc); if (SUCCEEDED(hr)) { string desc = temp_win32_null_terminated_wide_to_fixed_utf8(adapter_desc.Description); log("D3D11 adapter is: %s", desc); } else { log_error("Failed to get adapter description"); } } else { log_error("Failed querying targeted d3d11_ adapter"); } d3d11_update_swapchain(); { D3D11_BLEND_DESC bd = ZERO(D3D11_BLEND_DESC); bd.RenderTarget[0].BlendEnable = TRUE; bd.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; bd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; bd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; hr = VTABLE(CreateBlendState, d3d11_device, &bd, &d3d11_blend_state); win32_check_hr(hr); VTABLE(OMSetBlendState, d3d11_context, d3d11_blend_state, NULL, 0xffffffff); } { D3D11_RASTERIZER_DESC desc = ZERO(D3D11_RASTERIZER_DESC); desc.FillMode = D3D11_FILL_SOLID; //desc.CullMode = D3D11_CULL_BACK; desc.FrontCounterClockwise = FALSE; desc.DepthClipEnable = FALSE; desc.CullMode = D3D11_CULL_NONE; hr = VTABLE(CreateRasterizerState, d3d11_device, &desc, &d3d11_rasterizer); win32_check_hr(hr); VTABLE(RSSetState, d3d11_context, d3d11_rasterizer); } // COnst buffer /*{ D3D11_BUFFER_DESC bd; bd.ByteWidth = align_forward(sizeof(GlobalConstBuffer), 16); bd.Usage = D3D11_USAGE_DYNAMIC; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; ID3D11Device_CreateBuffer(dx_state.d3d_device, &bd, NULL, &dx_state.const_buffer_resource); }*/ /*{ D3D11_BUFFER_DESC bd; bd.ByteWidth = align_forward(sizeof(BatchUniforms), 16); bd.Usage = D3D11_USAGE_DYNAMIC; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; ID3D11Device_CreateBuffer(dx_state.d3d_device, &bd, NULL, &render_st.batch.ubo); }*/ { D3D11_SAMPLER_DESC sd = ZERO(D3D11_SAMPLER_DESC); sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; sd.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; sd.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; sd.ComparisonFunc = D3D11_COMPARISON_NEVER; hr = VTABLE(CreateSamplerState, d3d11_device, &sd, &d3d11_image_sampler); win32_check_hr(hr); } // We are ooga booga devs so we read the file and compile #if OOGABOOGA_DEV string source; bool source_ok = os_read_entire_file("oogabooga/dev/d3d11_image_shader.hlsl", &source, get_heap_allocator()); // #Leak assert(source_ok, "Could not open d3d11_image_shader source"); // Compile vertex shader ID3DBlob* vs_blob = NULL; ID3DBlob* err_blob = NULL; hr = D3DCompile((char*)source.data, source.count, 0, 0, 0, "vs_main", "vs_5_0", 0, 0, &vs_blob, &err_blob); assert(SUCCEEDED(hr), "Vertex Shader Compilation Error: %cs\n", (char*)VTABLE(GetBufferPointer, err_blob)); // Compile pixel shader ID3DBlob* ps_blob = NULL; hr = D3DCompile((char*)source.data, source.count, 0, 0, 0, "ps_main", "ps_5_0", 0, 0, &ps_blob, &err_blob); assert(SUCCEEDED(hr), "Vertex Shader Compilation Error: %cs\n", (char*)VTABLE(GetBufferPointer, err_blob)); void *vs_buffer = VTABLE(GetBufferPointer, vs_blob); u64 vs_size = VTABLE(GetBufferSize, vs_blob); void *ps_buffer = VTABLE(GetBufferPointer, ps_blob); u64 ps_size = VTABLE(GetBufferSize, ps_blob); log_verbose("Shaders compiled"); /// // Dump blobs to the .c File blob_file = os_file_open("oogabooga/d3d11_image_shader_bytecode.c", O_WRITE | O_CREATE); os_file_write_string(blob_file, STR("/*\n")); os_file_write_string(blob_file, STR("<<<<<< Bytecode compiled fro HLSL code below: >>>>>>\n\n")); os_file_write_string(blob_file, source); os_file_write_string(blob_file, STR("\n*/\n\n")); os_file_write_string(blob_file, STR("const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[]= {\n")); for (u64 i = 0; i < vs_size; i++) { os_file_write_string(blob_file, tprint("0x%02x", (int)((u8*)vs_buffer)[i])); if (i < vs_size-1) os_file_write_string(blob_file, STR(", ")); if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, STR("\n")); } os_file_write_string(blob_file, STR("\n};\n")); os_file_write_string(blob_file, STR("const u8 IMAGE_SHADER_PIXEL_BLOB_BYTES[]= {\n")); for (u64 i = 0; i < ps_size; i++) { os_file_write_string(blob_file, tprint("0x%02x", (int)((u8*)ps_buffer)[i])); if (i < ps_size-1) os_file_write_string(blob_file, STR(", ")); if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, STR("\n")); } os_file_write_string(blob_file, STR("\n};\n")); os_file_close(blob_file); #else const void *vs_buffer = IMAGE_SHADER_VERTEX_BLOB_BYTES; u64 vs_size = sizeof(IMAGE_SHADER_VERTEX_BLOB_BYTES); const void *ps_buffer = IMAGE_SHADER_PIXEL_BLOB_BYTES; u64 ps_size = sizeof(IMAGE_SHADER_PIXEL_BLOB_BYTES); log_verbose("Cached shaders loaded"); #endif // Create the shaders hr = VTABLE(CreateVertexShader, d3d11_device, vs_buffer, vs_size, NULL, &d3d11_image_vertex_shader); win32_check_hr(hr); hr = VTABLE(CreatePixelShader, d3d11_device, ps_buffer, ps_size, NULL, &d3d11_image_pixel_shader); win32_check_hr(hr); log_verbose("Shaders created"); #if OOGABOOGA_DEV D3D11Release(vs_blob); D3D11Release(ps_blob); #endif D3D11_INPUT_ELEMENT_DESC layout[4]; memset(layout, 0, sizeof(layout)); layout[0] = (D3D11_INPUT_ELEMENT_DESC){ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(D3D11_Vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 }; layout[1] = (D3D11_INPUT_ELEMENT_DESC){ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(D3D11_Vertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }; layout[2] = (D3D11_INPUT_ELEMENT_DESC){ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(D3D11_Vertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 }; layout[3] = (D3D11_INPUT_ELEMENT_DESC){ "TEXTURE_INDEX", 0, DXGI_FORMAT_R32_SINT, 0, offsetof(D3D11_Vertex, texture_index), D3D11_INPUT_PER_VERTEX_DATA, 0 }; hr = VTABLE(CreateInputLayout, d3d11_device, layout, 4, vs_buffer, vs_size, &d3d11_image_vertex_layout); log_info("D3D11 init done"); } void d3d11_draw_call(int number_of_rendered_quads, ID3D11ShaderResourceView **textures, u64 num_textures) { VTABLE(OMSetBlendState, d3d11_context, d3d11_blend_state, 0, 0xffffffff); VTABLE(OMSetRenderTargets, d3d11_context, 1, &d3d11_window_render_target_view, 0); VTABLE(RSSetState, d3d11_context, d3d11_rasterizer); D3D11_VIEWPORT viewport = ZERO(D3D11_VIEWPORT); viewport.Width = d3d11_swap_chain_width; viewport.Height = d3d11_swap_chain_height; viewport.MaxDepth = 1.0; VTABLE(RSSetViewports, d3d11_context, 1, &viewport); UINT stride = sizeof(D3D11_Vertex); UINT offset = 0; VTABLE(IASetInputLayout, d3d11_context, d3d11_image_vertex_layout); VTABLE(IASetVertexBuffers, d3d11_context, 0, 1, &d3d11_quad_vbo, &stride, &offset); VTABLE(IASetPrimitiveTopology, d3d11_context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); VTABLE(VSSetShader, d3d11_context, d3d11_image_vertex_shader, NULL, 0); VTABLE(PSSetShader, d3d11_context, d3d11_image_pixel_shader, NULL, 0); VTABLE(PSSetSamplers, d3d11_context, 0, 1, &d3d11_image_sampler); VTABLE(PSSetShaderResources, d3d11_context, 0, num_textures, textures); VTABLE(ClearRenderTargetView, d3d11_context, d3d11_window_render_target_view, (float*)&window.clear_color); VTABLE(Draw, d3d11_context, number_of_rendered_quads * 6, 0); } void gfx_update() { if (window.should_close) return; VTABLE(ClearRenderTargetView, d3d11_context, d3d11_window_render_target_view, (float*)&window.clear_color); HRESULT hr; /// // purge garbage for (u64 i = 0; i < draw_frame.garbage_stack_count; i++) { ID3D11ShaderResourceView *view = draw_frame.garbage_stack[i]; ID3D11Resource *resource = 0; VTABLE(GetResource, view, &resource); ID3D11Texture2D *texture = 0; hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture); if (SUCCEEDED(hr)) { D3D11Release(view); D3D11Release(texture); log("Destroyed an image"); } else { panic("Unhandled D3D11 resource deletion"); } } /// // Maybe resize swap chain RECT client_rect; bool ok = GetClientRect(window._os_handle, &client_rect); assert(ok, "GetClientRect failed with error code %lu", GetLastError()); u32 window_width = client_rect.right-client_rect.left; u32 window_height = client_rect.bottom-client_rect.top; if (window_width != d3d11_swap_chain_width || window_height != d3d11_swap_chain_height) { d3d11_update_swapchain(); } /// // Maybe grow quad vbo u32 required_size = sizeof(D3D11_Vertex) * draw_frame.num_blocks*QUADS_PER_BLOCK*6; if (required_size > d3d11_quad_vbo_size) { if (d3d11_quad_vbo) { D3D11Release(d3d11_quad_vbo); dealloc(get_heap_allocator(), d3d11_staging_quad_buffer); } D3D11_BUFFER_DESC desc = ZERO(D3D11_BUFFER_DESC); desc.Usage = D3D11_USAGE_DYNAMIC; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; desc.ByteWidth = required_size; desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; HRESULT hr = VTABLE(CreateBuffer, d3d11_device, &desc, 0, &d3d11_quad_vbo); assert(SUCCEEDED(hr), "CreateBuffer failed"); d3d11_quad_vbo_size = required_size; d3d11_staging_quad_buffer = alloc(get_heap_allocator(), d3d11_quad_vbo_size); log_verbose("Grew quad vbo to %d bytes.", d3d11_quad_vbo_size); } f64 rest_before = os_get_current_time_in_seconds(); if (draw_frame.num_blocks > 0) { /// // Render geometry from into vbo quad list ID3D11ShaderResourceView *textures[32]; ID3D11ShaderResourceView *last_texture = 0; u64 num_textures = 0; D3D11_Vertex* head = (D3D11_Vertex*)d3d11_staging_quad_buffer; D3D11_Vertex* pointer = head; u64 number_of_rendered_quads = 0; Draw_Quad_Block *block = &first_block; tm_scope_cycles("Quad processing") { while (block != 0 && block->num_quads > 0) tm_scope_cycles("ad2As") { for (u64 i = 0; i < block->num_quads; i++) tm_scope_cycles("Single quad") { Draw_Quad *q = &block->quad_buffer[i]; int texture_index = -1; if (q->image) { if (!q->image->gfx_handle) { D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC); desc.Width = q->image->width; desc.Height = q->image->height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA data = ZERO(D3D11_SUBRESOURCE_DATA); data.pSysMem = q->image->data; data.SysMemPitch = q->image->width * 4; // #Magicvalue assuming 4 channels ID3D11Texture2D* texture = 0; HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data, &texture); win32_check_hr(hr); hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &q->image->gfx_handle); win32_check_hr(hr); log_verbose("Created an image of width %d and height %d.", q->image->width, q->image->height); } if (last_texture == q->image->gfx_handle) { texture_index = (int)(num_textures-1); } else { // First look if texture is already bound for (u64 j = 0; j < num_textures; j++) { if (textures[j] == q->image->gfx_handle) { texture_index = (int)j; break; } } // Otherwise use a new slot if (texture_index <= -1) { if (num_textures >= 32) { // If max textures reached, make a draw call and start over D3D11_MAPPED_SUBRESOURCE buffer_mapping; VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &buffer_mapping); memcpy(buffer_mapping.pData, d3d11_staging_quad_buffer, number_of_rendered_quads*sizeof(D3D11_Vertex)*6); VTABLE(Unmap, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0); d3d11_draw_call(number_of_rendered_quads, textures, num_textures); head = (D3D11_Vertex*)d3d11_staging_quad_buffer; num_textures = 0; texture_index = 0; number_of_rendered_quads = 0; pointer = head; } else { texture_index = (int)num_textures; num_textures += 1; } } } textures[texture_index] = q->image->gfx_handle; last_texture = q->image->gfx_handle; } // We will write to 6 vertices for the one quad (two tris) { D3D11_Vertex* BL = pointer + 0; D3D11_Vertex* TL = pointer + 1; D3D11_Vertex* TR = pointer + 2; D3D11_Vertex* BL2 = pointer + 3; D3D11_Vertex* TR2 = pointer + 4; D3D11_Vertex* BR = pointer + 5; pointer += 6; BL->position = v4(q->bottom_left.x, q->bottom_left.y, 0, 1); TL->position = v4(q->top_left.x, q->top_left.y, 0, 1); TR->position = v4(q->top_right.x, q->top_right.y, 0, 1); BR->position = v4(q->bottom_right.x, q->bottom_right.y, 0, 1); BL->uv = v2(q->uv.x1, q->uv.y1); TL->uv = v2(q->uv.x1, q->uv.y2); TR->uv = v2(q->uv.x2, q->uv.y2); BR->uv = v2(q->uv.x2, q->uv.y1); BL->color = TL->color = TR->color = BR->color = q->color; BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index; *BL2 = *BL; *TR2 = *TR; number_of_rendered_quads += 1; } } block = block->next; } } D3D11_MAPPED_SUBRESOURCE buffer_mapping; VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &buffer_mapping); memcpy(buffer_mapping.pData, d3d11_staging_quad_buffer, number_of_rendered_quads*sizeof(D3D11_Vertex)*6); VTABLE(Unmap, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0); /// // Draw call u64 before_draw = os_get_current_cycle_count(); d3d11_draw_call(number_of_rendered_quads, textures, num_textures); u64 after_draw = os_get_current_cycle_count(); //log("Draw call took %llu cycles", after_draw-before_draw); } f64 rest_after = os_get_current_time_in_seconds(); if (is_key_just_pressed('E')) log("The rest took %.2fms", (rest_after-rest_before)*1000.0); f64 before_present = os_get_current_time_in_seconds(); hr = VTABLE(Present, d3d11_swap_chain, gfx._can_vsync && gfx.enable_vsync, 0); f64 after = os_get_current_time_in_seconds(); if (is_key_just_pressed('E')) log("Present took %.2fms", (after-before_present)*1000.0); win32_check_hr(hr); #if CONFIGURATION == DEBUG /// // Check debug messages, output to stdout ID3D11InfoQueue* info_q = 0; hr = VTABLE(QueryInterface, d3d11_device, &IID_ID3D11InfoQueue, (void**)&info_q); if (SUCCEEDED(hr)) { u64 msg_count = VTABLE(GetNumStoredMessagesAllowedByRetrievalFilter, info_q); for (u64 i = 0; i < msg_count; i++) { SIZE_T msg_size = 0; VTABLE(GetMessage, info_q, i, 0, &msg_size); D3D11_MESSAGE* msg = (D3D11_MESSAGE*)talloc(msg_size); if (msg) { VTABLE(GetMessage, info_q, i, msg, &msg_size); // Get the actual message d3d11_debug_callback(msg->Category, msg->Severity, msg->ID, msg->pDescription); } } } #endif reset_draw_frame(&draw_frame); }