Renamed "directx" to dx11 in several variable names, types and defines.

Added date to NOTEs and TODOs.
Tried to make log strings more useful, even if I don't know how you display things log with log_os.
This commit is contained in:
Simon Anciaux 2024-02-28 17:59:36 +01:00 committed by Peter Slattery
parent 7ce0a7d698
commit d0a18fcdb7
3 changed files with 273 additions and 249 deletions

View File

@ -1,7 +1,7 @@
#define DIRECTX_MAX_TEXTURE_COUNT 32 #define DX11_MAX_TEXTURE_COUNT 32
struct DirectXTexture { struct DX11Texture {
ID3D11Texture2D* pointer; ID3D11Texture2D* pointer;
ID3D11ShaderResourceView* view; ID3D11ShaderResourceView* view;
}; };
@ -13,7 +13,7 @@ struct GL_Program {
b8 valid; b8 valid;
}; };
struct DirectX { struct DX11 {
b8 initialized; b8 initialized;
ID3D11Device1* device; ID3D11Device1* device;
ID3D11DeviceContext1* context; ID3D11DeviceContext1* context;
@ -24,24 +24,25 @@ struct DirectX {
ID3D11Buffer* vertex_buffer; ID3D11Buffer* vertex_buffer;
ID3D11Buffer* constants_buffer; ID3D11Buffer* constants_buffer;
// NOTE(simon): To keep the API the same since the OpenGL texture handle are store in other places // NOTE(simon, 28/02/24): To keep the API the same since the OpenGL texture handle are store in
// than the graphics parts (e.g. in the font Face struct), we create an array of textures, and use // other places than the graphics parts (e.g. in the font Face struct), we create an array of
// the indices as texture handles. // textures, and use the indices as texture handles.
DirectXTexture textures[ DIRECTX_MAX_TEXTURE_COUNT + 1 ]; DX11Texture textures[ DX11_MAX_TEXTURE_COUNT + 1 ];
// NOTE(simon): First slot in the array should not be used so we can consider an index of 0 to be invalid. // NOTE(simon, 28/02/24): The first slot in the array should not be used so we can consider an
// OpenGL should not return 0 for texture handle, so we sort of do the same. // index of 0 to be invalid. OpenGL should not return 0 for texture handle, so we sort of do
// the same.
u32 texture_count; u32 texture_count;
}; };
global DirectX g_directx = { }; global DX11 g_dx11 = { };
// NOTE(simon): Passing 0 for texid use the reserved texture in the array, and passing a resource // NOTE(simon, 28/02/24): Passing 0 for texid use the reserved texture in the array, and passing a
// view of zero unbinds the resource. // resource view of zero unbinds the resource.
internal void internal void
gl__bind_texture(Render_Target *t, i32 texid){ gl__bind_texture(Render_Target *t, i32 texid){
if (t->bound_texture != texid){ if (t->bound_texture != texid){
DirectXTexture* texture = g_directx.textures + texid; DX11Texture* texture = g_dx11.textures + texid;
g_directx.context->PSSetShaderResources( 0, 1, &texture->view ); g_dx11.context->PSSetShaderResources( 0, 1, &texture->view );
t->bound_texture = texid; t->bound_texture = texid;
} }
} }
@ -50,8 +51,8 @@ internal void
gl__bind_any_texture(Render_Target *t){ gl__bind_any_texture(Render_Target *t){
if (t->bound_texture == 0){ if (t->bound_texture == 0){
Assert(t->fallback_texture_id != 0); Assert(t->fallback_texture_id != 0);
DirectXTexture* texture = g_directx.textures + t->fallback_texture_id; DX11Texture* texture = g_dx11.textures + t->fallback_texture_id;
g_directx.context->PSSetShaderResources( 0, 1, &texture->view ); g_dx11.context->PSSetShaderResources( 0, 1, &texture->view );
t->bound_texture = t->fallback_texture_id; t->bound_texture = t->fallback_texture_id;
} }
} }
@ -61,16 +62,16 @@ gl__get_texture(Vec3_i32 dim, Texture_Kind texture_kind){
u32 texid = 0; u32 texid = 0;
if ( g_directx.texture_count < DIRECTX_MAX_TEXTURE_COUNT + 1 ) { if ( g_dx11.texture_count < ArrayCount( g_dx11.textures ) ) {
texid = g_directx.texture_count; texid = g_dx11.texture_count;
g_directx.texture_count++; g_dx11.texture_count++;
} else { } else {
for ( u32 i = 1; i < g_directx.texture_count; i++ ) { for ( u32 i = 1; i < g_dx11.texture_count; i++ ) {
DirectXTexture* texture = g_directx.textures + i; DX11Texture* texture = g_dx11.textures + i;
if ( !texture->pointer && !texture->view ) { if ( !texture->pointer && !texture->view ) {
texid = i; texid = i;
@ -81,7 +82,7 @@ gl__get_texture(Vec3_i32 dim, Texture_Kind texture_kind){
if ( texid ) { if ( texid ) {
DirectXTexture* texture = g_directx.textures + texid; DX11Texture* texture = g_dx11.textures + texid;
Assert( texture->pointer == 0 ); Assert( texture->pointer == 0 );
Assert( texture->view == 0 ); Assert( texture->view == 0 );
@ -99,8 +100,8 @@ gl__get_texture(Vec3_i32 dim, Texture_Kind texture_kind){
// NOTE(simon, 28/02/24): I initialize the texture with zeros. In practice it doesn't seem // NOTE(simon, 28/02/24): I initialize the texture with zeros. In practice it doesn't seem
// to matter, but since the shader use a bilinear filter, the unitialized data in the // to matter, but since the shader use a bilinear filter, the unitialized data in the
// texture could change the result of the filtering for texel at the edge of a character. // texture could change the result of the filtering for texel at the edge of a character.
// I did some test with the rectangle packer to have a border around character but got // I did some tests with the rectangle packer to have a border around character but got the
// the exact same render, so I doesn't matter much. // exact same render, so It doesn't matter much.
D3D11_SUBRESOURCE_DATA* texture_data = push_array_zero( &win32vars.frame_arena, D3D11_SUBRESOURCE_DATA, dim.z ); D3D11_SUBRESOURCE_DATA* texture_data = push_array_zero( &win32vars.frame_arena, D3D11_SUBRESOURCE_DATA, dim.z );
u8* initial_data = push_array_zero( &win32vars.frame_arena, u8, dim.x * dim.y ); u8* initial_data = push_array_zero( &win32vars.frame_arena, u8, dim.x * dim.y );
@ -109,13 +110,13 @@ gl__get_texture(Vec3_i32 dim, Texture_Kind texture_kind){
texture_data[ i ].SysMemPitch = dim.x; texture_data[ i ].SysMemPitch = dim.x;
} }
HRESULT hr = g_directx.device->CreateTexture2D( &texture_desc, texture_data, &texture->pointer ); HRESULT hr = g_dx11.device->CreateTexture2D( &texture_desc, texture_data, &texture->pointer );
pop_array( &win32vars.frame_arena, u8, dim.x * dim.y ); pop_array( &win32vars.frame_arena, u8, dim.x * dim.y );
pop_array( &win32vars.frame_arena, D3D11_SUBRESOURCE_DATA, dim.z ); pop_array( &win32vars.frame_arena, D3D11_SUBRESOURCE_DATA, dim.z );
if ( SUCCEEDED( hr ) ) { if ( SUCCEEDED( hr ) ) {
hr = g_directx.device->CreateShaderResourceView( ( ID3D11Resource* ) texture->pointer, 0, &texture->view ); hr = g_dx11.device->CreateShaderResourceView( ( ID3D11Resource* ) texture->pointer, 0, &texture->view );
} }
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
@ -143,21 +144,21 @@ gl__get_texture(Vec3_i32 dim, Texture_Kind texture_kind){
internal b32 internal b32
gl__fill_texture(Texture_Kind texture_kind, u32 texid, Vec3_i32 p, Vec3_i32 dim, void *data){ gl__fill_texture(Texture_Kind texture_kind, u32 texid, Vec3_i32 p, Vec3_i32 dim, void *data){
// NOTE(simon): The OpenGL version always returns false. // NOTE(simon, 28/02/24): The OpenGL version always returns false.
b32 result = false; b32 result = false;
// NOTE(simon): In the OpenGL version, if we don't pass zero as texture handle, the function // NOTE(simon, 28/02/24): In the OpenGL version, if we pass zero as texture handle, the
// works on the currently bound texture. In directx we need to get the texture pointer. We // function works on the currently bound texture. In directx we need to get the texture pointer.
// could retrieve that from Render_Target->bound_texture, but we don't have that as a parameter // We could retrieve that from Render_Target->bound_texture, but we don't have that as a
// to this function and don't want to change the signature since it's used by the font // parameter to this function and don't want to change the signature since it's used by the
// rendering code and other platforms. Fortunately the only call that specified 0 for the // font rendering code and other platforms. Fortunately the only call that specified 0 for the
// texture handle was for the creation of the fallback texture in gl_render, and we can modify // texture handle was for the creation of the fallback texture in gl_render, and we can modify
// that call to pass the fallback texture handle. // that call to pass the fallback texture handle.
Assert( texid != 0 ); Assert( texid != 0 );
if (dim.x > 0 && dim.y > 0 && dim.z > 0){ if (dim.x > 0 && dim.y > 0 && dim.z > 0){
DirectXTexture* texture = g_directx.textures + texid; DX11Texture* texture = g_dx11.textures + texid;
D3D11_BOX box = { }; D3D11_BOX box = { };
box.left = p.x; box.left = p.x;
@ -168,7 +169,7 @@ gl__fill_texture(Texture_Kind texture_kind, u32 texid, Vec3_i32 p, Vec3_i32 dim,
box.back = 1; box.back = 1;
u32 sub_resource_index = D3D11CalcSubresource( 0 /* MipSlice */, p.z /* ArraySlice */, 1 /* MipLevels */ ); u32 sub_resource_index = D3D11CalcSubresource( 0 /* MipSlice */, p.z /* ArraySlice */, 1 /* MipLevels */ );
g_directx.context->UpdateSubresource( texture->pointer, sub_resource_index, &box, data, dim.x, dim.x * dim.y ); g_dx11.context->UpdateSubresource( texture->pointer, sub_resource_index, &box, data, dim.x, dim.x * dim.y );
} }
return(result); return(result);
@ -178,7 +179,7 @@ internal void gl__free_texture( u32 texid ) {
if ( texid ) { if ( texid ) {
DirectXTexture* texture = g_directx.textures + texid; DX11Texture* texture = g_dx11.textures + texid;
if ( texture->view ) { if ( texture->view ) {
texture->view->Release( ); texture->view->Release( );
@ -194,7 +195,7 @@ internal void gl__free_texture( u32 texid ) {
char *gl__vertex = R"foo( char *gl__vertex = R"foo(
// NOTE(simon): The layout of this is (constants are store in 16 bytes vectors (4 floats)) // NOTE(simon, 28/02/24): The layout of this is (constants are store in 16 bytes vectors (4 floats))
// vector1: view_m._11, view_m._12, 0, 0 // vector1: view_m._11, view_m._12, 0, 0
// vector2: view_m._21, view_m._22, view_t.x, view_t.y // vector2: view_m._21, view_m._22, view_t.x, view_t.y
cbuffer constants : register( b0 ) { cbuffer constants : register( b0 ) {
@ -223,7 +224,7 @@ output_t main(input_t input) {
output_t output; output_t output;
output.position = float4( mul( view_m, ( input.vertex_p - view_t ) ), 0.0, 1.0 ); output.position = float4( mul( view_m, ( input.vertex_p - view_t ) ), 0.0, 1.0 );
// NOTE(simon): The input colors are BGRA, we need them as RGBA. // NOTE(simon, 28/02/24): The input colors are BGRA, we need them as RGBA.
output.color = input.vertex_c.zyxw; output.color = input.vertex_c.zyxw;
output.uvw = input.vertex_t; output.uvw = input.vertex_t;
output.xy = input.vertex_p; output.xy = input.vertex_p;
@ -278,10 +279,10 @@ float4 main( input_t input ) : SV_TARGET {
} }
)foo"; )foo";
// NOTE(simon): This function is not generic. It can compile any shader, but the vertex input // NOTE(simon, 28/02/24): This function is not generic. It can compile any shader, but the vertex
// layout is fixed. 4coder only has one vertex format and shader, so we could remove this function // input layout is fixed. 4coder only has one vertex format and shader, so we could remove this
// and move its content in the win32_gl_create_window. I removed the header parameter as it's not // function and move its content in the win32_gl_create_window. I removed the header parameter as
// useful in directx. // it's not useful in directx.
internal GL_Program internal GL_Program
gl__make_program( char* vertex, char* pixel ) { gl__make_program( char* vertex, char* pixel ) {
@ -324,7 +325,7 @@ gl__make_program( char* vertex, char* pixel ) {
break; break;
} }
hr = g_directx.device->CreateVertexShader( vs_blob->GetBufferPointer( ), vs_blob->GetBufferSize( ), 0, &vertex_shader ); hr = g_dx11.device->CreateVertexShader( vs_blob->GetBufferPointer( ), vs_blob->GetBufferSize( ), 0, &vertex_shader );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( "Failed to create a vertex shader.\n" ); log_os( "Failed to create a vertex shader.\n" );
@ -354,7 +355,7 @@ gl__make_program( char* vertex, char* pixel ) {
layout_desc[ 3 ].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; layout_desc[ 3 ].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
layout_desc[ 3 ].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; layout_desc[ 3 ].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
hr = g_directx.device->CreateInputLayout( layout_desc, ArrayCount( layout_desc ), vs_blob->GetBufferPointer( ), vs_blob->GetBufferSize( ), &input_layout ); hr = g_dx11.device->CreateInputLayout( layout_desc, ArrayCount( layout_desc ), vs_blob->GetBufferPointer( ), vs_blob->GetBufferSize( ), &input_layout );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( "Failed to create input layout.\n" ); log_os( "Failed to create input layout.\n" );
@ -376,7 +377,7 @@ gl__make_program( char* vertex, char* pixel ) {
break; break;
} }
hr = g_directx.device->CreatePixelShader( ps_blob->GetBufferPointer( ), ps_blob->GetBufferSize( ), 0, &pixel_shader ); hr = g_dx11.device->CreatePixelShader( ps_blob->GetBufferPointer( ), ps_blob->GetBufferSize( ), 0, &pixel_shader );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( "Failed to create a pixel shader.\n" ); log_os( "Failed to create a pixel shader.\n" );
@ -441,39 +442,41 @@ gl_render(Render_Target *t){
if (first_call){ if (first_call){
// NOTE(simon): Most of the code here has been moved in win32_gl_create_window because if // NOTE(simon, 28/02/24): Most of the code here has been moved in win32_gl_create_window
// that code fails we should exit the application directly. // because if that code fails we should exit the application directly.
first_call = false; first_call = false;
u32 stride = sizeof( Render_Vertex ); u32 stride = sizeof( Render_Vertex );
u32 offset = 0; u32 offset = 0;
g_directx.context->IASetVertexBuffers( 0, 1, &g_directx.vertex_buffer, &stride, &offset ); g_dx11.context->IASetVertexBuffers( 0, 1, &g_dx11.vertex_buffer, &stride, &offset );
g_directx.context->IASetInputLayout( g_directx.gpu_program.layout ); g_dx11.context->IASetInputLayout( g_dx11.gpu_program.layout );
g_directx.context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); g_dx11.context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
g_directx.context->VSSetShader( g_directx.gpu_program.vertex, 0, 0 ); g_dx11.context->VSSetShader( g_dx11.gpu_program.vertex, 0, 0 );
g_directx.context->VSSetConstantBuffers( 0, 1, &g_directx.constants_buffer ); g_dx11.context->VSSetConstantBuffers( 0, 1, &g_dx11.constants_buffer );
g_directx.context->PSSetShader( g_directx.gpu_program.pixel, 0, 0 ); g_dx11.context->PSSetShader( g_dx11.gpu_program.pixel, 0, 0 );
g_directx.context->PSSetSamplers( 0, 1, &g_directx.sampler ); g_dx11.context->PSSetSamplers( 0, 1, &g_dx11.sampler );
{ {
t->fallback_texture_id = gl__get_texture(V3i32(2, 2, 1), TextureKind_Mono); t->fallback_texture_id = gl__get_texture(V3i32(2, 2, 1), TextureKind_Mono);
u8 white_block[] = { 0xFF, 0xFF, 0xFF, 0xFF, }; u8 white_block[] = { 0xFF, 0xFF, 0xFF, 0xFF, };
// NOTE(simon): Passing the fallback texture, because we can't rely on the fact that // NOTE(simon, 28/02/24): Passing the fallback texture, because we can't rely on the
// gl__get_texture has bound the fallback texture. // fact that gl__get_texture has bound the fallback texture.
gl__fill_texture(TextureKind_Mono, t->fallback_texture_id, V3i32(0, 0, 0), V3i32(2, 2, 1), white_block); gl__fill_texture(TextureKind_Mono, t->fallback_texture_id, V3i32(0, 0, 0), V3i32(2, 2, 1), white_block);
} }
} }
// NOTE(simon): OMSetRenderTargets needs to be set each frame when using a FLIP swap chain. // NOTE(simon, 28/02/24): OMSetRenderTargets needs to be set each frame when using a FLIP swap
g_directx.context->OMSetRenderTargets( 1, &g_directx.render_target_view, 0 ); // chain.
g_dx11.context->OMSetRenderTargets( 1, &g_dx11.render_target_view, 0 );
i32 width = t->width; i32 width = t->width;
i32 height = t->height; i32 height = t->height;
// NOTE(simon): Viewport (0, 0) is top left in directx. Important for viewport and scissor calls. // NOTE(simon, 28/02/24): Viewport (0, 0) is top left in directx. Important for viewport and
// scissor calls.
D3D11_VIEWPORT viewport = { D3D11_VIEWPORT viewport = {
0, // TopLeftX 0, // TopLeftX
@ -484,7 +487,7 @@ gl_render(Render_Target *t){
1// MaxDepth 1// MaxDepth
}; };
g_directx.context->RSSetViewports( 1, &viewport ); g_dx11.context->RSSetViewports( 1, &viewport );
D3D11_RECT scissor = { D3D11_RECT scissor = {
0, // left 0, // left
@ -493,26 +496,29 @@ gl_render(Render_Target *t){
height // bottom height // bottom
}; };
g_directx.context->RSSetScissorRects( 1, &scissor ); g_dx11.context->RSSetScissorRects( 1, &scissor );
float magenta[ 4 ] = { 1.0f, 0.0f, 1.0f, 1.0f }; float magenta[ 4 ] = { 1.0f, 0.0f, 1.0f, 1.0f };
g_directx.context->ClearRenderTargetView( g_directx.render_target_view, magenta ); g_dx11.context->ClearRenderTargetView( g_dx11.render_target_view, magenta );
// NOTE(simon): The constants (uniforms) were set in the render loop in the OpenGL version. // NOTE(simon, 28/02/24): The constants (uniforms) were set in the render loop in the OpenGL
// But since they don't vary between draw calls I moved the code before the render loop. // version. But since they don't vary between draw calls I moved the code before the render
// loop.
D3D11_MAPPED_SUBRESOURCE constants_map = { }; D3D11_MAPPED_SUBRESOURCE constants_map = { };
HRESULT hr = g_directx.context->Map( ( ID3D11Resource* ) g_directx.constants_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &constants_map ); HRESULT hr = g_dx11.context->Map( ( ID3D11Resource* ) g_dx11.constants_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &constants_map );
// NOTE(simon): The layout of the constants buffer was a bit confusing. This link explains a // NOTE(simon, 28/02/24): The layout of the constants buffer was a bit confusing. This link
// little about how data is laid out: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules // explains a little about how data is laid out:
// The article doesn't explain anything about matrices. What I found out while making this work is // https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
// that each row or column (depending on if we use column or row major matrices) of a matrix // The article doesn't explain anything about matrices. What I found out while making this work
// is that each row or column (depending on if we use column or row major matrices) of a matrix
// needs to start on a new 16 bytes vector. For a 2 by 2 matrix, this means that there are two // needs to start on a new 16 bytes vector. For a 2 by 2 matrix, this means that there are two
// register elements at the end of the first vector that aren't used. // register elements at the end of the first vector that aren't used.
// Another thing is that the second vector only needs the first two elements for the matrix, // Another thing is that the second vector only needs the first two elements for the matrix,
// so the two elements we want to put next can be in the same vector. // so the two elements we want to put next can be in the same vector.
// NOTE(simon): The code here could be shorter, but I prefer to make it clear what's happening. // NOTE(simon, 28/02/24): The code here could be shorter, but I prefer to make it clear what's
// happening.
f32 view_m[ 4 ] = { f32 view_m[ 4 ] = {
2.0f / width, 0, 2.0f / width, 0,
0, -2.0f / height 0, -2.0f / height
@ -532,7 +538,7 @@ gl_render(Render_Target *t){
vector_2[ 2 ] = view_t[ 0 ]; vector_2[ 2 ] = view_t[ 0 ];
vector_2[ 3 ] = view_t[ 1 ]; vector_2[ 3 ] = view_t[ 1 ];
g_directx.context->Unmap( ( ID3D11Resource* ) g_directx.constants_buffer, 0 ); g_dx11.context->Unmap( ( ID3D11Resource* ) g_dx11.constants_buffer, 0 );
gl__bind_texture( t, 0 ); gl__bind_texture( t, 0 );
@ -557,7 +563,7 @@ gl_render(Render_Target *t){
group_scissor.top = box.y0; group_scissor.top = box.y0;
group_scissor.bottom = box.y1; group_scissor.bottom = box.y1;
g_directx.context->RSSetScissorRects( 1, &group_scissor ); g_dx11.context->RSSetScissorRects( 1, &group_scissor );
i32 vertex_count = group->vertex_list.vertex_count; i32 vertex_count = group->vertex_list.vertex_count;
if (vertex_count > 0){ if (vertex_count > 0){
@ -569,21 +575,22 @@ gl_render(Render_Target *t){
gl__bind_any_texture(t); gl__bind_any_texture(t);
} }
// NOTE(simon): We fill the buffer, draw what we filled and then do the next group, // NOTE(simon, 28/02/24): We fill the buffer, draw what we filled and then do the next
// which allows to always start drawing from vertex 0. Alternatively we could do a pass // group, which allows to always start drawing from vertex 0. Alternatively we could
// to fill the vertex buffer completly so we only map the vertex buffer once, and then // do a pass to fill the vertex buffer completly so we only map the vertex buffer once,
// a second pass that just execute the draw calls. It doesn't seems necessary since we // and then a second pass that just execute the draw calls. It doesn't seems necessary
// have less than 10 draw call. // since we have less than 10 draw call.
D3D11_MAPPED_SUBRESOURCE vertex_map = { }; D3D11_MAPPED_SUBRESOURCE vertex_map = { };
hr = g_directx.context->Map( ( ID3D11Resource* ) g_directx.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertex_map ); hr = g_dx11.context->Map( ( ID3D11Resource* ) g_dx11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertex_map );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
// NOTE(simon): It's improbable that Map will fail, but if it does we just stop // NOTE(simon, 28/02/24): It's improbable that Map will fail, but if it does we
// rendering, and we'll try on the next frame. We could just skip the group and try // just stop rendering, and we'll try on the next frame. We could just skip the
// with the next (using 'continue' instead of 'break'), but Map would probably fail // group and try with the next (using 'continue' instead of 'break'), but Map would
// again. Waiting for the next frame "might" work. I don't really know. We could // probably fail again. Waiting for the next frame "might" work. I don't really
// also just exit the application assuming we won't be able to render anything. // know. We could also just exit the application assuming we won't be able to
// render anything.
break; break;
} }
@ -598,9 +605,9 @@ gl_render(Render_Target *t){
bytes += size; bytes += size;
} }
g_directx.context->Unmap( ( ID3D11Resource* ) g_directx.vertex_buffer, 0 ); g_dx11.context->Unmap( ( ID3D11Resource* ) g_dx11.vertex_buffer, 0 );
g_directx.context->Draw( vertex_count, 0 ); g_dx11.context->Draw( vertex_count, 0 );
} }
} }
} }

View File

@ -12,7 +12,7 @@
// #define FPS 144 // #define FPS 144
// #define frame_useconds (1000000 / FPS) // #define frame_useconds (1000000 / FPS)
#define WIN32_DIRECTX #define WIN32_DX11
#include <stdio.h> #include <stdio.h>
@ -657,7 +657,7 @@ os_popup_error(char *title, char *message){
#include "4ed_font_provider_freetype.h" #include "4ed_font_provider_freetype.h"
#include "4ed_font_provider_freetype.cpp" #include "4ed_font_provider_freetype.cpp"
#if defined( WIN32_DIRECTX ) #if defined( WIN32_DX11 )
#include "win32_directx.cpp" #include "win32_directx.cpp"
#else #else
#include "win32_opengl.cpp" #include "win32_opengl.cpp"
@ -825,28 +825,28 @@ win32_resize(i32 width, i32 height){
target.width = width; target.width = width;
target.height = height; target.height = height;
#if defined( WIN32_DIRECTX ) #if defined( WIN32_DX11 )
HRESULT hr = S_OK; HRESULT hr = S_OK;
ID3D11Texture2D* frame_buffer = 0; ID3D11Texture2D* frame_buffer = 0;
do { do {
if ( g_directx.initialized ) { if ( g_dx11.initialized ) {
if ( g_directx.render_target_view ) { if ( g_dx11.render_target_view ) {
g_directx.render_target_view->Release( ); g_dx11.render_target_view->Release( );
g_directx.render_target_view = 0; g_dx11.render_target_view = 0;
} }
hr = g_directx.swap_chain->ResizeBuffers( 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0 ); hr = g_dx11.swap_chain->ResizeBuffers( 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0 );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( "Failed to resize the swap chain buffers.\n" ); log_os( "Failed to resize the swap chain buffers.\n" );
break; break;
} }
hr = g_directx.swap_chain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( void** ) &frame_buffer ); hr = g_dx11.swap_chain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( void** ) &frame_buffer );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( "Failled to get the swap chain back buffer.\n" ); log_os( "Failled to get the swap chain back buffer.\n" );
@ -854,16 +854,17 @@ win32_resize(i32 width, i32 height){
} }
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc = { 0 }; D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc = { 0 };
// NOTE(simon): 4coder checks for sRGB support but never actually enables it in the // NOTE(simon, 28/02/24): 4coder checks for sRGB support but never actually enables
// OpenGL version. Note that enabling it would require to convert collors passed to the // it in the OpenGL version (never calls glEnable( GL_FRAMEBUFFER_SRGB ) ).
// shader to linear (when using sRBG back buffer, the shader values must be linear // Note that enabling it would require to convert collors
// values). This would be more problematic than just passing linear values as the // passed to the shader to linear (when using sRBG back buffer, the shader values
// blending wouldn't produce the same result as with sRGB off. // must be linear values). This would be more problematic than just passing linear
// values as the blending wouldn't produce the same result as with sRGB off.
// render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; // render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
hr = g_directx.device->CreateRenderTargetView( ( ID3D11Resource* ) frame_buffer, &render_target_view_desc, &g_directx.render_target_view ); hr = g_dx11.device->CreateRenderTargetView( ( ID3D11Resource* ) frame_buffer, &render_target_view_desc, &g_dx11.render_target_view );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( "Failed to create a render target view.\n" ); log_os( "Failed to create a render target view.\n" );
@ -880,12 +881,12 @@ win32_resize(i32 width, i32 height){
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
if ( g_directx.render_target_view ) { if ( g_dx11.render_target_view ) {
g_directx.render_target_view->Release( ); g_dx11.render_target_view->Release( );
g_directx.render_target_view = 0; g_dx11.render_target_view = 0;
} }
// NOTE(simon): Failing here means no rendering possible, so we exit. // NOTE(simon, 28/02/24): Failing here means no rendering possible, so we exit.
exit( 1 ); exit( 1 );
} }
@ -1748,7 +1749,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
window_rect.bottom - window_rect.top, window_rect.bottom - window_rect.top,
((window_style & WS_MAXIMIZE) != 0)); ((window_style & WS_MAXIMIZE) != 0));
#if defined( WIN32_DIRECTX ) #if defined( WIN32_DX11 )
if( !win32_gl_create_window( &win32vars.window_handle, window_style, window_rect ) ) { if( !win32_gl_create_window( &win32vars.window_handle, window_style, window_rect ) ) {
exit(1); exit(1);
} }
@ -2041,9 +2042,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
win32vars.lctrl_lalt_is_altgr = (b8)result.lctrl_lalt_is_altgr; win32vars.lctrl_lalt_is_altgr = (b8)result.lctrl_lalt_is_altgr;
// NOTE(allen): render // NOTE(allen): render
#if defined( WIN32_DIRECTX ) #if defined( WIN32_DX11 )
gl_render(&target); gl_render(&target);
g_directx.swap_chain->Present( 1, 0 ); g_dx11.swap_chain->Present( 1, 0 );
#else #else
HDC hdc = GetDC(win32vars.window_handle); HDC hdc = GetDC(win32vars.window_handle);
gl_render(&target); gl_render(&target);
@ -2085,7 +2086,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
win32vars.first = false; win32vars.first = false;
} }
#if defined( WIN32_DIRECTX ) && !SHIP_MODE #if defined( WIN32_DX11 ) && !SHIP_MODE
win32_gl_cleanup( ); win32_gl_cleanup( );
#endif #endif

View File

@ -28,21 +28,21 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
*wnd_out = 0; *wnd_out = 0;
Assert( g_directx.initialized == 0 ); Assert( g_dx11.initialized == 0 );
Assert( g_directx.device == 0 ); Assert( g_dx11.device == 0 );
Assert( g_directx.context == 0 ); Assert( g_dx11.context == 0 );
Assert( g_directx.swap_chain == 0 ); Assert( g_dx11.swap_chain == 0 );
Assert( g_directx.sampler == 0 ); Assert( g_dx11.sampler == 0 );
Assert( g_directx.render_target_view == 0 ); Assert( g_dx11.render_target_view == 0 );
Assert( g_directx.gpu_program.vertex == 0 ); Assert( g_dx11.gpu_program.vertex == 0 );
Assert( g_directx.gpu_program.layout == 0 ); Assert( g_dx11.gpu_program.layout == 0 );
Assert( g_directx.gpu_program.pixel == 0 ); Assert( g_dx11.gpu_program.pixel == 0 );
Assert( g_directx.gpu_program.valid == 0 ); Assert( g_dx11.gpu_program.valid == 0 );
Assert( g_directx.vertex_buffer == 0 ); Assert( g_dx11.vertex_buffer == 0 );
Assert( g_directx.constants_buffer == 0 ); Assert( g_dx11.constants_buffer == 0 );
Assert( g_directx.texture_count == 0 ); Assert( g_dx11.texture_count == 0 );
g_directx = { }; g_dx11 = { };
HINSTANCE this_instance = GetModuleHandle(0); HINSTANCE this_instance = GetModuleHandle(0);
@ -57,18 +57,18 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
do { do {
// NOTE(simon): There is nothing in the code suggesting that this function could be called several time. // NOTE(simon, 28/02/24): There is nothing in the code suggesting that this function could
// If it is called several time, we would need to make sure that we cleaned up previous DirectX resources. // be called several time. If it is called several time, we would need to make sure that
// The reason this function would be called twice would be if it failed previously, and in that case we // we cleaned up previous DirectX resources. The reason this function could be called twice
// clean up everythings so we should be good. Still we assume it's only ever call once. // would be if it failed previously, and in that case we clean up everything before
// exiting the function so we should be good. Still we assume it's only ever call once.
Assert( first_call ); Assert( first_call );
if (first_call){ if (first_call){
first_call = false; first_call = false;
// NOTE(allen): Register the graphics window class log_os( " Registering graphics class...\n" );
log_os(" registering graphics class...\n");
WNDCLASSW wndclass = {}; WNDCLASSW wndclass = {};
wndclass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS; wndclass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
@ -77,23 +77,25 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
wndclass.hInstance = this_instance; wndclass.hInstance = this_instance;
wndclass.lpszClassName = L"GRAPHICS-WINDOW-NAME"; wndclass.lpszClassName = L"GRAPHICS-WINDOW-NAME";
if (RegisterClassW(&wndclass) == 0){ if (RegisterClassW(&wndclass) == 0){
log_os(" Failed.\n");
break; break;
} }
} }
// NOTE(allen): Create the graphics window log_os( " Creating graphics window...\n" );
log_os(" creating graphics window...\n");
wnd = CreateWindowExW(0, L"GRAPHICS-WINDOW-NAME", L"GRAPHICS", style, wnd = CreateWindowExW(0, L"GRAPHICS-WINDOW-NAME", L"GRAPHICS", style,
CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top,
0, 0, this_instance, 0); 0, 0, this_instance, 0);
if (wnd == 0) { if (wnd == 0) {
log_os( " Failed to create a window.\n" ); log_os( " Failed.\n" );
break; break;
} }
// NOTE(simon): We are creating a directx 11.1 device and context (supported since windows 8). log_os( " Creating a d3d11 hardware device and context...\n" );
// NOTE(simon, 28/02/24): We are creating a directx 11.1 device and context (supported
// since windows 8).
D3D_FEATURE_LEVEL feature_levels[ ] = { D3D_FEATURE_LEVEL_11_1 }; D3D_FEATURE_LEVEL feature_levels[ ] = { D3D_FEATURE_LEVEL_11_1 };
u32 device_flags = 0; u32 device_flags = 0;
@ -106,54 +108,59 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
HRESULT hr = D3D11CreateDevice( 0, D3D_DRIVER_TYPE_HARDWARE, 0, device_flags, feature_levels, ArrayCount( feature_levels ), D3D11_SDK_VERSION, &base_device, 0, &base_device_context ); HRESULT hr = D3D11CreateDevice( 0, D3D_DRIVER_TYPE_HARDWARE, 0, device_flags, feature_levels, ArrayCount( feature_levels ), D3D11_SDK_VERSION, &base_device, 0, &base_device_context );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a hardware DirectX device and context.\n" ); log_os( " Failed.\n" );
log_os( " Trying to create a software (WARP) DirectX device.\n" ); log_os( " Creating a d3d11 software (WARP) device and context...\n" );
// NOTE(simon): Try creating a high performance software device as a fallback. // NOTE(simon, 28/02/24): Try creating a high performance software device as a fallback.
hr = D3D11CreateDevice( 0, D3D_DRIVER_TYPE_WARP, 0, device_flags, feature_levels, ArrayCount( feature_levels ), D3D11_SDK_VERSION, &base_device, 0, &base_device_context ); hr = D3D11CreateDevice( 0, D3D_DRIVER_TYPE_WARP, 0, device_flags, feature_levels, ArrayCount( feature_levels ), D3D11_SDK_VERSION, &base_device, 0, &base_device_context );
} }
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create software (WARP) DirectX device and context.\n" ); log_os( " Failed.\n" );
break; break;
} }
hr = base_device->QueryInterface( __uuidof( ID3D11Device1 ), ( void** ) &g_directx.device ); log_os( " Creating a ID3D11Device1...\n" );
hr = base_device->QueryInterface( __uuidof( ID3D11Device1 ), ( void** ) &g_dx11.device );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a ID3D11Device1.\n" ); log_os( " Failed.\n" );
break; break;
} }
hr = base_device_context->QueryInterface( __uuidof( ID3D11DeviceContext1 ), ( void** ) &g_directx.context ); log_os( " Creating a ID3D11DeviceContext1...\n" );
hr = base_device_context->QueryInterface( __uuidof( ID3D11DeviceContext1 ), ( void** ) &g_dx11.context );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a ID3D11DeviceContext1.\n" ); log_os( " Failed.\n" );
break; break;
} }
ID3D11Device1* device = g_directx.device; ID3D11Device1* device = g_dx11.device;
ID3D11DeviceContext1* context = g_directx.context; ID3D11DeviceContext1* context = g_dx11.context;
#if !SHIP_MODE #if !SHIP_MODE
log_os( " Getting ID3D11InfoQueue. This is not important if you're not debugging graphics...\n" );
ID3D11InfoQueue* info; ID3D11InfoQueue* info;
hr = device->QueryInterface( __uuidof( ID3D11InfoQueue ), ( void** ) &info ); hr = device->QueryInterface( __uuidof( ID3D11InfoQueue ), ( void** ) &info );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to get ID3D11InfoQueue. This is not important if you're not debugging graphics.\n" ); log_os( " Failed.\n" );
} else { } else {
info->SetBreakOnSeverity( D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE ); info->SetBreakOnSeverity( D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE );
info->SetBreakOnSeverity( D3D11_MESSAGE_SEVERITY_ERROR, TRUE ); info->SetBreakOnSeverity( D3D11_MESSAGE_SEVERITY_ERROR, TRUE );
info->Release( ); info->Release( );
} }
log_os( " Getting IDXGIDebug1. This is not important if you're not debugging graphics...\n" );
hr = DXGIGetDebugInterface1( 0, __uuidof( IDXGIDebug1 ), ( void** ) &dxgi_debug ); hr = DXGIGetDebugInterface1( 0, __uuidof( IDXGIDebug1 ), ( void** ) &dxgi_debug );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to get IDXGIDebug1. This is not important if you're not debugging graphics.\n" ); log_os( " Failed.\n" );
} }
#endif #endif
// NOTE(simon): sRGB should be supported by any hardware now, but there was a check so I added one. // NOTE(simon, 28/02/24): sRGB should be supported by any hardware now, but there was a
// check so I added one. The OpenGL version never enables sRGB.
DXGI_FORMAT back_buffer_format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; DXGI_FORMAT back_buffer_format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
UINT format_support = 0; UINT format_support = 0;
@ -169,16 +176,17 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
log_os( " sRBG back buffer supported.\n" ); log_os( " sRBG back buffer supported.\n" );
} }
log_os( " Creating a IDXGIFactory2...\n" );
hr = CreateDXGIFactory( __uuidof( IDXGIFactory2 ), ( void** ) &dxgi_factory ); hr = CreateDXGIFactory( __uuidof( IDXGIFactory2 ), ( void** ) &dxgi_factory );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create IDXGIFactory2.\n" ); log_os( " Failed.\n" );
break; break;
} }
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = { }; DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = { };
// NOTE(simon): Can't request sRGB format here when using FLIP_* swap chain. It's requested we creating the render target view. // NOTE(simon, 28/02/24): Can't request sRGB format here when using FLIP_* swap chain. It's
// NOTE(simon): 4coder never calls glEnable( GL_FRAMEBUFFER_SRGB ) so we don't enable sRGB. // requested when creating the render target view.
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0; swap_chain_desc.SampleDesc.Quality = 0;
@ -187,14 +195,15 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
swap_chain_desc.Scaling = DXGI_SCALING_NONE; swap_chain_desc.Scaling = DXGI_SCALING_NONE;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
hr = dxgi_factory->CreateSwapChainForHwnd( device, wnd, &swap_chain_desc, 0, 0, &g_directx.swap_chain ); log_os( " Creating a IDXGISwapChain1...\n" );
hr = dxgi_factory->CreateSwapChainForHwnd( device, wnd, &swap_chain_desc, 0, 0, &g_dx11.swap_chain );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create IDXGISwapChain1.\n" ); log_os( " Failed.\n" );
break; break;
} }
// NOTE(simon): We setup alpha blending here as it's always on in 4coder. // NOTE(simon, 28/02/24): We setup alpha blending here as it's always on in 4coder.
D3D11_BLEND_DESC blend_state_desc = { }; D3D11_BLEND_DESC blend_state_desc = { };
blend_state_desc.RenderTarget[ 0 ].BlendEnable = TRUE; blend_state_desc.RenderTarget[ 0 ].BlendEnable = TRUE;
blend_state_desc.RenderTarget[ 0 ].SrcBlend = D3D11_BLEND_SRC_ALPHA; blend_state_desc.RenderTarget[ 0 ].SrcBlend = D3D11_BLEND_SRC_ALPHA;
@ -205,35 +214,35 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
blend_state_desc.RenderTarget[ 0 ].BlendOpAlpha = D3D11_BLEND_OP_ADD; blend_state_desc.RenderTarget[ 0 ].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blend_state_desc.RenderTarget[ 0 ].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; blend_state_desc.RenderTarget[ 0 ].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
log_os( " Creating a blend state...\n" );
hr = device->CreateBlendState( &blend_state_desc, &blend_state ); hr = device->CreateBlendState( &blend_state_desc, &blend_state );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a blend state.\n" ); log_os( " Failed.\n" );
break; break;
} }
log_os( " Setting blend state...\n" );
context->OMSetBlendState( blend_state, 0, 0xffffffff ); context->OMSetBlendState( blend_state, 0, 0xffffffff );
// NOTE(simon): Enable scissor and disable backface culling. // NOTE(simon, 28/02/24): Enable scissor and disable backface culling.
D3D11_RASTERIZER_DESC1 rasterizer_desc = { }; D3D11_RASTERIZER_DESC1 rasterizer_desc = { };
rasterizer_desc.FillMode = D3D11_FILL_SOLID; rasterizer_desc.FillMode = D3D11_FILL_SOLID;
rasterizer_desc.CullMode = D3D11_CULL_NONE; rasterizer_desc.CullMode = D3D11_CULL_NONE;
rasterizer_desc.DepthClipEnable = TRUE; rasterizer_desc.DepthClipEnable = TRUE;
rasterizer_desc.ScissorEnable = TRUE; rasterizer_desc.ScissorEnable = TRUE;
log_os( " Creating a rasterizer state...\n" );
hr = device->CreateRasterizerState1( &rasterizer_desc, &rasterizer_state ); hr = device->CreateRasterizerState1( &rasterizer_desc, &rasterizer_state );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a rasterizer state.\n" ); log_os( " Failed.\n" );
break; break;
} }
log_os( " Setting rasterizer state...\n" );
context->RSSetState( rasterizer_state ); context->RSSetState( rasterizer_state );
// NOTE(simon): Not setting depth stencil as 4coder doesn't use it. // NOTE(simon, 28/02/24): Not setting depth stencil as 4coder doesn't use it.
// NOTE(simon): Swap interval is a parameter of swap_chain->present. // NOTE(simon, 28/02/24): Swap interval is a parameter of swap_chain->present.
D3D11_SAMPLER_DESC linear_desc = { }; D3D11_SAMPLER_DESC linear_desc = { };
linear_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; linear_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
@ -244,56 +253,62 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
linear_desc.MinLOD = 0; linear_desc.MinLOD = 0;
linear_desc.MaxLOD = D3D11_FLOAT32_MAX; linear_desc.MaxLOD = D3D11_FLOAT32_MAX;
hr = device->CreateSamplerState( &linear_desc, &g_directx.sampler ); log_os( " Creating a sampler state...\n" );
hr = device->CreateSamplerState( &linear_desc, &g_dx11.sampler );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a sampler state.\n" ); log_os( " Failed.\n" );
break; break;
} }
// NOTE(simon): We create the vertex buffer, constants buffers and shader here because if // NOTE(simon, 28/02/24): We create the vertex buffer, constants buffers and shader here
// we can't create them we won't be able to render anything and so we should just exit the program. // because if we can't create them we won't be able to render anything and so we should
// just exit the program.
D3D11_BUFFER_DESC vertex_buffer_desc = { }; D3D11_BUFFER_DESC vertex_buffer_desc = { };
// NOTE(simon): Reserving 400K vertices which is about 11 megabytes and would allow 100K characters. // NOTE(simon, 28/02/24): Reserving 400K vertices which is about 11 megabytes and would
// On a 1080p monitor, with 4 by 10 pixels characters we would need // allow 100K characters. On a 1080p monitor, with 4 by 10 pixels characters we would need
// (1920/4)*(1080/10) = 51840 characters to fill the screen. // (1920/4)*(1080/10) = 51840 characters to fill the screen.
vertex_buffer_desc.ByteWidth = 400000 * sizeof( Render_Vertex ); vertex_buffer_desc.ByteWidth = 400000 * sizeof( Render_Vertex );
vertex_buffer_desc.Usage = D3D11_USAGE_DYNAMIC; vertex_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
vertex_buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertex_buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertex_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; vertex_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = device->CreateBuffer( &vertex_buffer_desc, 0, &g_directx.vertex_buffer ); log_os( " Creating a vertex buffer...\n" );
hr = device->CreateBuffer( &vertex_buffer_desc, 0, &g_dx11.vertex_buffer );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a vertex buffer.\n" ); log_os( " Failed.\n" );
break; break;
} }
D3D11_BUFFER_DESC constants_buffer_desc = { }; D3D11_BUFFER_DESC constants_buffer_desc = { };
// NOTE(simon): constants buffer size needs to be a multiple of 16. // NOTE(simon, 28/02/24): constants buffer size needs to be a multiple of 16.
// NOTE(simon): The layout is explained where we set the values in the buffer in gl_render. // NOTE(simon, 28/02/24): The layout is explained where we set the values in the buffer in
// gl_render.
constants_buffer_desc.ByteWidth = 32; constants_buffer_desc.ByteWidth = 32;
constants_buffer_desc.Usage = D3D11_USAGE_DYNAMIC; constants_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
constants_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; constants_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constants_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; constants_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = device->CreateBuffer( &constants_buffer_desc, 0, &g_directx.constants_buffer ); log_os( " Creating a constants buffer...\n" );
hr = device->CreateBuffer( &constants_buffer_desc, 0, &g_dx11.constants_buffer );
if ( FAILED( hr ) ) { if ( FAILED( hr ) ) {
log_os( " Failed to create a constants buffer.\n" ); log_os( " Failed.\n" );
break; break;
} }
g_directx.gpu_program = gl__make_program( gl__vertex, gl__fragment ); g_dx11.gpu_program = gl__make_program( gl__vertex, gl__fragment );
if ( !g_directx.gpu_program.valid ) { if ( !g_dx11.gpu_program.valid ) {
break; break;
} }
*wnd_out = wnd; *wnd_out = wnd;
g_directx.texture_count = 1; // NOTE(simon): Reserve the first texture slot as a invalid/unbind texture. // NOTE(simon, 28/02/24): Reserve the first texture slot as a invalid/unbind texture.
g_directx.initialized = true; g_dx11.texture_count = 1;
g_dx11.initialized = true;
result = true; result = true;
} while ( 0 ); } while ( 0 );
@ -305,62 +320,63 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
( *wnd_out ) = 0; ( *wnd_out ) = 0;
} }
if ( g_directx.context ) { if ( g_dx11.context ) {
g_directx.context->OMSetBlendState( 0, 0, 0xffffffff ); g_dx11.context->OMSetBlendState( 0, 0, 0xffffffff );
g_directx.context->RSSetState( 0 ); g_dx11.context->RSSetState( 0 );
} }
if ( g_directx.constants_buffer ) { if ( g_dx11.constants_buffer ) {
g_directx.constants_buffer->Release( ); g_dx11.constants_buffer->Release( );
g_directx.constants_buffer = 0; g_dx11.constants_buffer = 0;
} }
if ( g_directx.vertex_buffer ) { if ( g_dx11.vertex_buffer ) {
g_directx.vertex_buffer->Release( ); g_dx11.vertex_buffer->Release( );
g_directx.vertex_buffer = 0; g_dx11.vertex_buffer = 0;
} }
if ( g_directx.gpu_program.valid ) { if ( g_dx11.gpu_program.valid ) {
if ( g_directx.gpu_program.vertex ) { if ( g_dx11.gpu_program.vertex ) {
g_directx.gpu_program.vertex->Release( ); g_dx11.gpu_program.vertex->Release( );
g_directx.gpu_program.vertex = 0; g_dx11.gpu_program.vertex = 0;
} }
if ( g_directx.gpu_program.layout ) { if ( g_dx11.gpu_program.layout ) {
g_directx.gpu_program.layout->Release( ); g_dx11.gpu_program.layout->Release( );
g_directx.gpu_program.layout = 0; g_dx11.gpu_program.layout = 0;
} }
if ( g_directx.gpu_program.pixel ) { if ( g_dx11.gpu_program.pixel ) {
g_directx.gpu_program.pixel->Release( ); g_dx11.gpu_program.pixel->Release( );
g_directx.gpu_program.pixel = 0; g_dx11.gpu_program.pixel = 0;
} }
} }
// NOTE(simon): No render target view at this point as it's created in the WM_SIZE message. // NOTE(simon, 28/02/24): No render target view at this point as it's created in the
// WM_SIZE message.
if ( g_directx.sampler ) { if ( g_dx11.sampler ) {
g_directx.sampler->Release( ); g_dx11.sampler->Release( );
g_directx.sampler = 0; g_dx11.sampler = 0;
} }
if ( g_directx.swap_chain ) { if ( g_dx11.swap_chain ) {
g_directx.swap_chain->Release( ); g_dx11.swap_chain->Release( );
g_directx.swap_chain = 0; g_dx11.swap_chain = 0;
} }
if ( g_directx.context ) { if ( g_dx11.context ) {
g_directx.context->Release( ); g_dx11.context->Release( );
g_directx.context = 0; g_dx11.context = 0;
} }
if ( g_directx.device ) { if ( g_dx11.device ) {
g_directx.device->Release( ); g_dx11.device->Release( );
g_directx.device = 0; g_dx11.device = 0;
} }
g_directx.initialized = false; g_dx11.initialized = false;
#if SHIP_MODE #if SHIP_MODE
os_popup_error( "Error", "Window creation failed."); os_popup_error( "Error", "Window creation failed.");
@ -397,26 +413,26 @@ win32_gl_create_window(HWND *wnd_out, DWORD style, RECT rect){
#if !SHIP_MODE #if !SHIP_MODE
// NOTE(simon): Only call this when working on 4coder, to make sure we don't do something stupid. // NOTE(simon, 28/02/24): Only call this when working on 4coder, to make sure we don't do something
// In SHIP_MODE we let the os clean up resources. // stupid. In SHIP_MODE we let the os clean up resources.
internal void internal void
win32_gl_cleanup( void ) { win32_gl_cleanup( void ) {
if ( dxgi_debug && g_directx.initialized ) { if ( dxgi_debug && g_dx11.initialized ) {
OutputDebugString( L"win32_gl_cleanup start report...\n" ); OutputDebugString( L"win32_gl_cleanup start report...\n" );
dxgi_debug->ReportLiveObjects( DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL ); dxgi_debug->ReportLiveObjects( DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL );
g_directx.initialized = false; g_dx11.initialized = false;
if ( g_directx.context ) { if ( g_dx11.context ) {
g_directx.context->OMSetBlendState( 0, 0, 0xffffffff ); g_dx11.context->OMSetBlendState( 0, 0, 0xffffffff );
g_directx.context->RSSetState( 0 ); g_dx11.context->RSSetState( 0 );
} }
for ( u32 i = 1; i < g_directx.texture_count; i++ ) { for ( u32 i = 1; i < g_dx11.texture_count; i++ ) {
DirectXTexture* texture = g_directx.textures + i; DX11Texture* texture = g_dx11.textures + i;
if ( texture->view ) { if ( texture->view ) {
texture->view->Release( ); texture->view->Release( );
@ -429,62 +445,62 @@ win32_gl_cleanup( void ) {
} }
} }
g_directx.texture_count = 0; g_dx11.texture_count = 0;
if ( g_directx.constants_buffer ) { if ( g_dx11.constants_buffer ) {
g_directx.constants_buffer->Release( ); g_dx11.constants_buffer->Release( );
g_directx.constants_buffer = 0; g_dx11.constants_buffer = 0;
} }
if ( g_directx.vertex_buffer ) { if ( g_dx11.vertex_buffer ) {
g_directx.vertex_buffer->Release( ); g_dx11.vertex_buffer->Release( );
g_directx.vertex_buffer = 0; g_dx11.vertex_buffer = 0;
} }
if ( g_directx.gpu_program.valid ) { if ( g_dx11.gpu_program.valid ) {
if ( g_directx.gpu_program.vertex ) { if ( g_dx11.gpu_program.vertex ) {
g_directx.gpu_program.vertex->Release( ); g_dx11.gpu_program.vertex->Release( );
g_directx.gpu_program.vertex = 0; g_dx11.gpu_program.vertex = 0;
} }
if ( g_directx.gpu_program.layout ) { if ( g_dx11.gpu_program.layout ) {
g_directx.gpu_program.layout->Release( ); g_dx11.gpu_program.layout->Release( );
g_directx.gpu_program.layout = 0; g_dx11.gpu_program.layout = 0;
} }
if ( g_directx.gpu_program.pixel ) { if ( g_dx11.gpu_program.pixel ) {
g_directx.gpu_program.pixel->Release( ); g_dx11.gpu_program.pixel->Release( );
g_directx.gpu_program.pixel = 0; g_dx11.gpu_program.pixel = 0;
} }
} }
if ( g_directx.render_target_view ) { if ( g_dx11.render_target_view ) {
g_directx.render_target_view->Release( ); g_dx11.render_target_view->Release( );
g_directx.render_target_view = 0; g_dx11.render_target_view = 0;
} }
if ( g_directx.sampler ) { if ( g_dx11.sampler ) {
g_directx.sampler->Release( ); g_dx11.sampler->Release( );
g_directx.sampler = 0; g_dx11.sampler = 0;
} }
if ( g_directx.swap_chain ) { if ( g_dx11.swap_chain ) {
g_directx.swap_chain->Release( ); g_dx11.swap_chain->Release( );
g_directx.swap_chain = 0; g_dx11.swap_chain = 0;
} }
if ( g_directx.context ) { if ( g_dx11.context ) {
g_directx.context->Release( ); g_dx11.context->Release( );
g_directx.context = 0; g_dx11.context = 0;
} }
if ( g_directx.device ) { if ( g_dx11.device ) {
g_directx.device->Release( ); g_dx11.device->Release( );
g_directx.device = 0; g_dx11.device = 0;
} }
OutputDebugString( L"win32_gl_cleanup end report (nothing should be printed after this line)...\n" ); OutputDebugString( L"win32_gl_cleanup end report (nothing printed after this line means everything is OK)...\n" );
dxgi_debug->ReportLiveObjects( DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL ); dxgi_debug->ReportLiveObjects( DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL );
} }
} }