mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-11 03:08:41 +00:00
huge disaster with double frame buffer fixed, still no manual support but we are at least alive again
This commit is contained in:
parent
b916506f89
commit
f903ac86d7
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,4 +3,5 @@ data/*
|
|||
bin/*
|
||||
*.obj
|
||||
*.log
|
||||
*.spv
|
||||
*.res
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
#include "../platform/win32/audio/DirectSound.h"
|
||||
#elif XAUDIO2
|
||||
#include "../platform/win32/audio/XAudio2.h"
|
||||
#elif WASAPI
|
||||
#include "../platform/win32/audio/Wasapi.h"
|
||||
#endif
|
||||
|
||||
enum AudioEffect {
|
||||
|
|
@ -86,6 +88,8 @@ struct AudioMixer {
|
|||
DirectSoundSetting api_setting;
|
||||
#elif XAUDIO2
|
||||
XAudio2Setting api_setting;
|
||||
#elif WASAPI
|
||||
WasapiSetting api_setting;
|
||||
#endif
|
||||
|
||||
// @todo Replace HWND with our own typedef for linux
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@
|
|||
#include "../stdlib/Types.h"
|
||||
#include "../math/matrix/MatrixFloat32.h"
|
||||
|
||||
#define SOUND_API_DIRECT_SOUND 0
|
||||
#define SOUND_API_XAUDIO2 1
|
||||
enum SoundApiType : byte {
|
||||
SOUND_API_TYPE_DIRECT_SOUND,
|
||||
SOUND_API_TYPE_XAUDIO2,
|
||||
SOUND_API_TYPE_WASAPI,
|
||||
};
|
||||
|
||||
struct AudioSetting {
|
||||
f32 master_volume;
|
||||
|
|
@ -30,7 +33,7 @@ struct AudioSetting {
|
|||
// usually 2 * 16 = 4
|
||||
byte sample_size;
|
||||
|
||||
// how often has the audio_play been called (required for xaudio)
|
||||
// how often has the audio_play been called (required for xaudio to switch between 2 buffers)
|
||||
byte sample_output;
|
||||
|
||||
// max buffer content/size
|
||||
|
|
@ -41,10 +44,8 @@ struct AudioSetting {
|
|||
uint32 sample_buffer_size;
|
||||
int16* buffer;
|
||||
|
||||
byte type = SOUND_API_DIRECT_SOUND;
|
||||
SoundApiType type;
|
||||
byte latency;
|
||||
|
||||
// @todo add more settings e.g. repeat etc
|
||||
};
|
||||
|
||||
struct AudioLocationSetting {
|
||||
|
|
|
|||
7
error/HammingCodes.h
Normal file
7
error/HammingCodes.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef TOS_ERROR_HAMMING_CODES_H
|
||||
#define TOS_ERROR_HAMMING_CODES_H
|
||||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../utils/BitUtils.h"
|
||||
|
||||
#endif
|
||||
|
|
@ -9,7 +9,13 @@
|
|||
#ifndef TOS_GPUAPI_OPENGL_GPU_API_CONTAINER
|
||||
#define TOS_GPUAPI_OPENGL_GPU_API_CONTAINER
|
||||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "OpenglUtils.h"
|
||||
|
||||
struct GpuApiContainer {
|
||||
uint32 frames_in_flight;
|
||||
uint32 framebuffer_idx;
|
||||
OpenglFrameData* framebuffers;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
1543
gpuapi/opengl/OpenglDefines.h
Normal file
1543
gpuapi/opengl/OpenglDefines.h
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -29,10 +29,32 @@
|
|||
#include "../../platform/linux/Window.h"
|
||||
#endif
|
||||
|
||||
inline
|
||||
void change_viewport(Window* w, int32 offset_x = 0, int32 offset_y = 0)
|
||||
struct OpenglFrameData {
|
||||
uint32 framebuffer;
|
||||
uint32 renderbuffer;
|
||||
Texture* texture;
|
||||
|
||||
// msaa data
|
||||
uint32 framebuffer_msaa;
|
||||
uint32 colorbuffer_msaa;
|
||||
uint32 depthbuffer_msaa;
|
||||
Texture* texture_msaa;
|
||||
};
|
||||
|
||||
void opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||
{
|
||||
glViewport(offset_x, offset_y, w->width, w->height);
|
||||
if (severity < GL_DEBUG_SEVERITY_LOW) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(message, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
inline
|
||||
void change_viewport(int16 width, int16 height, int32 offset_x = 0, int32 offset_y = 0)
|
||||
{
|
||||
glViewport(offset_x, offset_y, width, height);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -44,11 +66,7 @@ void vsync_set(int32 on)
|
|||
inline
|
||||
void wireframe_mode(bool on)
|
||||
{
|
||||
if (on) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
} else {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
glPolygonMode(GL_FRONT_AND_BACK, on ? GL_LINE : GL_FILL);
|
||||
}
|
||||
|
||||
struct OpenglInfo {
|
||||
|
|
@ -144,16 +162,10 @@ void load_texture_to_gpu(const Texture* texture, int32 mipmap_level = 0)
|
|||
inline
|
||||
void texture_use(const Texture* texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + texture->sample_id);
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint) texture->id);
|
||||
}
|
||||
uint32 texture_data_type = get_texture_data_type(texture->texture_data_type);
|
||||
|
||||
// @todo should be texture_use, the Texture holds information that should make it possible to determine 1D or 2D
|
||||
inline
|
||||
void texture_use_1D(const Texture* texture, uint32 texture_unit)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + texture->sample_id);
|
||||
glBindTexture(GL_TEXTURE_1D, (GLuint) texture->id);
|
||||
glBindTexture(texture_data_type, (GLuint) texture->id);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -485,6 +497,12 @@ void gpuapi_error()
|
|||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#define ASSERT_GPU_API() gpuapi_error()
|
||||
#else
|
||||
#define ASSERT_GPU_API() ((void) 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
void render_9_patch(GLuint texture,
|
||||
int32 imgWidth, int32 imgHeight,
|
||||
|
|
|
|||
|
|
@ -12,26 +12,12 @@
|
|||
#include <windows.h>
|
||||
#include "../../platform/win32/Window.h"
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "OpenglDefines.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "OpenGL32.Lib")
|
||||
#endif
|
||||
#pragma comment(lib, "OpenGL32.Lib")
|
||||
|
||||
typedef unsigned int GLenum;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef signed char GLbyte;
|
||||
typedef short GLshort;
|
||||
typedef int GLint;
|
||||
typedef int GLsizei;
|
||||
typedef unsigned char GLubyte;
|
||||
typedef unsigned short GLushort;
|
||||
typedef unsigned int GLuint;
|
||||
typedef float GLfloat;
|
||||
typedef float GLclampf;
|
||||
typedef double GLdouble;
|
||||
typedef double GLclampd;
|
||||
typedef void GLvoid;
|
||||
typedef ptrdiff_t GLsizeiptr;
|
||||
typedef ptrdiff_t GLintptr;
|
||||
|
||||
extern "C" {
|
||||
WINGDIAPI void APIENTRY glAccum (GLenum op, GLfloat value);
|
||||
|
|
@ -403,6 +389,15 @@ extern "C" {
|
|||
typedef void WINAPI type_glTexImage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
|
||||
static type_glTexImage2DMultisample* glTexImage2DMultisample;
|
||||
|
||||
typedef GLsync WINAPI type_glFenceSync(GLenum condition, GLbitfield flags);
|
||||
static type_glFenceSync* glFenceSync;
|
||||
|
||||
typedef GLenum WINAPI type_glClientWaitSync(GLsync GLsync, GLbitfield flags, GLuint64 timeout);
|
||||
static type_glClientWaitSync* glClientWaitSync;
|
||||
|
||||
typedef void WINAPI type_glDeleteSync(GLsync GLsync);
|
||||
static type_glDeleteSync* glDeleteSync;
|
||||
|
||||
typedef void WINAPI type_glBindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
static type_glBindFramebuffer* glBindFramebuffer;
|
||||
|
||||
|
|
@ -598,6 +593,10 @@ static type_glDrawElementsInstanced* glDrawElementsInstanced;
|
|||
typedef void WINAPI type_glProgramParameteri(GLuint program, GLenum pname, GLint value);
|
||||
static type_glProgramParameteri* glProgramParameteri;
|
||||
|
||||
typedef void WINAPI gl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
|
||||
typedef void WINAPI type_glDebugMessageCallback(gl_debug_callback* callback, const void* userParam);
|
||||
static type_glDebugMessageCallback* glDebugMessageCallback;
|
||||
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
||||
|
|
@ -661,8 +660,6 @@ void set_pixel_format(HDC hdc, int32 multisampling = 0)
|
|||
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
|
||||
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
||||
WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE,
|
||||
WGL_SAMPLE_BUFFERS_ARB, (int32) (multisampling > 0),
|
||||
WGL_SAMPLES_ARB, multisampling, // MSAA
|
||||
0,
|
||||
};
|
||||
|
||||
|
|
@ -771,6 +768,9 @@ void opengl_init_wgl()
|
|||
void opengl_init_gl()
|
||||
{
|
||||
glTexImage2DMultisample = (type_glTexImage2DMultisample *) wglGetProcAddress("glTexImage2DMultisample");
|
||||
glFenceSync = (type_glFenceSync *) wglGetProcAddress("glFenceSync");
|
||||
glClientWaitSync = (type_glClientWaitSync *) wglGetProcAddress("glClientWaitSync");
|
||||
glDeleteSync = (type_glDeleteSync *) wglGetProcAddress("glDeleteSync");
|
||||
glBindFramebuffer = (type_glBindFramebuffer *) wglGetProcAddress("glBindFramebuffer");
|
||||
glGenFramebuffers = (type_glGenFramebuffers *) wglGetProcAddress("glGenFramebuffers");
|
||||
glFramebufferTexture2D = (type_glFramebufferTexture2D *) wglGetProcAddress("glFramebufferTexture2D");
|
||||
|
|
@ -836,6 +836,7 @@ void opengl_init_gl()
|
|||
glDrawArraysInstanced = (type_glDrawArraysInstanced *) wglGetProcAddress("glDrawArraysInstanced");
|
||||
glDrawElementsInstanced = (type_glDrawElementsInstanced *) wglGetProcAddress("glDrawElementsInstanced");
|
||||
glProgramParameteri = (type_glProgramParameteri *) wglGetProcAddress("glProgramParameteri");
|
||||
glDebugMessageCallback = (type_glDebugMessageCallback *) wglGetProcAddress("glDebugMessageCallback");
|
||||
}
|
||||
|
||||
void opengl_destroy(Window* window)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef TOS_GPUAPI_VULKAN_GPU_API_CONTAINER
|
||||
#define TOS_GPUAPI_VULKAN_GPU_API_CONTAINER
|
||||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
struct GpuApiContainer {
|
||||
|
|
@ -16,13 +17,22 @@ struct GpuApiContainer {
|
|||
VkSurfaceKHR surface;
|
||||
VkDevice device;
|
||||
VkSwapchainKHR swapchain;
|
||||
uint32 swapchain_image_count;
|
||||
VkFormat swapchain_image_format;
|
||||
VkImage* swapchain_images; // swapchain_image_count
|
||||
VkImageView* swapchain_image_views; // swapchain_image_count
|
||||
VkFramebuffer* swapchain_framebuffers; // swapchain_image_count
|
||||
VkExtent2D swapchain_extent;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkFramebuffer framebuffer;
|
||||
VkQueue graphicsQueue;
|
||||
VkRenderPass renderPass;
|
||||
VkQueue graphics_queue;
|
||||
VkQueue present_queue;
|
||||
VkRenderPass render_pass;
|
||||
VkPipeline pipeline;
|
||||
VkCommandPool commandPool;
|
||||
VkCommandBuffer commandBuffer;
|
||||
VkCommandPool command_pool;
|
||||
VkCommandBuffer command_buffer;
|
||||
VkSemaphore image_available_semaphore;
|
||||
VkSemaphore render_finished_semaphore;
|
||||
VkFence in_flight_fence;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -24,8 +24,6 @@ inline uint32_t shader_get_uniform_location(VkWriteDescriptorSet* descriptor, Vk
|
|||
descriptorWrite.dstArrayElement = 0;
|
||||
descriptorWrite.descriptorType = descriptorType;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.pBufferInfo->buffer = 0;
|
||||
descriptorWrite.pBufferInfo->offset = 0;
|
||||
}
|
||||
|
||||
inline void shader_set_value(VkDevice device, VkCommandBuffer commandBuffer, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType, int32_t value)
|
||||
|
|
@ -47,17 +45,17 @@ inline void shader_set_value(VkDevice device, VkCommandBuffer commandBuffer, VkD
|
|||
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
|
||||
}
|
||||
|
||||
VkShaderModule shader_make(VkDevice device, const char* source, int32 source_size, RingMemory* ring)
|
||||
VkShaderModule shader_make(VkDevice device, const char* source, int32 source_size)
|
||||
{
|
||||
// Create shader module create info
|
||||
VkShaderModuleCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = source_size;
|
||||
createInfo.pCode = (uint32 *) source;
|
||||
VkShaderModuleCreateInfo create_info = {};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
create_info.codeSize = source_size;
|
||||
create_info.pCode = (uint32 *) source;
|
||||
|
||||
// Create shader module
|
||||
VkShaderModule shaderModule;
|
||||
VkResult result = vkCreateShaderModule(device, &createInfo, NULL, &shaderModule);
|
||||
VkShaderModule shader_module;
|
||||
VkResult result = vkCreateShaderModule(device, &create_info, NULL, &shader_module);
|
||||
|
||||
if (result != VK_SUCCESS) {
|
||||
LOG("Failed to create shader module", true, true);
|
||||
|
|
@ -66,72 +64,7 @@ VkShaderModule shader_make(VkDevice device, const char* source, int32 source_siz
|
|||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return shaderModule;
|
||||
}
|
||||
|
||||
VkPipeline program_make(
|
||||
VkDevice device,
|
||||
VkShaderModule vertex_shader,
|
||||
VkShaderModule fragment_shader,
|
||||
VkShaderModule geometry_shader,
|
||||
VkPipelineLayout pipeline_layout,
|
||||
VkRenderPass render_pass,
|
||||
RingMemory* ring
|
||||
) {
|
||||
VkPipelineShaderStageCreateInfo shaderStages[3];
|
||||
|
||||
// Vertex shader
|
||||
shaderStages[0] = {};
|
||||
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
shaderStages[0].module = vertex_shader;
|
||||
shaderStages[0].pName = "main";
|
||||
|
||||
// Fragment shader
|
||||
shaderStages[1] = {};
|
||||
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shaderStages[1].module = fragment_shader;
|
||||
shaderStages[1].pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo* geometryShaderStage = NULL;
|
||||
|
||||
// Optional Geometry shader
|
||||
if (geometry_shader != VK_NULL_HANDLE) {
|
||||
geometryShaderStage = &shaderStages[2];
|
||||
geometryShaderStage->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
geometryShaderStage->stage = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
geometryShaderStage->module = geometry_shader;
|
||||
geometryShaderStage->pName = "main";
|
||||
}
|
||||
|
||||
// Create the pipeline
|
||||
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {};
|
||||
pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineCreateInfo.stageCount = (geometry_shader != VK_NULL_HANDLE) ? 3 : 2;
|
||||
pipelineCreateInfo.pStages = shaderStages;
|
||||
pipelineCreateInfo.pInputAssemblyState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pVertexInputState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pViewportState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pRasterizationState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pMultisampleState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pDepthStencilState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pColorBlendState = NULL; // Define if needed
|
||||
pipelineCreateInfo.pDynamicState = NULL; // Define if needed
|
||||
pipelineCreateInfo.layout = pipeline_layout;
|
||||
pipelineCreateInfo.renderPass = render_pass;
|
||||
pipelineCreateInfo.subpass = 0; // Assumes 0 subpass
|
||||
pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
|
||||
VkPipeline graphicsPipeline;
|
||||
VkResult result = vkCreateGraphicsPipeline(device, VK_NULL_HANDLE, &pipelineCreateInfo, NULL, &graphicsPipeline);
|
||||
|
||||
if (result != VK_SUCCESS) {
|
||||
LOG("Failed to create program", true, true);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return graphicsPipeline;
|
||||
return shader_module;
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
|
|||
761
gpuapi/vulkan/VulkanUtils.h
Normal file
761
gpuapi/vulkan/VulkanUtils.h
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef TOS_GPUAPI_VULKAN_UTILS_H
|
||||
#define TOS_GPUAPI_VULKAN_UTILS_H
|
||||
|
||||
#if _WIN32
|
||||
#ifndef VK_USE_PLATFORM_WIN32_KHR
|
||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
||||
#endif
|
||||
|
||||
#include <vulkan/vulkan_win32.h>
|
||||
#include "../../platform/win32/Window.h"
|
||||
#elif __linux__
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
#endif
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vector>
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "ShaderUtils.h"
|
||||
#include "../../utils/TestUtils.h"
|
||||
#include "../../log/Log.h"
|
||||
#include "../../memory/RingMemory.h"
|
||||
|
||||
PACKED_STRUCT;
|
||||
// WARNING: indices values start at one (are offset by +1) because 0 means no value in our implementation
|
||||
// The reason for the packing is that sometimes we want to use it as an array
|
||||
// I am only packing it on the off chance there is some funky behaviour.
|
||||
struct VulkanQueueFamilyIndices {
|
||||
uint32 graphics_family;
|
||||
uint32 present_family;
|
||||
};
|
||||
UNPACKED_STRUCT;
|
||||
|
||||
struct VulkanSwapChainSupportDetails {
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
|
||||
uint32 format_size;
|
||||
VkSurfaceFormatKHR* formats;
|
||||
|
||||
uint32 present_mode_size;
|
||||
VkPresentModeKHR* present_modes;
|
||||
};
|
||||
|
||||
inline
|
||||
void change_viewport(Window* w, int32 offset_x = 0, int32 offset_y = 0)
|
||||
{
|
||||
// @todo implement
|
||||
}
|
||||
|
||||
// @todo Implement logging of if() conditions
|
||||
bool vulkan_check_validation_layer_support(const char** validation_layers, uint32 validation_layer_count, RingMemory* ring) {
|
||||
uint32 layer_count;
|
||||
vkEnumerateInstanceLayerProperties(&layer_count, NULL);
|
||||
|
||||
VkLayerProperties* available_layers = (VkLayerProperties *) ring_get_memory(ring, layer_count * sizeof(VkLayerProperties));
|
||||
vkEnumerateInstanceLayerProperties(&layer_count, available_layers);
|
||||
|
||||
for (uint32 i = 0; i < validation_layer_count; ++i) {
|
||||
bool layerFound = false;
|
||||
|
||||
for (uint32 j = 0; j < layer_count; ++j) {
|
||||
if (strcmp(validation_layers[i], available_layers[j].layerName) == 0) {
|
||||
layerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!layerFound) {
|
||||
LOG_FORMAT("Vulkan ValidationLayer: %s\n", LOG_DATA_CHAR_STR, &validation_layers[i], true, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_callback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* debug_callback_data, void*
|
||||
) {
|
||||
LOG(debug_callback_data->pMessage, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
void vulkan_populate_debug_messenger_create_info(VkDebugUtilsMessengerCreateInfoEXT* create_info)
|
||||
{
|
||||
create_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
create_info->messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
create_info->messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
create_info->pfnUserCallback = vulkan_debug_callback;
|
||||
}
|
||||
|
||||
VkResult vulkan_debug_utils_messenger_create(
|
||||
VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* create_info,
|
||||
const VkAllocationCallbacks* allocator, VkDebugUtilsMessengerEXT* debug_messenger
|
||||
) {
|
||||
PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
|
||||
if (!func) {
|
||||
ASSERT_SIMPLE(func);
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
return func(instance, create_info, allocator, debug_messenger);
|
||||
}
|
||||
|
||||
void vulkan_debug_messenger_setup(VkInstance instance, VkDebugUtilsMessengerEXT* debug_messenger)
|
||||
{
|
||||
VkDebugUtilsMessengerCreateInfoEXT create_info = {};
|
||||
vulkan_populate_debug_messenger_create_info(&create_info);
|
||||
|
||||
if (vulkan_debug_utils_messenger_create(instance, &create_info, NULL, debug_messenger) != VK_SUCCESS) {
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan_instance_create(
|
||||
VkInstance* instance, const char** extensions, uint32 extension_count,
|
||||
const char** validation_layers = NULL, uint32 validation_layer_count = 0,
|
||||
RingMemory* ring = NULL
|
||||
) {
|
||||
if (validation_layer_count
|
||||
&& !vulkan_check_validation_layer_support(validation_layers, validation_layer_count, ring)
|
||||
) {
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
VkApplicationInfo app_info = {};
|
||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
app_info.pApplicationName = "";
|
||||
app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
app_info.pEngineName = "TalesOfSouls";
|
||||
app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
app_info.apiVersion = VK_API_VERSION_1_0;
|
||||
|
||||
VkInstanceCreateInfo create_info = {};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
create_info.pApplicationInfo = &app_info;
|
||||
|
||||
create_info.enabledExtensionCount = extension_count;
|
||||
create_info.ppEnabledExtensionNames = extensions;
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {};
|
||||
if (validation_layer_count) {
|
||||
create_info.enabledLayerCount = validation_layer_count;
|
||||
create_info.ppEnabledLayerNames = validation_layers;
|
||||
|
||||
vulkan_populate_debug_messenger_create_info(&debug_create_info);
|
||||
create_info.pNext = (VkDebugUtilsMessengerCreateInfoEXT *) &debug_create_info;
|
||||
}
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateInstance(&create_info, NULL, instance)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateInstance: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan_surface_create(VkInstance instance, VkSurfaceKHR* surface, Window* window)
|
||||
{
|
||||
#if _WIN32
|
||||
VkWin32SurfaceCreateInfoKHR surface_create_info = {};
|
||||
surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
surface_create_info.hwnd = window->hwnd;
|
||||
surface_create_info.hinstance = window->hInstance;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateWin32SurfaceKHR(instance, &surface_create_info, NULL, surface)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateWin32SurfaceKHR: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
return;
|
||||
}
|
||||
#elif __linux__
|
||||
#endif
|
||||
}
|
||||
|
||||
bool vulkan_device_supports_extensions(VkPhysicalDevice device, const char** device_extensions, uint32 device_extension_count, RingMemory* ring) {
|
||||
uint32 extension_count;
|
||||
vkEnumerateDeviceExtensionProperties(device, NULL, &extension_count, NULL);
|
||||
|
||||
VkExtensionProperties* available_extensions = (VkExtensionProperties *) ring_get_memory(ring, extension_count * sizeof(VkExtensionProperties));
|
||||
vkEnumerateDeviceExtensionProperties(device, NULL, &extension_count, available_extensions);
|
||||
|
||||
for (int32 i = 0; i < device_extension_count; ++i) {
|
||||
bool found = false;
|
||||
for (int32 j = 0; j < extension_count; ++j) {
|
||||
if (strcmp(device_extensions[i], available_extensions[j].extensionName) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
LOG_FORMAT("Vulkan DeviceExtensions: %s\n", LOG_DATA_CHAR_STR, &device_extensions[i], true, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VulkanQueueFamilyIndices vulkan_find_queue_families(VkPhysicalDevice physical_device, VkSurfaceKHR surface, RingMemory* ring)
|
||||
{
|
||||
VulkanQueueFamilyIndices indices = {};
|
||||
uint32 queue_family_count = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, NULL);
|
||||
|
||||
VkQueueFamilyProperties* queue_families = (VkQueueFamilyProperties *) ring_get_memory(ring, (queue_family_count + 1) * sizeof(VkQueueFamilyProperties));
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families);
|
||||
|
||||
for (int32 i = 0; i < queue_family_count; ++i) {
|
||||
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
indices.graphics_family = i + 1;
|
||||
}
|
||||
|
||||
VkBool32 present_support = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support);
|
||||
|
||||
if (present_support) {
|
||||
indices.present_family = i + 1;
|
||||
}
|
||||
|
||||
if (indices.graphics_family && indices.present_family) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
// WARNING: Since we use a RingMemory for the data, we need to copy it if we want it to be persistent
|
||||
VulkanSwapChainSupportDetails vulkan_query_swap_chain_support(VkPhysicalDevice physical_device, VkSurfaceKHR surface, RingMemory* ring)
|
||||
{
|
||||
VulkanSwapChainSupportDetails details;
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &details.capabilities);
|
||||
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details.format_size, NULL);
|
||||
|
||||
if (details.format_size) {
|
||||
details.formats = (VkSurfaceFormatKHR *) ring_get_memory(ring, (details.format_size + 1) * sizeof(VkSurfaceFormatKHR));
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details.format_size, details.formats);
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details.present_mode_size, NULL);
|
||||
|
||||
if (details.present_mode_size) {
|
||||
details.present_modes = (VkPresentModeKHR *) ring_get_memory(ring, (details.present_mode_size + 1) * sizeof(VkPresentModeKHR));
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details.present_mode_size, details.present_modes);
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
bool vulkan_is_device_suitable(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const char** device_extensions, uint32 device_extension_count, RingMemory* ring)
|
||||
{
|
||||
VulkanQueueFamilyIndices indices = vulkan_find_queue_families(physical_device, surface, ring);
|
||||
bool extensions_supported = vulkan_device_supports_extensions(physical_device, device_extensions, device_extension_count, ring);
|
||||
|
||||
bool swap_chain_adequate = false;
|
||||
if (extensions_supported) {
|
||||
VulkanSwapChainSupportDetails swap_chain_support = vulkan_query_swap_chain_support(physical_device, surface, ring);
|
||||
swap_chain_adequate = swap_chain_support.format_size && swap_chain_support.present_modes;
|
||||
}
|
||||
|
||||
return indices.graphics_family && indices.present_family
|
||||
&& extensions_supported && swap_chain_adequate;
|
||||
}
|
||||
|
||||
// @todo Do we want to implement something similar in opengl that does something vaguely different despite not really necessary? (see wglGetGPUIDs, wglCreateAssociatedContextAMD)
|
||||
void gpuapi_pick_physical_device(
|
||||
VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice* physical_device,
|
||||
const char** device_extensions, uint32 device_extension_count, RingMemory* ring
|
||||
) {
|
||||
uint32 device_count;
|
||||
vkEnumeratePhysicalDevices(instance, &device_count, NULL);
|
||||
|
||||
VkPhysicalDevice* devices = (VkPhysicalDevice *) ring_get_memory(ring, device_count * sizeof(VkPhysicalDevice));
|
||||
vkEnumeratePhysicalDevices(instance, &device_count, devices);
|
||||
|
||||
for (int32 i = 0; i < device_count; ++i) {
|
||||
if (vulkan_is_device_suitable(devices[i], surface, device_extensions, device_extension_count, ring)) {
|
||||
// @question Do we really have to do a memcpy or could we just assign? Isn't VkPhysicalDevice just a pointer internally?
|
||||
memcpy(physical_device, &devices[i], sizeof(VkPhysicalDevice));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("Vulkan failed to find physical device\n", true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
void gpuapi_create_logical_device(
|
||||
VkInstance instance, VkSurfaceKHR surface, VkDevice* device, VkPhysicalDevice physical_device,
|
||||
VkQueue* graphics_queue, VkQueue* present_queue,
|
||||
const char** device_extensions, uint32 device_extension_count,
|
||||
const char** validation_layers, uint32 validation_layer_count, RingMemory* ring
|
||||
) {
|
||||
VulkanQueueFamilyIndices indices = vulkan_find_queue_families(physical_device, surface, ring);
|
||||
|
||||
VkDeviceQueueCreateInfo* queue_create_infos = (VkDeviceQueueCreateInfo *) ring_get_memory(ring, 2 * sizeof(VkDeviceQueueCreateInfo), 4, true);
|
||||
|
||||
f32 queue_priority = 1.0f;
|
||||
uint32 queue_create_info_count = 1;
|
||||
queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_create_infos[0].queueFamilyIndex = indices.graphics_family;
|
||||
queue_create_infos[0].queueCount = 1;
|
||||
queue_create_infos[0].pQueuePriorities = &queue_priority;
|
||||
|
||||
if (indices.present_family != indices.graphics_family) {
|
||||
queue_create_infos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_create_infos[1].queueFamilyIndex = indices.present_family;
|
||||
queue_create_infos[1].queueCount = 1;
|
||||
queue_create_infos[1].pQueuePriorities = &queue_priority;
|
||||
++queue_create_info_count;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures device_features = {};
|
||||
VkDeviceCreateInfo create_info = {};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
create_info.queueCreateInfoCount = queue_create_info_count;
|
||||
create_info.pQueueCreateInfos = queue_create_infos;
|
||||
create_info.pEnabledFeatures = &device_features;
|
||||
create_info.enabledExtensionCount = device_extension_count;
|
||||
create_info.ppEnabledExtensionNames = device_extensions;
|
||||
|
||||
if (validation_layers) {
|
||||
create_info.enabledLayerCount = validation_layer_count;
|
||||
create_info.ppEnabledLayerNames = validation_layers;
|
||||
} else {
|
||||
create_info.enabledLayerCount = 0;
|
||||
}
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateDevice(physical_device, &create_info, NULL, device)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateDevice: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(*device, indices.graphics_family, 0, graphics_queue);
|
||||
vkGetDeviceQueue(*device, indices.present_family, 0, present_queue);
|
||||
}
|
||||
|
||||
// WARNING: swapchain_images needs to already have reserved enough memory
|
||||
// @todo How can we ensure swapchain_images has enough but not too much space?
|
||||
void vulkan_swap_chain_create(
|
||||
VkDevice device, VkPhysicalDevice physical_device, VkSurfaceKHR surface,
|
||||
VkSwapchainKHR* swapchain, VkImage* swapchain_images, uint32* swapchain_image_count,
|
||||
VkFormat* swapchain_image_format, VkExtent2D* swapchain_extent,
|
||||
Window* window, RingMemory* ring
|
||||
) {
|
||||
VulkanSwapChainSupportDetails swap_chain_support = vulkan_query_swap_chain_support(physical_device, surface, ring);
|
||||
|
||||
VkSurfaceFormatKHR* surface_format = &swap_chain_support.formats[0];
|
||||
for (int32 i = 0; i < swap_chain_support.format_size; ++i) {
|
||||
if (swap_chain_support.formats[i].format == VK_FORMAT_B8G8R8A8_SRGB
|
||||
&& swap_chain_support.formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
|
||||
) {
|
||||
surface_format = &swap_chain_support.formats[i];
|
||||
}
|
||||
}
|
||||
|
||||
VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
for (int32 i = 0; i < swap_chain_support.present_mode_size; ++i) {
|
||||
if (swap_chain_support.present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
present_mode = swap_chain_support.present_modes[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (swap_chain_support.capabilities.currentExtent.width != UINT32_MAX) {
|
||||
*swapchain_extent = swap_chain_support.capabilities.currentExtent;
|
||||
} else {
|
||||
swapchain_extent->width = OMS_CLAMP(
|
||||
window->width,
|
||||
swap_chain_support.capabilities.maxImageExtent.width,
|
||||
swap_chain_support.capabilities.minImageExtent.width
|
||||
);
|
||||
|
||||
swapchain_extent->height = OMS_CLAMP(
|
||||
window->height,
|
||||
swap_chain_support.capabilities.maxImageExtent.height,
|
||||
swap_chain_support.capabilities.minImageExtent.height
|
||||
);
|
||||
}
|
||||
|
||||
uint32 image_count = swap_chain_support.capabilities.minImageCount + 1;
|
||||
if (swap_chain_support.capabilities.maxImageCount > 0
|
||||
&& image_count > swap_chain_support.capabilities.maxImageCount
|
||||
) {
|
||||
image_count = swap_chain_support.capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR create_info = {};
|
||||
create_info.minImageCount = image_count;
|
||||
create_info.imageFormat = surface_format->format;
|
||||
create_info.imageColorSpace = surface_format->colorSpace;
|
||||
create_info.imageExtent = *swapchain_extent;
|
||||
create_info.imageArrayLayers = 1;
|
||||
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
VulkanQueueFamilyIndices indices = vulkan_find_queue_families(physical_device, surface, ring);
|
||||
|
||||
if (indices.graphics_family != indices.present_family) {
|
||||
create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
create_info.queueFamilyIndexCount = 2;
|
||||
create_info.pQueueFamilyIndices = (uint32 *) &indices;
|
||||
} else {
|
||||
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
}
|
||||
|
||||
create_info.preTransform = swap_chain_support.capabilities.currentTransform;
|
||||
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
create_info.presentMode = present_mode;
|
||||
create_info.clipped = VK_TRUE;
|
||||
create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateSwapchainKHR(device, &create_info, NULL, swapchain)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateSwapchainKHR: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
vkGetSwapchainImagesKHR(device, *swapchain, swapchain_image_count, NULL);
|
||||
vkGetSwapchainImagesKHR(device, *swapchain, swapchain_image_count, swapchain_images);
|
||||
|
||||
memcpy(swapchain_image_format, &surface_format->format, sizeof(VkFormat));
|
||||
}
|
||||
|
||||
void vulkan_image_views_create(
|
||||
VkDevice device, VkImageView* swapchain_image_views,
|
||||
VkImage* swapchain_images, uint32 swapchain_image_count, VkFormat swapchain_image_format
|
||||
) {
|
||||
VkResult result;
|
||||
for (size_t i = 0; i < swapchain_image_count; ++i) {
|
||||
VkImageViewCreateInfo create_info = {};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
create_info.image = swapchain_images[i];
|
||||
create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
create_info.format = swapchain_image_format;
|
||||
create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
create_info.subresourceRange.baseMipLevel = 0;
|
||||
create_info.subresourceRange.levelCount = 1;
|
||||
create_info.subresourceRange.baseArrayLayer = 0;
|
||||
create_info.subresourceRange.layerCount = 1;
|
||||
|
||||
if ((result = vkCreateImageView(device, &create_info, NULL, &swapchain_image_views[i])) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateImageView: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_render_pass(
|
||||
VkDevice device, VkRenderPass* render_pass, VkFormat swapchain_image_format
|
||||
) {
|
||||
VkAttachmentDescription colorAttachment = {};
|
||||
colorAttachment.format = swapchain_image_format;
|
||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference colorAttachmentRef = {};
|
||||
colorAttachmentRef.attachment = 0;
|
||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorAttachmentRef;
|
||||
|
||||
VkSubpassDependency dependency = {};
|
||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependency.dstSubpass = 0;
|
||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.srcAccessMask = 0;
|
||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
renderPassInfo.dependencyCount = 1;
|
||||
renderPassInfo.pDependencies = &dependency;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateRenderPass(device, &renderPassInfo, NULL, render_pass)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateRenderPass: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
|
||||
// @todo This is very similar to program_make in opengl. Consider to rename opengl
|
||||
void vulkan_pipeline_create(
|
||||
VkDevice device,
|
||||
VkShaderModule vertex_shader,
|
||||
VkShaderModule fragment_shader,
|
||||
VkShaderModule geometry_shader,
|
||||
VkPipeline* pipeline,
|
||||
VkPipelineLayout* pipeline_layout,
|
||||
VkRenderPass render_pass,
|
||||
const char* source,
|
||||
int32 source_size
|
||||
)
|
||||
{
|
||||
uint32 stage_count = 0;
|
||||
VkPipelineShaderStageCreateInfo shaderStages[3];
|
||||
|
||||
VkPipelineShaderStageCreateInfo vs_stage_create = {};
|
||||
vs_stage_create.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vs_stage_create.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vs_stage_create.module = vertex_shader;
|
||||
vs_stage_create.pName = "main";
|
||||
++stage_count;
|
||||
|
||||
VkPipelineShaderStageCreateInfo fs_stage_create = {};
|
||||
fs_stage_create.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fs_stage_create.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fs_stage_create.module = fragment_shader;
|
||||
fs_stage_create.pName = "main";
|
||||
++stage_count;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 0;
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = 0;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
|
||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.scissorCount = 1;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.depthClampEnable = VK_FALSE;
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
rasterizer.depthBiasEnable = VK_FALSE;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling.sampleShadingEnable = VK_FALSE;
|
||||
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
colorBlending.logicOpEnable = VK_FALSE;
|
||||
colorBlending.logicOp = VK_LOGIC_OP_COPY;
|
||||
colorBlending.attachmentCount = 1;
|
||||
colorBlending.pAttachments = &colorBlendAttachment;
|
||||
colorBlending.blendConstants[0] = 0.0f;
|
||||
colorBlending.blendConstants[1] = 0.0f;
|
||||
colorBlending.blendConstants[2] = 0.0f;
|
||||
colorBlending.blendConstants[3] = 0.0f;
|
||||
|
||||
VkDynamicState dynamicStates[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {};
|
||||
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamicState.dynamicStateCount = ARRAY_COUNT(dynamicStates);
|
||||
dynamicState.pDynamicStates = dynamicStates;
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.setLayoutCount = 0;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 0;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL, pipeline_layout)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreatePipelineLayout: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stageCount = stage_count;
|
||||
pipelineInfo.pStages = shaderStages;
|
||||
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||
pipelineInfo.pViewportState = &viewportState;
|
||||
pipelineInfo.pRasterizationState = &rasterizer;
|
||||
pipelineInfo.pMultisampleState = &multisampling;
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = &dynamicState;
|
||||
pipelineInfo.layout = *pipeline_layout;
|
||||
pipelineInfo.renderPass = render_pass;
|
||||
pipelineInfo.subpass = 0;
|
||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
|
||||
if ((result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, pipeline)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateGraphicsPipelines: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
vkDestroyShaderModule(device, vertex_shader, NULL);
|
||||
vkDestroyShaderModule(device, fragment_shader, NULL);
|
||||
}
|
||||
|
||||
// @todo consider to rename to same name as opengl
|
||||
// WARNING: swapchain_framebuffers needs to be initialized
|
||||
void vulkan_framebuffer_create(
|
||||
VkDevice device, VkFramebuffer* swapchain_framebuffers,
|
||||
VkImageView* swapchain_image_views, uint32 swapchain_image_count, VkExtent2D swapchain_extent,
|
||||
VkRenderPass render_pass
|
||||
) {
|
||||
VkResult result;
|
||||
for (uint32 i = 0; i < swapchain_image_count; i++) {
|
||||
VkImageView attachments[] = {
|
||||
swapchain_image_views[i]
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = render_pass;
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.pAttachments = attachments;
|
||||
framebufferInfo.width = swapchain_extent.width;
|
||||
framebufferInfo.height = swapchain_extent.height;
|
||||
framebufferInfo.layers = 1;
|
||||
|
||||
if ((result = vkCreateFramebuffer(device, &framebufferInfo, NULL, &swapchain_framebuffers[i])) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateFramebuffer: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan_command_pool_create(
|
||||
VkDevice device, VkCommandPool* command_pool,
|
||||
VkPhysicalDevice physical_device, VkSurfaceKHR surface, RingMemory* ring
|
||||
) {
|
||||
VulkanQueueFamilyIndices queue_family_indices = vulkan_find_queue_families(physical_device, surface, ring);
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
poolInfo.queueFamilyIndex = queue_family_indices.graphics_family;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateCommandPool(device, &poolInfo, NULL, command_pool)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkCreateCommandPool: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan_command_buffer_create(VkDevice device, VkCommandBuffer* command_buffer, VkCommandPool command_pool)
|
||||
{
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = command_pool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkAllocateCommandBuffers(device, &allocInfo, command_buffer)) != VK_SUCCESS) {
|
||||
LOG_FORMAT("Vulkan vkAllocateCommandBuffers: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan_sync_objects_create(VkDevice device, VkSemaphore* image_available_semaphore, VkSemaphore* render_finished_semaphore, VkFence* in_flight_fence)
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphoreInfo = {};
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
VkFenceCreateInfo fenceInfo{};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
VkResult result;
|
||||
if ((result = vkCreateSemaphore(device, &semaphoreInfo, NULL, image_available_semaphore)) != VK_SUCCESS
|
||||
|| (result = vkCreateSemaphore(device, &semaphoreInfo, NULL, render_finished_semaphore)) != VK_SUCCESS
|
||||
|| (result = vkCreateFence(device, &fenceInfo, NULL, in_flight_fence)) != VK_SUCCESS
|
||||
) {
|
||||
LOG_FORMAT("Vulkan vulkan_sync_objects_create: %d\n", LOG_DATA_INT32, (int32 *) &result, true, true);
|
||||
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
/*
|
||||
void vulkan_command_buffer_record(
|
||||
VkCommandBuffer command_buffer
|
||||
) {
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
|
||||
if (vkBeginCommandBuffer(command_buffer, &beginInfo) != VK_SUCCESS) {
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
|
||||
VkRenderPassBeginInfo renderPassInfo{};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassInfo.renderPass = renderPass;
|
||||
renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
|
||||
renderPassInfo.renderArea.offset = {0, 0};
|
||||
renderPassInfo.renderArea.extent = swapChainExtent;
|
||||
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
renderPassInfo.clearValueCount = 1;
|
||||
renderPassInfo.pClearValues = &clearColor;
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(swapChainExtent.width);
|
||||
viewport.height = static_cast<float>(swapChainExtent.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = swapChainExtent;
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
|
||||
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
|
||||
ASSERT_SIMPLE(false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
12
log/Log.h
12
log/Log.h
|
|
@ -14,7 +14,7 @@
|
|||
#include "Debug.h"
|
||||
|
||||
#ifndef MAX_LOG_LENGTH
|
||||
#define MAX_LOG_LENGTH 128
|
||||
#define MAX_LOG_LENGTH 256
|
||||
#endif
|
||||
|
||||
enum LogDataType {
|
||||
|
|
@ -35,6 +35,16 @@ void log(const char* format, LogDataType data_type, void* data, bool should_log,
|
|||
void log_increment(int32, int64);
|
||||
void log_counter(int32, int64);
|
||||
|
||||
#define LOG_PERFORMANCE_START(time_start) \
|
||||
({ \
|
||||
time_start = __rdtsc(); \
|
||||
})
|
||||
|
||||
#define LOG_PERFORMANCE_END(time_start) \
|
||||
({ \
|
||||
printf("%ld\n", __rdtsc() - (time_start)); \
|
||||
})
|
||||
|
||||
#if (!DEBUG && !INTERNAL)
|
||||
// Don't perform any logging at log level 0
|
||||
#define LOG(str, should_log, save) log((str), (should_log), (save), __FILE__, __func__, __LINE__)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#define NOGDICAPMASKS 1
|
||||
#define NOVIRTUALKEYCODES 1
|
||||
#define NOWINMESSAGES 1
|
||||
//#define NOWINMESSAGES 0
|
||||
#define NOWINSTYLES 1
|
||||
#define NOSYSMETRICS 1
|
||||
#define NOMENUS 1
|
||||
|
|
@ -30,20 +30,20 @@
|
|||
#define NODRAWTEXT 1
|
||||
#define NOGDI 1
|
||||
#define NOKERNEL 1
|
||||
#define NOUSER 1
|
||||
//#define NOUSER 0
|
||||
#define NONLS 1
|
||||
#define NOMB 1
|
||||
#define NOMEMMGR 1
|
||||
#define NOMETAFILE 1
|
||||
#define NOMINMAX 1
|
||||
#define NOMSG 1
|
||||
//#define NOMSG 0
|
||||
#define NOOPENFILE 1
|
||||
#define NOSCROLL 1
|
||||
#define NOSERVICE 1
|
||||
#define NOSOUND 1
|
||||
#define NOTEXTMETRIC 1
|
||||
#define NOWH 1
|
||||
#define NOWINOFFSETS 1
|
||||
//#define NOWH 0
|
||||
//#define NOWINOFFSETS 0
|
||||
#define NOCOMM 1
|
||||
#define NOKANJI 1
|
||||
#define NOHELP 1
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ bool library_load(Library* lib)
|
|||
lib->handle = LoadLibraryA((LPCSTR) dst);
|
||||
if (!lib->handle) {
|
||||
lib->is_valid= false;
|
||||
ASSERT_SIMPLE(false);
|
||||
|
||||
return lib->is_valid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <wbemidl.h>
|
||||
#include <comdef.h>
|
||||
#include <winnls.h>
|
||||
#include <wingdi.h>
|
||||
#include <hidsdi.h>
|
||||
|
||||
#if __aarch64__
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
typedef HINSTANCE WindowInstance;
|
||||
|
||||
struct Window {
|
||||
// @question Should we implement a virtual width/height (e.g. I think apple has that where physical resolution < virtual resolution?!)
|
||||
uint16 width;
|
||||
uint16 height;
|
||||
|
||||
|
|
@ -32,9 +33,12 @@ struct Window {
|
|||
|
||||
HWND hwnd;
|
||||
HDC hdc;
|
||||
HGLRC openGLRC;
|
||||
HINSTANCE hInstance;
|
||||
|
||||
// @bug This should only be available on opengl.
|
||||
// The problem is the main program doesn't know which gpuapi we are using, so maybe a void pointer?
|
||||
HGLRC openGLRC;
|
||||
|
||||
char name[32];
|
||||
WindowState state_old;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct DirectSoundSetting {
|
|||
};
|
||||
|
||||
// BEGIN: Dynamically load DirectSound
|
||||
typedef HRESULT WINAPI audio_create(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN);
|
||||
typedef HRESULT WINAPI DirectSoundCreate8_t(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN);
|
||||
HRESULT WINAPI DirectSoundCreate8Stub(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_settin
|
|||
return;
|
||||
}
|
||||
|
||||
audio_create* DirectSoundCreate8 = (audio_create *) GetProcAddress(lib, "DirectSoundCreate8");
|
||||
DirectSoundCreate8_t* DirectSoundCreate8 = (DirectSoundCreate8_t *) GetProcAddress(lib, "DirectSoundCreate8");
|
||||
|
||||
if (!DirectSoundCreate8 || !SUCCEEDED(DirectSoundCreate8(0, &api_setting->audio_handle, 0))) {
|
||||
LOG("DirectSound: DirectSoundCreate8 failed\n", true, true);
|
||||
|
|
|
|||
201
platform/win32/audio/Wasapi.h
Normal file
201
platform/win32/audio/Wasapi.h
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef TOS_SOUND_WASAPI_H
|
||||
#define TOS_SOUND_WASAPI_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
#include <endpointvolume.h>
|
||||
#include <commdlg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include "../../../audio/AudioSetting.h"
|
||||
#include "../../../utils/MathUtils.h"
|
||||
#include "../../../log/Log.h"
|
||||
#include "../../../audio/Audio.cpp"
|
||||
|
||||
struct WasapiSetting {
|
||||
IAudioClient* audio_handle;
|
||||
IAudioRenderClient* render_client;
|
||||
};
|
||||
|
||||
// BEGIN: Dynamically load DirectSound
|
||||
typedef HRESULT WINAPI CoInitializeEx_t(LPVOID, DWORD);
|
||||
typedef HRESULT WINAPI CoCreateInstance_t(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*);
|
||||
|
||||
typedef HRESULT WINAPI IMMDeviceEnumerator_GetDefaultAudioEndpoint_t(IMMDeviceEnumerator*, EDataFlow, ERole, IMMDevice**);
|
||||
typedef HRESULT WINAPI IMMDevice_Activate_t(IMMDevice*, REFIID, DWORD, PROPVARIANT*, void**);
|
||||
|
||||
typedef HRESULT WINAPI IAudioClient_GetMixFormat_t(IAudioClient*, WAVEFORMATEX**);
|
||||
typedef HRESULT WINAPI IAudioClient_Initialize_t(IAudioClient*, AUDCLNT_SHAREMODE, DWORD, REFERENCE_TIME, REFERENCE_TIME, WAVEFORMATEX*, void*);
|
||||
typedef HRESULT WINAPI IAudioClient_Start_t(IAudioClient*);
|
||||
typedef HRESULT WINAPI IAudioClient_Stop_t(IAudioClient*);
|
||||
typedef HRESULT WINAPI IAudioClient_GetService_t(IAudioClient*, REFIID, void**);
|
||||
// END: Dynamically load DirectSound
|
||||
|
||||
void audio_load(HWND hwnd, AudioSetting* setting, WasapiSetting* api_setting) {
|
||||
HMODULE ole32 = LoadLibraryExA((LPCSTR) "ole32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!ole32) {
|
||||
LOG("Wasapi: Couldn't load ole32.dll\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CoInitializeEx_t* co_initialize_ex = (CoInitializeEx_t *) GetProcAddress(ole32, "CoInitializeEx");
|
||||
CoCreateInstance_t* co_create_instance = (CoCreateInstance_t *) GetProcAddress(ole32, "CoCreateInstance");
|
||||
|
||||
if (!co_initialize_ex || !co_create_instance) {
|
||||
LOG("Wasapi: ole32 function binding failed\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HMODULE mmdevapi = LoadLibraryExA((LPCSTR) "mmdevapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!mmdevapi) {
|
||||
LOG("Wasapi: Couldn't load mmdevapi.dll\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IMMDeviceEnumerator_GetDefaultAudioEndpoint_t* IMMDeviceEnumerator_GetDefaultAudioEndpoint = (IMMDeviceEnumerator_GetDefaultAudioEndpoint_t *) GetProcAddress(mmdevapi, "IMMDeviceEnumerator_GetDefaultAudioEndpoint");
|
||||
IMMDevice_Activate_t* IMMDevice_Activate = (IMMDevice_Activate_t *) GetProcAddress(mmdevapi, "IMMDevice_Activate");
|
||||
|
||||
if (!IMMDeviceEnumerator_GetDefaultAudioEndpoint || !IMMDevice_Activate) {
|
||||
LOG("Wasapi: mmdevapi function binding failed\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HMODULE audioclient = LoadLibraryExA((LPCSTR) "audioclient.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!audioclient) {
|
||||
LOG("Wasapi: Couldn't load audioclient.dll\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IAudioClient_GetMixFormat_t* pIAudioClient_GetMixFormat = (IAudioClient_GetMixFormat_t *) GetProcAddress(audioclient, "IAudioClient_GetMixFormat");
|
||||
IAudioClient_Initialize_t* pIAudioClient_Initialize = (IAudioClient_Initialize_t *) GetProcAddress(audioclient, "IAudioClient_Initialize");
|
||||
IAudioClient_Start_t* pIAudioClient_Start = (IAudioClient_Start_t *) GetProcAddress(audioclient, "IAudioClient_Start");
|
||||
IAudioClient_Stop_t* pIAudioClient_Stop = (IAudioClient_Stop_t *) GetProcAddress(audioclient, "IAudioClient_Stop");
|
||||
IAudioClient_GetService_t* pIAudioClient_GetService = (IAudioClient_GetService_t *) GetProcAddress(audioclient, "IAudioClient_GetService");
|
||||
|
||||
if (!pIAudioClient_GetMixFormat || !pIAudioClient_Initialize || !pIAudioClient_Start || !pIAudioClient_Stop || !pIAudioClient_GetService) {
|
||||
LOG("Wasapi: audioclient function binding failed\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr = co_initialize_ex(NULL, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Wasapi: Wasapi initialize failed\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IMMDeviceEnumerator* enumerator;
|
||||
IMMDevice* device;
|
||||
|
||||
hr = co_create_instance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **) &enumerator);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Wasapi: Wasapi CreateInstance failed\n", true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Wasapi: Wasapi DefaultAudioEndpoint failed\n", true, true);
|
||||
|
||||
enumerator->Release();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hr = IMMDevice_Activate(device, IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &api_setting->audio_handle);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Wasapi: Wasapi DeviceActivate failed\n", true, true);
|
||||
|
||||
device->Release();
|
||||
enumerator->Release();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
device->Release();
|
||||
enumerator->Release();
|
||||
|
||||
// Initializing the audio client
|
||||
WAVEFORMATEX *pwfx = NULL;
|
||||
api_setting->audio_handle->GetMixFormat(&pwfx);
|
||||
api_setting->audio_handle->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, pwfx, NULL);
|
||||
api_setting->audio_handle->GetService(IID_IAudioRenderClient, (void **) &api_setting->render_client);
|
||||
}
|
||||
|
||||
inline
|
||||
void audio_play(AudioSetting* setting, WasapiSetting* api_setting) {
|
||||
if (!api_setting->audio_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
api_setting->audio_handle->Start();
|
||||
}
|
||||
|
||||
inline
|
||||
void audio_stop(AudioSetting* setting, WasapiSetting* api_setting) {
|
||||
if (!api_setting->audio_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
api_setting->audio_handle->Stop();
|
||||
}
|
||||
|
||||
inline
|
||||
void audio_free(AudioSetting* setting, WasapiSetting* api_setting)
|
||||
{
|
||||
if (!api_setting->render_client) {
|
||||
api_setting->render_client->Release();
|
||||
}
|
||||
|
||||
if (!api_setting->audio_handle) {
|
||||
api_setting->audio_handle->Release();
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
uint32 audio_buffer_fillable(const AudioSetting* setting, const WasapiSetting* api_setting)
|
||||
{
|
||||
if (!api_setting->audio_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 buffer_frame_count;
|
||||
api_setting->audio_handle->GetBufferSize(&buffer_frame_count);
|
||||
|
||||
uint32 frames_padding;
|
||||
api_setting->audio_handle->GetCurrentPadding(&frames_padding);
|
||||
|
||||
return buffer_frame_count - frames_padding;
|
||||
}
|
||||
|
||||
inline
|
||||
void audio_play_buffer(AudioSetting* setting, WasapiSetting* api_setting) {
|
||||
if (!api_setting->audio_handle || setting->sample_buffer_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @question Do we have to change it from sample_buffer_size to sample count?
|
||||
byte* buffer;
|
||||
api_setting->render_client->GetBuffer(setting->sample_buffer_size, (byte **) &buffer);
|
||||
|
||||
memcpy(buffer, setting->buffer, setting->sample_buffer_size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -27,7 +27,7 @@ struct XAudio2Setting {
|
|||
};
|
||||
|
||||
// BEGIN: Dynamically load XAudio2
|
||||
typedef HRESULT WINAPI audio_create(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
|
||||
typedef HRESULT WINAPI XAudio2Create_t(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
|
||||
HRESULT WINAPI XAudio2CreateStub(IXAudio2**, UINT32, XAUDIO2_PROCESSOR) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) {
|
|||
return;
|
||||
}
|
||||
|
||||
audio_create* XAudio2Create = (audio_create *) GetProcAddress(lib, "XAudio2Create");
|
||||
XAudio2Create_t* XAudio2Create = (XAudio2Create_t *) GetProcAddress(lib, "XAudio2Create");
|
||||
if (!XAudio2Create || !SUCCEEDED(XAudio2Create(&api_setting->audio_handle, 0, XAUDIO2_DEFAULT_PROCESSOR))) {
|
||||
LOG("Xaudio2: XAudio2Create failed\n", true, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#define OMS_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define OMS_MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||
#define OMS_CLAMP(a, b, c) (OMS_MAX(OMS_MIN((a), (b)), (c)))
|
||||
#define OMS_CLAMP(val, high, low) (OMS_MAX(OMS_MIN((val), (high)), (low)))
|
||||
#define OMS_ABS(a) ((a) > 0 ? (a) : -(a))
|
||||
#define OMS_DEG2RAD(angle) ((angle) * OMS_PI / 180.0f)
|
||||
#define OMS_RAD2DEG(angle) ((angle) * 180.0f / OMS_PI)
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ str_concat(
|
|||
return len_total + len;
|
||||
}
|
||||
|
||||
// @question Why is this called str_add instead of str_concat like the other functions?
|
||||
inline void
|
||||
str_add(char* base, const char* src)
|
||||
{
|
||||
|
|
@ -570,6 +571,7 @@ bool str_is_comment(char* str)
|
|||
return (*str == '/' && str[1] == '/') || (*str == '/' && str[1] == '*');
|
||||
}
|
||||
|
||||
// @question Isn't that basically like move_to? Consider to unify
|
||||
inline
|
||||
void str_skip(char** str, char delim)
|
||||
{
|
||||
|
|
@ -621,13 +623,16 @@ void str_skip_list(char** __restrict str, const char* __restrict delim, int32 le
|
|||
}
|
||||
|
||||
inline
|
||||
void str_skip_until_list(char** __restrict str, const char* __restrict delim, int32 len)
|
||||
void str_skip_until_list(char** __restrict str, const char* __restrict delim)
|
||||
{
|
||||
while (**str != '\0') {
|
||||
for (int32 i = 0; i < len; ++i) {
|
||||
if (**str == delim[i]) {
|
||||
const char* delim_temp = delim;
|
||||
while (*delim_temp) {
|
||||
if (**str == *delim_temp) {
|
||||
return;
|
||||
}
|
||||
|
||||
++delim_temp;
|
||||
}
|
||||
|
||||
++(*str);
|
||||
|
|
|
|||
|
|
@ -81,12 +81,9 @@
|
|||
if constexpr (!(a)) { \
|
||||
*(volatile int *) 0 = 0; \
|
||||
}
|
||||
|
||||
#define ASSERT_GPU_API() gpuapi_error()
|
||||
#else
|
||||
#define ASSERT_SIMPLE(a) ((void) 0)
|
||||
#define ASSERT_SIMPLE_CONST(a) ((void) 0)
|
||||
#define ASSERT_GPU_API() ((void) 0)
|
||||
#endif
|
||||
|
||||
#define ASSERT_TRUE(a) \
|
||||
|
|
@ -119,4 +116,14 @@
|
|||
} \
|
||||
})
|
||||
|
||||
#define ASSERT_PERFORMANCE_START(time_start) \
|
||||
({ \
|
||||
time_start = __rdtsc(); \
|
||||
})
|
||||
|
||||
#define ASSERT_PERFORMANCE_END(time_start, max_duration) \
|
||||
({ \
|
||||
ASSERT_TRUE(__rdtsc() - (time_start) <= (max_duration)); \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user