新增scope_exit(copy from unreal engine)

新增pixel shader绘制到一张rt
This commit is contained in:
Nanako 2024-02-03 02:23:15 +08:00
parent 9e79dae3c9
commit 64db7ba909
18 changed files with 269 additions and 43 deletions

View File

@ -51,6 +51,9 @@ public:
std::shared_ptr<texture> load_texture(const std::string& path) const;
std::shared_ptr<texture> create_texture(const unsigned char* data, const int width, const int height) const;
std::shared_ptr<render_target> 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_; }

View File

@ -8,3 +8,4 @@
#else
#define CORE_API __declspec(dllimport)
#endif

71
core/misc/scope_exit.h Normal file
View File

@ -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 <typename FuncType>
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 <typename FuncType>
scope_guard<FuncType> operator+(FuncType&& in_func)
{
return scope_guard<FuncType>((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() + [&]()

View File

@ -86,10 +86,10 @@ Slang::ComPtr<slang::ISession> renderer_opengl::create_slang_session(const std::
return out;
}
std::shared_ptr<shader> renderer_opengl::load_shader(const std::string& module_name, const std::string& entry_name)
std::shared_ptr<shader> renderer_opengl::load_shader(const std::string& entry_name)
{
auto handle = std::make_shared<slang_handle>();
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<shader> out;

View File

@ -10,7 +10,7 @@ public:
void shutdown() override;
Slang::ComPtr<slang::ISession> create_slang_session(const std::string& shader_path) override;
std::shared_ptr<shader> load_shader(const std::string& module_name, const std::string& entry_name) override;
std::shared_ptr<shader> load_shader(const std::string& entry_name) override;
void new_frame(SDL_Window* window_handle) override;
void end_frame(SDL_Window* window_handle) override;

View File

@ -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<shader> 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_;
}

View File

@ -21,7 +21,8 @@ public:
void init_slang(const std::string& shader_path);
virtual Slang::ComPtr<slang::ISession> create_slang_session(const std::string& shader_path) = 0;
virtual Slang::ComPtr<slang::ISession> get_slang_session() { return session_; }
virtual std::shared_ptr<shader> load_shader(const std::string& module_name, const std::string& entry_name) = 0;
virtual std::shared_ptr<shader> load_shader(const std::string& entry_name) = 0;
virtual std::shared_ptr<shader> 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<slang::ISession> session_;
std::shared_ptr<shader> default_vs_;
bool vsync_ = true;
};

View File

@ -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<shader> in_vertex_shader = nullptr) {}
// param setters
virtual void set_constant_buffer(const char* name, void* buffer, int size) = 0;

View File

@ -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");

View File

@ -74,10 +74,10 @@ Slang::ComPtr<slang::ISession> renderer_dx11::create_slang_session(const std::st
return out;
}
std::shared_ptr<shader> renderer_dx11::load_shader(const std::string& module_name, const std::string& entry_name)
std::shared_ptr<shader> renderer_dx11::load_shader(const std::string& entry_name)
{
auto handle = std::make_shared<slang_handle>();
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();

View File

@ -7,6 +7,7 @@
#include "slang-com-ptr.h"
#include "slang.h"
class shader_vs_dx11;
extern ref_count_ptr<ID3D11Device> g_d3d11_device;
extern ref_count_ptr<ID3D11DeviceContext> g_d3d11_device_context;
extern ref_count_ptr<IDXGISwapChain> g_d3d11_swap_chain;
@ -20,7 +21,7 @@ public:
void shutdown() override;
Slang::ComPtr<slang::ISession> create_slang_session(const std::string& shader_path) override;
std::shared_ptr<shader> load_shader(const std::string& module_name, const std::string& entry_name) override;
std::shared_ptr<shader> load_shader(const std::string& entry_name) override;
void new_frame(SDL_Window* window_handle) override;
void end_frame(SDL_Window* window_handle) override;

View File

@ -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<render_target> in_render_target)
@ -108,18 +109,9 @@ void shader_cs_dx11::set_render_target(const char* name, std::shared_ptr<render_
}
}
void cs_dx11_compute_callback(const ImDrawList* parent_list, const ImDrawCmd* cmd)
{
const shader_cs_dx11::dx11_cs_data* data = static_cast<shader_cs_dx11::dx11_cs_data*>(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();
}

View File

@ -6,7 +6,7 @@ class shader_cs_dx11 : public shader_dx11
{
public:
explicit shader_cs_dx11(const std::shared_ptr<slang_handle>& 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<render_target> 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<std::string, std::shared_ptr<uav_buffer_dx11>> uav_buffers_;

View File

@ -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<texture> in_texture)

View File

@ -3,7 +3,10 @@
#include <ranges>
#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<shader> in_vertex_shader)
{
if (!draw_data.initialized)
{
draw_data.ps = this;
{
draw_data.render_target = std::static_pointer_cast<render_target_dx11>(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();
}

View File

@ -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<shader> in_vertex_shader = nullptr) override;
struct ps_data
{
shader_ps_dx11* ps;
std::shared_ptr<render_target_dx11> render_target;
ref_count_ptr<ID3D11Buffer> vertex_buffer;
ref_count_ptr<ID3D11Buffer> index_buffer;
std::weak_ptr<shader> vertex_shader;
bool initialized = false;
} draw_data;
private:
Slang::ComPtr<ID3D11PixelShader> pixel_shader_;

View File

@ -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;
}

View File

@ -18,8 +18,10 @@ public:
[[nodiscard]] bool is_initialized() const override { return vertex_shader_ != nullptr; }
private:
Slang::ComPtr<ID3D11VertexShader> vertex_shader_;
Slang::ComPtr<ID3D11InputLayout> input_layout_;
ID3D11VertexShader* prev_shader_ = nullptr;
ID3D11ClassInstance** prev_class_instances_ = nullptr;
unsigned int prev_class_instances_num_ = 0;
ID3D11InputLayout* prev_input_layout_ = nullptr;
};