About to set BufferLayout

main
xszAzy 3 months ago
parent 34e7d142aa
commit f2e64bc0db

@ -10,8 +10,13 @@
1817955824A247CA9F871398 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA5C1300C9792D32A5828940 /* CoreFoundation.framework */; };
1EA5B05892FFF54A10E37E98 /* LayerStack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD1D7500EF4751B223383B40 /* LayerStack.cpp */; };
40821283ADAA20F5AF3D10C3 /* Sandbox.mm in Sources */ = {isa = PBXBuildFile; fileRef = DB139FCB287695FD9E95960B /* Sandbox.mm */; };
470E4F862E92E62C0001CB6D /* MTKViewDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 470E4F852E92E62C0001CB6D /* MTKViewDelegate.mm */; };
471F408B2E9048F700A39495 /* Shader.metal in Sources */ = {isa = PBXBuildFile; fileRef = 0EC3D68640BD2138BA9C5CC6 /* Shader.metal */; };
472151D42E953F6D00E52696 /* VertexArray.mm in Sources */ = {isa = PBXBuildFile; fileRef = 472151D32E953F6D00E52696 /* VertexArray.mm */; };
475DDCC62E8D968900D66434 /* ImGuiLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 475DDCC52E8D968900D66434 /* ImGuiLayer.mm */; };
479A9D0A2E93ED400019F59F /* Buffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 479A9D092E93ED400019F59F /* Buffer.mm */; };
479A9D0D2E942C4E0019F59F /* IndexBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 479A9D0C2E942C4E0019F59F /* IndexBuffer.mm */; };
479A9D102E942CBD0019F59F /* VertexBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 479A9D0F2E942CBD0019F59F /* VertexBuffer.mm */; };
47A97AAA2E8EB34B00293FA8 /* Renderer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47A97AA92E8EB34B00293FA8 /* Renderer.mm */; };
47A97AAE2E8EDBAD00293FA8 /* ViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47A97AAD2E8EDBAD00293FA8 /* ViewController.mm */; };
47F2B42A2E918103005D0A7A /* Shader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 47F2B4292E918103005D0A7A /* Shader.mm */; };
@ -78,8 +83,18 @@
28A2B695BB308087240924D5 /* MacWindow.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objc; name = MacWindow.mm; path = src/MEL/Window/MacWindow.mm; sourceTree = "<group>"; };
333B5CED59618C9FC068832D /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Log.h; path = src/MEL/Log/Log.h; sourceTree = "<group>"; };
38BBC2DB812CA70DC5CB791B /* MetalLearning.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MetalLearning.app; sourceTree = BUILT_PRODUCTS_DIR; };
470E4F842E92E62C0001CB6D /* MTKViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MTKViewDelegate.h; path = src/MEL/Renderer/MTKViewDelegate.h; sourceTree = "<group>"; };
470E4F852E92E62C0001CB6D /* MTKViewDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MTKViewDelegate.mm; path = src/MEL/Renderer/MTKViewDelegate.mm; sourceTree = "<group>"; };
472151D22E953F6D00E52696 /* VertexArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VertexArray.h; sourceTree = "<group>"; };
472151D32E953F6D00E52696 /* VertexArray.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VertexArray.mm; sourceTree = "<group>"; };
475DDCC42E8D968900D66434 /* ImGuiLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImGuiLayer.h; sourceTree = "<group>"; };
475DDCC52E8D968900D66434 /* ImGuiLayer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImGuiLayer.mm; sourceTree = "<group>"; };
479A9D082E93ED400019F59F /* Buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = "<group>"; };
479A9D092E93ED400019F59F /* Buffer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Buffer.mm; sourceTree = "<group>"; };
479A9D0B2E942C4E0019F59F /* IndexBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IndexBuffer.h; sourceTree = "<group>"; };
479A9D0C2E942C4E0019F59F /* IndexBuffer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = IndexBuffer.mm; sourceTree = "<group>"; };
479A9D0E2E942CBD0019F59F /* VertexBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VertexBuffer.h; sourceTree = "<group>"; };
479A9D0F2E942CBD0019F59F /* VertexBuffer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VertexBuffer.mm; sourceTree = "<group>"; };
47A97AA82E8EB31500293FA8 /* Renderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Renderer.h; path = src/MEL/Renderer/Renderer.h; sourceTree = "<group>"; };
47A97AA92E8EB34B00293FA8 /* Renderer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = Renderer.mm; path = src/MEL/Renderer/Renderer.mm; sourceTree = "<group>"; };
47A97AAC2E8EDBAD00293FA8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
@ -155,6 +170,8 @@
2C8FAEDB7CA3438DFF21751B /* MEL */ = {
isa = PBXGroup;
children = (
472151D12E953F5900E52696 /* VertexArray */,
479A9D072E93ED2A0019F59F /* Buffer */,
47F2B4272E9180E3005D0A7A /* Shader */,
7B436A80AD3CB532271BF0C0 /* Application.h */,
6038CC64F5AF8B96644BE2A4 /* Application.mm */,
@ -188,6 +205,16 @@
name = backends;
sourceTree = "<group>";
};
472151D12E953F5900E52696 /* VertexArray */ = {
isa = PBXGroup;
children = (
472151D22E953F6D00E52696 /* VertexArray.h */,
472151D32E953F6D00E52696 /* VertexArray.mm */,
);
name = VertexArray;
path = src/MEL/VertexArray;
sourceTree = "<group>";
};
475DDCC32E8D966F00D66434 /* ImGuiLayer */ = {
isa = PBXGroup;
children = (
@ -198,6 +225,20 @@
path = src/MEL/ImGuiLayer;
sourceTree = "<group>";
};
479A9D072E93ED2A0019F59F /* Buffer */ = {
isa = PBXGroup;
children = (
479A9D082E93ED400019F59F /* Buffer.h */,
479A9D092E93ED400019F59F /* Buffer.mm */,
479A9D0B2E942C4E0019F59F /* IndexBuffer.h */,
479A9D0C2E942C4E0019F59F /* IndexBuffer.mm */,
479A9D0E2E942CBD0019F59F /* VertexBuffer.h */,
479A9D0F2E942CBD0019F59F /* VertexBuffer.mm */,
);
name = Buffer;
path = src/MEL/Buffer;
sourceTree = "<group>";
};
47A97AAB2E8EDB8A00293FA8 /* ViewController */ = {
isa = PBXGroup;
children = (
@ -293,6 +334,8 @@
6188BCBA2816B42C9618DAFA /* AppDelegate.mm */,
47A97AA82E8EB31500293FA8 /* Renderer.h */,
47A97AA92E8EB34B00293FA8 /* Renderer.mm */,
470E4F842E92E62C0001CB6D /* MTKViewDelegate.h */,
470E4F852E92E62C0001CB6D /* MTKViewDelegate.mm */,
);
name = Renderer;
sourceTree = "<group>";
@ -432,6 +475,7 @@
buildActionMask = 2147483647;
files = (
471F408B2E9048F700A39495 /* Shader.metal in Sources */,
472151D42E953F6D00E52696 /* VertexArray.mm in Sources */,
CE38F4BC94C6EC2E02C912FC /* Application.mm in Sources */,
CA73010C21D873FED3E68F4C /* Entrypoint.mm in Sources */,
969729155D252087CB274755 /* MacInput.mm in Sources */,
@ -444,7 +488,11 @@
47F2B42A2E918103005D0A7A /* Shader.mm in Sources */,
70B86CF5705B5027AAB00335 /* CocoaWindow.mm in Sources */,
BC2CC98D9B49E3BF77533FCD /* MacWindow.mm in Sources */,
479A9D0A2E93ED400019F59F /* Buffer.mm in Sources */,
470E4F862E92E62C0001CB6D /* MTKViewDelegate.mm in Sources */,
479A9D102E942CBD0019F59F /* VertexBuffer.mm in Sources */,
40821283ADAA20F5AF3D10C3 /* Sandbox.mm in Sources */,
479A9D0D2E942C4E0019F59F /* IndexBuffer.mm in Sources */,
B24E4279E3323A6BF64A70B9 /* melpch.mm in Sources */,
93CEE37D2C46D0EF582DC1BD /* imgui_impl_metal.mm in Sources */,
FF1219CB5B991E3DE43BD80B /* imgui_impl_osx.mm in Sources */,

@ -7,7 +7,7 @@
<key>MetalLearning.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
</dict>
</dict>

@ -1,27 +1,20 @@
#include <metal_stdlib>
using namespace metal;
struct VertexIn {
float3 position [[attribute(0)]];
float3 color [[attribute(1)]];
};
struct VertexOut{
float4 position [[position]];
float4 color;
};
vertex VertexOut vertexShader(uint vertexID [[vertex_id]]){
float2 positions[3]={
float2(0.0,0.5),
float2(-0.5,-0.5),
float2(0.5,-0.5)
};
float4 colors[3]={
float4(1.0,0.0,0.0,1.0),
float4(0.0,1.0,0.0,1.0),
float4(0.0,0.0,1.0,1.0)
};
vertex VertexOut vertexShader(const VertexIn in [[stage_in]]){
VertexOut out;
out.position=float4(positions[vertexID],0.0,1.0);
out.color=colors[vertexID];
out.position=float4(in.position,1.0);
out.color=float4(in.color,1.0);
return out;
}

@ -4,10 +4,13 @@
#include "Events/ApplicationEvent.h"
#include "Layer/LayerStack.h"
#include "ImGuiLayer/ImGuiLayer.h"
#include "Shader/Shader.h"
#include "MTKViewDelegate.h"
namespace MEL{
class Window;
class Renderer;
class Shader;
class VertexArray;
}
namespace MEL {
class Application{
@ -25,14 +28,22 @@ namespace MEL {
inline Renderer* GetRenderer(){return m_Renderer;}
private:
bool OnWindowClose(WindowCloseEvent& event);
public:
//Metal unique render
void RenderOneFrame();
private:
std::unique_ptr<Window> m_Window;
MELMTKViewDelegate* m_ViewDelegate;
Renderer* m_Renderer;
ImGuiLayer* m_ImGuiLayer;
bool m_Running=true;
LayerStack m_LayerStack;
std::shared_ptr<Shader> m_CurrentShader;
static Application* s_Instance;
std::shared_ptr<VertexArray> m_VertexArray;
};
Application* CreateApplication();
}

@ -3,6 +3,10 @@
#include "Application.h"
#include "MacWindow.h"
#import "Buffer/VertexBuffer.h"
#import "Buffer/IndexBuffer.h"
#import "VertexArray/VertexArray.h"
namespace MEL{
Application* Application::s_Instance=nullptr;
@ -10,11 +14,46 @@ namespace MEL{
s_Instance=this;
m_Window=std::unique_ptr<Window>(Window::Create());
m_Window->SetEventCallback(MEL_BIND_EVENT_FN(Application::OnEvent));
//Get Renderer first
auto* macWindow=static_cast<MacWindow*>(m_Window.get());
m_Renderer=macWindow->GetRenderer();
//then push imgui layer
m_ImGuiLayer=new ImGuiLayer();
PushOverlay(m_ImGuiLayer);
//create vertex array
m_VertexArray=MEL::VertexArray::Create();
//set vertex and index buffer
float vertices[]={
-0.5f,-0.5f,0.0f,
0.4f,0.2f,0.4f,
0.5f,-0.5f,0.0f,
0.1f,0.7f,0.1f,
0.0f,0.5f,0.0f,
0.1f,0.3f,0.4f
};
uint32_t indices[]={0,1,2};
auto basicVB=VertexBuffer::Create(vertices, sizeof(vertices));
auto basicIB=IndexBuffer::Create(indices, 3);
basicVB->SetSlot(0);
m_VertexArray->AddVertexBuffer(basicVB);
m_VertexArray->SetIndexBuffer(basicIB);
//create shader(this can be done in sandbox)
auto defaultShader=MEL::Shader::CreateFromDefaultLibrary("DefaultShader",
@"vertexShader",@"fragmentShader");
if(defaultShader)
defaultShader->CreatePipelineState();
m_CurrentShader=defaultShader;
//initialize layers
for(Layer* layer:m_LayerStack)
layer->OnAttach();
}
Application::~Application(){
@ -44,8 +83,15 @@ namespace MEL{
NSApplication* application=[NSApplication sharedApplication];
AppDelegate* appDelegate=[[AppDelegate alloc] init];
[application setDelegate:appDelegate];
MTKView* mtkView=m_Renderer->GetMTKView();
m_ViewDelegate=[[MELMTKViewDelegate alloc] initWithApplication:this];
[mtkView setDelegate:m_ViewDelegate];
[application finishLaunching];
[application activateIgnoringOtherApps:YES];
while (m_Running){
@autoreleasepool {
NSEvent* event;
@ -56,33 +102,12 @@ namespace MEL{
[application sendEvent:event];
}
if(m_Renderer){
m_Renderer->BeginFrame();
m_Renderer->BeginScene();
m_Renderer->CreatePipelineState();
m_ImGuiLayer->Begin();
m_Renderer->DrawIndexed(3);
for(Layer* layer:m_LayerStack)
layer->OnUpdate();
for (Layer* layer :m_LayerStack)
layer->OnImGuiRender();
m_ImGuiLayer->End();
m_Renderer->EndScene();
m_Renderer->EndFrame();
}
m_Window->OnUpdate();
[NSThread sleepForTimeInterval:0.001];
[NSThread sleepForTimeInterval:0.016];
m_Window->Show();
}
}
[m_ViewDelegate release];
[application stop:nil];
}
@ -96,4 +121,36 @@ namespace MEL{
overlay->OnAttach();
}
void Application::RenderOneFrame(){
if(m_Renderer){
//begin frame(command buffer)
m_Renderer->BeginFrame();
//begin scene(pipeline desc,encoder,with sets)
m_Renderer->BeginScene();
//ImGui UI frame begin
m_ImGuiLayer->Begin();
//upper three must call
if(m_CurrentShader&&m_VertexArray){
m_CurrentShader->Bind();
m_Renderer->DrawIndexed(m_VertexArray);
}
//layers
for(Layer* layer:m_LayerStack)
layer->OnUpdate();
//ImGui draw
for (Layer* layer :m_LayerStack)
layer->OnImGuiRender();
//end ImGui
m_ImGuiLayer->End();
//end scene
m_Renderer->EndScene();
//end frame
m_Renderer->EndFrame();
}
}
}

@ -0,0 +1,35 @@
#pragma once
#include<Metal/Metal.h>
#include "Application.h"
namespace MEL{
enum class BufferUsage{
Static,
Dynamic,
Stream
};
enum class BufferType{
Vertex,
Index,
Uniform
};
class Buffer{
public:
virtual ~Buffer();
virtual void Bind()=0;
virtual void SetData(void* data,uint32_t size)=0;
id<MTLBuffer> GetBuffer()const{return m_MetalBuffer;}
BufferType GetType()const{return m_Type;}
BufferUsage GetUsage()const{return m_Usage;}
uint32_t GetSize()const{return m_Size;}
protected:
Buffer(BufferType type,BufferUsage usage);
id<MTLBuffer> m_MetalBuffer=nil;
BufferType m_Type;
BufferUsage m_Usage;
uint32_t m_Size=0;
};
}

@ -0,0 +1,12 @@
#include "Buffer.h"
namespace MEL {
Buffer::Buffer(BufferType type,BufferUsage usage)
:m_Type(type),m_Usage(usage){
}
Buffer::~Buffer(){
if(m_MetalBuffer){
m_MetalBuffer=nil;
}
}
}

@ -0,0 +1,22 @@
#pragma once
#include<Metal/Metal.h>
#import "Buffer.h"
namespace MEL {
class IndexBuffer: public Buffer{
public:
static std::shared_ptr<IndexBuffer> Create(uint32_t* indices,uint32_t count);
IndexBuffer(uint32_t* indices,uint32_t count);
~IndexBuffer(){};
void Bind() override;
void SetData(void* data,uint32_t size)override;
uint32_t GetCount()const {return m_Count;}
MTLIndexType GetIndexType()const {return MTLIndexTypeUInt32;}
private:
uint32_t m_Count=0;
};
}

@ -0,0 +1,43 @@
#include "IndexBuffer.h"
namespace MEL{
/////////////IndexBuffer////////////////////
std::shared_ptr<IndexBuffer> IndexBuffer::Create(uint32_t *indices, uint32_t count){
return std::make_shared<IndexBuffer>(indices,count);
}
IndexBuffer::IndexBuffer(uint32_t* indices,uint32_t count)
:Buffer(BufferType::Index, BufferUsage::Static),m_Count(count){
m_Size=count*sizeof(uint32_t);
auto renderer=Application::Get().GetRenderer();
id<MTLDevice> device=renderer->GetMetalDevice();
MTLResourceOptions options=MTLResourceStorageModeShared;
m_MetalBuffer=[device newBufferWithBytes:indices
length:m_Size
options:options];
if(m_MetalBuffer){
[m_MetalBuffer retain];
MEL_CORE_INFO("Created IndexBuffer:{} indices({} bytes)",count,m_Size);
}
else{
MEL_CORE_ERROR("Failed to create IndexBuffer:{} indices",count);
}
}
void IndexBuffer::Bind(){}//Index don't need to bind manually
void IndexBuffer::SetData(void *data, uint32_t size){
if(m_MetalBuffer)return;
if(size>m_Size){
MEL_CORE_WARN("IndexBuffer::SetData: size{} exceeds buffer capacity{}",size,m_Size);
return;
}
void* BufferContents=[m_MetalBuffer contents];
if(BufferContents&&data){
memcpy(BufferContents, data, size);
}
}
}

@ -0,0 +1,21 @@
#pragma once
#include<Metal/Metal.h>
#import "Buffer.h"
namespace MEL {
class VertexBuffer: public Buffer{
public:
static std::shared_ptr<VertexBuffer> Create(void *data, uint32_t size,BufferUsage usage=BufferUsage::Static);
static std::shared_ptr<VertexBuffer> Create(uint32_t size);
VertexBuffer(void* data,uint32_t size,BufferUsage usage);
void Bind() override;
void SetData(void *data, uint32_t size) override;
void SetSlot(uint32_t slot){m_Slot=slot;}
uint32_t GetSlot()const{return m_Slot;}
private:
uint32_t m_Slot=0;
};
}

@ -0,0 +1,63 @@
#include "VertexBuffer.h"
namespace MEL{
/////////////VertexBuffer////////////////////
std::shared_ptr<VertexBuffer> VertexBuffer::Create(void *data, uint32_t size,BufferUsage usage){
return std::make_shared<VertexBuffer>(data,size,usage);
}
std::shared_ptr<VertexBuffer> VertexBuffer::Create(uint32_t size){
return std::make_shared<VertexBuffer>(nullptr,size,BufferUsage::Dynamic);
}
VertexBuffer::VertexBuffer(void* data,uint32_t size,BufferUsage usage)
:Buffer(BufferType::Vertex, usage){
auto renderer=Application::Get().GetRenderer();
id<MTLDevice> device=renderer->GetMetalDevice();
MTLResourceOptions options=MTLResourceStorageModeShared;
if(data){
m_MetalBuffer=[device newBufferWithBytes:data
length:size
options:options];
}
else{
m_MetalBuffer=[device newBufferWithLength:size
options:options];
}
if(m_MetalBuffer){
[m_MetalBuffer retain];
MEL_CORE_INFO("Created VertexBuffer:{} bytes",size);
}
else{
MEL_CORE_ERROR("Failed to create VertexBuffer:{} bytes",size);
}
}
void VertexBuffer::Bind(){
auto renderer=Application::Get().GetRenderer();
id<MTLRenderCommandEncoder> encoder=renderer->GetCurrentEncoder();
if(encoder&&m_MetalBuffer){
[encoder setVertexBuffer:m_MetalBuffer
offset:0
atIndex:m_Slot];
}
}
void VertexBuffer::SetData(void *data, uint32_t size){
if(!m_MetalBuffer)return;
if(size>m_Size){
MEL_CORE_WARN("VertexBuffer::SetData: size{} exceeds buffer capacity{}",size,m_Size);
return;
}
void* BufferContents=[m_MetalBuffer contents];
if(BufferContents&&data){
memcpy(BufferContents, data, size);
}
}
}

@ -0,0 +1,11 @@
#import "melpch.h"
namespace MEL{
class Application;
}
@interface MELMTKViewDelegate : NSObject<MTKViewDelegate>
-(instancetype)initWithApplication:
(MEL::Application*)application;
@end

@ -0,0 +1,31 @@
#import "MTKViewDelegate.h"
#include "Application.h"
#include "Renderer/Renderer.h"
#include "Shader/Shader.h"
@implementation MELMTKViewDelegate{
MEL::Application* _application;
}
-(instancetype)initWithApplication:(MEL::Application*)application{
self=[super init];
if(self){
_application=application;
}
return self;
}
-(void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size{
MEL_CORE_INFO("Drawable Size Will change to:{}x{}",(int)size.width,(int)size.height);
if(_application&&_application->GetRenderer()){
_application->GetRenderer()->OnResize((uint32_t)size.width, (uint32_t)size.height);
}
}
-(void)drawInMTKView:(MTKView *)view{
if(!_application)return;
_application->RenderOneFrame();
}
@end

@ -1,8 +1,9 @@
#pragma once
#include "MEL.h"
#include "Shader/Shader.h"
#include "Log.h"
namespace MEL {
class VertexArray;
class Renderer{
public:
Renderer(MTKView* mtkview);
@ -12,15 +13,13 @@ namespace MEL {
void BeginScene();
void EndScene();
void EndFrame();
void DrawIndexed(uint32_t indexcount);
void CreatePipelineState();
void SetVertexBuffer(void* data,size_t size);
void SetIndexBuffer(uint32_t* indices,uint32_t count);
void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray);
void SetCurrentPipelineState(id<MTLRenderPipelineState> pipelineState);
void OnResize(uint32_t width,uint32_t height);
void SetupPipeline();
public:
void SetImGuiEnabled(bool enabled){m_ImGuiEnabled=enabled;};
bool IsImGuiEnabled(){return m_ImGuiEnabled;}
@ -30,6 +29,8 @@ namespace MEL {
public:
MTKView* GetMTKView(){return m_View;}
id<MTLDevice> GetMetalDevice(){return m_Device;}
id<MTLRenderCommandEncoder> GetCurrentEncoder(){return m_CurrentEncoder;}
void UpdateViewport();
private:
MTKView* m_View;
@ -37,14 +38,13 @@ namespace MEL {
id<MTLCommandQueue> m_CommandQueue;
id<MTLCommandBuffer> m_CommandBuffer;
id<MTLRenderCommandEncoder> m_CurrentEncoder;
id<MTLRenderPipelineState> m_CurrentPipeline;
id<MTLRenderPipelineState> m_CurrentPipeline=nil;
vector_uint2 m_ViewportSize;
id<MTLBuffer> m_VertexBuffer;
id<MTLBuffer> m_IndexBuffer;
bool m_FrameStarted;
bool is_default=true;
//imgui source
MTLViewport m_MTLViewportSize;
private:
bool m_ImGuiEnabled=false;
};

@ -3,13 +3,15 @@
#import "imgui_impl_metal.h"
#import "imgui_impl_osx.h"
#include "VertexArray/VertexArray.h"
#import "Buffer/VertexBuffer.h"
#import "Buffer/IndexBuffer.h"
namespace MEL{
Renderer::Renderer(MTKView* mtkview):
m_View(mtkview),
m_Device([mtkview device]),
m_CurrentPipeline(nullptr),
m_VertexBuffer(nil),
m_IndexBuffer(nil),
m_CommandBuffer(nullptr),
m_CurrentEncoder(nullptr)
{
@ -28,22 +30,32 @@ namespace MEL{
}
void Renderer::BeginFrame(){
m_CommandBuffer=[m_CommandQueue commandBuffer];
//debug mode
//MEL_CORE_INFO("====Begin Frame====");
if(!m_Device){
//MEL_CORE_ERROR("NO DEVICE");
return;
}
if(!m_CommandQueue){
//MEL_CORE_ERROR("No Command queue");
return;
}
//set viewport in this frame
m_ViewportSize={
(uint32_t)m_View.drawableSize.width,
(uint32_t)m_View.drawableSize.height
};
m_FrameStarted=true;
UpdateViewport();
m_CommandBuffer=[m_CommandQueue commandBuffer];
//MEL_CORE_INFO("Creates commandbuffer:{}",(void*)m_CommandBuffer);
}
void Renderer::BeginScene(){
if(!m_FrameStarted){
NSLog(@"Call BeginFrame() first");
return;
}
//create render pass descriptor
//debug mode
//MEL_CORE_INFO("----Begin Scene----");
//get render pass descriptor
MTLRenderPassDescriptor* renderPassDescriptor=m_View.currentRenderPassDescriptor;
//MEL_CORE_INFO("Descriptor{}",(void*)renderPassDescriptor);
if(renderPassDescriptor==nil){
NSLog(@"No renderpass");
[m_CommandBuffer commit];
@ -51,82 +63,82 @@ namespace MEL{
}
//create encoder for current scene
m_CurrentEncoder=[m_CommandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
//MEL_CORE_INFO("encoder{}",(void*)m_CurrentEncoder);
//set viewport and pipeline state
MTLViewport viewport={0,0,(double)m_ViewportSize.x,(double)m_ViewportSize.y,0,1};
[m_CurrentEncoder setViewport:viewport];
[m_CurrentEncoder setViewport:m_MTLViewportSize];
//MEL_CORE_INFO("encoder viewport{}x{}",m_MTLViewportSize.width,m_MTLViewportSize.height);
if(m_CurrentPipeline){
[m_CurrentEncoder setRenderPipelineState:m_CurrentPipeline];
//MEL_CORE_INFO("encoder pipeline set");
}
}
void Renderer::EndScene(){
[m_CurrentEncoder endEncoding];
m_CurrentEncoder=nullptr;
//m_CurrentEncoder=nullptr;
//MEL_CORE_INFO("----End Scene----");
}
void Renderer::EndFrame(){
if(!m_FrameStarted)return;
if(m_CommandBuffer){
[m_CommandBuffer presentDrawable:[m_View currentDrawable]];
//MEL_CORE_INFO("commandbuffer drawable{}",(void*)[m_View currentDrawable]);
[m_CommandBuffer commit];
//MEL_CORE_INFO("====End Frame====");
}
m_CommandBuffer=nullptr;
m_CurrentEncoder=nullptr;
m_FrameStarted=false;
}
void Renderer::DrawIndexed(uint32_t indexcount){
if(m_CurrentPipeline)
[m_CurrentEncoder setRenderPipelineState:m_CurrentPipeline];
void Renderer::DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray){
if(!vertexArray){
MEL_CORE_ERROR("No array");
return;
}
if(!m_CurrentEncoder){
MEL_CORE_ERROR("No encoder");
return;
}
vertexArray->Bind();
if(m_VertexBuffer)
[m_CurrentEncoder setVertexBuffer:m_VertexBuffer offset:0 atIndex:0];
bool using_auto_draw=true;
if(!using_auto_draw){
auto indexBuffer=vertexArray->GetIndexBuffer();
if(indexBuffer&&indexBuffer->GetBuffer()){
[m_CurrentEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:indexcount
indexCount:indexBuffer->GetCount()
indexType:MTLIndexTypeUInt32
indexBuffer:m_IndexBuffer
indexBuffer:indexBuffer->GetBuffer()
indexBufferOffset:0];
}
else{
[m_CurrentEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:indexcount];
auto vertexBuffers=vertexArray->GetVertexBuffers();
if(!vertexBuffers.empty()&&vertexBuffers[0]){
uint32_t vertexCount=vertexBuffers[0]->GetSize()/sizeof(float)/3;
[m_CurrentEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:vertexCount];
}
}
}
void Renderer::CreatePipelineState(){
id<MTLLibrary> defaultLibrary=[m_Device newDefaultLibrary];
NSError* error=nil;
if(!defaultLibrary){
NSLog(@"Failed to load Metal library: %@",error);
}
error=nil;
id<MTLFunction> vertexFunction=[defaultLibrary newFunctionWithName:@"vertexShader"];
id<MTLFunction> fragmentFunction=[defaultLibrary newFunctionWithName:@"fragmentShader"];
#pragma mark - Pipeline settings
void Renderer::SetCurrentPipelineState(id<MTLRenderPipelineState> pipelineState){
if(m_CurrentPipeline==pipelineState)return;
if(!vertexFunction || !fragmentFunction){
NSLog(@"Note:Custom shaders not found,only ImGui rendering will be available!");
return;
if(m_CurrentPipeline){
[m_CurrentPipeline release];
//MEL_CORE_INFO("release pipeline to create new");
}
MTLRenderPipelineDescriptor* pipeLineDescriptor=[[MTLRenderPipelineDescriptor alloc] init];
pipeLineDescriptor.vertexFunction=vertexFunction;
pipeLineDescriptor.fragmentFunction=fragmentFunction;
pipeLineDescriptor.colorAttachments[0].pixelFormat=MTLPixelFormatBGRA8Unorm;
m_CurrentPipeline=[m_Device newRenderPipelineStateWithDescriptor:pipeLineDescriptor
error:&error];
m_CurrentPipeline=[pipelineState retain];
//MEL_CORE_INFO("Pipeline retain{}",(void*)m_CurrentPipeline);
if(!m_CurrentPipeline){
NSLog(@"create pipeline state failed:%@",error);
if(m_CurrentEncoder&&m_CurrentPipeline){
[m_CurrentEncoder setRenderPipelineState:m_CurrentPipeline];
//MEL_CORE_INFO("encoder set pipeline");
}
}
@ -134,20 +146,22 @@ namespace MEL{
m_ViewportSize={width,height};
}
void Renderer::SetupPipeline(){
CreatePipelineState();
}
#pragma mark - ImGui Controll
void Renderer::BeginImGui(){
ImGuiIO& io=ImGui::GetIO();
io.DisplaySize=ImVec2(m_ViewportSize.x,m_ViewportSize.y);
//MEL_CORE_INFO("Set ImGui display size{},{}",io.DisplaySize.x,io.DisplaySize.y);
MTLRenderPassDescriptor* renderPassDescriptor=m_View.currentRenderPassDescriptor;
if(!renderPassDescriptor){
NSLog(@"no render pass descriptor");
return;
}
ImGui_ImplMetal_NewFrame(renderPassDescriptor);
ImGui_ImplOSX_NewFrame(m_View);
ImGui::NewFrame();
//MEL_CORE_INFO("ImGui new frame with pipe desc{}",(void*)renderPassDescriptor);
}
void Renderer::EndImGui(){
@ -159,21 +173,21 @@ namespace MEL{
ImDrawData* drawData=ImGui::GetDrawData();
ImGui_ImplMetal_RenderDrawData(drawData, m_CommandBuffer, m_CurrentEncoder);
MTLViewport viewport={0,0,(double)m_ViewportSize.x,(double)m_ViewportSize.y,0,1};
[m_CurrentEncoder setViewport:viewport];
}
#pragma mark - Buffer sets
void Renderer::SetVertexBuffer(void *data, size_t size){
is_default=false;
m_VertexBuffer=[m_Device newBufferWithBytes:data
length:size
options:MTLResourceStorageModeShared];
//MEL_CORE_INFO("ImGui draw with data{}",(void*)drawData);
}
void Renderer::SetIndexBuffer(uint32_t *indices, uint32_t count){
is_default=false;
m_IndexBuffer=[m_Device newBufferWithBytes:indices
length:count*sizeof(uint32_t)
options:MTLResourceStorageModeShared];
#pragma mark - Test methods
void Renderer::UpdateViewport(){
m_ViewportSize={
(uint32_t)m_View.currentRenderPassDescriptor.colorAttachments[0].texture.width,
(uint32_t)m_View.currentRenderPassDescriptor.colorAttachments[0].texture.height
};
m_MTLViewportSize={
0,0,
(double)m_ViewportSize.x,
(double)m_ViewportSize.y,
1,0
};
//MEL_CORE_INFO("Viewport size:{}x{}",(double)m_ViewportSize.x,(double)m_ViewportSize.y);
}
}

@ -2,28 +2,43 @@
#include "MEL.h"
#include<string>
#include<unordered_map>
namespace MEL{
class Shader{
public:
Shader(const std::string& name);
~Shader();
static std::shared_ptr<Shader>CreateFromSource(const std::string& name,const std::string& source);
static std::shared_ptr<Shader>CreateFromLibrary(const std::string& name,const std::string& librarypath);
static std::shared_ptr<Shader>CreateFromSource(const std::string& name,const std::string& source,
NSString* vertexFuncName,NSString* fragmentFuncName);
static std::shared_ptr<Shader>CreateFromLibrary(const std::string& name,const std::string& librarypath,
NSString* vertexFuncName,NSString* fragmentFuncName);
static std::shared_ptr<Shader>CreateFromDefaultLibrary(const std::string& name,
NSString* vertexFuncName,NSString* fragmentFuncName);
id<MTLFunction> GetVertexFunction()const {return m_VertexFunction;}
id<MTLFunction> GetIndexFunction()const {return m_FragmentFunction;}
id<MTLFunction> GetFragmentFunction()const {return m_FragmentFunction;}
const std::string& GetName(){return m_Name;}
bool CreatePipelineState();
id<MTLRenderPipelineState> GetPipelineState()const{return m_PipelineState;}
void Bind();
private:
Shader(const std::string& name);
bool LoadFromSource(const std::string& source);
bool LoadFromLibrary(const std::string& librarypath);
bool LoadFromSource(const std::string& source,
NSString* vertexFuncName,NSString* fragmentFuncName);
bool LoadFromLibrary(const std::string& librarypath,
NSString* vertexFuncName,NSString* fragmentFuncName);
bool LoadFromDefaultLibrary(NSString* vertexFuncName,NSString* fragmentFuncName);
private:
std::string m_Name;
id<MTLFunction> m_VertexFunction=nil;
id<MTLFunction> m_FragmentFunction=nil;
id<MTLLibrary> m_Library;
id<MTLRenderPipelineState> m_PipelineState=nil;
};
}

@ -3,20 +3,30 @@
namespace MEL{
Shader::Shader(const std::string& name):m_Name(name){
}
std::shared_ptr<Shader> Shader::CreateFromSource(const std::string& name, const std::string &source){
std::shared_ptr<Shader> Shader::CreateFromSource(const std::string& name, const std::string &source,
NSString* vertexFuncName,NSString* fragmentFuncName){
auto shader=std::make_shared<Shader>(name);
if(shader->LoadFromSource(source))
if(shader->LoadFromSource(source,vertexFuncName,fragmentFuncName))
return shader;
return nullptr;
}
std::shared_ptr<Shader> Shader::CreateFromLibrary(const std::string& name,const std::string& librarypath){
std::shared_ptr<Shader> Shader::CreateFromLibrary(const std::string& name,const std::string& librarypath,
NSString* vertexFuncName,NSString* fragmentFuncName){
auto shader=std::make_shared<Shader>(name);
if(shader->LoadFromLibrary(librarypath))
if(shader->LoadFromLibrary(librarypath,vertexFuncName,fragmentFuncName))
return shader;
return nullptr;
}
std::shared_ptr<Shader> Shader::CreateFromDefaultLibrary(const std::string& name,
NSString* vertexFuncName,NSString* fragmentFuncName){
auto shader=std::make_shared<Shader>(name);
if(shader->LoadFromDefaultLibrary(vertexFuncName,fragmentFuncName))
return shader;
return nullptr;
}
bool Shader::LoadFromSource(const std::string &source){
bool Shader::LoadFromSource(const std::string &source,
NSString* vertexFuncName,NSString* fragmentFuncName){
auto renderer=Application::Get().GetRenderer();
id<MTLDevice> device=renderer->GetMetalDevice();
@ -31,23 +41,120 @@ namespace MEL{
return false;
}
m_VertexFunction=[library newFunctionWithName:@"vertexShader"];
m_FragmentFunction=[library newFunctionWithName:@"fragmentShader"];
m_VertexFunction=[library newFunctionWithName:vertexFuncName];
m_FragmentFunction=[library newFunctionWithName:fragmentFuncName];
if(!m_VertexFunction||!m_FragmentFunction){
MEL_CORE_ERROR("No vertex or fragment function:{}",m_Name);
return false;
}
[library retain];
m_Library=library;
MEL_CORE_INFO("Shader from source:{}",m_Name);
return true;
}
bool Shader::LoadFromLibrary(const std::string &librarypath,
NSString* vertexFuncName,NSString* fragmentFuncName){
auto renderer=Application::Get().GetRenderer();
id<MTLDevice> device=renderer->GetMetalDevice();
NSError* error=nil;
NSString* path=[NSString stringWithUTF8String:librarypath.c_str()];
NSURL* libraryURL=[NSURL fileURLWithPath:path];
id<MTLLibrary> library=[device newLibraryWithURL:libraryURL
error:&error];
if(!library){
MEL_CORE_ERROR("Failed to load metallib {},{}",librarypath,[[error localizedDescription] UTF8String]);
return false;
}
m_VertexFunction=[library newFunctionWithName:vertexFuncName];
m_FragmentFunction=[library newFunctionWithName:fragmentFuncName];
if(!m_VertexFunction||!m_FragmentFunction){
MEL_CORE_ERROR("Metallib '{}' missing required functions",librarypath);
return false;
}
MEL_CORE_INFO("Load Shader from metlallib:{}",m_Name);
return true;
}
bool Shader::LoadFromDefaultLibrary(NSString* vertexFuncName,NSString* fragmentFuncName){
auto renderer=Application::Get().GetRenderer();
id<MTLDevice> device=renderer->GetMetalDevice();
id<MTLLibrary>defaultLibrary=[device newDefaultLibrary];
if(!defaultLibrary){
MEL_CORE_ERROR("Failed to load default library:{}",m_Name);
return false;
}
m_VertexFunction=[defaultLibrary newFunctionWithName:vertexFuncName];
m_FragmentFunction=[defaultLibrary newFunctionWithName:fragmentFuncName];
if(!m_VertexFunction||!m_FragmentFunction){
MEL_CORE_ERROR("Default library missing vertex or fragment function,only render imgui");
return false;
}
MEL_CORE_INFO("Load Shader from default library:{}",m_Name);
return true;
}
bool Shader::CreatePipelineState(){
auto renderer=Application::Get().GetRenderer();
id<MTLDevice> device=renderer->GetMetalDevice();
if(!m_VertexFunction||!m_FragmentFunction){
MEL_CORE_WARN("No shader function:{}",m_Name);
return false;
}
MTLRenderPipelineDescriptor* pipelineDescriptor=[[MTLRenderPipelineDescriptor alloc]init];
pipelineDescriptor.vertexFunction=m_VertexFunction;
pipelineDescriptor.fragmentFunction=m_FragmentFunction;
pipelineDescriptor.colorAttachments[0].pixelFormat=MTLPixelFormatBGRA8Unorm;
MTLVertexDescriptor* vertexDescriptor=[[MTLVertexDescriptor alloc]init];
vertexDescriptor.attributes[0].format=MTLVertexFormatFloat3;
vertexDescriptor.attributes[0].offset=0;
vertexDescriptor.attributes[0].bufferIndex=0;
vertexDescriptor.attributes[1].format=MTLVertexFormatFloat3;
vertexDescriptor.attributes[1].offset=12;
vertexDescriptor.attributes[1].bufferIndex=0;
vertexDescriptor.layouts[0].stride=24;
vertexDescriptor.layouts[0].stepFunction=MTLVertexStepFunctionPerVertex;
pipelineDescriptor.vertexDescriptor=vertexDescriptor;
NSError* error=nil;
m_PipelineState=[device newRenderPipelineStateWithDescriptor:pipelineDescriptor
error:&error];
//[pipelineDescriptor release];
if(!m_PipelineState){
MEL_CORE_ERROR("Failed to create pipeline state for shader:{},{}",m_Name,[[error localizedDescription]UTF8String]);
return false;
}
MEL_CORE_INFO("Create pipeline state for shader:{}",m_Name);
return true;
}
void Shader::Bind(){
auto renderer=Application::Get().GetRenderer();
renderer->SetCurrentPipelineState(m_PipelineState);
}
Shader::~Shader(){
//maybe auto release
if(m_VertexFunction)
[m_VertexFunction release];
if(m_FragmentFunction)
[m_FragmentFunction release];
}
}

@ -0,0 +1,29 @@
#pragma once
#include "Buffer/VertexBuffer.h"
#include "Buffer/IndexBuffer.h"
namespace MEL{
class VertexArray{
public:
static std::shared_ptr<VertexArray> Create();
VertexArray();
~VertexArray();
void Bind()const;
void Unbind()const;
void AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBuffer);
void SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer);
const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBuffers() const{return m_VertexBuffers;}
const std::shared_ptr<IndexBuffer>& GetIndexBuffer()const {return m_IndexBuffer;}
uint32_t GetIndexCount()const {return m_IndexBuffer?m_IndexBuffer->GetCount():0;}
private:
std::vector<std::shared_ptr<VertexBuffer>> m_VertexBuffers;
std::shared_ptr<IndexBuffer> m_IndexBuffer;
mutable uint32_t m_CurrentSlot;
};
}

@ -0,0 +1,52 @@
#include "VertexArray.h"
#include "Renderer.h"
namespace MEL{
std::shared_ptr<VertexArray> VertexArray::Create(){
return std::make_shared<VertexArray>();
}
VertexArray::VertexArray():m_CurrentSlot(0){
}
VertexArray::~VertexArray(){
}
void VertexArray::Bind() const{
auto renderer=Application::Get().GetRenderer();
id<MTLRenderCommandEncoder> encoder=renderer->GetCurrentEncoder();
if(!encoder){
MEL_CORE_WARN("VertexArray::Bind: No active render command encoder");
return;
}
m_CurrentSlot=0;
for(const auto& vertexBuffer:m_VertexBuffers){
if(vertexBuffer&&vertexBuffer->GetBuffer()){
[encoder setVertexBuffer:vertexBuffer->GetBuffer()
offset:0
atIndex:m_CurrentSlot];
m_CurrentSlot++;
}
}
}
void VertexArray::Unbind()const{
}
void VertexArray::AddVertexBuffer(const std::shared_ptr<VertexBuffer> &vertexBuffer){
if(vertexBuffer){
m_VertexBuffers.push_back(vertexBuffer);
MEL_CORE_INFO("VertexArray:Added vertex buffer at slot {}",m_VertexBuffers.size()-1);
}
}
void VertexArray::SetIndexBuffer(const std::shared_ptr<IndexBuffer> &indexBuffer){
m_IndexBuffer=indexBuffer;
if(indexBuffer){
MEL_CORE_INFO("VertexArray: Set index buffer with {} indices",indexBuffer->GetCount());
}
}
}

@ -45,11 +45,11 @@
#pragma mark - MTKViewDelegate
-(void)drawInMTKView:(MTKView *)view{
[_renderer drawInMTKView:view];
}
-(void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size{
[_renderer mtkView:view drawableSizeWillChange:size];
auto renderer=
}
*/
-(MTKView*)getMetalView{

@ -29,6 +29,7 @@ namespace MEL {
void Show()override;
virtual Renderer* GetRenderer()const override{return m_Renderer;}
private:
virtual void Init(const WindowProps& props);
virtual void ShutDown();

@ -24,6 +24,10 @@ public:
//MEL_INFO("testing update");
}
void OnAttach() override{
}
void OnEvent(MEL::Event& e) override{
MEL_INFO("testing event{0}",e.ToString());
}

Loading…
Cancel
Save