rtengine/src/renderer/dx11/commands.cpp
2024-05-19 12:48:50 +02:00

168 lines
6.3 KiB
C++

#include <d3d11.h>
#include <d3d11_1.h>
#include "gfx/renderer_api.h"
#include "runtime/mem_arena.h"
#include "device_objects.hpp"
#include "gpu.hpp"
extern "C" void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle cmdhandle,
const rt_cmd_begin_pass_info *info) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
if (cmd->annotation) {
WCHAR wname[128];
if (rtUTF8ToWStr(info->name, wname, sizeof(wname)) == RT_SUCCESS)
cmd->annotation->BeginEvent(wname);
}
// Setup rtvs
ID3D11RenderTargetView *rtvs[4];
ID3D11DepthStencilView *dsv = nullptr;
for (uint32_t i = 0; i < info->color_buffer_count; ++i) {
rt_render_target *rt = rtGetRenderTarget(info->color_buffers[i]);
if (!RT_VERIFY(rt))
return;
RT_ASSERT(rt->IsColorRenderTarget(), "Needs to provide a valid color render target");
rtvs[i] = rt->rtv;
if (info->color_buffer_loads[i] == RT_PASS_LOAD_MODE_CLEAR) {
FLOAT color[4] = {
info->color_buffer_clear_values[i].color.r,
info->color_buffer_clear_values[i].color.g,
info->color_buffer_clear_values[i].color.b,
info->color_buffer_clear_values[i].color.a,
};
cmd->context->ClearRenderTargetView(rt->rtv, color);
}
}
rt_render_target *dsvrt = rtGetRenderTarget(info->depth_stencil_buffer);
if (dsvrt) {
RT_ASSERT(dsvrt->IsDepthStencilTarget(),
"Need to provide a valid depth stencil render target");
dsv = dsvrt->dsv;
if (info->depth_stencil_buffer_load == RT_PASS_LOAD_MODE_CLEAR)
cmd->context->ClearDepthStencilView(
dsv,
(dsvrt->HasStencilComponent()) ? D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL
: D3D11_CLEAR_DEPTH,
info->depth_stencil_buffer_clear_value.depth_stencil.depth,
static_cast<UINT8>(info->depth_stencil_buffer_clear_value.depth_stencil.stencil));
}
cmd->context->OMSetRenderTargets(static_cast<UINT>(info->color_buffer_count), rtvs, dsv);
D3D11_VIEWPORT viewport;
viewport.TopLeftX = static_cast<float>(info->render_area.offset.x);
viewport.TopLeftY = static_cast<float>(info->render_area.offset.y);
viewport.Width = static_cast<float>(info->render_area.size.x);
viewport.Height = static_cast<float>(info->render_area.size.y);
viewport.MinDepth = 0.f;
viewport.MaxDepth = 1.f;
cmd->context->RSSetViewports(1, &viewport);
// We currently only support triangles, so here is a good place to set this
cmd->context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
extern "C" void RT_RENDERER_API_FN(CmdEndPass)(rt_command_buffer_handle cmdhandle) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
if (cmd->annotation) {
cmd->annotation->EndEvent();
}
}
extern "C" void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmdhandle,
rt_render_target_handle target,
rt_render_target_state state) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
RT_UNUSED(target);
RT_UNUSED(state);
}
extern "C" void
RT_RENDERER_API_FN(CmdFlushRenderTargetWrite)(rt_command_buffer_handle cmdhandle,
rt_render_target_handle render_target) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
RT_UNUSED(render_target);
}
extern "C" void RT_RENDERER_API_FN(CmdBindPipeline)(rt_command_buffer_handle cmdhandle,
rt_pipeline_handle pipeline_handle) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
rt_pipeline *pipeline = rtGetPipeline(pipeline_handle);
if (pipeline->IsComputePipeline()) {
rtReportError("dx11",
"Attempted to bind a compute pipeline via CmdBindPipeline. Use "
"CmdBindComputePipeline instead.");
return;
}
auto context = cmd->context;
context->IASetInputLayout(pipeline->input_layout);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->VSSetShader(pipeline->vertex_shader, nullptr, 0);
context->PSSetShader(pipeline->pixel_shader, nullptr, 0);
context->RSSetState(pipeline->rasterizer_state);
}
extern "C" void RT_RENDERER_API_FN(CmdBindVertexBuffers)(rt_command_buffer_handle cmdhandle,
uint32_t first_binding,
uint32_t count,
const rt_buffer_handle *buffers,
const uint32_t *_strides,
const uint32_t *_offsets) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
if (!temp.arena)
return;
ID3D11Buffer **vbos = RT_ARENA_PUSH_ARRAY(temp.arena, ID3D11Buffer *, count);
static_assert(sizeof(UINT) == sizeof(uint32_t));
const UINT *offsets = _offsets;
const UINT *strides = _strides;
if (!vbos || !strides)
goto out;
if (!offsets) {
offsets = RT_ARENA_PUSH_ARRAY_ZERO(temp.arena, UINT, count);
}
for (uint32_t i = 0; i < count; ++i) {
rt_buffer *buffer = rtGetBuffer(buffers[i]);
RT_ASSERT(buffer->type == RT_BUFFER_TYPE_VERTEX, "Buffer must be a vertex buffer");
vbos[i] = buffer->buffer;
}
cmd->context->IASetVertexBuffers(first_binding, count, vbos, strides, offsets);
out:
rtReturnTemporaryArena(temp);
}
extern "C" void
RT_RENDERER_API_FN(CmdDraw)(rt_command_buffer_handle cmdhandle, uint32_t first, uint32_t count) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
if (!RT_VERIFY(cmd))
return;
cmd->context->Draw(count, first);
}