/* * Tuxánci 2 - A first person shooter * Copyright (C) 2007-2011 Tuxánci Development Team * Copyright (C) 2025-2026 Connor Thomson * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "ta_sdl.h" #include "window.h" #include "files.h" #include "text.h" #include "logging.h" #include "screen.h" #define SPIRV_ENTRY_POINT "main" SDL_GPUDevice *ta_gpu_device; SDL_GPUGraphicsPipeline *ta_gpu_text_pipeline; SDL_GPUTexture *ta_gpu_text_texture; SDL_GPUSampler *ta_gpu_text_sampler; Uint32 ta_gpu_text_texture_width; Uint32 ta_gpu_text_texture_height; static SDL_GPUTexture *ta_gpu_msaa_texture; static SDL_GPUTexture *ta_gpu_depth_texture; SDL_GPUSampleCount ta_gpu_sample_count = SDL_GPU_SAMPLECOUNT_8; SDL_GPUTextureFormat ta_gpu_swapchain_format; static Uint32 ta_gpu_msaa_texture_width; static Uint32 ta_gpu_msaa_texture_height; static SDL_GPUCommandBuffer *ta_gpu_command_buffer; static SDL_GPUTexture *ta_gpu_swapchain_texture; static void ta_gpu_resize_msaa_texture(SDL_GPUTextureFormat format) { if (ta_gpu_msaa_texture_width == (Uint32)ta_window_width && ta_gpu_msaa_texture_height == (Uint32)ta_window_height && ta_gpu_msaa_texture) { return; } SDL_ReleaseGPUTexture(ta_gpu_device, ta_gpu_msaa_texture); SDL_ReleaseGPUTexture(ta_gpu_device, ta_gpu_depth_texture); ta_gpu_msaa_texture = NULL; ta_gpu_depth_texture = NULL; SDL_GPUTextureCreateInfo texture_info = { .type = SDL_GPU_TEXTURETYPE_2D, .format = format, .usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET, .width = (Uint32)ta_window_width, .height = (Uint32)ta_window_height, .layer_count_or_depth = 1, .num_levels = 1, .sample_count = ta_gpu_sample_count, }; ta_gpu_msaa_texture = ta_sdl_create_gpu_texture(ta_gpu_device, &texture_info); texture_info.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; texture_info.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; ta_gpu_depth_texture = ta_sdl_create_gpu_texture(ta_gpu_device, &texture_info); ta_gpu_msaa_texture_width = (Uint32)ta_window_width; ta_gpu_msaa_texture_height = (Uint32)ta_window_height; } static SDL_GPUShader *ta_gpu_load_shader(SDL_GPUDevice *device, const void *code, size_t code_size, SDL_GPUShaderStage stage, Uint32 num_samplers, Uint32 num_uniform_buffers) { SDL_GPUShaderCreateInfo info = { .code = code, .code_size = code_size, .entrypoint = SPIRV_ENTRY_POINT, .format = SDL_GPU_SHADERFORMAT_SPIRV, .stage = stage, .num_samplers = num_samplers, .num_uniform_buffers = num_uniform_buffers, }; SDL_GPUShader *shader = ta_sdl_create_gpu_shader(device, &info); return shader; } void ta_gpu_init(void) { ta_gpu_device = ta_sdl_create_gpu_device(); ta_sdl_claim_window_for_gpu_device(ta_gpu_device, ta_window); ta_gpu_swapchain_format = SDL_GetGPUSwapchainTextureFormat(ta_gpu_device, ta_window); ta_gpu_resize_msaa_texture(ta_gpu_swapchain_format); SDL_GPUShader *vertex_shader = ta_gpu_load_shader( ta_gpu_device, file_text_vert_slang_spv_start, file_text_vert_slang_spv_size, SDL_GPU_SHADERSTAGE_VERTEX, 0, 1 ); SDL_GPUShader *fragment_shader = ta_gpu_load_shader( ta_gpu_device, file_text_frag_slang_spv_start, file_text_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0 ); SDL_GPUColorTargetDescription color_target = { .format = ta_gpu_swapchain_format, .blend_state = { .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, .color_blend_op = SDL_GPU_BLENDOP_ADD, .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE, .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, .alpha_blend_op = SDL_GPU_BLENDOP_ADD, .enable_blend = true, }, }; SDL_GPUGraphicsPipelineCreateInfo pipeline_info = { .vertex_shader = vertex_shader, .fragment_shader = fragment_shader, .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, .target_info = { .num_color_targets = 1, .color_target_descriptions = &color_target, }, .multisample_state = { .sample_count = ta_gpu_sample_count, }, }; ta_gpu_text_pipeline = ta_sdl_create_gpu_graphics_pipeline(ta_gpu_device, &pipeline_info); SDL_ReleaseGPUShader(ta_gpu_device, vertex_shader); SDL_ReleaseGPUShader(ta_gpu_device, fragment_shader); SDL_GPUSamplerCreateInfo sampler_info = { .min_filter = SDL_GPU_FILTER_LINEAR, .mag_filter = SDL_GPU_FILTER_LINEAR, .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, .address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, .address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, .address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, }; ta_gpu_text_sampler = ta_sdl_create_gpu_sampler(ta_gpu_device, &sampler_info); } void ta_gpu_start_frame(void) { ta_gpu_command_buffer = ta_sdl_acquire_gpu_command_buffer(ta_gpu_device); ta_gpu_swapchain_texture = NULL; ta_gpu_swapchain_format = SDL_GetGPUSwapchainTextureFormat(ta_gpu_device, ta_window); ta_sdl_wait_and_acquire_gpu_swapchain_texture(ta_gpu_command_buffer, ta_window, &ta_gpu_swapchain_texture); if (ta_gpu_swapchain_texture) { ta_gpu_resize_msaa_texture(ta_gpu_swapchain_format); } } void ta_gpu_end_frame(void) { if (ta_gpu_swapchain_texture) { ta_gpu_upload_text(ta_gpu_command_buffer); ta_screen_upload(ta_gpu_command_buffer); float red = 0.0f; float green = 0.0f; float blue = 0.0f; float alpha = 1.0f; SDL_GPUColorTargetInfo color_target = { .texture = ta_gpu_msaa_texture, .load_op = SDL_GPU_LOADOP_CLEAR, .store_op = SDL_GPU_STOREOP_RESOLVE, .resolve_texture = ta_gpu_swapchain_texture, .clear_color = { red, green, blue, alpha }, }; SDL_GPUDepthStencilTargetInfo depth_target = { .texture = ta_gpu_depth_texture, .clear_depth = 1.0f, .load_op = SDL_GPU_LOADOP_CLEAR, .store_op = SDL_GPU_STOREOP_DONT_CARE, .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE, }; SDL_GPURenderPass *render_pass = ta_sdl_begin_gpu_render_pass( ta_gpu_command_buffer, &color_target, 1, &depth_target ); ta_text_render(ta_gpu_command_buffer, render_pass); ta_screen_render(ta_gpu_command_buffer, render_pass); SDL_EndGPURenderPass(render_pass); } ta_sdl_submit_gpu_command_buffer(ta_gpu_command_buffer); }