Triangle with per vertex colors

This commit is contained in:
azraptor 2025-04-11 12:49:15 -04:00
commit 270132a58e
5 changed files with 388 additions and 0 deletions

57
.gitignore vendored Normal file
View File

@ -0,0 +1,57 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
SDL3/
build/
.cache/
.vscode/

75
CMakeLists.txt Normal file
View File

@ -0,0 +1,75 @@
cmake_minimum_required(VERSION 3.10)
project(sdlgpu1 VERSION 0.1.0 LANGUAGES C CXX)
SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)
set(EXE_NAME ${CMAKE_PROJECT_NAME})
#set(PROGRAM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vulkanapp.cc)
# Get our GLSL shaders
set(SHADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
set(SHADER_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
file(GLOB SHADERS ${SHADER_DIR}/*.vert
${SHADER_DIR}/*.frag
${SHADER_DIR}/*.comp
${SHADER_DIR}/*.geom
${SHADER_DIR}/*.tesc
${SHADER_DIR}/*.tese
${SHADER_DIR}/*.mesh
${SHADER_DIR}/*.task
${SHADER_DIR}/*.rgen
${SHADER_DIR}/*.rchit
${SHADER_DIR}/*.rmiss
)
option(SDL3_NONSYSTEM "Use SDL2 from folder in source tree" ON)
if(SDL3_NONSYSTEM)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SDL3 ${CMAKE_CURRENT_BINARY_DIR}/SDL3 EXCLUDE_FROM_ALL)
else()
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-shared)
endif()
find_package(Vulkan REQUIRED COMPONENTS glslc)
# Compile each shader
foreach(SHADER IN LISTS SHADERS)
get_filename_component(FILENAME ${SHADER} NAME)
add_custom_command(OUTPUT ${SHADER_BIN_DIR}/${FILENAME}.spv
COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER} -o ${SHADER_BIN_DIR}/${FILENAME}.spv
DEPENDS ${SHADER}
COMMENT "Compiling Shader ${FILENAME}")
list(APPEND SPV_SHADERS ${SHADER_BIN_DIR}/${FILENAME}.spv)
endForeach()
# Shader target
add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS})
add_executable(${EXE_NAME} ${CMAKE_SOURCE_DIR}/main.c ${SHADERS})
if(WIN32)
add_custom_command(
TARGET ${EXE_NAME} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy $<TARGET_FILE:SDL3::SDL3-shared> $<TARGET_FILE_DIR:${EXE_NAME}>
VERBATIM
)
endif()
set_target_properties(${EXE_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS ON
)
target_include_directories(${EXE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include)
add_dependencies(${EXE_NAME} shaders)
if(CMAKE_COMPILER_IS_GNUCC)
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra)
elseif(MSVC)
target_compile_options(${EXE_NAME} PRIVATE /W4)
endif()
# Linking
target_link_libraries(${EXE_NAME} PRIVATE SDL3::SDL3)

201
main.c Normal file
View File

@ -0,0 +1,201 @@
#include <SDL3/SDL.h>
SDL_GPUShader *loadShader(SDL_GPUDevice *device,
const char *filename,
Uint32 samplerCount,
Uint32 uniformBufferCount,
Uint32 storageBufferCount,
Uint32 storageTextureCount) {
SDL_GPUShaderStage stage;
if(SDL_strstr(filename, ".vert"))
stage = SDL_GPU_SHADERSTAGE_VERTEX;
else if(SDL_strstr(filename, ".frag"))
stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
else {
SDL_Log("Invalid shader stage!");
return NULL;
}
SDL_GPUShaderFormat backendFmt = SDL_GetGPUShaderFormats(device);
SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_INVALID;
const char *entryPoint;
if(backendFmt & SDL_GPU_SHADERFORMAT_SPIRV) {
format = SDL_GPU_SHADERFORMAT_SPIRV;
entryPoint = "main";
} else {
SDL_Log("Unsupported shader format!");
return NULL;
}
size_t fSize = 0;
void *byteCode = SDL_LoadFile(filename, &fSize);
if(byteCode == NULL) {
SDL_Log("Could not load shader bytecode from file: %s", filename);
return NULL;
}
SDL_GPUShaderCreateInfo shaderInfo = {
.code = (Uint8*)byteCode,
.code_size = fSize,
.entrypoint = entryPoint,
.format = format,
.stage = stage,
.num_samplers = samplerCount,
.num_uniform_buffers = uniformBufferCount,
.num_storage_buffers = storageBufferCount,
.num_storage_textures = storageTextureCount
};
SDL_GPUShader *shader = SDL_CreateGPUShader(device, &shaderInfo);
if(shader == NULL) {
SDL_Log("Could not create shader!");
SDL_free(byteCode);
return NULL;
}
SDL_free(byteCode);
return shader;
}
int main(int argc, char **argv) {
SDL_Window *window = NULL;
SDL_GPUDevice *GPUDevice = NULL;
SDL_GPUTexture *swapchainTexture = NULL;
SDL_GPUCommandBuffer *commandBuf = NULL;
SDL_GPURenderPass *renderPass = NULL;
SDL_GPUShader *vertexShader = NULL;
SDL_GPUShader *fragShader = NULL;
SDL_GPUGraphicsPipeline *pipeline = NULL;
bool done = false;
if(!SDL_Init(SDL_INIT_VIDEO)) {
SDL_Log("Unable to initialize SDL3: %s", SDL_GetError());
return 1;
}
// Create the GPU device
GPUDevice = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV, true, "vulkan");
const char* device_driver = SDL_GetGPUDeviceDriver(GPUDevice);
SDL_Log("Created GPU device with driver: %s\n", device_driver);
if(GPUDevice == NULL) {
SDL_Log("Create GPU failed");
return 1;
}
// Create the window
window = SDL_CreateWindow("SDL3 Window", 640, 480, SDL_WINDOW_RESIZABLE);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
if (window == NULL) {
SDL_Log("Could not create window: %s\n", SDL_GetError());
return 1;
}
// Tie the window to our GPU
if(!SDL_ClaimWindowForGPUDevice(GPUDevice, window)) {
SDL_Log("Claiming SDL3 window failed");
return 1;
}
// Shader time
vertexShader = loadShader(GPUDevice, "triangle.vert.spv", 0, 0, 0, 0);
if(vertexShader == NULL)
{
SDL_Log("Could not create vertex shader!");
return 1;
}
fragShader = loadShader(GPUDevice, "color.frag.spv", 0, 0, 0, 0);
if(fragShader == NULL)
{
SDL_Log("Could not create fragment shader!");
return 1;
}
// Creating the pipelines
SDL_GPUGraphicsPipelineCreateInfo pipelineCreateInfo = {
.target_info = {
.num_color_targets = 1,
.color_target_descriptions = (SDL_GPUColorTargetDescription[]){{
.format = SDL_GetGPUSwapchainTextureFormat(GPUDevice, window)
}},
},
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
.vertex_shader = vertexShader,
.fragment_shader = fragShader,
};
pipelineCreateInfo.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
pipeline = SDL_CreateGPUGraphicsPipeline(GPUDevice, &pipelineCreateInfo);
if(pipeline == NULL) {
SDL_Log("Could not create pipeline");
return 1;
}
// Free up shaders that are now bound to pipeline
SDL_ReleaseGPUShader(GPUDevice, vertexShader);
SDL_ReleaseGPUShader(GPUDevice, fragShader);
// Now to loop
while (!done) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_EVENT_QUIT) {
done = true;
}
}
// Get our command buffer
commandBuf = SDL_AcquireGPUCommandBuffer(GPUDevice);
if(commandBuf == NULL) {
SDL_Log("Could not get command buf!");
return 1;
}
// Get our swapchain
if(!SDL_WaitAndAcquireGPUSwapchainTexture(commandBuf, window, &swapchainTexture, NULL, NULL)) {
SDL_Log("Could not create swapchain!");
return 1;
}
// Handle the swapchain
if(swapchainTexture != NULL) {
// Clear (background) color
SDL_GPUColorTargetInfo colorInfo = {
.texture = swapchainTexture,
.clear_color = (SDL_FColor){0.25f, 0.5f, 0.1f, 1.0f},
.load_op = SDL_GPU_LOADOP_CLEAR,
.store_op = SDL_GPU_STOREOP_STORE
};
// Now for the render pass
renderPass = SDL_BeginGPURenderPass(commandBuf, &colorInfo, 1, NULL);
SDL_BindGPUGraphicsPipeline(renderPass, pipeline);
SDL_DrawGPUPrimitives(renderPass, 3, 1, 0, 0);
SDL_EndGPURenderPass(renderPass);
} else {
SDL_Log("Swapchain texture just does not exist! %s", SDL_GetError());
return 1;
}
SDL_SubmitGPUCommandBuffer(commandBuf);
}
// Cleanup
SDL_ReleaseGPUGraphicsPipeline(GPUDevice, pipeline);
SDL_ReleaseWindowFromGPUDevice(GPUDevice, window);
SDL_DestroyWindow(window);
SDL_DestroyGPUDevice(GPUDevice);
SDL_Quit();
return 0;
}

13
shaders/color.frag Normal file
View File

@ -0,0 +1,13 @@
#version 450
// layout(location = 0) in vec4 in_var_TEXCOORD0;
// layout(location = 0) out vec4 out_var_SV_Target0;
layout(location = 0) in vec4 inColor;
layout(location = 0) out vec4 outColor;
void main()
{
outColor = inColor;
}

42
shaders/triangle.vert Normal file
View File

@ -0,0 +1,42 @@
#version 450
vec2 temp_pos;
vec4 temp_color;
// layout(location = 0) out vec4 out_var_TEXCOORD0;
layout(location = 0) out vec4 outColor;
void main()
{
vec4 color;
vec2 pos;
if (uint(gl_VertexIndex) == 0u)
{
color = vec4(1.0, 0.0, 0.0, 1.0);
pos = vec2(-0.5);
}
else
{
vec4 vert_color;
vec2 vert_pos;
if (uint(gl_VertexIndex) == 1u)
{
vert_color = vec4(0.0, 1.0, 0.0, 1.0);
vert_pos = vec2(0.5, -0.5);
}
else
{
bool index_exists = uint(gl_VertexIndex) == 2u;
vert_color = mix(temp_color, vec4(0.0, 0.0, 1.0, 1.0), bvec4(index_exists));
vert_pos = mix(temp_pos, vec2(0.0, 0.5), bvec2(index_exists));
}
color = vert_color;
pos = vert_pos;
}
// out_var_TEXCOORD0 = color;
outColor = color;
gl_Position = vec4(pos, 0.0, 1.0);
}