vulkan游戏引擎的核心device核心文件实现

1.vulkan_device.h

#pragma once

#include "vulkan_types.inl"

b8 vulkan_device_create(vulkan_context* context);

void vulkan_device_destroy(vulkan_context* context);

void vulkan_device_query_swapchain_support(

    VkPhysicalDevice physical_device,

    VkSurfaceKHR surface,

    vulkan_swapchain_support_info* out_support_info

);

b8 vulkan_device_detect_depth_format(vulkan_device* device);

2.vulkan_device.c

#include "vulkan_device.h"

#include "core/logger.h"

#include "core/kstring.h"

#include "core/kmemory.h"

#include "containers/darray.h"

#include "vulkan_types.inl"

#include "vulkan_backend.h"

#include "vulkan_swapchain.h"


 

typedef struct vulkan_physical_device_requirements{

    b8 graphics;

    b8 present;

    b8 compute;

    b8 transfer;

    //darray

    const char** device_extension_names;

    b8 sampler_anisotropy;

    b8 discrete_gpu;

}vulkan_physical_device_requirements;


 

typedef struct vulkan_physical_device_queue_family_info

{

    u32 graphics_family_index;

    u32 present_family_index;

    u32 compute_family_index;

    u32 transfer_family_index;

}vulkan_physical_device_queue_family_info;


 

b8 select_physical_device(vulkan_context* context);


 

static b8 physical_device_meets_requirements(

    //vulkan_context* context,

    VkPhysicalDevice device,

    VkSurfaceKHR surface,

    const VkPhysicalDeviceProperties* properties,

    const VkPhysicalDeviceFeatures* features,

    const vulkan_physical_device_requirements* requirements,

    vulkan_physical_device_queue_family_info* out_queue_family_info,

    vulkan_swapchain_support_info* out_swapchain_support

);


 

b8 vulkan_device_create(vulkan_context* context)

{

    if(!select_physical_device(context))

    {

        return false;


 

    }

    KINFO("Creating logical device...");

    b8 present_shares_graphics_queue = context->device.graphics_queue_index == context->device.present_queue_index;

    b8 transfer_shares_graphics_queue = context->device.graphics_queue_index == context->device.transfer_queue_index;

    //b8 present_must_share_graphics = false;

    u32 index_count = 1;

    if(!present_shares_graphics_queue)

    {

        index_count++;



 

    }

    if(!transfer_shares_graphics_queue)

    {


 

        index_count++;


 

    }

    u32 indices[32];

    u8 index = 0;

    indices[index++] = context->device.graphics_queue_index;

    if(!present_shares_graphics_queue)

    {

        indices[index++] = context->device.present_queue_index;

    }

    if(!transfer_shares_graphics_queue)

    {

        indices[index++] = context->device.transfer_queue_index;


 

    }

    VkDeviceQueueCreateInfo queue_create_infos[32];

   

    for(u32 i = 0;i <index_count;++i)

    {

        queue_create_infos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;

        queue_create_infos[i].queueFamilyIndex = indices[i];

        queue_create_infos[i].queueCount = 1;

        if(indices[i] == context->device.graphics_queue_index)

        {

            queue_create_infos[i].queueCount = 2;


 

        }

     

            queue_create_infos[i].flags = 0;

            queue_create_infos[i].pNext = 0;

            f32 queue_priority = 1.0f;

            queue_create_infos[i].pQueuePriorities = &queue_priority;

    }

         //shoule be config driven

    VkPhysicalDeviceFeatures device_features = {};

    device_features.samplerAnisotropy = VK_TRUE;

    VkDeviceCreateInfo device_create_info = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};

    device_create_info.queueCreateInfoCount = index_count;

    device_create_info.pQueueCreateInfos = queue_create_infos;

    device_create_info.pEnabledFeatures = &device_features;

    device_create_info.enabledExtensionCount = 1;

    const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME;

    device_create_info.ppEnabledExtensionNames  = &extension_names;


 

    device_create_info.enabledLayerCount = 0;

    device_create_info.ppEnabledLayerNames = 0;

    //没有实现

   

    //Create the device

    VK_CHECK(vkCreateDevice(

            context->device.physical_device,

            &device_create_info,

            context->allocator,

            &context->device.logical_device

        ));

    KINFO("Logical device created.");

    vkGetDeviceQueue(

        context->device.logical_device,

        context->device.graphics_queue_index,

        0,

        &context->device.graphics_queue


 

    );

    vkGetDeviceQueue(

        context->device.logical_device,

        context->device.present_queue_index,

        0,

        &context->device.present_queue



 

    );

   

    vkGetDeviceQueue(

    context->device.logical_device,

    context->device.transfer_queue_index,

    0,

    &context->device.transfer_queue);

    KINFO("Queues obtained.");

   

   

     //Create command pool for graphics queue.

     VkCommandPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};

     pool_create_info.queueFamilyIndex = context->device.graphics_queue_index;

     pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;

    VK_CHECK(vkCreateCommandPool(

        context->device.logical_device,

        &pool_create_info,

        context->allocator,

        &context->device.graphics_command_pool

    ));

    KINFO("Graphics command pool created.");


 

    return true;



 

   

   

}

void vulkan_device_destroy(vulkan_context* context)

{


 

    //Unset queues

    context->device.graphics_queue = 0;

    context->device.present_queue  = 0;

    context->device.transfer_queue = 0;


 

    KINFO("Destroying command pools...");

    vkDestroyCommandPool(

        context->device.logical_device,

        context->device.graphics_command_pool,

        context->allocator

    );



 

    //Destroy logical device

    KINFO("Destroying logical device...");

    if(context->device.logical_device)

    {

        vkDestroyDevice(context->device.logical_device,context->allocator);

        context->device.logical_device = 0;



 

    }


 

    //Physical devices are not destroyed

    KINFO("Releasing physical device resources...");

    context->device.physical_device = 0;

    if(context->device.swapchain_support.formats)

    {

        kfree(

            context->device.swapchain_support.formats,

            sizeof(VkSurfaceFormatKHR)* context->device.swapchain_support.format_count,

            MEMORY_TAG_RENDERER



 

        );

        context->device.swapchain_support.formats = 0;

        context->device.swapchain_support.format_count = 0;



 

    }

   

   

    if(context->device.swapchain_support.present_modes)

    {

        kfree(

            context->device.swapchain_support.present_modes,

            sizeof(VkSurfaceFormatKHR)* context->device.swapchain_support.present_mode_count,

            MEMORY_TAG_RENDERER



 

        );

        context->device.swapchain_support.present_modes = 0;

        context->device.swapchain_support.present_mode_count = 0;



 

    }




 

    kzero_memory(

        &context->device.swapchain_support.capabilities,

        sizeof(context->device.swapchain_support.capabilities)



 

    );

    context->device.graphics_queue_index = -1;

    context->device.present_queue_index = -1;

    context->device.transfer_queue_index = -1;

   


 

}


 

void vulkan_device_query_swapchain_support(

    VkPhysicalDevice physical_device,

    VkSurfaceKHR surface,

    vulkan_swapchain_support_info* out_support_info

){

    //Surface capabilities

    VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(

        physical_device,

        surface,

        &out_support_info->capabilities

    ));

    VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(

        physical_device,

        surface,

        &out_support_info->format_count,

        0

    ));


 

    if(out_support_info->format_count !=0)

    {

        if(!out_support_info->formats)

        {

            out_support_info->formats = kallocate(sizeof(VkSurfaceFormatKHR)*out_support_info->format_count,MEMORY_TAG_RENDERER);


 

        }

        VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(

            physical_device,

            surface,

            &out_support_info->format_count,

            out_support_info->formats

        ));

         if(out_support_info->format_count != 0)

    {

        if(!out_support_info->formats)

        {


 

            out_support_info->formats = kallocate(sizeof(VkSurfaceFormatKHR) * out_support_info->format_count,MEMORY_TAG_RENDERER);



 

        }

        VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(

            physical_device,

            surface,

            &out_support_info->present_mode_count,

           0

        ));

        if(out_support_info->present_mode_count != 0)

        {

            if(!out_support_info->present_modes)

            {

                out_support_info->present_modes = kallocate(sizeof(VkPresentModeKHR)* out_support_info->present_mode_count,MEMORY_TAG_RENDERER);



 

            }

            VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(


 

                physical_device,

                surface,

                &out_support_info->present_mode_count,

                out_support_info->present_modes



 

            ));






 

        }





 

    }






 

    }

    VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(

        physical_device,

        surface,

        &out_support_info->present_mode_count,

        0

    ));

   


 

}


 

b8 vulkan_device_detect_depth_format(vulkan_device* device)

{

    const u64 candidate_count = 3;

    VkFormat candidates[3] = {

        VK_FORMAT_D32_SFLOAT,

        VK_FORMAT_D32_SFLOAT_S8_UINT,

        VK_FORMAT_D24_UNORM_S8_UINT

    };

    u32 flags = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;

    for (u64 i = 0;i<candidate_count;++i)

    {

        VkFormatProperties properties;

        vkGetPhysicalDeviceFormatProperties(device->physical_device,candidates[i], &properties);

        if((properties.linearTilingFeatures & flags) == flags)

        {

              device->depth_format = candidates[i];

              return true;


 

        }else if((properties.optimalTilingFeatures & flags) == flags)

        {

            device->depth_format = candidates[i];

            return true;



 

        }


 

     

    }


 

    return false;



 

}






 

b8 select_physical_device(vulkan_context* context)

{

    u32 physical_device_count = 0;

    VK_CHECK(vkEnumeratePhysicalDevices(context->instance,&physical_device_count,0));

    if(physical_device_count == 0)

    {

        KFATAL("No devices which support vulkan were found.");

        return false;

    }


 

    const u32 max_device_count = 32;

    VkPhysicalDevice physical_devices[max_device_count];

    VK_CHECK(vkEnumeratePhysicalDevices(context->instance,&physical_device_count,physical_devices));

    for(u32 i = 0;i<physical_device_count;++i)

    {

     

        VkPhysicalDeviceProperties properties;

        vkGetPhysicalDeviceProperties(physical_devices[i],&properties);

        VkPhysicalDeviceFeatures features;

        vkGetPhysicalDeviceFeatures(physical_devices[i],&features);

        VkPhysicalDeviceMemoryProperties memory;

        vkGetPhysicalDeviceMemoryProperties(physical_devices[i],&memory);

          vulkan_physical_device_requirements requirements = {};

        requirements.graphics = true;

        requirements.present = true;

        requirements.transfer = true;

       

        requirements.sampler_anisotropy = true;

        requirements.discrete_gpu = true;

        requirements.device_extension_names = darray_create(const char*);

        darray_push(requirements.device_extension_names,&VK_KHR_SWAPCHAIN_EXTENSION_NAME);

        vulkan_physical_device_queue_family_info queue_info = {};

        b8 result = physical_device_meets_requirements(

            //context,

            physical_devices[i],

            context->surface,

            &properties,

            &features,

            &requirements,

            &queue_info,

            &context->device.swapchain_support);

            if(result)

            {

                KINFO("Selected device: '%s'.",properties.deviceName);

                //GPU type

                switch(properties.deviceType)

                {

                    default:

                        case VK_PHYSICAL_DEVICE_TYPE_OTHER:

                            KINFO("GPU type is Unknown.");

                            break;

                        case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:

                            KINFO("GPU type is Integrated.");

                            break;

                        case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:

                            KINFO("GPU type is Descrete.");

                            break;

                        case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:

                            KINFO("GPU type is Virtual.");

                            break;

                        case VK_PHYSICAL_DEVICE_TYPE_CPU:

                            KINFO("GPU type is CPU.");

                            break;


 

                }



 

                KINFO(

                    "GPU Driver version: %d,%d,%d",

                    VK_VERSION_MAJOR(properties.driverVersion),

                    VK_VERSION_MINOR(properties.driverVersion),

                    VK_VERSION_PATCH(properties.driverVersion)




 

                );

                //Vulkan API version

                KINFO(

                    "Vulkan API version: %d,%d,%d",

                    VK_VERSION_MAJOR(properties.apiVersion),

                    VK_VERSION_MINOR(properties.apiVersion),

                    VK_VERSION_PATCH(properties.apiVersion)

                );


 

                //Memory information

                for(u32 j = 0;j <memory.memoryHeapCount;++j)

                {

                    f32 memory_size_gib = (((f32)memory.memoryHeaps[j].size)/1024.0f/1024.0f/1024.0f);

                    if(memory.memoryHeaps[j].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)

                    {

                        KINFO("Local GPU memory: %.2f GiB",memory_size_gib);



 

                    }else

                    {

                        KINFO("Shared System memory: %.2f GiB",memory_size_gib);



 

                    }



 

                }



 

                context->device.physical_device = physical_devices[i];

                context->device.graphics_queue_index = queue_info.graphics_family_index;

                context->device.present_queue_index = queue_info.present_family_index;

                context->device.transfer_queue_index = queue_info.transfer_family_index;



 

                context->device.properties = properties;

                context->device.features = features;

                context->device.memory = memory;

                break;

            }

    }


 

    if(!context->device.physical_device)

    {

        KERROR("NO physical devices were found which meet the requirements.");

        return false;

    }

    KINFO("Physical device selected.");

    return true;


 

}





 

b8 physical_device_meets_requirements(

    //vulkan_context* context,

    VkPhysicalDevice device,

    VkSurfaceKHR surface,

    const VkPhysicalDeviceProperties* properties,

    const VkPhysicalDeviceFeatures* features,

    const vulkan_physical_device_requirements* requirements,

    vulkan_physical_device_queue_family_info* out_queue_info,

    vulkan_swapchain_support_info* out_swapchain_support

   

)

{

    out_queue_info->graphics_family_index = -1;

    out_queue_info->present_family_index = -1;

    out_queue_info->compute_family_index = -1;

    out_queue_info->transfer_family_index = -1;


 

    if(requirements->discrete_gpu)

    {

        if(properties->deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)

        {


 

            KINFO("Device is not a discrete GPU,and one is required.Skipping.");

            return false;




 

        }



 

    }

   

   


 

    u32 queue_family_count = 0;

    vkGetPhysicalDeviceQueueFamilyProperties(device,&queue_family_count,0);

    VkQueueFamilyProperties queue_families[32];

    vkGetPhysicalDeviceQueueFamilyProperties(device,&queue_family_count,queue_families);

    KINFO("Graphics | Present | Compute | Transfer | Name");

    u8 min_transfer_score = 255;

    for(u32 i = 0;i <queue_family_count;++i)

    {

        u8 current_transfer_score = 0;

        //Graphics queue

        if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)

        {

            out_queue_info->graphics_family_index  = i;

            ++current_transfer_score;




 

        }

        //Compute queue

        if(queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT)

        {


 

            out_queue_info->compute_family_index = i;

            ++current_transfer_score;



 

        }

        if(queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT)

        {

            if(current_transfer_score <= min_transfer_score)

            {

                min_transfer_score = current_transfer_score;

                out_queue_info->transfer_family_index = i;



 

            }


 

        }


 

        VkBool32 supports_present = VK_FALSE;

        VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(device,i,surface,&supports_present));

        if(supports_present)

        {


 

          out_queue_info->present_family_index = i;




 

        }

       

    }



 

     KINFO(" %d| %d| %d| %d |%s",

   

        out_queue_info->graphics_family_index != -1,

        out_queue_info->present_family_index != -1,

        out_queue_info->compute_family_index != -1,

        out_queue_info->transfer_family_index != -1,

   

        properties->deviceName

   

   

    );

   

     if (

        (!requirements->graphics || (requirements->graphics && out_queue_info->graphics_family_index != -1)) &&

        (!requirements->present || (requirements->present && out_queue_info->present_family_index != -1)) &&

        (!requirements->compute || (requirements->compute && out_queue_info->compute_family_index != -1)) &&

        (!requirements->transfer || (requirements->transfer && out_queue_info->transfer_family_index != -1))) {

        KINFO("Device meets queue requirements.");

        KTRACE("Graphics Family Index: %i", out_queue_info->graphics_family_index);

        KTRACE("Present Family Index:  %i", out_queue_info->present_family_index);

        KTRACE("Transfer Family Index: %i", out_queue_info->transfer_family_index);

        KTRACE("Compute Family Index:  %i", out_queue_info->compute_family_index);

        //Qure swapchain support

        vulkan_device_query_swapchain_support(

            device,

            surface,

            out_swapchain_support


 

        );


 

        if(out_swapchain_support->format_count < 1 || out_swapchain_support->present_mode_count < 1)

        {

            if(out_swapchain_support->formats)

            {

                kfree(out_swapchain_support->formats,sizeof(VkSurfaceFormatKHR) * out_swapchain_support->format_count,MEMORY_TAG_RENDERER);


 

            }

            if(out_swapchain_support->present_modes)

            {

                kfree(out_swapchain_support->present_modes,sizeof(VkPresentModeKHR)*out_swapchain_support->present_mode_count,MEMORY_TAG_RENDERER);



 

            }

            KINFO("Required swapchain support not present.skipping device");

            return false;




 

        }





 

    //Device extensions

    if(requirements->device_extension_names)

    {

        u32 available_extension_count = 0;

        VkExtensionProperties* available_extensions = 0;

        VK_CHECK(vkEnumerateDeviceExtensionProperties(

            device,

            0,

            &available_extension_count,

            0



 

        ));

        if(available_extension_count != 0)

        {

            available_extensions = kallocate(sizeof(VkExtensionProperties)* available_extension_count,MEMORY_TAG_RENDERER);

            VK_CHECK(vkEnumerateDeviceExtensionProperties(

                device,

                0,

                &available_extension_count,

                available_extensions


 

            ));

            u32 required_extension_count = darray_length(requirements->device_extension_names);

            for(u32 i = 0;i<required_extension_count;++i)

            {

                b8 found = false;

                for(u32 j = 0;j<available_extension_count;++j){

                    if(strings_equal(requirements->device_extension_names[i],available_extensions[j].extensionName))

                    {

                    found =true;

                    break;



 

                     }

               

                }

                if(!found)

                {

                KINFO("Required extensions not found: '%s',skipping device.",requirements->device_extension_names[i]);

                kfree(available_extensions,sizeof(VkExtensionProperties) * available_extension_count,MEMORY_TAG_RENDERER);

                break;



 

                 }

               

            }

       

        }

            kfree(available_extensions,sizeof(VkExtensionProperties)* available_extension_count,MEMORY_TAG_RENDERER);


 

        }

       

   

     

        // Sampler anisotropy

        if (requirements->sampler_anisotropy && !features->samplerAnisotropy) {

            KINFO("Device does not support samplerAnisotropy, skipping.");

            return false;

        }

        // Device meets all requirements.

        return true;

    }

    return false;

   

           

   

}

   



 

   



 

制作游戏引擎是一项复杂而富有挑战性的任务,涉及到计算机科学的多个方面,包括图形学、物理学、音频处理等。下面将详细介绍创建一个基本功能齐全的游戏引擎所需的主要步骤和关键技术点。 ### 1. 明确目标与规划 在开始编码之前,首先要明确你要构建的是什么样的游戏引擎及其特性: - **确定适用范围**:是通用型还是针对某一类特定类型的游戏? - **性能考量**:是否追求极致性能优化?对于不同硬件的支持程度如何? ### 2. 构建基础框架 这是整个引擎的核心结构设计阶段,在此期间你需要考虑以下几个要点: #### A. 初始化与主循环(Main Loop) 编写程序启动后的初始化代码,设置必要的环境变量如分辨率大小等,并建立一个持续运行直到用户退出为止的时间轴机制——即“帧”更新周期。 ```cpp while (!done) { // 更新状态 UpdateGameState(); // 绘制当前帧图像数据至屏幕缓冲区 RenderFrame(); // 检查是否有事件发生(键盘输入/鼠标点击...) } ``` #### B. 内存管理和资源加载卸载策略 制定一套有效的内存分配方案以减少碎片化问题的发生频率;同时也要有合理的资产管理系统保证所有纹理文件、模型数据等能在合适时机被正确读取进来又及时释放出去避免浪费空间占用过多而导致崩溃现象。 #### C. 平台无关性和跨平台兼容能力的设计原则 尽量让底层API调用保持一致以便将来可以轻松移植到其他操作系统之上而不必做太多改动工作量巨大修改源码的情况。 ### 3. 实现渲染系统 #### D. 图形绘制接口的选择与集成 选择合适的图形库作为绘图后端,比如OpenGL或者DirectX/Vulkan等等。这一步骤决定了后续所有的可视化内容是如何呈现在玩家眼前的。 #### E. 光栅化算法&着色器编程 深入学习GPU的工作原理以及片元着色器(Fragment Shader)/顶点着色器(Vertex Shader)的作用机理,能够让你更精准地控制每像素颜色计算过程实现高质量光照效果阴影投射等功能。 #### F. 场景管理及摄像机组件添加 为了高效组织场景中的物体位置信息,引入八叉树/Octree这样的空间分区技术有助于加速碰撞检测距离测试等工作流程。另外还需配备虚拟相机视角变换矩阵数学运算组件使得观察角度随意切换成为可能。 ### 4. 开发物理仿真模块 为了让游戏角色动作显得自然流畅并且满足现实世界的力学规律,则需要借助第三方库(如Bullet Physics/BepuPhysics)或自行研发的一套简单刚体动力学规则来进行交互式反馈模拟实验。 ### 5. 音频处理单元组装 声音同样是营造沉浸感不可或缺的一部分,因此必须重视音效系统的建设。可以从OpenAL/SFML等开源项目着手研究混响回声定位环绕立体声等高级属性调节技巧。 ### 6. 输入设备支持完善 最后别忘了为人机界面(Human Interface Device,HID)做好充分准备,无论是传统的键鼠操控模式还是新型VR控制器都应囊括进去,确保最终成品具备良好的用户体验度。 以上只是大致概括了自制一款完整版游戏引擎所需要经历的一些主要里程碑式的节点而已,实际上还有很多细节需要注意和完善才能打造出真正实用可靠的产品出来!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Magnum Lehar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值