168 lines
6.3 KiB
C++
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);
|
|
}
|