diff --git a/.gitignore b/.gitignore index 54a9b36..5d28fcc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -/.vscode/ -/.vs/ -/build/ -/out/ +.vscode/ +.vs/ +build/ +out/ +xcode/ +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f1314a..2ef1d88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,47 +7,37 @@ if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") endif() find_package(Vulkan REQUIRED) -set(LIB_PATH "") -if (WIN32) - if (IS_32_BIT) - set(LIB_PATH "tests/vendor/lib/vc-x86") - if (MINGW) - set(LIB_PATH "tests/vendor/lib/mingw-w32") - endif() - else() - set(LIB_PATH "tests/vendor/lib/vc-x64") - if (MINGW) - set(LIB_PATH "tests/vendor/lib/mingw-w64") - endif() - endif() -else() - find_package(glfw3 REQUIRED) -endif() -if (NOT "${LIB_PATH}" STREQUAL "") - link_directories(${LIB_PATH}) +set(SOURCES "kgfx/src/kgfx_vk.cpp") +if (APPLE) + list(APPEND SOURCES "kgfx/src/kgfx_vk_cocoa.mm") endif() -file(GLOB_RECURSE SOURCES "kgfx/src/*.cpp" "tests/*.cpp") -add_executable(kgfx ${SOURCES}) +add_library(kgfx_vk SHARED ${SOURCES}) -target_link_libraries(kgfx Vulkan::Vulkan) +target_link_libraries(kgfx_vk Vulkan::Vulkan) include_directories(${Vulkan_INCLUDE_DIRS} "kgfx/include" "tests/vendor/include") -if (WIN32) - target_link_libraries(kgfx glfw3) -else() - target_link_libraries(kgfx glfw) -endif() - -include_directories(${GLFW_INCLUDE_DIRS}) - if (LINUX) - target_link_libraries(kgfx X11) + target_link_libraries(kgfx_vk X11) elseif (APPLE) - target_link_libraries(kgfx "-framework Cocoa") - target_link_libraries(kgfx "-framework QuartzCore") + target_link_libraries(kgfx_vk "-framework Cocoa") + target_link_libraries(kgfx_vk "-framework QuartzCore") endif() +target_compile_definitions(kgfx_vk PRIVATE KGFX_DYNAMIC_BUILD) + +set_property(TARGET kgfx_vk PROPERTY CXX_STANDARD 17) + +add_library(kgfx_mtl SHARED "kgfx/src/kgfx_mtl.mm") + +target_link_libraries(kgfx_mtl "-framework Metal") +target_link_libraries(kgfx_mtl "-framework Cocoa") +target_link_libraries(kgfx_mtl "-framework QuartzCore") +target_link_libraries(kgfx_mtl "-framework Quartz") + +include_directories("kgfx/include") + +target_compile_definitions(kgfx_vk PRIVATE KGFX_DYNAMIC_BUILD) -set_property(TARGET kgfx PROPERTY CXX_STANDARD 17) +set_property(TARGET kgfx_mtl PROPERTY CXX_STANDARD 17) diff --git a/kgfx/include/kgfx/kgfx.h b/kgfx/include/kgfx/kgfx.h index edbed23..ee99f5e 100644 --- a/kgfx/include/kgfx/kgfx.h +++ b/kgfx/include/kgfx/kgfx.h @@ -342,11 +342,6 @@ typedef struct KGFXRasterizerState { KGFXbool clockWiseFrontFace; } KGFXRasterizerState; -typedef struct KGFXFramebufferDesc { - KGFXTexture* pTextures; - KGFXu32 textureCount; -} KGFXFramebufferDesc; - typedef struct KGFXSwapchainDesc { KGFXSurface surface; KGFXFormat imageFormat; @@ -614,16 +609,8 @@ KGFX_API KGFXbool kgfxEnumerateSurfaceFormats( KGFX_API KGFXbool kgfxEnumerateSurfacePresentModes( KGFXDevice device, KGFXSurface surface, - KGFXu32 presetModeIndex, + KGFXu32 presentModeIndex, KGFXPresentMode* pPresentMode); - -KGFX_API KGFXu32 kgfxGetSurfaceWidth( - KGFXDevice device, - KGFXSurface surface); - -KGFX_API KGFXu32 kgfxGetSurfaceHeight( - KGFXDevice device, - KGFXSurface surface); #ifdef __cplusplus } diff --git a/kgfx/src/kgfx_mtl.mm b/kgfx/src/kgfx_mtl.mm new file mode 100644 index 0000000..db27ab6 --- /dev/null +++ b/kgfx/src/kgfx_mtl.mm @@ -0,0 +1,895 @@ +#import +#import +#import + +#define KGFX_COCOA +#include + +#include +#include + +#include + +namespace kgfx { + +namespace mtl { + +struct CommandRepository { + struct ICommand { + virtual void encode(id encoder) = 0; + }; + + template + struct Command : ICommand { + Command(Ts... ts) : args(ts...) {} + + void encode(id encoder) override { + reinterpret_cast(objc_msgSend)(encoder, std::get(args)...); + } + + std::tuple args; + }; + + void encode(id encoder) { + for (ICommand* const& cmd : commands) { + cmd->encode(encoder); + } + } + + void clear() { + commands.clear(); + } + + std::vector commands; +}; + +constexpr MTLVertexFormat vertexFormat(KGFXFormat format) { + switch (format) { + case KGFX_FORMAT_R8_UINT: + return MTLVertexFormatUChar; + case KGFX_FORMAT_R8_SINT: + return MTLVertexFormatChar; + case KGFX_FORMAT_R8_UNORM: + return MTLVertexFormatUCharNormalized; + case KGFX_FORMAT_R8_SNORM: + return MTLVertexFormatCharNormalized; + + case KGFX_FORMAT_R8G8_UINT: + return MTLVertexFormatUChar2; + case KGFX_FORMAT_R8G8_SINT: + return MTLVertexFormatChar2; + case KGFX_FORMAT_R8G8_UNORM: + return MTLVertexFormatUChar2Normalized; + case KGFX_FORMAT_R8G8_SNORM: + return MTLVertexFormatChar2Normalized; + + case KGFX_FORMAT_R8G8B8A8_UINT: + return MTLVertexFormatUChar4; + case KGFX_FORMAT_R8G8B8A8_SINT: + return MTLVertexFormatChar4; + case KGFX_FORMAT_R8G8B8A8_UNORM: + return MTLVertexFormatUChar4Normalized; + case KGFX_FORMAT_R8G8B8A8_SNORM: + return MTLVertexFormatChar4Normalized; + + case KGFX_FORMAT_R16_UINT: + return MTLVertexFormatUShort; + case KGFX_FORMAT_R16_SINT: + return MTLVertexFormatShort; + case KGFX_FORMAT_R16_UNORM: + return MTLVertexFormatUShortNormalized; + case KGFX_FORMAT_R16_SNORM: + return MTLVertexFormatShortNormalized; + case KGFX_FORMAT_R16_FLOAT: + return MTLVertexFormatHalf; + + case KGFX_FORMAT_R16G16_UINT: + return MTLVertexFormatUShort2; + case KGFX_FORMAT_R16G16_SINT: + return MTLVertexFormatShort2; + case KGFX_FORMAT_R16G16_UNORM: + return MTLVertexFormatUShort2Normalized; + case KGFX_FORMAT_R16G16_SNORM: + return MTLVertexFormatShort2Normalized; + case KGFX_FORMAT_R16G16_FLOAT: + return MTLVertexFormatHalf2; + + case KGFX_FORMAT_R16G16B16A16_UINT: + return MTLVertexFormatUShort4; + case KGFX_FORMAT_R16G16B16A16_SINT: + return MTLVertexFormatShort4; + case KGFX_FORMAT_R16G16B16A16_UNORM: + return MTLVertexFormatUShort4Normalized; + case KGFX_FORMAT_R16G16B16A16_SNORM: + return MTLVertexFormatShort4Normalized; + case KGFX_FORMAT_R16G16B16A16_FLOAT: + return MTLVertexFormatHalf4; + + case KGFX_FORMAT_R32_UINT: + return MTLVertexFormatUInt; + case KGFX_FORMAT_R32_SINT: + return MTLVertexFormatInt; + case KGFX_FORMAT_R32_FLOAT: + return MTLVertexFormatFloat; + + case KGFX_FORMAT_R32G32_UINT: + return MTLVertexFormatUInt2; + case KGFX_FORMAT_R32G32_SINT: + return MTLVertexFormatInt2; + case KGFX_FORMAT_R32G32_FLOAT: + return MTLVertexFormatFloat2; + + case KGFX_FORMAT_R32G32B32A32_UINT: + return MTLVertexFormatUInt4; + case KGFX_FORMAT_R32G32B32A32_SINT: + return MTLVertexFormatInt4; + case KGFX_FORMAT_R32G32B32A32_FLOAT: + return MTLVertexFormatFloat4; + + default: + case KGFX_FORMAT_UNKNOWN: + return MTLVertexFormatInvalid; + } +} + +constexpr MTLPixelFormat pixelFormat(KGFXFormat format) { + switch (format) { + case KGFX_FORMAT_R8_UINT: + return MTLPixelFormatR8Uint; + case KGFX_FORMAT_R8_SINT: + return MTLPixelFormatR8Sint; + case KGFX_FORMAT_R8_UNORM: + return MTLPixelFormatR8Unorm; + case KGFX_FORMAT_R8_SNORM: + return MTLPixelFormatR8Snorm; + + case KGFX_FORMAT_R8G8_UINT: + return MTLPixelFormatRG8Uint; + case KGFX_FORMAT_R8G8_SINT: + return MTLPixelFormatRG8Sint; + case KGFX_FORMAT_R8G8_UNORM: + return MTLPixelFormatRG8Unorm; + case KGFX_FORMAT_R8G8_SNORM: + return MTLPixelFormatRG8Snorm; + + case KGFX_FORMAT_R8G8B8A8_UINT: + return MTLPixelFormatRGBA8Uint; + case KGFX_FORMAT_R8G8B8A8_SINT: + return MTLPixelFormatRGBA8Sint; + case KGFX_FORMAT_R8G8B8A8_UNORM: + return MTLPixelFormatRGBA8Unorm; + case KGFX_FORMAT_R8G8B8A8_SNORM: + return MTLPixelFormatRGBA8Snorm; + + case KGFX_FORMAT_R8G8B8A8_SRGB: + return MTLPixelFormatRGBA8Unorm_sRGB; + case KGFX_FORMAT_B8G8R8A8_SRGB: + return MTLPixelFormatBGRA8Unorm_sRGB; + + case KGFX_FORMAT_R16_UINT: + return MTLPixelFormatR16Uint; + case KGFX_FORMAT_R16_SINT: + return MTLPixelFormatR16Sint; + case KGFX_FORMAT_R16_UNORM: + return MTLPixelFormatR16Unorm; + case KGFX_FORMAT_R16_SNORM: + return MTLPixelFormatR16Snorm; + case KGFX_FORMAT_R16_FLOAT: + return MTLPixelFormatR16Float; + + case KGFX_FORMAT_R16G16_UINT: + return MTLPixelFormatRG16Uint; + case KGFX_FORMAT_R16G16_SINT: + return MTLPixelFormatRG16Sint; + case KGFX_FORMAT_R16G16_UNORM: + return MTLPixelFormatRG16Unorm; + case KGFX_FORMAT_R16G16_SNORM: + return MTLPixelFormatRG16Snorm; + case KGFX_FORMAT_R16G16_FLOAT: + return MTLPixelFormatRG16Float; + + case KGFX_FORMAT_R16G16B16A16_UINT: + return MTLPixelFormatRGBA16Uint; + case KGFX_FORMAT_R16G16B16A16_SINT: + return MTLPixelFormatRGBA16Sint; + case KGFX_FORMAT_R16G16B16A16_UNORM: + return MTLPixelFormatRGBA16Unorm; + case KGFX_FORMAT_R16G16B16A16_SNORM: + return MTLPixelFormatRGBA16Snorm; + case KGFX_FORMAT_R16G16B16A16_FLOAT: + return MTLPixelFormatRGBA16Float; + + case KGFX_FORMAT_R32_UINT: + return MTLPixelFormatR32Uint; + case KGFX_FORMAT_R32_SINT: + return MTLPixelFormatR32Sint; + case KGFX_FORMAT_R32_FLOAT: + return MTLPixelFormatR32Float; + + case KGFX_FORMAT_R32G32_UINT: + return MTLPixelFormatRG32Uint; + case KGFX_FORMAT_R32G32_SINT: + return MTLPixelFormatRG32Sint; + case KGFX_FORMAT_R32G32_FLOAT: + return MTLPixelFormatRG32Float; + + case KGFX_FORMAT_R32G32B32A32_UINT: + return MTLPixelFormatRGBA32Uint; + case KGFX_FORMAT_R32G32B32A32_SINT: + return MTLPixelFormatRGBA32Sint; + case KGFX_FORMAT_R32G32B32A32_FLOAT: + return MTLPixelFormatRGBA32Float; + + case KGFX_FORMAT_D32_FLOAT: + return MTLPixelFormatDepth32Float; + case KGFX_FORMAT_D24_UNORM_S8_UINT: + return MTLPixelFormatDepth24Unorm_Stencil8; + case KGFX_FORMAT_D16_UNORM: + return MTLPixelFormatDepth16Unorm; + + case KGFX_FORMAT_UNKNOWN: + default: + return MTLPixelFormatInvalid; + } +} + +constexpr MTLVertexStepFunction inputRate(KGFXVertexInputRate rate) { + switch (rate) { + case KGFX_VERTEX_INPUT_RATE_PER_INSTANCE: + return MTLVertexStepFunctionPerInstance; + + default: + case KGFX_VERTEX_INPUT_RATE_PER_VERTEX: + return MTLVertexStepFunctionPerVertex; + } +} + +constexpr MTLPrimitiveTopologyClass topology(KGFXTopology topology) { + switch (topology) { + case KGFX_TOPOLOGY_POINT_LIST: + return MTLPrimitiveTopologyClassPoint; + case KGFX_TOPOLOGY_LINE_LIST: + case KGFX_TOPOLOGY_LINE_STRIP: + return MTLPrimitiveTopologyClassLine; + case KGFX_TOPOLOGY_TRIANGLE_LIST: + case KGFX_TOPOLOGY_TRIANGLE_STRIP: + return MTLPrimitiveTopologyClassTriangle; + + default: + return MTLPrimitiveTopologyClassUnspecified; + } +} + +constexpr MTLPrimitiveType primitiveType(KGFXTopology topology) { + switch (topology) { + case KGFX_TOPOLOGY_POINT_LIST: + return MTLPrimitiveTypePoint; + case KGFX_TOPOLOGY_LINE_LIST: + return MTLPrimitiveTypeLine; + case KGFX_TOPOLOGY_LINE_STRIP: + return MTLPrimitiveTypeLineStrip; + case KGFX_TOPOLOGY_TRIANGLE_LIST: + return MTLPrimitiveTypeTriangle; + case KGFX_TOPOLOGY_TRIANGLE_STRIP: + return MTLPrimitiveTypeTriangleStrip; + + default: + return MTLPrimitiveTypePoint; + } +} + +} /* namespace mtl */ + +} /* namespace kgfx */ + +struct KGFXInstance_t { + KGFXInstanceFlagBits flags; + KGFXSurfaceType surfaceType; + PFN_KGFXDebugMessenger debugMessenger; + + std::vector adapters; + std::vector> deviceFormats; + + struct { + NSArray>* devices; + } mtl; +}; + +struct KGFXQueue_t { + KGFXInstance instance; + KGFXDevice device; +}; + +struct KGFXDevice_t { + KGFXInstance instance; + KGFXu32 adapterID; + + KGFXQueue_t queue; + + struct { + id device; + } mtl; +}; + +struct KGFXCommandPool_t { + KGFXInstance instance; + KGFXDevice device; + + struct { + id commandQueue; + } mtl; +}; + +struct KGFXCommandList_t { + KGFXInstance instance; + KGFXDevice device; + KGFXCommandPool commandPool; + + kgfx::mtl::CommandRepository repo; + + struct { + id commandBuffer; + id commandEncoder; + } mtl; + + struct { + std::optional viewport; + std::vector vertexBuffers; + std::vector vertexBufferOffsets; + + KGFXBuffer indexBuffer; + KGFXu64 indexBufferOffset; + + struct { + KGFXu32 vertexCount; + KGFXu32 instanceCount; + KGFXu32 vertexOffset; + KGFXu32 instanceOffset; + } draw; + } bound; +}; + +struct KGFXShader_t { + KGFXInstance instance; + KGFXDevice device; + KGFXShaderStage stage; + + struct { + id library; + id function; + } mtl; +}; + +struct KGFXPipeline_t { + KGFXInstance instance; + KGFXDevice device; + + struct { + id graphicsPipeline; + MTLPrimitiveType primitiveType; + } mtl; +}; + +struct KGFXTexture_t { + KGFXInstance instance; + KGFXDevice device; + + KGFXFormat format; + KGFXu32 width; + KGFXu32 height; + KGFXu32 depth; + + KGFXSwapchain swapchain; + bool isBackbuffer; + + struct { + id texture; + } mtl; +}; + +struct KGFXSwapchain_t { + KGFXInstance instance; + KGFXDevice device; + + KGFXTexture_t backbuffer; + + struct { + id drawable; + } mtl; +}; + +struct KGFXSurface_t { + KGFXInstance instance; + + struct { + CAMetalLayer* layer; + } mtl; +}; + +KGFXInstance kgfxCreateInstance( + KGFXInstanceFlagBits flags, + KGFXSurfaceType surfaceType) +{ + if (surfaceType != KGFX_SURFACE_TYPE_NONE && surfaceType != KGFX_SURFACE_TYPE_COCOA) { + return nullptr; + } + + KGFXInstance instance = new KGFXInstance_t {}; + instance->flags = flags; + instance->surfaceType = surfaceType; + + NSArray>* devices = MTLCopyAllDevices(); + instance->adapters.resize([devices count]); + instance->deviceFormats.resize([devices count]); + for (NSUInteger i = 0; i < [devices count]; ++i) { + id device = [devices objectAtIndex:i]; + NSString* name = [device name]; + + KGFXAdapter adapter = {}; + if ([name containsString:@"Intel"]) { + adapter.properties.vendor = KGFX_ADAPTER_VENDOR_INTEL; + } else if ([name containsString:@"AMD"]) { + adapter.properties.vendor = KGFX_ADAPTER_VENDOR_AMD; + } else if ([name containsString:@"NVIDIA"]) { + adapter.properties.vendor = KGFX_ADAPTER_VENDOR_NVIDIA; + } else if ([name containsString:@"Apple"]) { + adapter.properties.vendor = KGFX_ADAPTER_VENDOR_APPLE; + } else { + adapter.properties.vendor = KGFX_ADAPTER_VENDOR_UNKNOWN; + } + + adapter.properties.adapterType = [device isLowPower] ? KGFX_ADAPTER_TYPE_INTEGRATED : KGFX_ADAPTER_TYPE_DISCRETE; + adapter.properties.anisotropicSampling = KGFX_FALSE; + adapter.properties.geometrySupport = KGFX_FALSE; + adapter.properties.maxTextureDimensions[0] = ([device supportsFamily:MTLGPUFamilyApple2]) ? 8192 : 16384; + adapter.properties.maxTextureDimensions[1] = ([device supportsFamily:MTLGPUFamilyApple2]) ? 8192 : 16384; + adapter.properties.maxTextureDimensions[2] = 2048; + adapter.properties.maxFramebufferDimensions[0] = adapter.properties.maxTextureDimensions[0]; + adapter.properties.maxFramebufferDimensions[1] = adapter.properties.maxTextureDimensions[1]; + adapter.properties.maxFramebufferDimensions[2] = adapter.properties.maxTextureDimensions[2]; + instance->adapters[i] = adapter; + + for (KGFXFormat format = KGFX_FORMAT_MIN; format < KGFX_FORMAT_MAX; format = static_cast(static_cast(format) + 1)) { + MTLTextureDescriptor* descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:kgfx::mtl::pixelFormat(format) width:1 height:1 mipmapped:NO]; + + id texture = [device newTextureWithDescriptor:descriptor]; + [descriptor release]; + + if (texture != nil) { + [texture release]; + instance->deviceFormats[i].push_back(format); + } + } + } + + instance->mtl.devices = devices; + return instance; +} + +void kgfxDestroyInstance(KGFXInstance instance) { + if (instance == nullptr) { + return; + } + + [instance->mtl.devices dealloc]; + [instance->mtl.devices release]; + delete instance; +} + +void kgfxSetInstanceDebugMessageCallback( + KGFXInstance instance, + PFN_KGFXDebugMessenger debugMessenger) +{ + return; +} + +KGFXbool kgfxEnumerateDeviceAdapters( + KGFXInstance instance, + KGFXu32 adapterID, + KGFXAdapter* pAdapter) +{ + if (adapterID >= instance->adapters.size()) { + return KGFX_FALSE; + } + + if (pAdapter != nullptr) { + *pAdapter = instance->adapters[adapterID]; + } + + return KGFX_TRUE; +} + +KGFXDevice kgfxCreateDevice( + KGFXInstance instance, + KGFXu32 adapterID) +{ + if (adapterID >= instance->adapters.size()) { + return nullptr; + } + + KGFXDevice device = new KGFXDevice_t {}; + device->instance = instance; + device->adapterID = adapterID; + device->queue = {}; + device->queue.instance = instance; + device->queue.device = device; + device->mtl.device = [instance->mtl.devices objectAtIndex:adapterID]; + return device; +} + +void kgfxDestroyDevice( + KGFXInstance instance, + KGFXDevice device) +{ + delete device; +} + +KGFXQueue kgfxGetDeviceQueue( + KGFXDevice device, + KGFXQueueType queueType) +{ + return &device->queue; +} + +KGFXCommandPool kgfxCreateCommandPool( + KGFXDevice device, + KGFXQueue queue, + KGFXu32 commandListCount) +{ + KGFXCommandPool commandPool = new KGFXCommandPool_t {}; + commandPool->instance = device->instance; + commandPool->device = device; + commandPool->mtl.commandQueue = [device->mtl.device newCommandQueueWithMaxCommandBufferCount:commandListCount]; + return commandPool; +} + +void kgfxDestroyCommandPool( + KGFXDevice device, + KGFXCommandPool commandPool) +{ + [commandPool->mtl.commandQueue release]; + delete commandPool; +} + +KGFXCommandList kgfxCreateCommandList( + KGFXDevice device, + KGFXCommandPool commandPool, + KGFXCommandListType commandListType) +{ + KGFXCommandList commandList = new KGFXCommandList_t {}; + commandList->instance = device->instance; + commandList->device = device; + commandList->commandPool = commandPool; + commandList->mtl.commandBuffer = nil; + return commandList; +} + +void kgfxDestroyCommandList( + KGFXDevice device, + KGFXCommandList commandList) +{ + delete commandList; +} + +KGFXbool kgfxResetCommandList( + KGFXDevice device, + KGFXCommandList commandList) +{ + commandList->mtl.commandBuffer = nil; + commandList->mtl.commandEncoder = nil; + + return KGFX_TRUE; +} + +KGFXbool kgfxBeginCommandList( + KGFXCommandList commandList) +{ + commandList->mtl.commandBuffer = [commandList->commandPool->mtl.commandQueue commandBuffer]; + commandList->mtl.commandEncoder = nil; + + return KGFX_TRUE; +} + +void kgfxCommandSetViewport( + KGFXCommandList commandList, + KGFXViewport* pViewport) +{ + commandList->bound.viewport = *pViewport; +} + +void kgfxCommandBindVertexBuffers( + KGFXCommandList commandList, + KGFXBuffer* pBuffers, + KGFXu32 bufferCount, + KGFXu64* pBufferOffsets) +{ + commandList->bound.vertexBuffers.resize(bufferCount); + for (KGFXu32 i = 0; i < bufferCount; ++i) { + commandList->bound.vertexBuffers[i] = pBuffers[i]; + commandList->bound.vertexBufferOffsets[i] = pBufferOffsets[i]; + } +} + +void kgfxCommandBindIndexBuffer( + KGFXCommandList commandList, + KGFXBuffer buffer, + KGFXu64 offset) +{ + commandList->bound.indexBuffer = buffer; + commandList->bound.indexBufferOffset = offset; +} + +void kgfxCommandDraw( + KGFXCommandList commandList, + KGFXu32 vertexCount, + KGFXu32 instanceCount, + KGFXu32 vertexOffset, + KGFXu32 instanceOffset) +{ + commandList->bound.draw.vertexCount = vertexCount; + commandList->bound.draw.instanceCount = instanceCount; + commandList->bound.draw.vertexOffset = vertexOffset; + commandList->bound.draw.instanceOffset = instanceOffset; +} + +KGFXShader kgfxCreateShader( + KGFXDevice device, + KGFXShaderStage shaderStage, + KGFXShaderMedium shaderMedium, + void* pCode, + KGFXu32 codeLength, + const char* entryName) +{ + NSError* error = nil; + id library = [device->mtl.device newLibraryWithSource:[NSString stringWithCString:reinterpret_cast(pCode) encoding:NSUTF8StringEncoding] options:nil error:&error]; + if (error != nil) { + NSLog(@"kgfxCreateShader(): Failed to create underlying id: %@", [error localizedDescription]); + return nullptr; + } + + entryName = (entryName == nullptr) ? "main" : entryName; + + MTLFunctionDescriptor* descriptor = [MTLFunctionDescriptor new]; + [descriptor setName:[NSString stringWithCString:entryName encoding:NSUTF8StringEncoding]]; + id function = [library newFunctionWithDescriptor:descriptor error:&error]; + [descriptor release]; + + if (error != nil) { + NSLog(@"kgfxCreateShader(): Failed to create underlying id: %@", [error localizedDescription]); + return nullptr; + } + + KGFXShader shader = new KGFXShader_t {}; + shader->instance = device->instance; + shader->device = device; + shader->stage = shaderStage; + shader->mtl.library = library; + shader->mtl.function = function; + return shader; +} + +void kgfxDestroyShader( + KGFXDevice device, + KGFXShader shader) +{ + [shader->mtl.function release]; + [shader->mtl.library release]; + delete shader; +} + +KGFXPipeline kgfxCreatePipeline( + KGFXDevice device, + KGFXShader* pShaders, + KGFXu32 shaderCount, + KGFXPipelineVertexInput* pVertexInput, + KGFXRasterizerState* pRasterState, + KGFXFramebuffer framebuffer) +{ + MTLVertexDescriptor* vertexDesc = [MTLVertexDescriptor new]; + for (KGFXu32 i = 0; i < pVertexInput->bindingCount; ++i) { + for (KGFXu32 j = 0; j < pVertexInput->pBindings[i].attributeCount; ++j) { + vertexDesc.attributes[pVertexInput->pBindings[i].pAttributes[j].location].offset = pVertexInput->pBindings[i].pAttributes[j].offset; + vertexDesc.attributes[pVertexInput->pBindings[i].pAttributes[j].location].bufferIndex = pVertexInput->pBindings[i].binding; + vertexDesc.attributes[pVertexInput->pBindings[i].pAttributes[j].location].format = kgfx::mtl::vertexFormat(pVertexInput->pBindings[i].pAttributes[j].format); + } + + vertexDesc.layouts[i].stride = pVertexInput->pBindings[i].stride; + vertexDesc.layouts[i].stepFunction = kgfx::mtl::inputRate(pVertexInput->pBindings[i].inputRate); + vertexDesc.layouts[i].stepRate = 1; + } + + MTLRenderPipelineDescriptor* graphicsDesc = [MTLRenderPipelineDescriptor new]; + for (KGFXu32 i = 0; i < shaderCount; ++i) { + if (pShaders[i]->stage == KGFX_SHADER_STAGE_VERTEX) { + [graphicsDesc setVertexFunction:pShaders[i]->mtl.function]; + } else if (pShaders[i]->stage == KGFX_SHADER_STAGE_FRAGMENT) { + [graphicsDesc setFragmentFunction:pShaders[i]->mtl.function]; + } else { + return nullptr; + } + } + + [graphicsDesc setInputPrimitiveTopology:kgfx::mtl::topology(pRasterState->topology)]; + [graphicsDesc setVertexDescriptor:vertexDesc]; + + NSError* error = nil; + id graphicsPipeline = [device->mtl.device newRenderPipelineStateWithDescriptor:graphicsDesc error:&error]; + [graphicsDesc release]; + [vertexDesc release]; + if (error != nil) { + NSLog(@"kgfxCreatePipeline(): failed to create underlying id: %@", [error localizedDescription]); + return nullptr; + } + + KGFXPipeline pipeline = new KGFXPipeline_t {}; + pipeline->instance = device->instance; + pipeline->device = device; + pipeline->mtl.graphicsPipeline = graphicsPipeline; + pipeline->mtl.primitiveType = kgfx::mtl::primitiveType(pRasterState->topology); + return pipeline; +} + +void kgfxDestroyPipeline( + KGFXDevice device, + KGFXPipeline pipeline) +{ + [pipeline->mtl.graphicsPipeline release]; + delete pipeline; +} + +KGFXSwapchain kgfxCreateSwapchain( + KGFXDevice device, + KGFXSwapchainDesc* pSwapchainDesc) +{ + [pSwapchainDesc->surface->mtl.layer setDevice:device->mtl.device]; + [pSwapchainDesc->surface->mtl.layer setPixelFormat:kgfx::mtl::pixelFormat(pSwapchainDesc->imageFormat)]; + [pSwapchainDesc->surface->mtl.layer setDisplaySyncEnabled:(pSwapchainDesc->presentMode == KGFX_PRESENT_MODE_IMMEDIATE) ? NO : YES]; + + KGFXSwapchain swapchain = new KGFXSwapchain_t {}; + swapchain->instance = device->instance; + swapchain->device = device; + swapchain->backbuffer.instance = device->instance; + swapchain->backbuffer.device = device; + swapchain->backbuffer.format = pSwapchainDesc->imageFormat; + swapchain->backbuffer.isBackbuffer = true; + swapchain->backbuffer.swapchain = swapchain; + swapchain->mtl.drawable = [pSwapchainDesc->surface->mtl.layer nextDrawable]; + return swapchain; +} + +void kgfxDestroySwapchain( + KGFXDevice device, + KGFXSwapchain swapchain) +{ + delete swapchain; +} + +KGFXTexture kgfxGetSwapchainBackBuffer( + KGFXDevice device, + KGFXSwapchain swapchain) +{ + return &swapchain->backbuffer; +} + +KGFXTexture kgfxCreateTexture( + KGFXDevice device, + KGFXResourceType resourceType, + KGFXFormat format, + KGFXu32 width, + KGFXu32 height, + KGFXu32 depth) +{ + MTLTextureDescriptor* descriptor = [MTLTextureDescriptor new]; + [descriptor setTextureType:(height == 0) ? MTLTextureType1D : (depth == 0) ? MTLTextureType2D : MTLTextureType3D]; + [descriptor setPixelFormat:kgfx::mtl::pixelFormat(format)]; + [descriptor setWidth:width]; + [descriptor setHeight:(height == 0) ? 1 : height]; + [descriptor setDepth:(depth == 0) ? 1 : depth]; + + id mtlTexture = nil; + if (device->instance->adapters[device->adapterID].properties.vendor == KGFX_ADAPTER_VENDOR_APPLE || resourceType == KGFX_RESOURCE_TYPE_UPLOAD) { + mtlTexture = [device->mtl.device newSharedTextureWithDescriptor:descriptor]; + } else { + mtlTexture = [device->mtl.device newTextureWithDescriptor:descriptor]; + } + [descriptor release]; + + if (mtlTexture == nil) { + NSLog(@"kgfxCreateTexture(): failed to create underlying id"); + return nullptr; + } + + KGFXTexture texture = new KGFXTexture_t {}; + texture->instance = device->instance; + texture->device = device; + texture->format = format; + texture->width = width; + texture->height = height; + texture->depth = depth; + texture->isBackbuffer = false; + texture->swapchain = nullptr; + texture->mtl.texture = mtlTexture; + return texture; +} + +void kgfxDestroyTexture( + KGFXDevice device, + KGFXTexture texture) +{ + [texture->mtl.texture release]; + delete texture; +} + +KGFXBuffer kgfxCreateBuffer( + KGFXDevice device, + KGFXResourceType resourceType, + KGFXu64 size, + void* pData) +{ + MTLResourceOptions options = (resourceType == KGFX_RESOURCE_TYPE_UPLOAD || device->instance->adapters[device->adapterID].properties.vendor == KGFX_ADAPTER_VENDOR_APPLE) ? MTLResourceStorageModeShared : MTLResourceStorageModePrivate; + + id mtlBuffer = nil; + if (pData != nullptr) { + [device->mtl.device newBufferWithBytes:pData length:size options:options]; + } else { + [device->mtl.device newBufferWithLength:size options:options]; + } + + if ( +} + +KGFXSurface kgfxCreateSurfaceCocoa( + KGFXInstance instance, + void* window) +{ + NSWindow* nsWindow = reinterpret_cast(window); + + CAMetalLayer* layer = [CAMetalLayer layer]; + [[nsWindow contentView] setLayer:layer]; + [[nsWindow contentView] setWantsLayer:YES]; + [layer setContentsScale:[[nsWindow screen] backingScaleFactor]]; + + KGFXSurface surface = new KGFXSurface_t {}; + surface->instance = instance; + surface->mtl.layer = layer; + return surface; +} + +void kgfxDestroySurface( + KGFXInstance instance, + KGFXSurface surface) +{ + [surface->mtl.layer release]; + delete surface; +} + +KGFXbool kgfxEnumerateSurfaceFormats( + KGFXDevice device, + KGFXSurface surface, + KGFXu32 formatIndex, + KGFXFormat* pFormat) +{ + if (formatIndex >= device->instance->deviceFormats[device->adapterID].size()) { + return KGFX_FALSE; + } + + *pFormat = device->instance->deviceFormats[device->adapterID][formatIndex]; + return KGFX_TRUE; +} + +KGFXbool kgfxEnumerateSurfacePresentModes( + KGFXDevice device, + KGFXSurface surface, + KGFXu32 presentModeIndex, + KGFXPresentMode* pPresentMode) +{ + if (presentModeIndex == 0) { + *pPresentMode = KGFX_PRESENT_MODE_IMMEDIATE; + } else if (presentModeIndex == 1) { + *pPresentMode = KGFX_PRESENT_MODE_FIFO; + } else { + return KGFX_FALSE; + } + + return KGFX_TRUE; +} diff --git a/kgfx/src/kgfx_vk.cpp b/kgfx/src/kgfx_vk.cpp index a8a547f..276e623 100644 --- a/kgfx/src/kgfx_vk.cpp +++ b/kgfx/src/kgfx_vk.cpp @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include @@ -55,6 +53,7 @@ struct KGFXSurface_t { struct { void* pView; void* pLayer; + float contentsScale; } apple; #endif /* __APPLE__ */ }; @@ -871,6 +870,7 @@ static VkResult recreateSwapchain(KGFXSwapchain swapchain) { VkSwapchainKHR vkSwapchain; VkResult result = vkCreateSwapchainKHR(swapchain->device->vk.device, &swapchain->vk.createInfo, nullptr, &vkSwapchain); if (result != VK_SUCCESS) { + KGFX_LOGF(swapchain->instance, KGFX_OUTPUT, VERBOSE, "kgfxInternalRecreateSwapchain(): failed to create underlying swapchain {}", result); return result; } scope.addMess(vkDestroySwapchainKHR, swapchain->device->vk.device, swapchain->vk.swapchain, nullptr); @@ -1998,7 +1998,7 @@ void kgfxCommandBindFramebuffer( if (caps.currentExtent.width == 0 || caps.currentExtent.height == 0) { return; } - + tex->swapchain->minimized = false; width = tex->width; height = tex->height; @@ -2182,7 +2182,7 @@ void kgfxCommandDraw( } if (!commandList->hasBegun) { - KGFX_LOG(commandList->instance, KGFX_OUTPUT, ERROR, "kgfxCommandBindPipeline(): commandList has not begun"); + KGFX_LOG(commandList->instance, KGFX_OUTPUT, ERROR, "kgfxCommandDraw(): commandList has not begun"); return; } @@ -2696,6 +2696,10 @@ KGFXSwapchain kgfxCreateSwapchain( VkSurfaceCapabilitiesKHR capabilities; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->instance->vk.physicalDevices[device->adapterID], pSwapchainDesc->surface->vk.surface, &capabilities); + + KGFXu32 width = capabilities.currentExtent.width; + KGFXu32 height = capabilities.currentExtent.height; + if (capabilities.maxImageCount < pSwapchainDesc->imageCount) { KGFX_LOG(device->instance, KGFX_OUTPUT, ERROR, "kgfxCreateSwapchain(): pSwapchainDesc->imageCount is higher than maximum surface image count"); return nullptr; @@ -2712,8 +2716,8 @@ KGFXSwapchain kgfxCreateSwapchain( createInfo.minImageCount = pSwapchainDesc->imageCount; createInfo.imageFormat = kgfx::vk::format(pSwapchainDesc->imageFormat); createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - createInfo.imageExtent.width = capabilities.currentExtent.width; - createInfo.imageExtent.height = capabilities.currentExtent.height; + createInfo.imageExtent.width = width; + createInfo.imageExtent.height = height; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -3611,10 +3615,10 @@ KGFXSurface kgfxCreateSurfaceXlib( return surface; } #elif defined(__APPLE__) -#include -#include -#include -#include +extern "C" VkSurfaceKHR kgfxInternalCreateSurfaceCocoa( + VkInstance instance, + void* window, + float* pContentsScale); KGFXSurface kgfxCreateSurfaceCocoa( KGFXInstance instance, @@ -3629,81 +3633,22 @@ KGFXSurface kgfxCreateSurfaceCocoa( return nullptr; } - id view = reinterpret_cast(objc_msgSend)(reinterpret_cast(window), sel_getUid("contentView")); - if (instance->surfaceType != KGFX_SURFACE_TYPE_COCOA) { KGFX_LOG(instance, KGFX_OUTPUT, ERROR, "kgfxCreateSurfaceCocoa(): instance was not created with Cocoa surface capabilities"); return nullptr; } - id layer = reinterpret_cast(objc_msgSend)(objc_getClass("CAMetalLayer"), sel_getUid("layer")); - if (layer == nil) { - KGFX_LOG(instance, KGFX_OUTPUT, ERROR, "kgfxCreateSurfaceCocoa(): could not construct a metal layer"); - return nullptr; - } - - reinterpret_cast(objc_msgSend)(view, sel_getUid("layer"), layer); - reinterpret_cast(objc_msgSend)(view, sel_getUid("wantsLayer"), YES); - - VkSurfaceKHR vkSurface = nullptr; - if (instance->apple.metalSurfaceSupport) { - vkSurface = [instance, layer]() -> VkSurfaceKHR { - PFN_vkCreateMetalSurfaceEXT func = reinterpret_cast(vkGetInstanceProcAddr(instance->vk.instance, "vkCreateMetalSurfaceEXT")); - if (func == nullptr) { - return nullptr; - } - - VkMetalSurfaceCreateInfoEXT info = {}; - info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - info.pLayer = reinterpret_cast(layer); - - VkSurfaceKHR surf = nullptr; - if (func(instance->vk.instance, &info, nullptr, &surf) == VK_SUCCESS) { - return surf; - } - - return nullptr; - }(); - } - - void* pView = reinterpret_cast(view); - if (instance->apple.macOSSurfaceSupport && vkSurface == nullptr) { - vkSurface = [instance, pView, layer]() -> VkSurfaceKHR { - PFN_vkCreateMacOSSurfaceMVK func = reinterpret_cast(vkGetInstanceProcAddr(instance->vk.instance, "vkCreateMacOSSurfaceEXT")); - if (func == nullptr) { - return nullptr; - } - - VkMacOSSurfaceCreateInfoMVK info = {}; - info.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - info.pView = pView; - - VkSurfaceKHR surf; - if (func(instance->vk.instance, &info, nullptr, &surf) == VK_SUCCESS) { - return surf; - } - - info.pView = reinterpret_cast(layer); - if (func(instance->vk.instance, &info, nullptr, &surf) == VK_SUCCESS) { - return surf; - } - - return nullptr; - }(); - } - + float contentsScale = 1.0f; + VkSurfaceKHR vkSurface = kgfxInternalCreateSurfaceCocoa(instance->vk.instance, window, &contentsScale); if (vkSurface == nullptr) { - KGFX_LOG(instance, KGFX_OUTPUT, ERROR, "kgfxCreateSurfaceCocoa(): failed to create Vulkan surface via vkCreateMetalSurfaceEXT or vkCreateMacOSSurfaceMVK"); + KGFX_LOG(instance, KGFX_OUTPUT, ERROR, "kgfxCreateSurfaceCocoa(): failed to create underlying VkSurfaceKHR"); return nullptr; } KGFXSurface surface = new KGFXSurface_t{}; surface->instance = instance; - surface->vk.surface = vkSurface; - - surface->apple.pView = pView; - surface->apple.pLayer = reinterpret_cast(layer); + surface->apple.contentsScale = contentsScale; return surface; } #endif /* #if defined(WIN32) || defined(_WIN32) */ @@ -3776,7 +3721,7 @@ KGFXbool kgfxEnumerateSurfaceFormats( KGFXbool kgfxEnumerateSurfacePresentModes( KGFXDevice device, KGFXSurface surface, - KGFXu32 presetModeIndex, + KGFXu32 presentModeIndex, KGFXPresentMode* pPresentMode) { if (device == nullptr) { @@ -3817,7 +3762,7 @@ KGFXbool kgfxEnumerateSurfacePresentModes( } } - if (presetModeIndex >= presentModes.size()) { + if (presentModeIndex >= presentModes.size()) { return KGFX_FALSE; } @@ -3825,54 +3770,6 @@ KGFXbool kgfxEnumerateSurfacePresentModes( return KGFX_TRUE; } - *pPresentMode = presentModes[presetModeIndex]; + *pPresentMode = presentModes[presentModeIndex]; return KGFX_TRUE; } - -KGFXu32 kgfxGetSurfaceWidth( - KGFXDevice device, - KGFXSurface surface) -{ - if (device == nullptr) { - return 0; - } - - if (surface == nullptr) { - KGFX_LOG(device->instance, KGFX_OUTPUT, ERROR, "kgfxGetSurfaceWidth(): surface is invalid"); - return 0; - } - - if (device->instance != surface->instance) { - KGFX_LOG(device->instance, KGFX_OUTPUT, ERROR, "kgfxGetSurfaceWidth(): surface does not share an instance parent with device"); - KGFX_LOG(surface->instance, KGFX_OUTPUT, ERROR, "kgfxGetSurfaceWidth(): surface does not share an instance parent with device"); - return 0; - } - - VkSurfaceCapabilitiesKHR vkSurfaceCaps; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->instance->vk.physicalDevices[device->adapterID], surface->vk.surface, &vkSurfaceCaps); - return vkSurfaceCaps.currentExtent.width; -} - -KGFXu32 kgfxGetSurfaceHeight( - KGFXDevice device, - KGFXSurface surface) -{ - if (device == nullptr) { - return 0; - } - - if (surface == nullptr) { - KGFX_LOG(device->instance, KGFX_OUTPUT, ERROR, "kgfxGetSurfaceHeight(): surface is invalid"); - return 0; - } - - if (device->instance != surface->instance) { - KGFX_LOG(device->instance, KGFX_OUTPUT, ERROR, "kgfxGetSurfaceHeight(): surface does not share an instance parent with device"); - KGFX_LOG(surface->instance, KGFX_OUTPUT, ERROR, "kgfxGetSurfaceHeight(): surface does not share an instance parent with device"); - return 0; - } - - VkSurfaceCapabilitiesKHR vkSurfaceCaps; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->instance->vk.physicalDevices[device->adapterID], surface->vk.surface, &vkSurfaceCaps); - return vkSurfaceCaps.currentExtent.height; -} \ No newline at end of file diff --git a/kgfx/src/kgfx_vk_cocoa.mm b/kgfx/src/kgfx_vk_cocoa.mm new file mode 100644 index 0000000..aba6856 --- /dev/null +++ b/kgfx/src/kgfx_vk_cocoa.mm @@ -0,0 +1,57 @@ +#define KGFX_COCOA +#include + +#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT +#include + +#import +#import +#import + +extern "C" VkSurfaceKHR kgfxInternalCreateSurfaceCocoa( + VkInstance instance, + NSWindow* window, + float* pContentsScale) +{ + CAMetalLayer* layer = [CAMetalLayer layer]; + if (layer == nil) { + return nullptr; + } + + [layer setContentsScale:[window backingScaleFactor]]; + [window.contentView setLayer:layer]; + [window.contentView setWantsLayer:YES]; + + *pContentsScale = [window backingScaleFactor]; + + VkSurfaceKHR surface; + PFN_vkCreateMetalSurfaceEXT createMetalSurface = (PFN_vkCreateMetalSurfaceEXT) vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT"); + if (createMetalSurface != nullptr) { + VkMetalSurfaceCreateInfoEXT metalInfo = {}; + metalInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + metalInfo.pLayer = layer; + + if (createMetalSurface(instance, &metalInfo, nullptr, &surface) == VK_SUCCESS) { + return surface; + } + } + + PFN_vkCreateMacOSSurfaceMVK createMacOSSurface = (PFN_vkCreateMacOSSurfaceMVK) vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); + if (createMacOSSurface != nullptr) { + VkMacOSSurfaceCreateInfoMVK macOSInfo = {}; + macOSInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + macOSInfo.pView = (__bridge void*) window.contentView; + + if (createMacOSSurface(instance, &macOSInfo, nullptr, &surface) == VK_SUCCESS) { + return surface; + } + + macOSInfo.pView = (__bridge void*) layer; + if (createMacOSSurface(instance, &macOSInfo, nullptr, &surface) == VK_SUCCESS) { + return surface; + } + } + + return nullptr; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..dbd9f99 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.10) +project(kgfx_test) + +add_executable(kgfx_test_vk "main.cpp") +add_executable(kgfx_test_mtl "main.cpp") + +set(IS_32_BIT FALSE) +if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(IS_32_BIT TRUE) +endif() + +set(LIB_PATH "") +if (WIN32) + if (IS_32_BIT) + set(LIB_PATH "vendor/lib/vc-x86") + if (MINGW) + set(LIB_PATH "vendor/lib/mingw-w32") + endif() + else() + set(LIB_PATH "vendor/lib/vc-x64") + if (MINGW) + set(LIB_PATH "vendor/lib/mingw-w64") + endif() + endif() +else() + find_package(glfw3 REQUIRED) +endif() + +if (NOT "${LIB_PATH}" STREQUAL "") + target_link_directories(kgfx_test_vk ${LIB_PATH}) + target_link_directories(kgfx_test_mtl ${LIB_PATH}) +endif() + +if (WIN32) + target_link_libraries(kgfx_test_vk "glfw3") +else() + target_link_libraries(kgfx_test_vk "glfw") + target_link_libraries(kgfx_test_mtl "glfw") +endif() + +include_directories(${GLFW_INCLUDE_DIRS} "vendor/include" "../kgfx/include") + +target_link_directories(kgfx_test_vk PRIVATE "../build/Debug") +target_link_directories(kgfx_test_mtl PRIVATE "../build/Debug") + +target_link_libraries(kgfx_test_vk kgfx_vk) +target_link_libraries(kgfx_test_mtl kgfx_mtl) + +set_property(TARGET kgfx_test_vk PROPERTY CXX_STANDARD 17) +set_property(TARGET kgfx_test_mtl PROPERTY CXX_STANDARD 17) \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp index 990e702..fe7fed1 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -103,11 +103,6 @@ struct Scope { }; struct Globals { - bool VALIDATION = false; - bool DEBUG_MESSENGER = false; - bool ANISOTROPY = false; - uint32_t FRAMES_IN_FLIGHT = 4; - Scope scope; }; @@ -167,9 +162,6 @@ bool isMouseButtonUp(int button) { int main(int argc, char** argv) { Globals globals = {}; - globals.VALIDATION = true; - globals.DEBUG_MESSENGER = true; - globals.FRAMES_IN_FLIGHT = 1; std::filesystem::path path = std::filesystem::current_path(); @@ -233,21 +225,22 @@ int main(int argc, char** argv) { std::cout << "KGFX" << types[t] << " [" << severities[s] << "] " << m << std::endl; } ); - - KGFXSurface surface = nullptr; + + KGFXSurface surface; #if defined(WIN32) || defined(_WIN32) surface = kgfxCreateSurfaceWin32(instance, GetModuleHandle(nullptr), glfwGetWin32Window(window)); #elif defined(linux) || defined(__gnu_linux) - surface = kgfxCreateSurfaceXlib(instance, glfwGetX11Display(), glfwGetX11Window(window)); + surface = kgfxCreateSurfaceXlib(instance, glfwGetX11Display(window), glfwGetX11Window(window)); #elif defined(__APPLE__) surface = kgfxCreateSurfaceCocoa(instance, reinterpret_cast(glfwGetCocoaWindow(window))); #endif if (surface == nullptr) { - std::cout << "Failed to create surface" << std::endl; + std::cout << "Failed to create cocoa surface" << std::endl; return 1; } globals.scope.addMess(kgfxDestroySurface, instance, surface); + KGFXDevice device = kgfxCreateDevice(instance, 0); if (device == nullptr) { std::cout << "Failed to create device using adapter 0" << std::endl; @@ -263,33 +256,12 @@ int main(int argc, char** argv) { KGFXSwapchainDesc swapchainDesc = {}; swapchainDesc.surface = surface; - swapchainDesc.imageFormat = KGFX_FORMAT_UNKNOWN; + swapchainDesc.imageFormat = KGFX_FORMAT_B8G8R8A8_SRGB; swapchainDesc.presentMode = KGFX_PRESENT_MODE_FIFO; + swapchainDesc.imageWidth = 800; + swapchainDesc.imageHeight = 600; swapchainDesc.imageCount = 2; - - KGFXFormat fmt; - for (KGFXu32 i = 0; kgfxEnumerateSurfaceFormats(device, surface, i, &fmt); ++i) { - if (fmt == KGFX_FORMAT_B8G8R8A8_SRGB || fmt == KGFX_FORMAT_R8G8B8A8_SRGB) { - swapchainDesc.imageFormat = fmt; - break; - } - } - - if (swapchainDesc.imageFormat == KGFX_FORMAT_UNKNOWN) { - kgfxEnumerateSurfaceFormats(device, surface, 0, &fmt); - swapchainDesc.imageFormat = fmt; - } - - KGFXPresentMode presentMode; - for (KGFXu32 i = 0; kgfxEnumerateSurfacePresentModes(device, surface, i, &presentMode); ++i) { - if (presentMode == KGFX_PRESENT_MODE_MAILBOX) { - swapchainDesc.presentMode = presentMode; - break; - } else if (presentMode == KGFX_PRESENT_MODE_FIFO) { - swapchainDesc.presentMode = presentMode; - } - } - + KGFXSwapchain swapchain = kgfxCreateSwapchain(device, &swapchainDesc); if (swapchain == nullptr) { std::cout << "Failed to create swapchain" << std::endl; @@ -486,7 +458,11 @@ int main(int argc, char** argv) { kgfxSubmitCommandList(device, transferCommandList); int width, height; + double start; + double targetTime = 0.016666; while (!glfwWindowShouldClose(window)) { + start = glfwGetTime(); + glfwGetFramebufferSize(window, &width, &height); glfwPollEvents(); @@ -511,6 +487,12 @@ int main(int argc, char** argv) { kgfxEndCommandList(graphicsCommandList); kgfxSubmitCommandList(device, graphicsCommandList); kgfxPresentSwapchain(device, swapchain); + + double finish = glfwGetTime(); + while (finish - start < targetTime) { + finish = glfwGetTime(); + } + } return 0;