pipelines

This commit is contained in:
Kevin Trogant 2024-04-04 20:01:23 +02:00
parent e7971e7bad
commit 4d575dc229
6 changed files with 279 additions and 17 deletions

View File

@ -14,6 +14,25 @@ struct VSOutput
float4 Pos : SV_POSITION; float4 Pos : SV_POSITION;
}; };
VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) {
VSOutput output = (VSOutput)0;
return output;
}
END
dx11 BEGIN
#include "common.hlsl"
struct VSInput
{
};
struct VSOutput
{
float4 Pos : SV_POSITION;
};
VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) { VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) {
VSOutput output = (VSOutput)0; VSOutput output = (VSOutput)0;
return output; return output;
@ -27,6 +46,21 @@ struct PSOutput {
float4 Color : SV_TARGET0; float4 Color : SV_TARGET0;
}; };
PSOutput PsMain(void) {
PSOutput output = (PSOutput)0;
output.Color[0] = 0;
output.Color[1] = 0;
output.Color[2] = 0;
output.Color[3] = 0;
return output;
}
END
dx11 BEGIN
struct PSOutput {
float4 Color : SV_TARGET0;
};
PSOutput PsMain(void) { PSOutput PsMain(void) {
PSOutput output = (PSOutput)0; PSOutput output = (PSOutput)0;
output.Color[0] = 0; output.Color[0] = 0;

View File

@ -2,5 +2,6 @@ option('static_renderer', type : 'string', value : 'vk', description : 'Name of
option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux') option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux')
option('error_report_debugbreak', type : 'boolean', value : true, description : 'Debugbreak in ReportError') option('error_report_debugbreak', type : 'boolean', value : true, description : 'Debugbreak in ReportError')
option('enable_dxc_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dxc-based shader compiler.') option('enable_dxc_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dxc-based shader compiler.')
option('enable_dx11_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dx11-bases shader compiler.')
option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.') option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.')
option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.') option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.')

View File

@ -17,24 +17,24 @@ struct rt_render_target {
rt_pixel_format format; rt_pixel_format format;
bool HasStencilComponent() const { uint32_t version;
rt_render_target *next_free;
RT_INLINE bool HasStencilComponent() const {
return format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8; return format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8;
} }
bool IsColorRenderTarget() const { RT_INLINE bool IsColorRenderTarget() const {
RT_ASSERT(!(rtv != nullptr && dsv != nullptr), RT_ASSERT(!(rtv != nullptr && dsv != nullptr),
"A render target should not contain a render target and a depth stencil view"); "A render target should not contain a render target and a depth stencil view");
return rtv != nullptr; return rtv != nullptr;
} }
bool IsDepthStencilTarget() const { RT_INLINE bool IsDepthStencilTarget() const {
RT_ASSERT(!(rtv != nullptr && dsv != nullptr), RT_ASSERT(!(rtv != nullptr && dsv != nullptr),
"A render target should not contain a render target and a depth stencil view"); "A render target should not contain a render target and a depth stencil view");
return dsv != nullptr; return dsv != nullptr;
} }
uint32_t version;
rt_render_target *next_free;
}; };
struct rt_command_buffer { struct rt_command_buffer {
@ -55,8 +55,27 @@ struct rt_buffer {
rt_buffer *next_free; rt_buffer *next_free;
}; };
struct rt_pipeline {
ID3D11InputLayout *input_layout;
ID3D11VertexShader *vertex_shader;
ID3D11PixelShader *pixel_shader;
ID3D11ComputeShader *compute_shader;
rt_pipeline *next_free;
uint32_t version;
RT_INLINE bool IsComputePipeline() const {
RT_ASSERT(!(compute_shader && (vertex_shader || pixel_shader)),
"A pipeline should contain either a compute shader or graphics shaders.");
return compute_shader != nullptr;
}
};
rt_render_target *rtGetRenderTarget(rt_render_target_handle handle); rt_render_target *rtGetRenderTarget(rt_render_target_handle handle);
rt_command_buffer *rtGetCommandBuffer(rt_command_buffer_handle handle); rt_command_buffer *rtGetCommandBuffer(rt_command_buffer_handle handle);
rt_buffer *rtGetBuffer(rt_buffer_handle handle); rt_buffer *rtGetBuffer(rt_buffer_handle handle);
rt_pipeline *rtGetPipeline(rt_pipeline_handle handle);
#endif #endif

View File

@ -253,15 +253,6 @@ extern "C" {
#define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1) #define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1)
rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) {
RT_UNUSED(info);
RETURN_HANDLE_STUB(rt_pipeline_handle);
}
void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) {
RT_UNUSED(handle);
}
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count, rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
const rt_gpu_semaphore_info *info, const rt_gpu_semaphore_info *info,
rt_gpu_semaphore_handle *p_semaphores) { rt_gpu_semaphore_handle *p_semaphores) {

View File

@ -0,0 +1,217 @@
#include <d3d11.h>
#include <d3d11_1.h>
#include "gfx/effect.h"
#include "gfx/renderer_api.h"
#include "runtime/config.h"
#include "runtime/handles.h"
#include "runtime/mem_arena.h"
#include "runtime/threading_helpers.hpp"
#include "device_objects.hpp"
#include "gpu.hpp"
RT_CVAR_I(rt_Dx11MaxPipelines,
"Maximum number of simultaneously existing pipelines. Default: 128",
128);
static rt_pipeline *_pipelines;
static rt_pipeline *_first_free;
static rt_mutex *_lock;
rt_result InitPipelineManagement() {
_pipelines =
reinterpret_cast<rt_pipeline *>(calloc((size_t)rt_Dx11MaxPipelines.i, sizeof(rt_pipeline)));
if (!_pipelines)
return RT_OUT_OF_MEMORY;
_first_free = _pipelines + 1;
for (int i = 0; i < rt_Dx11MaxPipelines.i - 1; ++i)
_pipelines[i].next_free = &_pipelines[i + 1];
_lock = rtCreateMutex();
if (!_lock) {
free(_pipelines);
return RT_UNKNOWN_ERROR;
}
return RT_SUCCESS;
}
void ShutdownPipelineManagement() {
for (int i = 0; i < rt_Dx11MaxPipelines.i; ++i) {
if (_pipelines[i].compute_shader)
_pipelines[i].compute_shader->Release();
if (_pipelines[i].vertex_shader)
_pipelines[i].vertex_shader->Release();
if (_pipelines[i].pixel_shader)
_pipelines[i].pixel_shader->Release();
if (_pipelines[i].input_layout)
_pipelines[i].input_layout->Release();
}
free(_pipelines);
rtDestroyMutex(_lock);
}
rt_result GetShader(rt_resource_id id, rt_shader_info **p_shader, rt_arena *arena) {
size_t shader_size = rtGetResourceSize(id);
if (shader_size == 0)
return RT_INVALID_VALUE;
void *buffer = rtArenaPush(arena, shader_size);
if (!buffer)
return RT_OUT_OF_MEMORY;
rt_result res = rtGetResource(id, buffer);
if (res != RT_SUCCESS) {
rtArenaPop(arena, shader_size);
return res;
}
rt_resource *resource = reinterpret_cast<rt_resource *>(buffer);
RT_ASSERT(resource->type == RT_RESOURCE_SHADER, "Expected a shader");
*p_shader = reinterpret_cast<rt_shader_info *>(resource->data);
return RT_SUCCESS;
}
extern "C" rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) {
rt_pipeline *slot = nullptr;
{
auto lg = rtAutoLock(_lock);
slot = _first_free;
if (slot)
_first_free = slot->next_free;
}
if (!slot) {
rtLog("dx11", "Could not create pipeline, because no slots are available.");
return RT_INVALID_HANDLE;
}
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
if (info->vertex_shader != RT_INVALID_RESOURCE_ID) {
rt_shader_info *vs;
if (GetShader(info->vertex_shader, &vs, temp.arena) != RT_SUCCESS) {
rtReportError("dx11", "Could not retrieve vertex shader data.");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
void *bytecode = rtResolveRelptr(&vs->bytecode);
if (FAILED(g_gpu.device->CreateVertexShader(bytecode,
vs->bytecode_length,
NULL,
&slot->vertex_shader))) {
rtReportError("dx11", "Vertex shader creation failed");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
// TODO: effects should specify the expected vertex layout
// For now, we use a default
/* clang-format off */
D3D11_INPUT_ELEMENT_DESC default_layout[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
/* clang-format on */
if (FAILED(g_gpu.device->CreateInputLayout(default_layout,
RT_ARRAY_COUNT(default_layout),
bytecode,
vs->bytecode_length,
&slot->input_layout))) {
rtReportError("dx11", "Failed to create the vertex layout.");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
}
if (info->fragment_shader != RT_INVALID_RESOURCE_ID) {
rt_shader_info *vs;
if (GetShader(info->fragment_shader, &vs, temp.arena) != RT_SUCCESS) {
rtReportError("dx11", "Could not retrieve fragment shader data.");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
void *bytecode = rtResolveRelptr(&vs->bytecode);
if (FAILED(g_gpu.device->CreatePixelShader(bytecode,
vs->bytecode_length,
NULL,
&slot->pixel_shader))) {
rtReportError("dx11", "Fragment shader creation failed");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
}
if (info->compute_shader != RT_INVALID_RESOURCE_ID) {
rt_shader_info *vs;
if (GetShader(info->compute_shader, &vs, temp.arena) != RT_SUCCESS) {
rtReportError("dx11", "Could not retrieve compute shader data.");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
void *bytecode = rtResolveRelptr(&vs->bytecode);
if (FAILED(g_gpu.device->CreateComputeShader(bytecode,
vs->bytecode_length,
NULL,
&slot->compute_shader))) {
rtReportError("dx11", "Compute shader creation failed");
auto lg = rtAutoLock(_lock);
slot->next_free = _first_free;
_first_free = slot;
return RT_INVALID_HANDLE;
}
}
slot->version = (slot->version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION;
uint32_t index = static_cast<uint32_t>(slot - _pipelines);
return {slot->version, index};
}
extern "C" void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) {
if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxPipelines.i)
return;
auto lg = rtAutoLock(_lock);
if (handle.version != _pipelines[handle.index].version)
return;
if (_pipelines[handle.index].compute_shader)
_pipelines[handle.index].compute_shader->Release();
if (_pipelines[handle.index].vertex_shader)
_pipelines[handle.index].vertex_shader->Release();
if (_pipelines[handle.index].pixel_shader)
_pipelines[handle.index].pixel_shader->Release();
if (_pipelines[handle.index].input_layout)
_pipelines[handle.index].input_layout->Release();
_pipelines[handle.index].next_free = _first_free;
_pipelines[handle.index].version =
(_pipelines[handle.index].version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION;
_first_free = &_pipelines[handle.index];
}
rt_pipeline *rtGetPipeline(rt_pipeline_handle handle) {
if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxPipelines.i)
return nullptr;
auto lg = rtAutoLock(_lock);
if (handle.version != _pipelines[handle.index].version)
return nullptr;
return &_pipelines[handle.index];
}