add render command queue

This commit is contained in:
2025-11-22 09:13:48 +08:00
parent 69bdaaec2e
commit 36f886b189
19 changed files with 616 additions and 43 deletions

View File

@ -32,10 +32,16 @@ set(LINK_LIBRARIES
if(WIN32)
list(APPEND LINK_LIBRARIES opengl32)
elseif(UNIX AND NOT APPLE)
list(APPEND LINK_LIBRARIES GL)
find_package(X11 REQUIRED)
list(APPEND LINK_LIBRARIES GL ${X11_LIBRARIES})
endif()
set(TARGET_INCLUDE_DIR
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
${IMGUI_DIR}
)
# static library
set(STATIC_LIBRARY ${PROJECT_NAME}-static)
@ -47,8 +53,7 @@ target_compile_definitions(${STATIC_LIBRARY} PRIVATE
)
target_include_directories(${STATIC_LIBRARY} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
${TARGET_INCLUDE_DIR}
)
target_link_libraries(${STATIC_LIBRARY} PRIVATE
${LINK_LIBRARIES}
@ -73,7 +78,7 @@ target_compile_definitions(${SHARED_LIBRARY} PRIVATE
)
target_include_directories(${SHARED_LIBRARY} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
${TARGET_INCLUDE_DIR}
)
target_link_libraries(${SHARED_LIBRARY} PRIVATE
${LINK_LIBRARIES}

View File

@ -12,6 +12,7 @@
#include "Prism/Core/Events/Event.h"
#include "Prism/Core/Events/KeyEvent.h"
#include "Prism/Core/Events/MouseEvent.h"
#include "Prism/Renderer/Renderer.h"
#endif //PRISM_H

View File

@ -6,6 +6,7 @@
#include "Application.h"
#include "glad/glad.h"
#include "Prism/Renderer/Renderer.h"
namespace Prism
@ -25,6 +26,9 @@ namespace Prism
m_Window = std::unique_ptr<Window>(Window::Create());
m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
m_ImGuiLayer = new ImGuiLayer("ImGui Layer");
PushOverlay(m_ImGuiLayer);
}
Application::~Application()
@ -37,12 +41,14 @@ namespace Prism
while (m_Running)
{
glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
for (Layer* layer : m_LayerStack)
layer->OnUpdate();
Application* app = this;
PM_RENDER_1(app, { app->RenderImGui(); });
Renderer::Get().WaitAndRender();
m_Window->OnUpdate();
}
@ -62,6 +68,14 @@ namespace Prism
}
}
void Application::RenderImGui()
{
m_ImGuiLayer->Begin();
for (Layer* layer : m_LayerStack)
layer->OnImGuiRender();
m_ImGuiLayer->End();
}
void Application::PushLayer(Layer* layer)
{
m_LayerStack.PushLayer(layer);

View File

@ -8,6 +8,7 @@
#include "LayerStack.h"
#include "Window.h"
#include "Events/ApplicationEvent.h"
#include "ImGui/ImGuiLayer.h"
namespace Prism
{
@ -25,6 +26,8 @@ namespace Prism
virtual void OnEvent(Event& e);
void RenderImGui();
inline Window& GetWindow() { return *m_Window; }
inline static Application& Get() { return *s_Instance; }
@ -40,6 +43,7 @@ namespace Prism
bool m_Running = true;
LayerStack m_LayerStack;
ImGuiLayer* m_ImGuiLayer;
static Application* s_Instance;
};

View File

@ -11,8 +11,17 @@
#else
#define PRISM_API __declspec(dllimport)
#endif
// ImGui
#ifdef BUILD_PRISM_DLL
#define IMGUI_API __declspec(dllexport)
#else
#define IMGUI_API __declspec(dllimport)
#endif
#else
#define PRISM_API
#define IMGUI_API
#endif
#define BIT(x) (1 << x)
@ -32,5 +41,10 @@
#define PM_CORE_ASSERT(x, ...)
#endif
namespace Prism
{
using byte = unsigned char;
}
#endif //CORE_H

View File

@ -4,7 +4,6 @@
#include "ImGuiLayer.h"
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_glfw.h"
#include "GLFW/glfw3.h"
@ -28,6 +27,32 @@ namespace Prism
{
}
void ImGuiLayer::Begin()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void ImGuiLayer::End()
{
ImGuiIO& io = ImGui::GetIO();
Application& app = Application::Get();
io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
// Rendering
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
}
void ImGuiLayer::OnAttach()
{
// Setup Dear ImGui context
@ -54,7 +79,7 @@ namespace Prism
}
Application& app = Application::Get();
GLFWwindow* window = (GLFWwindow*)app.GetWindow().GetNativeWindow();
const auto window = static_cast<GLFWwindow*>(app.GetWindow().GetNativeWindow());
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
@ -69,31 +94,8 @@ namespace Prism
ImGui::DestroyContext();
}
void ImGuiLayer::OnUpdate()
void ImGuiLayer::OnImGuiRender()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
static bool show_demo_window = true;
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
ImGuiIO& io = ImGui::GetIO();
Application& app = Application::Get();
io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
// Rendering
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
}
}

View File

@ -5,10 +5,9 @@
#ifndef IMGUILAYER_H
#define IMGUILAYER_H
#include "imgui.h"
#include "Prism/Core/Layer.h"
#include "Prism/Core/Events/ApplicationEvent.h"
#include "Prism/Core/Events/KeyEvent.h"
#include "Prism/Core/Events/MouseEvent.h"
namespace Prism
{
@ -17,12 +16,14 @@ namespace Prism
public:
ImGuiLayer();
explicit ImGuiLayer(const std::string& name);
virtual ~ImGuiLayer() override;
void Begin();
void End();
virtual void OnAttach() override;
virtual void OnDetach() override;
virtual void OnUpdate() override;
virtual void OnImGuiRender() override;
private:
float m_Time = 0.0f;

View File

@ -19,6 +19,7 @@ namespace Prism
virtual void OnAttach() {}
virtual void OnDetach() {}
virtual void OnUpdate() {}
virtual void OnImGuiRender() {}
virtual void OnEvent(Event& e) {}
inline const std::string& GetName() const { return m_DebugName; }

View File

@ -10,7 +10,6 @@ namespace Prism
{
LayerStack::LayerStack()
{
m_LayerIterator = m_Layers.begin();
}
LayerStack::~LayerStack()
@ -21,7 +20,8 @@ namespace Prism
void LayerStack::PushLayer(Layer* layer)
{
m_LayerIterator = m_Layers.emplace(m_LayerIterator, layer);
m_Layers.emplace(m_Layers.begin() + m_LayerInsertIndex, layer);
m_LayerInsertIndex++;
}
void LayerStack::PushOverlay(Layer* layer)
@ -35,7 +35,7 @@ namespace Prism
if (it != m_Layers.end())
{
m_Layers.erase(it);
m_LayerIterator--;
m_LayerInsertIndex--;
}
}

View File

@ -25,7 +25,7 @@ namespace Prism
std::vector<Layer*>::iterator end() { return m_Layers.end(); }
private:
std::vector<Layer*> m_Layers;
std::vector<Layer*>::iterator m_LayerIterator;
unsigned int m_LayerInsertIndex = 0;
};
}

View File

@ -0,0 +1,24 @@
//
// Created by sfd on 25-11-21.
//
#include "Prism/Renderer/RendererAPI.h"
#include "glad/glad.h"
namespace Prism
{
void RendererAPI::Clear(const float r, const float g, const float b, const float a)
{
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void RendererAPI::SetClearColor(const float r, const float g, const float b, const float a)
{
glClearColor(r, g, b, a);
}
}

View File

@ -0,0 +1,61 @@
//
// Created by sfd on 25-11-21.
//
#include "RenderCommandQueue.h"
#include "Prism/Core/Core.h"
#include "Prism/Core/Log.h"
#define PM_RENDER_TRACE(...) PM_CORE_TRACE(__VA_ARGS__)
namespace Prism
{
RenderCommandQueue::RenderCommandQueue()
{
m_CommandBuffer = new unsigned char[10 * 1024 * 1024]; // 10mb buffer
m_CommandBufferPtr = m_CommandBuffer;
memset(m_CommandBuffer, 0, 10 * 1024 * 1024);
}
RenderCommandQueue::~RenderCommandQueue()
{
delete[] m_CommandBuffer;
}
void* RenderCommandQueue::Allocate(RenderCommandFn func, unsigned int size)
{
*(RenderCommandFn*)m_CommandBufferPtr = func;
m_CommandBufferPtr += sizeof(RenderCommandFn);
*(int*)m_CommandBufferPtr = size;
m_CommandBufferPtr += sizeof(unsigned int);
void* memory = m_CommandBufferPtr;
m_CommandBufferPtr += size;
m_CommandCount ++;
return memory;
}
void RenderCommandQueue::Execute()
{
PM_RENDER_TRACE("RenderCommandQueue::Execute -- {0} commands, {1} bytes", m_CommandCount, (m_CommandBufferPtr - m_CommandBuffer));
byte* buffer = m_CommandBuffer;
for (unsigned i = 0 ; i < m_CommandCount ; i++)
{
RenderCommandFn function = *(RenderCommandFn*)(buffer);
buffer += sizeof(RenderCommandFn);
unsigned int size = *(unsigned int*)buffer;
buffer += sizeof(unsigned int);
function(buffer);
buffer += size;
}
m_CommandBufferPtr = m_CommandBuffer;
m_CommandCount = 0;
}
}

View File

@ -0,0 +1,30 @@
//
// Created by sfd on 25-11-21.
//
#ifndef RENDERCOMMANDQUEUE_H
#define RENDERCOMMANDQUEUE_H
#include <functional>
namespace Prism
{
class PRISM_API RenderCommandQueue
{
public:
typedef void(*RenderCommandFn)(void*);
RenderCommandQueue();
~RenderCommandQueue();
void* Allocate(RenderCommandFn func, unsigned int size);
void Execute();
private:
unsigned char* m_CommandBuffer = nullptr;
unsigned char* m_CommandBufferPtr = nullptr;
unsigned int m_CommandCount = 0;
};
}
#endif //RENDERCOMMANDQUEUE_H

View File

@ -0,0 +1,43 @@
//
// Created by sfd on 25-11-21.
//
#include "Renderer.h"
#include "RendererAPI.h"
namespace Prism
{
Renderer* Renderer::s_Instance = new Renderer();
void Renderer::Clear()
{
}
void Renderer::Clear(float r, float g, float b, float a)
{
PM_RENDER_4(r, g, b, a, {
RendererAPI::Clear(r, g, b, a);
});
}
void Renderer::SetClearColor(float r, float g, float b, float a)
{
}
void Renderer::ClearMagenta()
{
Clear(1, 0, 1);
}
void Renderer::Init()
{
s_Instance = new Renderer();
}
void Renderer::WaitAndRender()
{
s_Instance->m_CommandQueue.Execute();
}
}

View File

@ -0,0 +1,155 @@
//
// Created by sfd on 25-11-21.
//
#ifndef RENDERER_H
#define RENDERER_H
#include "RenderCommandQueue.h"
#include "Prism/Core/Application.h"
namespace Prism
{
class PRISM_API Renderer
{
public:
typedef void(*RenderCommandFn)(void*);
static void Clear();
static void Clear(float r, float g, float b, float a = 1.0f);
static void SetClearColor(float r, float g, float b, float a);
// test
static void ClearMagenta();
void Init();
static void* Submit(const RenderCommandFn func, const unsigned int size)
{
return s_Instance->m_CommandQueue.Allocate(func, size);
}
void WaitAndRender();
inline static Renderer& Get() { return *s_Instance; }
private:
static Renderer* s_Instance;
// static inline Renderer* s_Instance = nullptr;
RenderCommandQueue m_CommandQueue;
};
#define PM_RENDER_PASTE2(a, b) a ## b
#define PM_RENDER_PASTE(a, b) PM_RENDER_PASTE2(a, b)
#define PM_RENDER_UNIQUE(x) PM_RENDER_PASTE(x, __LINE__)
#define PM_RENDER(code) \
struct PM_RENDER_UNIQUE(PMRenderCommand) \
{\
static void Execute(void*)\
{\
code\
}\
};\
{\
auto mem = RenderCommandQueue::Submit(sizeof(PM_RENDER_UNIQUE(PMRenderCommand)), PM_RENDER_UNIQUE(PMRenderCommand)::Execute);\
new (mem) PM_RENDER_UNIQUE(PMRenderCommand)();\
}\
#define PM_RENDER_1(arg0, code) \
do{\
struct PM_RENDER_UNIQUE(PMRenderCommand) \
{\
PM_RENDER_UNIQUE(PMRenderCommand)(typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type arg0) \
: m_arg0(arg0) {}\
\
static void Execute(void* self)\
{\
auto& arg0 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg0;\
code\
}\
\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type m_arg0;\
};\
{\
auto mem = ::Prism::Renderer::Submit(PM_RENDER_UNIQUE(PMRenderCommand)::Execute, sizeof(PM_RENDER_UNIQUE(PMRenderCommand)));\
new (mem) PM_RENDER_UNIQUE(PMRenderCommand)(arg0);\
} } while(0)
#define PM_RENDER_2(arg0, arg1, code) \
struct PM_RENDER_UNIQUE(PMRenderCommand) \
{\
PM_RENDER_UNIQUE(PMRenderCommand)(typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type arg0,\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg1)>::type>::type arg1) \
: m_arg0(arg0), m_arg1(arg1) {}\
\
static void Execute(void* self)\
{\
auto& arg0 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg0;\
auto& arg1 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg1;\
code\
}\
\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type m_arg0;\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg1)>::type>::type m_arg1;\
};\
{\
auto mem = ::Prism::Renderer::Submit(PM_RENDER_UNIQUE(PMRenderCommand)::Execute, sizeof(PM_RENDER_UNIQUE(PMRenderCommand)));\
new (mem) PM_RENDER_UNIQUE(PMRenderCommand)(arg0, arg1);\
}\
#define PM_RENDER_3(arg0, arg1, arg2, code) \
struct PM_RENDER_UNIQUE(PMRenderCommand) \
{\
PM_RENDER_UNIQUE(PMRenderCommand)(typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type arg0,\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg1)>::type>::type arg1,\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg2)>::type>::type arg2) \
: m_arg0(arg0), m_arg1(arg1), m_arg2(arg2) {}\
\
static void Execute(void* self)\
{\
auto& arg0 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg0;\
auto& arg1 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg1;\
auto& arg2 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg2;\
code\
}\
\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type m_arg0;\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg1)>::type>::type m_arg1;\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg2)>::type>::type m_arg2;\
};\
{\
auto mem = ::Prism::Renderer::Submit(PM_RENDER_UNIQUE(PMRenderCommand)::Execute, sizeof(PM_RENDER_UNIQUE(PMRenderCommand)));\
new (mem) PM_RENDER_UNIQUE(PMRenderCommand)(arg0, arg1, arg2);\
}\
#define PM_RENDER_4(arg0, arg1, arg2, arg3, code) \
struct PM_RENDER_UNIQUE(PMRenderCommand) \
{\
PM_RENDER_UNIQUE(PMRenderCommand)(typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type arg0,\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg1)>::type>::type arg1,\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg2)>::type>::type arg2,\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg3)>::type>::type arg3)\
: m_arg0(arg0), m_arg1(arg1), m_arg2(arg2), m_arg3(arg3) {}\
\
static void Execute(void* self)\
{\
auto& arg0 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg0;\
auto& arg1 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg1;\
auto& arg2 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg2;\
auto& arg3 = ((PM_RENDER_UNIQUE(PMRenderCommand)*)self)->m_arg3;\
code\
}\
\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg0)>::type>::type m_arg0;\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg1)>::type>::type m_arg1;\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg2)>::type>::type m_arg2;\
typename ::std::remove_const<typename ::std::remove_reference<decltype(arg3)>::type>::type m_arg3;\
};\
{\
auto mem = ::Prism::Renderer::Submit(PM_RENDER_UNIQUE(PMRenderCommand)::Execute, sizeof(PM_RENDER_UNIQUE(PMRenderCommand)));\
new (mem) PM_RENDER_UNIQUE(PMRenderCommand)(arg0, arg1, arg2, arg3);\
}
}
#endif //RENDERER_H

View File

@ -0,0 +1,18 @@
//
// Created by sfd on 25-11-21.
//
#ifndef RENDERERAPI_H
#define RENDERERAPI_H
namespace Prism
{
class PRISM_API RendererAPI
{
public:
static void Clear(float r, float g, float b, float a);
static void SetClearColor(float r, float g, float b, float a);
};
}
#endif //RENDERERAPI_H