diff --git a/core/application/application.h b/core/application/application.h index 0589b84..5378ff4 100644 --- a/core/application/application.h +++ b/core/application/application.h @@ -51,6 +51,9 @@ public: std::shared_ptr load_texture(const std::string& path) const; std::shared_ptr create_texture(const unsigned char* data, const int width, const int height) const; std::shared_ptr create_render_target(const int width, const int height, texture_format format) const; + + virtual const char* get_entry_model() const = 0; + virtual const char* get_draw_ps_vertex_shader_entry() const = 0; // Vertex Shader used for drawing ps renderer* get_renderer() const { return renderer_; } SDL_Window* get_window() const { return window_; } diff --git a/core/extern.h b/core/extern.h index 56378d0..41ac802 100644 --- a/core/extern.h +++ b/core/extern.h @@ -8,3 +8,4 @@ #else #define CORE_API __declspec(dllimport) #endif + diff --git a/core/misc/scope_exit.h b/core/misc/scope_exit.h new file mode 100644 index 0000000..de217cd --- /dev/null +++ b/core/misc/scope_exit.h @@ -0,0 +1,71 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +namespace scope_exit_support +{ + /** + * Not meant for direct consumption : use ON_SCOPE_EXIT instead. + * + * RAII class that calls a lambda when it is destroyed. + */ + template + class scope_guard + { + scope_guard(scope_guard&&) = delete; + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + + public: + // Given a lambda, constructs an RAII scope guard. + explicit scope_guard(FuncType&& InFunc) + : func_((FuncType&&)InFunc) + { + } + + // Causes the lambda to be executed. + ~scope_guard() + { + func_(); + } + + private: + // The lambda to be executed when this guard goes out of scope. + FuncType func_; + }; + + struct scope_guard_syntax_support + { + template + scope_guard operator+(FuncType&& in_func) + { + return scope_guard((FuncType&&)in_func); + } + }; +} + +#define UE_PRIVATE_SCOPE_EXIT_JOIN_INNER(A, B) A##B +#define UE_PRIVATE_SCOPE_EXIT_JOIN(A, B) UE_PRIVATE_SCOPE_EXIT_JOIN_INNER(A, B) + +/** + * Enables a lambda to be executed on scope exit. + * + * Example: + * { + * FileHandle* Handle = GetFileHandle(); + * ON_SCOPE_EXIT + * { + * CloseFile(Handle); + * }; + * + * DoSomethingWithFile( Handle ); + * + * // File will be closed automatically no matter how the scope is exited, e.g.: + * // * Any return statement. + * // * break or continue (if the scope is a loop body). + * // * An exception is thrown outside the block. + * // * Execution reaches the end of the block. + * } + */ +#define ON_SCOPE_EXIT const auto UE_PRIVATE_SCOPE_EXIT_JOIN(ScopeGuard_, __LINE__) = ::scope_exit_support::scope_guard_syntax_support() + [&]() diff --git a/core/rhi/opengl/renderer_opengl.cpp b/core/rhi/opengl/renderer_opengl.cpp index 15f2b0c..e3b7c15 100644 --- a/core/rhi/opengl/renderer_opengl.cpp +++ b/core/rhi/opengl/renderer_opengl.cpp @@ -86,10 +86,10 @@ Slang::ComPtr renderer_opengl::create_slang_session(const std:: return out; } -std::shared_ptr renderer_opengl::load_shader(const std::string& module_name, const std::string& entry_name) +std::shared_ptr renderer_opengl::load_shader(const std::string& entry_name) { auto handle = std::make_shared(); - if (!handle->init_slang_module(module_name, entry_name)) + if (!handle->init_slang_module(application::get()->get_entry_model(), entry_name)) return nullptr; const auto shader_type = handle->get_shader_type(); std::shared_ptr out; diff --git a/core/rhi/opengl/renderer_opengl.h b/core/rhi/opengl/renderer_opengl.h index 37ce9f2..047772a 100644 --- a/core/rhi/opengl/renderer_opengl.h +++ b/core/rhi/opengl/renderer_opengl.h @@ -10,7 +10,7 @@ public: void shutdown() override; Slang::ComPtr create_slang_session(const std::string& shader_path) override; - std::shared_ptr load_shader(const std::string& module_name, const std::string& entry_name) override; + std::shared_ptr load_shader(const std::string& entry_name) override; void new_frame(SDL_Window* window_handle) override; void end_frame(SDL_Window* window_handle) override; diff --git a/core/rhi/renderer.cpp b/core/rhi/renderer.cpp index 1915444..f8d9350 100644 --- a/core/rhi/renderer.cpp +++ b/core/rhi/renderer.cpp @@ -1,6 +1,15 @@ #include "renderer.h" +#include "application/application.h" + void renderer::init_slang(const std::string& shader_path) { session_ = create_slang_session(shader_path); } + +std::shared_ptr renderer::get_pixel_shader_render_default_vs() +{ + if (!default_vs_) + default_vs_ = load_shader(application::get()->get_draw_ps_vertex_shader_entry()); + return default_vs_; +} diff --git a/core/rhi/renderer.h b/core/rhi/renderer.h index 80c80aa..d9677af 100644 --- a/core/rhi/renderer.h +++ b/core/rhi/renderer.h @@ -21,7 +21,8 @@ public: void init_slang(const std::string& shader_path); virtual Slang::ComPtr create_slang_session(const std::string& shader_path) = 0; virtual Slang::ComPtr get_slang_session() { return session_; } - virtual std::shared_ptr load_shader(const std::string& module_name, const std::string& entry_name) = 0; + virtual std::shared_ptr load_shader(const std::string& entry_name) = 0; + virtual std::shared_ptr get_pixel_shader_render_default_vs(); virtual void new_frame(SDL_Window* window_handle) = 0; virtual void end_frame(SDL_Window* window_handle) = 0; @@ -33,5 +34,6 @@ public: void set_vsync(const bool vsync) { vsync_ = vsync; } protected: Slang::ComPtr session_; + std::shared_ptr default_vs_; bool vsync_ = true; }; diff --git a/core/rhi/shader.h b/core/rhi/shader.h index d6c79a9..76f930e 100644 --- a/core/rhi/shader.h +++ b/core/rhi/shader.h @@ -13,11 +13,11 @@ public: virtual bool init() { return false; } [[nodiscard]] virtual bool is_initialized() const = 0; [[nodiscard]] virtual bool is_valid() const { return handle_ != nullptr && is_initialized(); } - + virtual void bind() = 0; virtual void unbind() = 0; virtual void compute(int x, int y, int z) {} - virtual void draw(int width, int height) {} + virtual void draw(int width, int height, std::shared_ptr in_vertex_shader = nullptr) {} // param setters virtual void set_constant_buffer(const char* name, void* buffer, int size) = 0; diff --git a/core/rhi/slang_handle.cpp b/core/rhi/slang_handle.cpp index 783e603..9a92580 100644 --- a/core/rhi/slang_handle.cpp +++ b/core/rhi/slang_handle.cpp @@ -21,7 +21,7 @@ bool slang_handle::init_slang_module(const std::string& module_name, const std:: auto r = module->findEntryPointByName(entry_name.c_str(), entry_point.writeRef()); if (r != SLANG_OK) { - spdlog::error("slang: can't find entry point \"{}\"", entry_name.c_str()); + spdlog::error("slang: can't find entry point \"{}\": {}", entry_name.c_str(), r); return false; } @@ -49,16 +49,6 @@ bool slang_handle::init_slang_module(const std::string& module_name, const std:: #if _DEBUG spdlog::info("slang: shader type: {}", shader_type_); - spdlog::info("================parameters================"); - - for (int i = 0; i < layout->getParameterCount(); ++i) - { - slang::VariableLayoutReflection* reflection = layout->getParameterByIndex(i); - const auto type_reflection = reflection->getTypeLayout()->getType(); - - spdlog::info("{} {} {}; ", i, type_reflection->getName(), reflection->getName()); - } - spdlog::info("================parameters================"); #endif spdlog::info("slang: init slang handle successfully"); diff --git a/core/rhi/windows/dx11/renderer_dx11.cpp b/core/rhi/windows/dx11/renderer_dx11.cpp index 86dd808..b252eef 100644 --- a/core/rhi/windows/dx11/renderer_dx11.cpp +++ b/core/rhi/windows/dx11/renderer_dx11.cpp @@ -74,10 +74,10 @@ Slang::ComPtr renderer_dx11::create_slang_session(const std::st return out; } -std::shared_ptr renderer_dx11::load_shader(const std::string& module_name, const std::string& entry_name) +std::shared_ptr renderer_dx11::load_shader(const std::string& entry_name) { auto handle = std::make_shared(); - if (!handle->init_slang_module(module_name, entry_name)) + if (!handle->init_slang_module(application::get()->get_entry_model(), entry_name)) return nullptr; const auto shader_type = handle->get_shader_type(); diff --git a/core/rhi/windows/dx11/renderer_dx11.h b/core/rhi/windows/dx11/renderer_dx11.h index edfe4a6..97dbd79 100644 --- a/core/rhi/windows/dx11/renderer_dx11.h +++ b/core/rhi/windows/dx11/renderer_dx11.h @@ -7,6 +7,7 @@ #include "slang-com-ptr.h" #include "slang.h" +class shader_vs_dx11; extern ref_count_ptr g_d3d11_device; extern ref_count_ptr g_d3d11_device_context; extern ref_count_ptr g_d3d11_swap_chain; @@ -20,7 +21,7 @@ public: void shutdown() override; Slang::ComPtr create_slang_session(const std::string& shader_path) override; - std::shared_ptr load_shader(const std::string& module_name, const std::string& entry_name) override; + std::shared_ptr load_shader(const std::string& entry_name) override; void new_frame(SDL_Window* window_handle) override; void end_frame(SDL_Window* window_handle) override; diff --git a/core/rhi/windows/dx11/shader/shader_cs_dx11.cpp b/core/rhi/windows/dx11/shader/shader_cs_dx11.cpp index 422bc15..54f335f 100644 --- a/core/rhi/windows/dx11/shader/shader_cs_dx11.cpp +++ b/core/rhi/windows/dx11/shader/shader_cs_dx11.cpp @@ -93,6 +93,7 @@ void shader_cs_dx11::set_uav_buffer(const char* name, void* buffer, int size, in return; } find->second->set_buffer_data(buffer, size); + find->second->update_buffer(); } void shader_cs_dx11::set_render_target(const char* name, std::shared_ptr in_render_target) @@ -108,18 +109,9 @@ void shader_cs_dx11::set_render_target(const char* name, std::shared_ptr(cmd->UserCallbackData); - data->cs->bind(); - g_d3d11_device_context->Dispatch(data->x, data->y, data->z); - data->cs->unbind(); -} - void shader_cs_dx11::compute(int x, int y, int z) { - cs_data.x = x; - cs_data.y = y; - cs_data.z = z; - ImGui::GetWindowDrawList()->AddCallback(cs_dx11_compute_callback, &cs_data); + bind(); + g_d3d11_device_context->Dispatch(x, y, z); + unbind(); } diff --git a/core/rhi/windows/dx11/shader/shader_cs_dx11.h b/core/rhi/windows/dx11/shader/shader_cs_dx11.h index 4e49759..af9f04d 100644 --- a/core/rhi/windows/dx11/shader/shader_cs_dx11.h +++ b/core/rhi/windows/dx11/shader/shader_cs_dx11.h @@ -6,7 +6,7 @@ class shader_cs_dx11 : public shader_dx11 { public: explicit shader_cs_dx11(const std::shared_ptr& handle) - : shader_dx11(handle), cs_data({ this, 0, 0, 0 }) + : shader_dx11(handle) { } @@ -22,14 +22,6 @@ public: void set_render_target(const char* name, std::shared_ptr in_render_target) override; void compute(int x, int y, int z) override; - - struct dx11_cs_data - { - shader_cs_dx11* cs; - int x; - int y; - int z; - } cs_data; private: std::map> uav_buffers_; diff --git a/core/rhi/windows/dx11/shader/shader_dx11.cpp b/core/rhi/windows/dx11/shader/shader_dx11.cpp index 91d8db4..5121188 100644 --- a/core/rhi/windows/dx11/shader/shader_dx11.cpp +++ b/core/rhi/windows/dx11/shader/shader_dx11.cpp @@ -76,6 +76,7 @@ void shader_dx11::set_constant_buffer(const char* name, void* buffer, int size) find = constant_buffers_.find(name); } find->second->set_buffer_data(buffer); + find->second->update_buffer(); } void shader_dx11::set_texture(const char* name, std::shared_ptr in_texture) diff --git a/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp b/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp index ae179b6..de16d55 100644 --- a/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp +++ b/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp @@ -3,7 +3,10 @@ #include #include "constant_buffer_dx11.h" +#include "imgui_internal.h" #include "uav_buffer_dx11.h" +#include "application/application.h" +#include "misc/scope_exit.h" #include "rhi/windows/dx11/renderer_dx11.h" #include "rhi/windows/dx11/render_target_dx11.h" #include "rhi/windows/dx11/texture_dx11.h" @@ -63,3 +66,130 @@ HRESULT shader_ps_dx11::create_shader(ID3DBlob* blob, ID3D11Device* device) { return device->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, pixel_shader_.writeRef()); } + +void ps_dx11_compute_callback(const ImDrawList* parent_list, const ImDrawCmd* cmd) +{ + shader_ps_dx11::ps_data* data = (shader_ps_dx11::ps_data*)cmd->UserCallbackData; + auto& ps = data->ps; + auto& vertex_buffer = data->vertex_buffer; + auto& render_target = data->render_target; + auto& index_buffer = data->index_buffer; + auto vertex_shader = data->vertex_shader.lock(); + const int width = render_target->get_width(); + const int height = render_target->get_height(); + + D3D11_MAPPED_SUBRESOURCE vtx_resource; + ID3D11Buffer* vb = vertex_buffer; + if (g_d3d11_device_context->Map(vb, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) + return; + ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; + vtx_dst[0].pos = ImVec2(0, 0); + vtx_dst[0].uv = ImVec2(0, 0); + vtx_dst[0].col = 0xffffffff; + + vtx_dst[1].pos = ImVec2(width, 0); + vtx_dst[1].uv = ImVec2(1, 0); + vtx_dst[1].col = 0xffffffff; + + vtx_dst[2].pos = ImVec2(width, height); + vtx_dst[2].uv = ImVec2(1, 1); + vtx_dst[2].col = 0xffffffff; + + vtx_dst[3].pos = ImVec2(0, height); + vtx_dst[3].uv = ImVec2(0, 1); + vtx_dst[3].col = 0xffffffff; + g_d3d11_device_context->Unmap(vb, 0); + + const auto target_rtv = render_target->get_render_target_view().get_reference(); + g_d3d11_device_context->OMSetRenderTargets(1, &target_rtv, nullptr); + + g_d3d11_device_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + D3D11_VIEWPORT vp = {}; + vp.Width = width; + vp.Height = height; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = vp.TopLeftY = 0; + g_d3d11_device_context->RSSetViewports(1, &vp); + + vertex_shader->bind(); + + const unsigned int stride = sizeof(ImDrawVert); + const unsigned int offset = 0; + g_d3d11_device_context->IASetVertexBuffers(0, 1, &vb, &stride, &offset); + g_d3d11_device_context->IASetIndexBuffer(index_buffer, DXGI_FORMAT_R16_UINT, 0); + + // setup new scissors + D3D11_RECT new_scissors; + new_scissors.left = 0; + new_scissors.right = width; + new_scissors.top = 0; + new_scissors.bottom = height; + g_d3d11_device_context->RSSetScissorRects(1, &new_scissors); + + ps->bind(); + g_d3d11_device_context->DrawIndexed(6, 0, 0); + vertex_shader->unbind(); + ps->unbind(); + + ID3D11RenderTargetView* main_render_target = g_main_render_target_view.get_reference(); + g_d3d11_device_context->OMSetRenderTargets(1, &main_render_target, nullptr); +} + +void shader_ps_dx11::draw(int width, int height, std::shared_ptr in_vertex_shader) +{ + if (!draw_data.initialized) + { + draw_data.ps = this; + { + draw_data.render_target = std::static_pointer_cast(application::get()->create_render_target(width, height, texture_format::RGBA8)); + } + { + D3D11_BUFFER_DESC desc = {}; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.ByteWidth = sizeof(ImDrawVert) * 4; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + g_d3d11_device->CreateBuffer(&desc, nullptr, draw_data.vertex_buffer.get_init_reference()); + } + { + D3D11_BUFFER_DESC desc = {}; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.ByteWidth = sizeof(ImDrawIdx) * 6; + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + g_d3d11_device->CreateBuffer(&desc, nullptr, draw_data.index_buffer.get_init_reference()); + + // init index buffer + const ImDrawIdx indices[] = { 0, 1, 2, 0, 2, 3 }; + D3D11_MAPPED_SUBRESOURCE index_resource; + g_d3d11_device_context->Map(draw_data.index_buffer.get_reference(), 0, D3D11_MAP_WRITE_DISCARD, 0, &index_resource); + memcpy(index_resource.pData, indices, sizeof(indices)); + g_d3d11_device_context->Unmap(draw_data.index_buffer.get_reference(), 0); + } + draw_data.initialized = true; + } + if (!in_vertex_shader) + { + in_vertex_shader = application::get()->get_renderer()->get_pixel_shader_render_default_vs(); + const float L = 0; + const float R = width; + const float T = 0; + const float B = height; + float mvp[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, (R+L)/(L-R) }, + { 0.0f, 2.0f/(T-B), 0.0f, (T+B)/(B-T) }, + { 0.0f, 0.0f, 0.5f, 0.5f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, + }; + in_vertex_shader->set_constant_buffer("ProjectionMatrix", mvp, sizeof(mvp)); + } + draw_data.vertex_shader = in_vertex_shader; + + draw_data.render_target->resize(width, height); + ImGui::GetWindowDrawList()->AddCallback(ps_dx11_compute_callback, &draw_data); + ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_ResetRenderState, nullptr); + draw_data.render_target->draw(); +} diff --git a/core/rhi/windows/dx11/shader/shader_ps_dx11.h b/core/rhi/windows/dx11/shader/shader_ps_dx11.h index 6191a51..c1262e7 100644 --- a/core/rhi/windows/dx11/shader/shader_ps_dx11.h +++ b/core/rhi/windows/dx11/shader/shader_ps_dx11.h @@ -1,6 +1,7 @@ #pragma once #include "shader_dx11.h" #include "slang-com-ptr.h" +#include "misc/ref_counting.h" class shader_ps_dx11 : public shader_dx11 { @@ -9,6 +10,7 @@ public: : shader_dx11(handle) { } + void bind() override; void unbind() override; @@ -17,6 +19,19 @@ public: [[nodiscard]] ID3D11DeviceChild* get_shader() override { return pixel_shader_; } [[nodiscard]] const char* get_shader_model() const override { return "ps_5_0"; } [[nodiscard]] bool is_initialized() const override { return pixel_shader_ != nullptr; } + + void draw(int width, int height, std::shared_ptr in_vertex_shader = nullptr) override; + + struct ps_data + { + shader_ps_dx11* ps; + std::shared_ptr render_target; + ref_count_ptr vertex_buffer; + ref_count_ptr index_buffer; + std::weak_ptr vertex_shader; + + bool initialized = false; + } draw_data; private: Slang::ComPtr pixel_shader_; diff --git a/core/rhi/windows/dx11/shader/shader_vs_dx11.cpp b/core/rhi/windows/dx11/shader/shader_vs_dx11.cpp index a9361f6..33db6b0 100644 --- a/core/rhi/windows/dx11/shader/shader_vs_dx11.cpp +++ b/core/rhi/windows/dx11/shader/shader_vs_dx11.cpp @@ -16,7 +16,9 @@ void shader_vs_dx11::bind() } #endif g_d3d11_device_context->VSGetShader(&prev_shader_, prev_class_instances_, &prev_class_instances_num_); - + g_d3d11_device_context->IAGetInputLayout(&prev_input_layout_); + + g_d3d11_device_context->IASetInputLayout(input_layout_); g_d3d11_device_context->VSSetShader(vertex_shader_, nullptr, 0); if (const unsigned int constant_num = constant_buffers_.size(); constant_num > 0) { @@ -56,9 +58,24 @@ void shader_vs_dx11::unbind() prev_shader_ = nullptr; prev_class_instances_ = nullptr; prev_class_instances_num_ = 0; + + g_d3d11_device_context->IASetInputLayout(prev_input_layout_); + prev_input_layout_ = nullptr; } HRESULT shader_vs_dx11::create_shader(ID3DBlob* blob, ID3D11Device* device) { - return device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, vertex_shader_.writeRef()); + auto hr = device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, vertex_shader_.writeRef()); + if (hr != S_OK) + { + return hr; + } + // TODO: refactor this + D3D11_INPUT_ELEMENT_DESC local_layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)offsetof(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + return g_d3d11_device->CreateInputLayout(local_layout, 3, blob->GetBufferPointer(), blob->GetBufferSize(), input_layout_.writeRef()) != S_OK; } diff --git a/core/rhi/windows/dx11/shader/shader_vs_dx11.h b/core/rhi/windows/dx11/shader/shader_vs_dx11.h index c4ff419..454539a 100644 --- a/core/rhi/windows/dx11/shader/shader_vs_dx11.h +++ b/core/rhi/windows/dx11/shader/shader_vs_dx11.h @@ -18,8 +18,10 @@ public: [[nodiscard]] bool is_initialized() const override { return vertex_shader_ != nullptr; } private: Slang::ComPtr vertex_shader_; + Slang::ComPtr input_layout_; ID3D11VertexShader* prev_shader_ = nullptr; ID3D11ClassInstance** prev_class_instances_ = nullptr; unsigned int prev_class_instances_num_ = 0; + ID3D11InputLayout* prev_input_layout_ = nullptr; };