metal clear swapchain with blue

This commit is contained in:
2025-06-29 22:40:43 +03:00
parent b8e78174ad
commit 99eafb9443
13 changed files with 343 additions and 136 deletions

View File

@@ -133,7 +133,9 @@ void CBrushRendering::Init()
{"shaders/brush_vert.spv", SHADER_TYPE_VERTEX},
{"shaders/brush_frag.spv", SHADER_TYPE_FRAGMENT},
},
{}, 64,
{}, 64,
20,
{{0,0,EVertexFormat::VERTEX_FORMAT_X32Y32Z32}, {12,1,EVertexFormat::VERTEX_FORMAT_X32Y32}},
{EImageFormat::IMAGE_FORMAT_R8G8B8A8}
);
};

View File

@@ -6,24 +6,55 @@
#include "tier1/utlvector.h"
#include "tier0/platform.h"
#include "rendering.h"
#include "ml_video.h"
mat4 g_cameraView;
class CMlBuffer: public IBuffer
{
public:
void *Map() override;
void Unmap() override;
MTL::Buffer *m_buffer;
};
void *CMlBuffer::Map()
{
return m_buffer->contents();
}
void CMlBuffer::Unmap()
{
}
IStorageBuffer *IRenderer::CreateStorageBuffer( uint32_t uSize )
{
CMlBuffer *pBuffer = new CMlBuffer;
pBuffer->m_buffer = g_mlDevice->newBuffer(uSize, MTL::ResourceStorageModeShared);
return pBuffer;
}
IUniformBuffer *IRenderer::CreateUniformBuffer( uint32_t uSize )
{
CMlBuffer *pBuffer = new CMlBuffer;
pBuffer->m_buffer = g_mlDevice->newBuffer(uSize, MTL::ResourceStorageModeShared);
return pBuffer;
}
IVertexBuffer *IRenderer::CreateVertexBuffer( uint32_t uSize )
{
CMlBuffer *pBuffer = new CMlBuffer;
pBuffer->m_buffer = g_mlDevice->newBuffer(uSize, MTL::ResourceStorageModeShared);
return pBuffer;
}
IIndexBuffer *IRenderer::CreateIndexBuffer( uint32_t uSize )
{
CMlBuffer *pBuffer = new CMlBuffer;
pBuffer->m_buffer = g_mlDevice->newBuffer(uSize, MTL::ResourceStorageModeShared);
return pBuffer;
}
@@ -96,6 +127,8 @@ IGraphicsPipeline *IRenderer::CreateGraphicsPipeline(
CUtlVector<Shader_t> shaders,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormat,
CUtlVector<EImageFormat> outputFormats
)
{

12
engine/ml_video.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef ML_VIDEO_H
#define ML_VIDEO_H
#include "Metal/Metal.hpp"
#include "QuartzCore/QuartzCore.hpp"
extern CA::MetalLayer *g_mlLayer;
extern MTL::Device *g_mlDevice;
extern MTL::CommandQueue *g_mlCommandQueue;
extern NS::AutoreleasePool *g_mlPool;
#endif

View File

@@ -11,6 +11,7 @@
#define CA_PRIVATE_IMPLEMENTATION
#include "tier0/minmax_off.h"
#include "QuartzCore/CAMetalLayer.hpp"
#include "Metal/Metal.hpp"
#include "SDL3/SDL.h"
@@ -19,7 +20,30 @@
#include "SDL3/SDL_events.h"
#include "tier0/minmax.h"
char g_bConfigNotify = 0;
uint32_t g_nWindowWidth = 1280;
uint32_t g_nWindowHeight = 720;
SDL_Window *g_window;
SDL_MetalView g_mlView;
CA::MetalLayer *g_mlLayer;
MTL::Device *g_mlDevice;
MTL::CommandQueue *g_mlCommandQueue;
NS::AutoreleasePool *g_mlPool;
#if defined(__APPLE__) && defined(__MACH__)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
// iOS
#define SDL_METAL_VIEW UI::View
#define STBI_NO_THREAD_LOCALS
#else
// macOS
#define SDL_METAL_VIEW NS::View
#endif
#else
// Other platforms
#endif
void IInput::SetMouseMode( EMouseMode mode )
{
@@ -34,12 +58,131 @@ void IInput::SetMouseMode( EMouseMode mode )
}
}
EInputKey ISDL_KeyName(SDL_Keycode key)
{
switch(key)
{
case SDLK_ESCAPE: return KEY_ESCAPE;
case SDLK_1: return KEY_1;
case SDLK_2: return KEY_2;
case SDLK_3: return KEY_3;
case SDLK_4: return KEY_4;
case SDLK_5: return KEY_5;
case SDLK_6: return KEY_6;
case SDLK_7: return KEY_7;
case SDLK_8: return KEY_8;
case SDLK_9: return KEY_9;
case SDLK_0: return KEY_0;
case SDLK_A: return KEY_A;
case SDLK_B: return KEY_B;
case SDLK_C: return KEY_C;
case SDLK_D: return KEY_D;
case SDLK_E: return KEY_E;
case SDLK_F: return KEY_F;
case SDLK_G: return KEY_G;
case SDLK_H: return KEY_H;
case SDLK_I: return KEY_I;
case SDLK_J: return KEY_J;
case SDLK_K: return KEY_K;
case SDLK_L: return KEY_L;
case SDLK_M: return KEY_M;
case SDLK_N: return KEY_N;
case SDLK_O: return KEY_O;
case SDLK_P: return KEY_P;
case SDLK_Q: return KEY_Q;
case SDLK_R: return KEY_R;
case SDLK_S: return KEY_S;
case SDLK_T: return KEY_T;
case SDLK_U: return KEY_U;
case SDLK_V: return KEY_V;
case SDLK_W: return KEY_W;
case SDLK_X: return KEY_X;
case SDLK_Y: return KEY_Y;
case SDLK_Z: return KEY_Z;
}
return KEY_NONE;
};
void IVideo_HandleEvents()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
SDL_KeyboardEvent *key = &event.key;
SDL_MouseMotionEvent *motion = &event.motion;
switch (event.type)
{
case SDL_EVENT_WINDOW_RESIZED:
g_nWindowWidth = event.window.data1;
g_nWindowHeight = event.window.data2;
g_bConfigNotify = 2;
break;
case SDL_EVENT_KEY_DOWN:
if (!key->repeat)
IInput::KeyEvent(ISDL_KeyName(key->key),KEY_EVENT_TYPE_DOWN);
break;
case SDL_EVENT_KEY_UP:
key = &event.key;
if (!key->repeat)
IInput::KeyEvent(ISDL_KeyName(key->key),KEY_EVENT_TYPE_UP);
break;
case SDL_EVENT_MOUSE_MOTION:
IInput::AxisEvent(AXIS_MOUSE_X, motion->yrel*0.022);
IInput::AxisEvent(AXIS_MOUSE_Y, -motion->xrel*0.022);
break;
}
};
};
void IVideo::Init()
{
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
V_printf("%s\n",SDL_GetError());
g_window = SDL_CreateWindow("rtt", 1280, 720, SDL_WINDOW_VULKAN);
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
g_window = SDL_CreateWindow("rtt", 1280, 720, SDL_WINDOW_METAL);
g_mlView = SDL_Metal_CreateView(g_window);
g_mlLayer = (CA::MetalLayer*)SDL_Metal_GetLayer(g_mlView);
g_mlDevice = MTL::CreateSystemDefaultDevice();
g_mlLayer->setDevice(g_mlDevice);
g_mlLayer->setPixelFormat(MTL::PixelFormatBGRA8Unorm);
g_mlCommandQueue = g_mlDevice->newCommandQueue();
g_mlLayer->setDrawableSize(CGSizeMake(1280, 720));
}
void IVideo::Frame( float fDelta )
{
IVideo_HandleEvents();
NS::AutoreleasePool *pool = NS::AutoreleasePool::alloc()->init();
int w, h;
SDL_GetWindowSizeInPixels(g_window, &w, &h);
g_mlLayer->setDrawableSize(CGSizeMake(w, h));
CA::MetalDrawable *drawable = g_mlLayer->nextDrawable();
if (!drawable)
return;
MTL::CommandBuffer *commandBuffer = g_mlCommandQueue->commandBuffer();
MTL::RenderPassDescriptor *renderPass = MTL::RenderPassDescriptor::alloc()->init();
renderPass->colorAttachments()->object(0)->setTexture(drawable->texture());
renderPass->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionClear);
renderPass->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore);
renderPass->colorAttachments()->object(0)->setClearColor(MTL::ClearColor(0.0, 0, 1.0, 1.0));
MTL::RenderCommandEncoder *renderEncoder = commandBuffer->renderCommandEncoder(renderPass);
renderEncoder->endEncoding();
commandBuffer->presentDrawable(drawable);
commandBuffer->commit();
pool->release();
}
void IVideo::Deinit()
{
g_mlCommandQueue->release();
g_mlDevice->release();
};

View File

@@ -65,6 +65,35 @@ VkFormat IRenderer_FormatToVk( EImageFormat format )
}
};
VkFormat IRenderer_VertexToVk( EVertexFormat format )
{
switch (format)
{
case VERTEX_FORMAT_X16: return VK_FORMAT_R16_SFLOAT;
case VERTEX_FORMAT_X16Y16: return VK_FORMAT_R16G16_SFLOAT;
case VERTEX_FORMAT_X16Y16Z16: return VK_FORMAT_R16G16B16_SFLOAT;
case VERTEX_FORMAT_X16Y16Z16W16: return VK_FORMAT_R16G16B16A16_SFLOAT;
case VERTEX_FORMAT_X32: return VK_FORMAT_R32_SFLOAT;
case VERTEX_FORMAT_X32Y32: return VK_FORMAT_R32G32_SFLOAT;
case VERTEX_FORMAT_X32Y32Z32: return VK_FORMAT_R32G32B32_SFLOAT;
case VERTEX_FORMAT_X32Y32Z32W32: return VK_FORMAT_R32G32B32A32_SFLOAT;
}
};
uint32_t IRenderer_VertexToSize( EVertexFormat format )
{
switch (format)
{
case VERTEX_FORMAT_X16: return 2;
case VERTEX_FORMAT_X16Y16: return 4;
case VERTEX_FORMAT_X16Y16Z16: return 6;
case VERTEX_FORMAT_X16Y16Z16W16: return 8;
case VERTEX_FORMAT_X32: return 4;
case VERTEX_FORMAT_X32Y32: return 8;
case VERTEX_FORMAT_X32Y32Z32: return 12;
case VERTEX_FORMAT_X32Y32Z32W32: return 16;
}
}
VkAttachmentLoadOp IRenderer_LoadOpVk( EAttachmentLoadMode mode )
{
switch (mode)
@@ -228,11 +257,13 @@ void vk_shader_t::Destroy( void )
void vk_tripipeline_t::Create(
CUtlVector<vk_shader_t> &shaders,
CUtlVector<VkDescriptorSetLayoutBinding> &bindings,
uint32_t pushConstantSize,
CUtlVector<VkFormat> formats
)
CUtlVector<vk_shader_t> &shaders,
CUtlVector<VkDescriptorSetLayoutBinding> &bindings,
uint32_t pushConstantSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormat,
CUtlVector<VkFormat> formats
)
{
VkPushConstantRange pushConstantRange = {};
pushConstantRange.stageFlags = VK_SHADER_STAGE_ALL;
@@ -295,11 +326,32 @@ void vk_tripipeline_t::Create(
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
};
VkVertexInputBindingDescription vibd = {
.binding = 0,
.stride = nVertexSize,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
};
VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = sizeof(dynamicStates)/sizeof(VkDynamicState),
.pDynamicStates = dynamicStates,
};
CUtlVector<VkVertexInputAttributeDescription> viad(vertexFormat.GetSize());
for ( uint32_t i = 0; i < viad.GetSize(); i++ )
{
viad[i].location = 0;
viad[i].binding = vertexFormat[i].binding;
viad[i].format = IRenderer_VertexToVk(vertexFormat[i].format);
viad[i].offset = vertexFormat[i].offset;
}
VkPipelineVertexInputStateCreateInfo pvisci = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &vibd,
.vertexAttributeDescriptionCount = (uint32_t)vertexFormat.GetSize(),
};
VkPipelineInputAssemblyStateCreateInfo piasci = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
@@ -318,6 +370,7 @@ void vk_tripipeline_t::Create(
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = {};
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
graphicsPipelineCreateInfo.pVertexInputState = &pvisci;
graphicsPipelineCreateInfo.pInputAssemblyState = &piasci;
graphicsPipelineCreateInfo.layout = m_layout;
graphicsPipelineCreateInfo.pDynamicState = &pipelineDynamicStateCreateInfo;
@@ -808,6 +861,8 @@ IGraphicsPipeline *IRenderer::CreateGraphicsPipeline(
CUtlVector<Shader_t> shaders,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormats,
CUtlVector<EImageFormat> outputFormats
)
{
@@ -816,6 +871,7 @@ IGraphicsPipeline *IRenderer::CreateGraphicsPipeline(
CUtlVector<vk_shader_t> vkshaders(shaders.GetSize());
CUtlVector<VkDescriptorSetLayoutBinding> vkbindings(inputs.GetSize());
CUtlVector<VkFormat> vkformats(outputFormats.GetSize());
CUtlVector<VkVertexInputAttributeDescription> vkVertexFormats(vertexFormats.GetSize());
for ( uint32_t i = 0; i < vkshaders.GetSize(); i++ )
{
@@ -842,8 +898,9 @@ IGraphicsPipeline *IRenderer::CreateGraphicsPipeline(
{
vkformats[i] = IRenderer_FormatToVk(outputFormats[i]);
}
pipeline->m_pipeline.Create(vkshaders, vkbindings, nConstantsSize, vkformats);
return 0;
pipeline->m_pipeline.Create(vkshaders, vkbindings, nConstantsSize, nVertexSize, vertexFormats, vkformats);
return pipeline;
};

View File

@@ -35,6 +35,8 @@ struct vk_tripipeline_t
CUtlVector<vk_shader_t> &shaders,
CUtlVector<VkDescriptorSetLayoutBinding> &bindings,
uint32_t pushConstantsSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormat,
CUtlVector<VkFormat> formats
/* the rest of the stuff is set by the dynamic state */
/* literally */

View File

@@ -232,8 +232,7 @@ EInputKey ISDL_KeyName(SDL_Keycode key)
void IVideo::Init()
{
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
V_printf("%s\n",SDL_GetError());
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
g_window = SDL_CreateWindow("rtt", 1280, 720, SDL_WINDOW_VULKAN);
unsigned int nExtensionCount = 0;