mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-15 08:15:06 +00:00
obs/gs/vertexbuffer: Cleanup and add workaround for OBS Studio memory leak
This commit is contained in:
parent
b57c7975e3
commit
bbfacbc30b
2 changed files with 161 additions and 209 deletions
|
@ -22,120 +22,114 @@
|
||||||
#include "obs/gs/gs-helper.hpp"
|
#include "obs/gs/gs-helper.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
void gs::vertex_buffer::initialize(std::size_t capacity, std::size_t layers)
|
void gs::vertex_buffer::initialize(uint32_t capacity, uint8_t layers)
|
||||||
{
|
{
|
||||||
|
finalize();
|
||||||
|
|
||||||
if (capacity > MAXIMUM_VERTICES) {
|
if (capacity > MAXIMUM_VERTICES) {
|
||||||
throw std::out_of_range("capacity too large");
|
throw std::out_of_range("capacity");
|
||||||
}
|
}
|
||||||
if (layers > MAXIMUM_UVW_LAYERS) {
|
if (layers > MAXIMUM_UVW_LAYERS) {
|
||||||
throw std::out_of_range("too many layers");
|
throw std::out_of_range("layers");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory for data.
|
// Allocate memory for data.
|
||||||
_data = gs_vbdata_create();
|
_data = std::make_shared<decltype(_data)::element_type>();
|
||||||
_data->num = _capacity;
|
_data->num = _capacity;
|
||||||
_data->num_tex = _layers;
|
_data->num_tex = _layers;
|
||||||
_data->points = _positions = (vec3*)util::malloc_aligned(16, sizeof(vec3) * _capacity);
|
_data->points = _positions = (vec3*)util::malloc_aligned(16, sizeof(vec3) * _capacity);
|
||||||
memset(_positions, 0, sizeof(vec3) * _capacity);
|
|
||||||
_data->normals = _normals = (vec3*)util::malloc_aligned(16, sizeof(vec3) * _capacity);
|
_data->normals = _normals = (vec3*)util::malloc_aligned(16, sizeof(vec3) * _capacity);
|
||||||
memset(_normals, 0, sizeof(vec3) * _capacity);
|
|
||||||
_data->tangents = _tangents = (vec3*)util::malloc_aligned(16, sizeof(vec3) * _capacity);
|
_data->tangents = _tangents = (vec3*)util::malloc_aligned(16, sizeof(vec3) * _capacity);
|
||||||
memset(_tangents, 0, sizeof(vec3) * _capacity);
|
|
||||||
_data->colors = _colors = (uint32_t*)util::malloc_aligned(16, sizeof(uint32_t) * _capacity);
|
_data->colors = _colors = (uint32_t*)util::malloc_aligned(16, sizeof(uint32_t) * _capacity);
|
||||||
|
|
||||||
|
// Clear the allocated memory of any data.
|
||||||
|
memset(_positions, 0, sizeof(vec3) * _capacity);
|
||||||
|
memset(_normals, 0, sizeof(vec3) * _capacity);
|
||||||
|
memset(_tangents, 0, sizeof(vec3) * _capacity);
|
||||||
memset(_colors, 0, sizeof(uint32_t) * _capacity);
|
memset(_colors, 0, sizeof(uint32_t) * _capacity);
|
||||||
if (_layers > 0) {
|
|
||||||
_data->tvarray = _layer_data = (gs_tvertarray*)util::malloc_aligned(16, sizeof(gs_tvertarray) * _layers);
|
if (_layers == 0) {
|
||||||
for (std::size_t n = 0; n < _layers; n++) {
|
_data->tvarray = nullptr;
|
||||||
_layer_data[n].array = _uvs[n] = (vec4*)util::malloc_aligned(16, sizeof(vec4) * _capacity);
|
} else {
|
||||||
_layer_data[n].width = 4;
|
_data->tvarray = _uv_layers = (gs_tvertarray*)util::malloc_aligned(16, sizeof(gs_tvertarray) * _layers);
|
||||||
|
for (uint8_t n = 0; n < _layers; n++) {
|
||||||
|
_uv_layers[n].array = _uvs[n] = (vec4*)util::malloc_aligned(16, sizeof(vec4) * _capacity);
|
||||||
|
_uv_layers[n].width = 4;
|
||||||
memset(_uvs[n], 0, sizeof(vec4) * _capacity);
|
memset(_uvs[n], 0, sizeof(vec4) * _capacity);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
_data->tvarray = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gs::vertex_buffer::~vertex_buffer()
|
// Allocate actual GPU vertex buffer.
|
||||||
{
|
{
|
||||||
if (_positions) {
|
|
||||||
util::free_aligned(_positions);
|
|
||||||
_positions = nullptr;
|
|
||||||
}
|
|
||||||
if (_normals) {
|
|
||||||
util::free_aligned(_normals);
|
|
||||||
_normals = nullptr;
|
|
||||||
}
|
|
||||||
if (_tangents) {
|
|
||||||
util::free_aligned(_tangents);
|
|
||||||
_tangents = nullptr;
|
|
||||||
}
|
|
||||||
if (_colors) {
|
|
||||||
util::free_aligned(_colors);
|
|
||||||
_colors = nullptr;
|
|
||||||
}
|
|
||||||
for (std::size_t n = 0; n < _layers; n++) {
|
|
||||||
if (_uvs[n]) {
|
|
||||||
util::free_aligned(_uvs[n]);
|
|
||||||
_uvs[n] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_layer_data) {
|
|
||||||
util::free_aligned(_layer_data);
|
|
||||||
_layer_data = nullptr;
|
|
||||||
}
|
|
||||||
if (_data) {
|
|
||||||
memset(_data, 0, sizeof(gs_vb_data));
|
|
||||||
if (!_buffer) {
|
|
||||||
gs_vbdata_destroy(_data);
|
|
||||||
_data = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_buffer) {
|
|
||||||
auto gctx = gs::context();
|
auto gctx = gs::context();
|
||||||
gs_vertexbuffer_destroy(_buffer);
|
_buffer =
|
||||||
_buffer = nullptr;
|
decltype(_buffer)(gs_vertexbuffer_create(_data.get(), GS_DYNAMIC | GS_DUP_BUFFER), [this](gs_vertbuffer_t* v) {
|
||||||
}
|
try {
|
||||||
}
|
|
||||||
|
|
||||||
gs::vertex_buffer::vertex_buffer() : vertex_buffer(MAXIMUM_VERTICES, MAXIMUM_UVW_LAYERS) {}
|
|
||||||
|
|
||||||
gs::vertex_buffer::vertex_buffer(std::uint32_t vertices) : vertex_buffer(vertices, MAXIMUM_UVW_LAYERS) {}
|
|
||||||
|
|
||||||
gs::vertex_buffer::vertex_buffer(std::uint32_t vertices, std::uint8_t uvlayers)
|
|
||||||
: _size(vertices), _capacity(vertices), _layers(uvlayers), _positions(nullptr), _normals(nullptr),
|
|
||||||
_tangents(nullptr), _colors(nullptr), _data(nullptr), _buffer(nullptr), _layer_data(nullptr)
|
|
||||||
{
|
|
||||||
initialize(vertices, uvlayers);
|
|
||||||
|
|
||||||
if (vertices > MAXIMUM_VERTICES) {
|
|
||||||
throw std::out_of_range("vertices out of range");
|
|
||||||
}
|
|
||||||
if (uvlayers > MAXIMUM_UVW_LAYERS) {
|
|
||||||
throw std::out_of_range("uvlayers out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate GPU
|
|
||||||
auto gctx = gs::context();
|
auto gctx = gs::context();
|
||||||
_buffer = gs_vertexbuffer_create(_data, GS_DYNAMIC | GS_DUP_BUFFER);
|
gs_vertexbuffer_destroy(v);
|
||||||
memset(_data, 0, sizeof(gs_vb_data));
|
} catch (...) {
|
||||||
_data->num = _capacity;
|
if (obs_get_version() < MAKE_SEMANTIC_VERSION(26, 0, 0)) {
|
||||||
_data->num_tex = _layers;
|
// Fixes a memory leak with OBS Studio versions older than 26.x.
|
||||||
|
gs_vbdata_destroy(_obs_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_obs_data = gs_vertexbuffer_get_data(_buffer.get());
|
||||||
|
}
|
||||||
|
|
||||||
if (!_buffer) {
|
if (!_buffer) {
|
||||||
throw std::runtime_error("Failed to create vertex buffer.");
|
throw std::runtime_error("Failed to create vertex buffer.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cppcheck-suppress uninitMemberVar
|
void gs::vertex_buffer::finalize()
|
||||||
|
{
|
||||||
|
// Free data
|
||||||
|
util::free_aligned(_positions);
|
||||||
|
util::free_aligned(_normals);
|
||||||
|
util::free_aligned(_tangents);
|
||||||
|
util::free_aligned(_colors);
|
||||||
|
util::free_aligned(_uv_layers);
|
||||||
|
for (std::size_t n = 0; n < _layers; n++) {
|
||||||
|
util::free_aligned(_uvs[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buffer.reset();
|
||||||
|
_data.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
gs::vertex_buffer::~vertex_buffer()
|
||||||
|
{
|
||||||
|
finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
gs::vertex_buffer::vertex_buffer(uint32_t size, uint8_t layers)
|
||||||
|
: _capacity(size), _size(size), _layers(layers),
|
||||||
|
|
||||||
|
_buffer(nullptr), _data(nullptr),
|
||||||
|
|
||||||
|
_positions(nullptr), _normals(nullptr), _tangents(nullptr), _colors(nullptr), _uv_layers(nullptr), _uvs(),
|
||||||
|
|
||||||
|
_obs_data(nullptr)
|
||||||
|
{
|
||||||
|
initialize(_size, _layers);
|
||||||
|
}
|
||||||
|
|
||||||
gs::vertex_buffer::vertex_buffer(gs_vertbuffer_t* vb)
|
gs::vertex_buffer::vertex_buffer(gs_vertbuffer_t* vb)
|
||||||
: _size(0), _capacity(0), _layers(0), _positions(nullptr), _normals(nullptr), _tangents(nullptr), _colors(nullptr),
|
: _capacity(0), _size(0), _layers(0),
|
||||||
_uvs(), _data(nullptr), _buffer(nullptr), _layer_data(nullptr)
|
|
||||||
|
_buffer(nullptr), _data(nullptr),
|
||||||
|
|
||||||
|
_positions(nullptr), _normals(nullptr), _tangents(nullptr), _colors(nullptr), _uv_layers(nullptr), _uvs(),
|
||||||
|
|
||||||
|
_obs_data(nullptr)
|
||||||
{
|
{
|
||||||
auto gctx = gs::context();
|
auto gctx = gs::context();
|
||||||
gs_vb_data* vbd = gs_vertexbuffer_get_data(vb);
|
gs_vb_data* vbd = gs_vertexbuffer_get_data(vb);
|
||||||
if (!vbd)
|
if (!vbd)
|
||||||
throw std::runtime_error("vertex buffer with no data");
|
throw std::runtime_error("vertex buffer with no data");
|
||||||
|
|
||||||
initialize(vbd->num, vbd->num_tex);
|
initialize(static_cast<uint32_t>(vbd->num), static_cast<uint8_t>(vbd->num_tex));
|
||||||
|
|
||||||
if (_positions && vbd->points)
|
if (_positions && vbd->points)
|
||||||
memcpy(_positions, vbd->points, vbd->num * sizeof(vec3));
|
memcpy(_positions, vbd->points, vbd->num * sizeof(vec3));
|
||||||
|
@ -153,7 +147,6 @@ gs::vertex_buffer::vertex_buffer(gs_vertbuffer_t* vb)
|
||||||
} else if (vbd->tvarray[n].width < 4) {
|
} else if (vbd->tvarray[n].width < 4) {
|
||||||
for (std::size_t idx = 0; idx < _capacity; idx++) {
|
for (std::size_t idx = 0; idx < _capacity; idx++) {
|
||||||
float* mem = reinterpret_cast<float*>(vbd->tvarray[n].array) + (idx * vbd->tvarray[n].width);
|
float* mem = reinterpret_cast<float*>(vbd->tvarray[n].array) + (idx * vbd->tvarray[n].width);
|
||||||
// cppcheck-suppress memsetClassFloat
|
|
||||||
memset(&_uvs[n][idx], 0, sizeof(vec4));
|
memset(&_uvs[n][idx], 0, sizeof(vec4));
|
||||||
memcpy(&_uvs[n][idx], mem, vbd->tvarray[n].width);
|
memcpy(&_uvs[n][idx], mem, vbd->tvarray[n].width);
|
||||||
}
|
}
|
||||||
|
@ -163,114 +156,95 @@ gs::vertex_buffer::vertex_buffer(gs_vertbuffer_t* vb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cppcheck-suppress uninitMemberVar
|
gs::vertex_buffer::vertex_buffer(vertex_buffer const& other) : vertex_buffer(other._capacity, other._layers)
|
||||||
gs::vertex_buffer::vertex_buffer(vertex_buffer const& other) : vertex_buffer(other._capacity)
|
{ // Copy Constructor
|
||||||
{
|
|
||||||
// Copy Constructor
|
|
||||||
memcpy(_positions, other._positions, _capacity * sizeof(vec3));
|
memcpy(_positions, other._positions, _capacity * sizeof(vec3));
|
||||||
memcpy(_normals, other._normals, _capacity * sizeof(vec3));
|
memcpy(_normals, other._normals, _capacity * sizeof(vec3));
|
||||||
memcpy(_tangents, other._tangents, _capacity * sizeof(vec3));
|
memcpy(_tangents, other._tangents, _capacity * sizeof(vec3));
|
||||||
memcpy(_colors, other._colors, _capacity * sizeof(vec3));
|
memcpy(_colors, other._colors, _capacity * sizeof(vec3));
|
||||||
for (std::size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) {
|
for (std::size_t n = 0; n < other._layers; n++) {
|
||||||
memcpy(_uvs[n], other._uvs[n], _capacity * sizeof(vec3));
|
memcpy(_uvs[n], other._uvs[n], _capacity * sizeof(vec4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gs::vertex_buffer::vertex_buffer(vertex_buffer const&& other) noexcept : _uvs()
|
void gs::vertex_buffer::operator=(vertex_buffer const& other)
|
||||||
{
|
{ // Copy operator
|
||||||
// Move Constructor
|
initialize(other._capacity, other._layers);
|
||||||
|
_size = other._size;
|
||||||
|
|
||||||
|
// Copy actual data over.
|
||||||
|
memcpy(_positions, other._positions, other._capacity * sizeof(vec3));
|
||||||
|
memcpy(_normals, other._normals, other._capacity * sizeof(vec3));
|
||||||
|
memcpy(_tangents, other._tangents, other._capacity * sizeof(vec3));
|
||||||
|
memcpy(_colors, other._colors, other._capacity * sizeof(uint32_t));
|
||||||
|
memcpy(_uv_layers, other._uv_layers, sizeof(gs_tvertarray));
|
||||||
|
for (std::size_t n = 0; n < other._layers; n++) {
|
||||||
|
memcpy(_uvs[n], other._uvs[n], _capacity * sizeof(vec4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gs::vertex_buffer::vertex_buffer(vertex_buffer const&& other) noexcept
|
||||||
|
{ // Move Constructor
|
||||||
_capacity = other._capacity;
|
_capacity = other._capacity;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
_layers = other._layers;
|
_layers = other._layers;
|
||||||
|
_buffer = other._buffer;
|
||||||
|
_data = other._data;
|
||||||
_positions = other._positions;
|
_positions = other._positions;
|
||||||
_normals = other._normals;
|
_normals = other._normals;
|
||||||
_tangents = other._tangents;
|
_tangents = other._tangents;
|
||||||
_colors = other._colors;
|
_colors = other._colors;
|
||||||
|
_uv_layers = other._uv_layers;
|
||||||
for (std::size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) {
|
for (std::size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) {
|
||||||
_uvs[n] = other._uvs[n];
|
_uvs[n] = other._uvs[n];
|
||||||
}
|
}
|
||||||
_data = other._data;
|
_obs_data = other._obs_data;
|
||||||
_buffer = other._buffer;
|
|
||||||
_layer_data = other._layer_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gs::vertex_buffer::operator=(vertex_buffer const&& other) noexcept
|
void gs::vertex_buffer::operator=(vertex_buffer const&& other)
|
||||||
{
|
{ // Move Assignment
|
||||||
// Move Assignment
|
finalize();
|
||||||
/// First self-destruct (semi-destruct itself).
|
|
||||||
if (_positions) {
|
|
||||||
util::free_aligned(_positions);
|
|
||||||
_positions = nullptr;
|
|
||||||
}
|
|
||||||
if (_normals) {
|
|
||||||
util::free_aligned(_normals);
|
|
||||||
_normals = nullptr;
|
|
||||||
}
|
|
||||||
if (_tangents) {
|
|
||||||
util::free_aligned(_tangents);
|
|
||||||
_tangents = nullptr;
|
|
||||||
}
|
|
||||||
if (_colors) {
|
|
||||||
util::free_aligned(_colors);
|
|
||||||
_colors = nullptr;
|
|
||||||
}
|
|
||||||
for (std::size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) {
|
|
||||||
if (_uvs[n]) {
|
|
||||||
util::free_aligned(_uvs[n]);
|
|
||||||
_uvs[n] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_layer_data) {
|
|
||||||
util::free_aligned(_layer_data);
|
|
||||||
_layer_data = nullptr;
|
|
||||||
}
|
|
||||||
if (_data) {
|
|
||||||
memset(_data, 0, sizeof(gs_vb_data));
|
|
||||||
if (!_buffer) {
|
|
||||||
gs_vbdata_destroy(_data);
|
|
||||||
_data = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_buffer) {
|
|
||||||
auto gctx = gs::context();
|
|
||||||
gs_vertexbuffer_destroy(_buffer);
|
|
||||||
_buffer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Then assign new values.
|
|
||||||
_capacity = other._capacity;
|
_capacity = other._capacity;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
_layers = other._layers;
|
_layers = other._layers;
|
||||||
|
_buffer = other._buffer;
|
||||||
|
_data = other._data;
|
||||||
_positions = other._positions;
|
_positions = other._positions;
|
||||||
_normals = other._normals;
|
_normals = other._normals;
|
||||||
_tangents = other._tangents;
|
_tangents = other._tangents;
|
||||||
|
_colors = other._colors;
|
||||||
|
_uv_layers = other._uv_layers;
|
||||||
for (std::size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) {
|
for (std::size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) {
|
||||||
_uvs[n] = other._uvs[n];
|
_uvs[n] = other._uvs[n];
|
||||||
}
|
}
|
||||||
_data = other._data;
|
_obs_data = other._obs_data;
|
||||||
_buffer = other._buffer;
|
|
||||||
_layer_data = other._layer_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gs::vertex_buffer::resize(std::uint32_t new_size)
|
void gs::vertex_buffer::resize(uint32_t size)
|
||||||
{
|
{
|
||||||
if (new_size > _capacity) {
|
if (size > _capacity) {
|
||||||
throw std::out_of_range("new_size out of range");
|
throw std::out_of_range("size larger than capacity");
|
||||||
}
|
}
|
||||||
_size = new_size;
|
_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t gs::vertex_buffer::size()
|
uint32_t gs::vertex_buffer::size()
|
||||||
{
|
{
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t gs::vertex_buffer::capacity()
|
||||||
|
{
|
||||||
|
return _capacity;
|
||||||
|
}
|
||||||
|
|
||||||
bool gs::vertex_buffer::empty()
|
bool gs::vertex_buffer::empty()
|
||||||
{
|
{
|
||||||
return _size == 0;
|
return _size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gs::vertex gs::vertex_buffer::at(std::uint32_t idx)
|
const gs::vertex gs::vertex_buffer::at(uint32_t idx)
|
||||||
{
|
{
|
||||||
if (idx >= _size) {
|
if (idx >= _size) {
|
||||||
throw std::out_of_range("idx out of range");
|
throw std::out_of_range("idx out of range");
|
||||||
|
@ -283,17 +257,17 @@ const gs::vertex gs::vertex_buffer::at(std::uint32_t idx)
|
||||||
return vtx;
|
return vtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gs::vertex gs::vertex_buffer::operator[](std::uint32_t const pos)
|
const gs::vertex gs::vertex_buffer::operator[](uint32_t const pos)
|
||||||
{
|
{
|
||||||
return at(pos);
|
return at(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gs::vertex_buffer::set_uv_layers(std::uint32_t layers)
|
void gs::vertex_buffer::set_uv_layers(uint8_t layers)
|
||||||
{
|
{
|
||||||
_layers = layers;
|
_layers = layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t gs::vertex_buffer::get_uv_layers()
|
uint8_t gs::vertex_buffer::get_uv_layers()
|
||||||
{
|
{
|
||||||
return _layers;
|
return _layers;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +292,7 @@ uint32_t* gs::vertex_buffer::get_colors()
|
||||||
return _colors;
|
return _colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4* gs::vertex_buffer::get_uv_layer(std::size_t idx)
|
vec4* gs::vertex_buffer::get_uv_layer(uint8_t idx)
|
||||||
{
|
{
|
||||||
if (idx >= _layers) {
|
if (idx >= _layers) {
|
||||||
throw std::out_of_range("idx out of range");
|
throw std::out_of_range("idx out of range");
|
||||||
|
@ -328,40 +302,12 @@ vec4* gs::vertex_buffer::get_uv_layer(std::size_t idx)
|
||||||
|
|
||||||
gs_vertbuffer_t* gs::vertex_buffer::update(bool refreshGPU)
|
gs_vertbuffer_t* gs::vertex_buffer::update(bool refreshGPU)
|
||||||
{
|
{
|
||||||
if (!refreshGPU)
|
if (refreshGPU) {
|
||||||
return _buffer;
|
|
||||||
|
|
||||||
if (_size > _capacity)
|
|
||||||
throw std::out_of_range("size is larger than capacity");
|
|
||||||
|
|
||||||
// Update VertexBuffer data.
|
|
||||||
auto gctx = gs::context();
|
auto gctx = gs::context();
|
||||||
_data = gs_vertexbuffer_get_data(_buffer);
|
gs_vertexbuffer_flush_direct(_buffer.get(), _data.get());
|
||||||
memset(_data, 0, sizeof(gs_vb_data));
|
_obs_data = gs_vertexbuffer_get_data(_buffer.get());
|
||||||
_data->num = _capacity;
|
|
||||||
_data->points = _positions;
|
|
||||||
_data->normals = _normals;
|
|
||||||
_data->tangents = _tangents;
|
|
||||||
_data->colors = _colors;
|
|
||||||
_data->num_tex = _layers;
|
|
||||||
_data->tvarray = _layer_data;
|
|
||||||
for (std::size_t n = 0; n < _layers; n++) {
|
|
||||||
_layer_data[n].array = _uvs[n];
|
|
||||||
_layer_data[n].width = 4;
|
|
||||||
}
|
}
|
||||||
|
return _buffer.get();
|
||||||
// Update GPU
|
|
||||||
gs_vertexbuffer_flush(_buffer);
|
|
||||||
|
|
||||||
// WORKAROUND: OBS Studio 20.x and below incorrectly deletes data that it doesn't own.
|
|
||||||
memset(_data, 0, sizeof(gs_vb_data));
|
|
||||||
_data->num = _capacity;
|
|
||||||
_data->num_tex = _layers;
|
|
||||||
for (std::uint32_t n = 0; n < _layers; n++) {
|
|
||||||
_layer_data[n].width = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gs_vertbuffer_t* gs::vertex_buffer::update()
|
gs_vertbuffer_t* gs::vertex_buffer::update()
|
||||||
|
|
|
@ -25,23 +25,27 @@
|
||||||
|
|
||||||
namespace gs {
|
namespace gs {
|
||||||
class vertex_buffer {
|
class vertex_buffer {
|
||||||
std::uint32_t _size;
|
uint32_t _capacity;
|
||||||
std::uint32_t _capacity;
|
uint32_t _size;
|
||||||
std::uint32_t _layers;
|
uint8_t _layers;
|
||||||
|
|
||||||
|
// OBS GS Data
|
||||||
|
std::shared_ptr<gs_vertbuffer_t> _buffer;
|
||||||
|
std::shared_ptr<gs_vb_data> _data;
|
||||||
|
|
||||||
// Memory Storage
|
// Memory Storage
|
||||||
vec3* _positions;
|
vec3* _positions;
|
||||||
vec3* _normals;
|
vec3* _normals;
|
||||||
vec3* _tangents;
|
vec3* _tangents;
|
||||||
uint32_t* _colors;
|
uint32_t* _colors;
|
||||||
|
gs_tvertarray* _uv_layers;
|
||||||
vec4* _uvs[MAXIMUM_UVW_LAYERS];
|
vec4* _uvs[MAXIMUM_UVW_LAYERS];
|
||||||
|
|
||||||
// OBS GS Data
|
// OBS compatability
|
||||||
gs_vb_data* _data;
|
gs_vb_data* _obs_data;
|
||||||
gs_vertbuffer_t* _buffer;
|
|
||||||
gs_tvertarray* _layer_data;
|
|
||||||
|
|
||||||
void initialize(std::size_t capacity, std::size_t layers);
|
void initialize(uint32_t capacity, uint8_t layers);
|
||||||
|
void finalize();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~vertex_buffer();
|
virtual ~vertex_buffer();
|
||||||
|
@ -49,14 +53,14 @@ namespace gs {
|
||||||
/*!
|
/*!
|
||||||
* \brief Create a Vertex Buffer with the default number of Vertices.
|
* \brief Create a Vertex Buffer with the default number of Vertices.
|
||||||
*/
|
*/
|
||||||
vertex_buffer();
|
vertex_buffer() : vertex_buffer(MAXIMUM_VERTICES, MAXIMUM_UVW_LAYERS) {}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Create a Vertex Buffer with a specific number of Vertices.
|
* \brief Create a Vertex Buffer with a specific number of Vertices.
|
||||||
*
|
*
|
||||||
* \param vertices Number of vertices to store.
|
* \param vertices Number of vertices to store.
|
||||||
*/
|
*/
|
||||||
vertex_buffer(std::uint32_t vertices);
|
vertex_buffer(uint32_t vertices) : vertex_buffer(vertices, MAXIMUM_UVW_LAYERS) {}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Create a Vertex Buffer with a specific number of Vertices and uv layers.
|
* \brief Create a Vertex Buffer with a specific number of Vertices and uv layers.
|
||||||
|
@ -64,7 +68,7 @@ namespace gs {
|
||||||
* \param vertices Number of vertices to store.
|
* \param vertices Number of vertices to store.
|
||||||
* \param layers Number of uv layers to store.
|
* \param layers Number of uv layers to store.
|
||||||
*/
|
*/
|
||||||
vertex_buffer(std::uint32_t vertices, std::uint8_t layers);
|
vertex_buffer(uint32_t vertices, uint8_t layers);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Create a copy of a Vertex Buffer
|
* \brief Create a copy of a Vertex Buffer
|
||||||
|
@ -90,7 +94,7 @@ namespace gs {
|
||||||
*
|
*
|
||||||
* \param other
|
* \param other
|
||||||
*/
|
*/
|
||||||
void operator=(vertex_buffer const& other) = delete;
|
void operator=(vertex_buffer const& other);
|
||||||
|
|
||||||
// Move Constructor & Assignments
|
// Move Constructor & Assignments
|
||||||
|
|
||||||
|
@ -108,21 +112,23 @@ namespace gs {
|
||||||
*
|
*
|
||||||
* \param other
|
* \param other
|
||||||
*/
|
*/
|
||||||
void operator=(vertex_buffer const&& other) noexcept;
|
void operator=(vertex_buffer const&& other);
|
||||||
|
|
||||||
void resize(std::uint32_t new_size);
|
void resize(uint32_t new_size);
|
||||||
|
|
||||||
std::uint32_t size();
|
uint32_t size();
|
||||||
|
|
||||||
|
uint32_t capacity();
|
||||||
|
|
||||||
bool empty();
|
bool empty();
|
||||||
|
|
||||||
const gs::vertex at(std::uint32_t idx);
|
const gs::vertex at(uint32_t idx);
|
||||||
|
|
||||||
const gs::vertex operator[](std::uint32_t const pos);
|
const gs::vertex operator[](uint32_t const pos);
|
||||||
|
|
||||||
void set_uv_layers(std::uint32_t layers);
|
void set_uv_layers(uint8_t layers);
|
||||||
|
|
||||||
std::uint32_t get_uv_layers();
|
uint8_t get_uv_layers();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Directly access the positions buffer
|
* \brief Directly access the positions buffer
|
||||||
|
@ -162,7 +168,7 @@ namespace gs {
|
||||||
*
|
*
|
||||||
* \return A <vec4*> that points at the first vertex's uv.
|
* \return A <vec4*> that points at the first vertex's uv.
|
||||||
*/
|
*/
|
||||||
vec4* get_uv_layer(std::size_t idx);
|
vec4* get_uv_layer(uint8_t idx);
|
||||||
|
|
||||||
gs_vertbuffer_t* update();
|
gs_vertbuffer_t* update();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue