#include #include #include "gfx/renderer_api.h" #include "runtime/config.h" #include "runtime/handles.h" #include "runtime/threading_helpers.hpp" #include "device_objects.hpp" #include "gpu.hpp" RT_CVAR_I(rt_Dx11MaxBuffers, "Maximum number of simultaneously existing buffers. Default: 4096", 4096); static rt_buffer *_buffers; static rt_buffer *_first_free; static rt_mutex *_lock; rt_result InitBufferManagement() { _buffers = reinterpret_cast(calloc((size_t)rt_Dx11MaxBuffers.i, sizeof(rt_buffer))); if (!_buffers) { return RT_OUT_OF_MEMORY; } _lock = rtCreateMutex(); if (!_lock) { free(_buffers); return RT_UNKNOWN_ERROR; } _first_free = _buffers + 2; for (int i = 0; i < rt_Dx11MaxBuffers.i; ++i) { _buffers[i].next_free = &_buffers[i + 1]; } return RT_SUCCESS; } void ShutdownBufferManagement() { for (int i = 0; i < rt_Dx11MaxBuffers.i; ++i) { if (_buffers[i].buffer) _buffers[i].buffer->Release(); } free(_buffers); rtDestroyMutex(_lock); } rt_buffer *rtGetBuffer(rt_buffer_handle handle) { if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxBuffers.i) return nullptr; auto lg = rtAutoLock(_lock); if (handle.version != _buffers[handle.index].version) return nullptr; return &_buffers[handle.index]; } extern "C" rt_result RT_RENDERER_API_FN(CreateBuffers)(uint32_t count, const rt_buffer_info *info, rt_buffer_handle *p_buffers) { for (uint32_t i = 0; i < count; ++i) { rtLockMutex(_lock); rt_buffer *slot = _first_free; if (slot) _first_free = slot->next_free; rtUnlockMutex(_lock); if (!slot) { rtLog("dx11", "Failed to allocate a command buffer slot."); rtLockMutex(_lock); for (uint32_t j = 0; j < i; ++j) { rt_buffer *s = &_buffers[p_buffers[j].index]; s->next_free = _first_free; _first_free = s; _first_free = s; } rtUnlockMutex(_lock); return RT_OUT_OF_MEMORY; } D3D11_USAGE usage = D3D11_USAGE_DEFAULT; if (info[i].usage == RT_BUFFER_USAGE_STATIC) { usage = D3D11_USAGE_IMMUTABLE; } else if (info[i].usage == RT_BUFFER_USAGE_DYNAMIC) { usage = D3D11_USAGE_DEFAULT; } else if (info[i].usage == RT_BUFFER_USAGE_TRANSIENT) { usage = D3D11_USAGE_DYNAMIC; } UINT bind_flags = D3D11_BIND_UNORDERED_ACCESS; if (info[i].type == RT_BUFFER_TYPE_VERTEX) bind_flags = D3D11_BIND_VERTEX_BUFFER; else if (info[i].type == RT_BUFFER_TYPE_INDEX) bind_flags = D3D11_BIND_INDEX_BUFFER; else if (info[i].type == RT_BUFFER_TYPE_UNIFORM) bind_flags = D3D11_BIND_CONSTANT_BUFFER; else if (info[i].type == RT_BUFFER_TYPE_STORAGE) bind_flags = D3D11_BIND_UNORDERED_ACCESS; D3D11_BUFFER_DESC desc = {}; desc.ByteWidth = static_cast(((info[i].size + 15) / 16) * 16); desc.Usage = usage; desc.BindFlags = bind_flags; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; desc.StructureByteStride = 1; D3D11_SUBRESOURCE_DATA data; data.pSysMem = info->data; data.SysMemPitch = 0; data.SysMemSlicePitch = 0; if (FAILED( g_gpu.device->CreateBuffer(&desc, info[i].data ? &data : nullptr, &slot->buffer))) { rtLog("dx11", "Failed to create a deferred context."); auto lock_guard = rtAutoLock(_lock); for (uint32_t j = 0; j < i; ++j) { rt_buffer *s = &_buffers[p_buffers[j].index]; s->next_free = _first_free; _first_free = s; } return RT_UNKNOWN_ERROR; } slot->version = (slot->version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION; const uint32_t index = (uint32_t)(slot - _buffers); p_buffers[i].version = slot->version; p_buffers[i].index = index; } return RT_SUCCESS; } extern "C" void RT_RENDERER_API_FN(DestroyBuffers)(uint32_t count, rt_buffer_handle *buffers) { for (uint32_t i = 0; i < count; ++i) { if (!RT_IS_HANDLE_VALID(buffers[i]) || (int)buffers[i].index >= rt_Dx11MaxBuffers.i) continue; auto lg = rtAutoLock(_lock); if (buffers[i].version != _buffers[buffers[i].index].version) continue; _buffers[buffers[i].index].buffer->Release(); _buffers[buffers[i].index].next_free = _first_free; _first_free = &_buffers[buffers[i].index]; } }