From 8f4bbd5b325405aa307f18d3df9c96ced41a853e Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Mon, 22 Jan 2018 22:14:11 +0100 Subject: [PATCH] Fix rare crash on SSE capable computers (everyone) This crash happens every 1 in 100000 times in obs-stream-effects 64-bit, which has the same GS::VertexBuffer wrapper as node-obs::Display and Face Masks. The crash happens due to unlucky placement of the buffers, which need to be 16-byte aligned, otherwise we write into memory that we shouldn't have written to. This results in funky crashes down the road which make absolutely no sense at all with a mdmp or a simple stack trace, since the cause of the crash happened earlier. Affects pretty much all areas, as the Display was actively writing into memory of other areas. This might explain some exotic behavior we have seen, such as crashes inside the Chromium runtime or electron crashes. --- CMakeLists.txt | 4 + src/gs-limits.h | 26 +++ src/gs-vertex.cpp | 48 +++++ src/gs-vertex.h | 47 +++++ src/gs-vertexbuffer.cpp | 331 ++++++++++++++++++++++++++++++++ src/gs-vertexbuffer.h | 179 +++++++++++++++++ src/nodeobs_display.cpp | 414 ++++++++++++++++------------------------ src/nodeobs_display.h | 31 +-- src/util-memory.cpp | 43 +++++ src/util-memory.h | 98 ++++++++++ 10 files changed, 945 insertions(+), 276 deletions(-) create mode 100644 src/gs-limits.h create mode 100644 src/gs-vertex.cpp create mode 100644 src/gs-vertex.h create mode 100644 src/gs-vertexbuffer.cpp create mode 100644 src/gs-vertexbuffer.h create mode 100644 src/util-memory.cpp create mode 100644 src/util-memory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 36734b459..d57d32aaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,6 +161,10 @@ SET(PROJECT_SOURCE "src/nodeobs_obspp_manager.hpp" "src/nodeobs_obspp_manager.cpp" "src/nodeobs_obspp_index.hpp" "src/nodeobs_obspp_index.cpp" "src/nodeobs_content.h" + "src/gs-limits.h" + "src/gs-vertex.h" "src/gs-vertex.cpp" + "src/gs-vertexbuffer.h" "src/gs-vertexbuffer.cpp" + "src/util-memory.h" "src/util-memory.cpp" ) SET(PROJECT_LIBRARIES ${CMAKE_JS_LIB} diff --git a/src/gs-limits.h b/src/gs-limits.h new file mode 100644 index 000000000..6c54798a1 --- /dev/null +++ b/src/gs-limits.h @@ -0,0 +1,26 @@ +/* +* Modern effects for a modern Streamer +* Copyright (C) 2017 Michael Fabian Dirks +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#pragma once +#include + +namespace GS { + static const uint32_t MAXIMUM_VERTICES = 0xFFFFFFu; + static const uint32_t MAXIMUM_UVW_LAYERS = 8u; +} \ No newline at end of file diff --git a/src/gs-vertex.cpp b/src/gs-vertex.cpp new file mode 100644 index 000000000..82463256b --- /dev/null +++ b/src/gs-vertex.cpp @@ -0,0 +1,48 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-vertex.h" +#include "util-memory.h" + +GS::Vertex::Vertex() { + this->hasStore = true; + this->store = util::malloc_aligned(16, sizeof(vec3) * 3 + sizeof(uint32_t) + sizeof(vec4)*MAXIMUM_UVW_LAYERS); + this->position = reinterpret_cast(store); + this->normal = reinterpret_cast(reinterpret_cast(store) + (16 * 1)); + this->tangent = reinterpret_cast(reinterpret_cast(store) + (16 * 2)); + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + this->uv[n] = reinterpret_cast(reinterpret_cast(store) + (16 * (2 + n))); + } + this->color = reinterpret_cast(reinterpret_cast(store) + (16 * (3 + MAXIMUM_UVW_LAYERS))); +} + +GS::Vertex::~Vertex() { + if (hasStore) + util::free_aligned(store); +} + +GS::Vertex::Vertex(vec3* p, vec3* n, vec3* t, uint32_t* col, vec4* uvs[MAXIMUM_UVW_LAYERS]) + : position(p), normal(n), tangent(t), color(col) { + if (uvs != nullptr) { + for (size_t idx = 0; idx < MAXIMUM_UVW_LAYERS; idx++) { + this->uv[idx] = uvs[idx]; + } + } + this->hasStore = false; +} diff --git a/src/gs-vertex.h b/src/gs-vertex.h new file mode 100644 index 000000000..17581e337 --- /dev/null +++ b/src/gs-vertex.h @@ -0,0 +1,47 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "gs-limits.h" +#include +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +namespace GS { + struct Vertex { + vec3* position; + vec3* normal; + vec3* tangent; + uint32_t* color; + vec4* uv[MAXIMUM_UVW_LAYERS]; + + Vertex(); + Vertex(vec3* p, vec3* n, vec3* t, uint32_t* col, vec4* uv[MAXIMUM_UVW_LAYERS]); + ~Vertex(); + + private: + bool hasStore; + void* store; + }; +} diff --git a/src/gs-vertexbuffer.cpp b/src/gs-vertexbuffer.cpp new file mode 100644 index 000000000..655135245 --- /dev/null +++ b/src/gs-vertexbuffer.cpp @@ -0,0 +1,331 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-vertexbuffer.h" +#include "util-memory.h" +#include +extern "C" { +#pragma warning( push ) +#pragma warning( disable: 4201 ) +#include +#pragma warning( pop ) +} + +GS::VertexBuffer::~VertexBuffer() { + if (m_positions) { + util::free_aligned(m_positions); + m_positions = nullptr; + } + if (m_normals) { + util::free_aligned(m_normals); + m_normals = nullptr; + } + if (m_tangents) { + util::free_aligned(m_tangents); + m_tangents = nullptr; + } + if (m_colors) { + util::free_aligned(m_colors); + m_colors = nullptr; + } + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + if (m_uvs[n]) { + util::free_aligned(m_uvs[n]); + m_uvs[n] = nullptr; + } + } + if (m_layerdata) { + util::free_aligned(m_layerdata); + m_layerdata = nullptr; + } + if (m_vertexbufferdata) { + std::memset(m_vertexbufferdata, 0, sizeof(gs_vb_data)); + if (!m_vertexbuffer) { + gs_vbdata_destroy(m_vertexbufferdata); + m_vertexbufferdata = nullptr; + } + } + if (m_vertexbuffer) { + obs_enter_graphics(); + gs_vertexbuffer_destroy(m_vertexbuffer); + obs_leave_graphics(); + m_vertexbuffer = nullptr; + } +} + +GS::VertexBuffer::VertexBuffer(uint32_t maximumVertices) { + if (maximumVertices > MAXIMUM_VERTICES) { + throw std::out_of_range("maximumVertices out of range"); + } + + // Assign limits. + m_capacity = maximumVertices; + m_layers = MAXIMUM_UVW_LAYERS; + + // Allocate memory for data. + m_vertexbufferdata = gs_vbdata_create(); + m_vertexbufferdata->num = m_capacity; + m_vertexbufferdata->points = m_positions = (vec3*)util::malloc_aligned(16, sizeof(vec3) * m_capacity); + std::memset(m_positions, 0, sizeof(vec3) * m_capacity); + m_vertexbufferdata->normals = m_normals = (vec3*)util::malloc_aligned(16, sizeof(vec3) * m_capacity); + std::memset(m_normals, 0, sizeof(vec3) * m_capacity); + m_vertexbufferdata->tangents = m_tangents = (vec3*)util::malloc_aligned(16, sizeof(vec3) * m_capacity); + std::memset(m_tangents, 0, sizeof(vec3) * m_capacity); + m_vertexbufferdata->colors = m_colors = (uint32_t*)util::malloc_aligned(16, sizeof(uint32_t) * m_capacity); + std::memset(m_colors, 0, sizeof(uint32_t) * m_capacity); + m_vertexbufferdata->num_tex = m_layers; + m_vertexbufferdata->tvarray = m_layerdata = (gs_tvertarray*)util::malloc_aligned(16, sizeof(gs_tvertarray)* m_layers); + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + m_layerdata[n].array = m_uvs[n] = (vec4*)util::malloc_aligned(16, sizeof(vec4) * m_capacity); + m_layerdata[n].width = 4; + std::memset(m_uvs[n], 0, sizeof(vec4) * m_capacity); + } + + // Allocate GPU + obs_enter_graphics(); + m_vertexbuffer = gs_vertexbuffer_create(m_vertexbufferdata, GS_DYNAMIC); + std::memset(m_vertexbufferdata, 0, sizeof(gs_vb_data)); + m_vertexbufferdata->num = m_capacity; + m_vertexbufferdata->num_tex = m_layers; + obs_leave_graphics(); + if (!m_vertexbuffer) { + throw std::runtime_error("Failed to create vertex buffer."); + } +} + +GS::VertexBuffer::VertexBuffer(gs_vertbuffer_t* vb) { + gs_vb_data* vbd = gs_vertexbuffer_get_data(vb); + VertexBuffer((uint32_t)vbd->num); + this->SetUVLayers((uint32_t)vbd->num_tex); + + if (vbd->points != nullptr) + std::memcpy(m_positions, vbd->points, vbd->num * sizeof(vec3)); + if (vbd->normals != nullptr) + std::memcpy(m_normals, vbd->normals, vbd->num * sizeof(vec3)); + if (vbd->tangents != nullptr) + std::memcpy(m_tangents, vbd->tangents, vbd->num * sizeof(vec3)); + if (vbd->colors != nullptr) + std::memcpy(m_colors, vbd->colors, vbd->num * sizeof(uint32_t)); + if (vbd->tvarray != nullptr) { + for (size_t n = 0; n < vbd->num_tex; n++) { + if (vbd->tvarray[n].array != nullptr && vbd->tvarray[n].width <= 4 && vbd->tvarray[n].width > 0) { + if (vbd->tvarray[n].width == 4) { + std::memcpy(m_uvs[n], vbd->tvarray[n].array, vbd->num * sizeof(vec4)); + } else { + for (size_t idx = 0; idx < m_capacity; idx++) { + float* mem = reinterpret_cast(vbd->tvarray[n].array) + + (idx * vbd->tvarray[n].width); + std::memset(&m_uvs[n][idx], 0, sizeof(vec4)); + std::memcpy(&m_uvs[n][idx], mem, vbd->tvarray[n].width); + } + } + } + } + } +} + + +GS::VertexBuffer::VertexBuffer(VertexBuffer const& other) : VertexBuffer(other.m_capacity) { + // Copy Constructor + std::memcpy(m_positions, other.m_positions, m_capacity * sizeof(vec3)); + std::memcpy(m_normals, other.m_normals, m_capacity * sizeof(vec3)); + std::memcpy(m_tangents, other.m_tangents, m_capacity * sizeof(vec3)); + std::memcpy(m_colors, other.m_colors, m_capacity * sizeof(vec3)); + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + std::memcpy(m_uvs[n], other.m_uvs[n], m_capacity * sizeof(vec3)); + } +} + +GS::VertexBuffer::VertexBuffer(VertexBuffer const&& other) { + // Move Constructor + m_capacity = other.m_capacity; + m_size = other.m_size; + m_layers = other.m_layers; + m_positions = other.m_positions; + m_normals = other.m_normals; + m_tangents = other.m_tangents; + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + m_uvs[n] = other.m_uvs[n]; + } + m_vertexbufferdata = other.m_vertexbufferdata; + m_vertexbuffer = other.m_vertexbuffer; + m_layerdata = other.m_layerdata; +} + +void GS::VertexBuffer::operator=(VertexBuffer const&& other) { + // Move Assignment + /// First self-destruct (semi-destruct itself). + if (m_positions) { + util::free_aligned(m_positions); + m_positions = nullptr; + } + if (m_normals) { + util::free_aligned(m_normals); + m_normals = nullptr; + } + if (m_tangents) { + util::free_aligned(m_tangents); + m_tangents = nullptr; + } + if (m_colors) { + util::free_aligned(m_colors); + m_colors = nullptr; + } + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + if (m_uvs[n]) { + util::free_aligned(m_uvs[n]); + m_uvs[n] = nullptr; + } + } + if (m_layerdata) { + util::free_aligned(m_layerdata); + m_layerdata = nullptr; + } + if (m_vertexbufferdata) { + std::memset(m_vertexbufferdata, 0, sizeof(gs_vb_data)); + if (!m_vertexbuffer) { + gs_vbdata_destroy(m_vertexbufferdata); + m_vertexbufferdata = nullptr; + } + } + if (m_vertexbuffer) { + obs_enter_graphics(); + gs_vertexbuffer_destroy(m_vertexbuffer); + obs_leave_graphics(); + m_vertexbuffer = nullptr; + } + + /// Then assign new values. + m_capacity = other.m_capacity; + m_size = other.m_size; + m_layers = other.m_layers; + m_positions = other.m_positions; + m_normals = other.m_normals; + m_tangents = other.m_tangents; + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + m_uvs[n] = other.m_uvs[n]; + } + m_vertexbufferdata = other.m_vertexbufferdata; + m_vertexbuffer = other.m_vertexbuffer; + m_layerdata = other.m_layerdata; +} + +void GS::VertexBuffer::Resize(uint32_t new_size) { + if (new_size > m_capacity) { + throw std::out_of_range("new_size out of range"); + } + m_size = new_size; +} + +uint32_t GS::VertexBuffer::Size() { + return m_size; +} + +bool GS::VertexBuffer::Empty() { + return m_size == 0; +} + +const GS::Vertex GS::VertexBuffer::At(uint32_t idx) { + if ((idx < 0) || (idx >= m_size)) { + throw std::out_of_range("idx out of range"); + } + + GS::Vertex vtx(&m_positions[idx], &m_normals[idx], &m_tangents[idx], &m_colors[idx], nullptr); + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + vtx.uv[n] = &m_uvs[n][idx]; + } + return vtx; +} + +const GS::Vertex GS::VertexBuffer::operator[](uint32_t const pos) { + return At(pos); +} + +void GS::VertexBuffer::SetUVLayers(uint32_t layers) { + m_layers = layers; +} + +uint32_t GS::VertexBuffer::GetUVLayers() { + return m_layers; +} + +vec3* GS::VertexBuffer::GetPositions() { + return m_positions; +} + +vec3* GS::VertexBuffer::GetNormals() { + return m_normals; +} + +vec3* GS::VertexBuffer::GetTangents() { + return m_tangents; +} + +uint32_t* GS::VertexBuffer::GetColors() { + return m_colors; +} + +vec4* GS::VertexBuffer::GetUVLayer(size_t idx) { + if ((idx < 0) || (idx >= m_layers)) { + throw std::out_of_range("idx out of range"); + } + return m_uvs[idx]; +} + +gs_vertbuffer_t* GS::VertexBuffer::Update(bool refreshGPU) { + if (!refreshGPU) + return m_vertexbuffer; + + if (m_size > m_capacity) + throw std::out_of_range("size is larger than capacity"); + + // Update VertexBuffer data. + m_vertexbufferdata = gs_vertexbuffer_get_data(m_vertexbuffer); + std::memset(m_vertexbufferdata, 0, sizeof(gs_vb_data)); + m_vertexbufferdata->num = m_capacity; + m_vertexbufferdata->points = m_positions; + m_vertexbufferdata->normals = m_normals; + m_vertexbufferdata->tangents = m_tangents; + m_vertexbufferdata->colors = m_colors; + m_vertexbufferdata->num_tex = m_layers; + m_vertexbufferdata->tvarray = m_layerdata; + for (size_t n = 0; n < MAXIMUM_UVW_LAYERS; n++) { + m_layerdata[n].array = m_uvs[n]; + m_layerdata[n].width = 4; + } + + // Update GPU + obs_enter_graphics(); + gs_vertexbuffer_flush(m_vertexbuffer); + obs_leave_graphics(); + + // WORKAROUND: OBS Studio 20.x and below incorrectly deletes data that it doesn't own. + std::memset(m_vertexbufferdata, 0, sizeof(gs_vb_data)); + m_vertexbufferdata->num = m_capacity; + m_vertexbufferdata->num_tex = m_layers; + for (uint32_t n = 0; n < m_layers; n++) { + m_layerdata[n].width = 4; + } + + return m_vertexbuffer; +} + +gs_vertbuffer_t* GS::VertexBuffer::Update() { + return Update(true); +} diff --git a/src/gs-vertexbuffer.h b/src/gs-vertexbuffer.h new file mode 100644 index 000000000..a561e603f --- /dev/null +++ b/src/gs-vertexbuffer.h @@ -0,0 +1,179 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "gs-limits.h" +#include "gs-vertex.h" +#include "util-memory.h" +#include +extern "C" { +#pragma warning( push ) +#pragma warning( disable: 4201 ) +#include +#pragma warning( pop ) +} + +namespace GS { + class VertexBuffer { + public: + #pragma region Constructor & Destructor + virtual ~VertexBuffer(); + + /*! + * \brief Create a Vertex Buffer with a specific number of Vertices. + * + * \param maximumVertices Maximum amount of vertices to store. + */ + VertexBuffer(uint32_t maximumVertices); + + /*! + * \brief Create a Vertex Buffer with the maximum number of Vertices. + * + * \param maximumVertices Maximum amount of vertices to store. + */ + VertexBuffer() : VertexBuffer(MAXIMUM_VERTICES) {}; + + /*! + * \brief Create a copy of a Vertex Buffer + * Full Description below + * + * \param other The Vertex Buffer to copy + */ + VertexBuffer(gs_vertbuffer_t* other); + + #pragma endregion Constructor & Destructor + + #pragma region Copy/Move Constructors + // Copy Constructor & Assignments + + /*! + * \brief Copy Constructor + * + * + * \param other + */ + VertexBuffer(VertexBuffer const& other); + + /*! + * \brief Copy Assignment + * Unsafe operation and as such marked as deleted. + * + * \param other + */ + void operator=(VertexBuffer const& other) = delete; + + // Move Constructor & Assignments + + /*! + * \brief Move Constructor + * + * + * \param other + */ + VertexBuffer(VertexBuffer const&& other); + + /*! + * \brief Move Assignment + * + * + * \param other + */ + void operator=(VertexBuffer const&& other); + #pragma endregion Copy/Move Constructors + + + + void Resize(uint32_t new_size); + + uint32_t Size(); + + bool Empty(); + + const GS::Vertex At(uint32_t idx); + + const GS::Vertex operator[](uint32_t const pos); + + void SetUVLayers(uint32_t layers); + + uint32_t GetUVLayers(); + + /*! + * \brief Directly access the positions buffer + * Returns the internal memory that is assigned to hold all vertex positions. + * + * \return A that points at the first vertex's position. + */ + vec3* GetPositions(); + + /*! + * \brief Directly access the normals buffer + * Returns the internal memory that is assigned to hold all vertex normals. + * + * \return A that points at the first vertex's normal. + */ + vec3* GetNormals(); + + /*! + * \brief Directly access the tangents buffer + * Returns the internal memory that is assigned to hold all vertex tangents. + * + * \return A that points at the first vertex's tangent. + */ + vec3* GetTangents(); + + /*! + * \brief Directly access the colors buffer + * Returns the internal memory that is assigned to hold all vertex colors. + * + * \return A that points at the first vertex's color. + */ + uint32_t* GetColors(); + + /*! + * \brief Directly access the uv buffer + * Returns the internal memory that is assigned to hold all vertex uvs. + * + * \return A that points at the first vertex's uv. + */ + vec4* GetUVLayer(size_t idx); + + #pragma region Update / Grab GS object + gs_vertbuffer_t* Update(); + + gs_vertbuffer_t* Update(bool refreshGPU); + #pragma endregion Update / Grab GS object + + private: + uint32_t m_size; + uint32_t m_capacity; + uint32_t m_layers; + + // Memory Storage + vec3 *m_positions; + vec3 *m_normals; + vec3 *m_tangents; + uint32_t *m_colors; + vec4 *m_uvs[MAXIMUM_UVW_LAYERS]; + + // OBS GS Data + gs_vb_data* m_vertexbufferdata; + gs_vertbuffer_t* m_vertexbuffer; + gs_tvertarray* m_layerdata; + }; +} diff --git a/src/nodeobs_display.cpp b/src/nodeobs_display.cpp index 043fe679a..f2e992ff4 100644 --- a/src/nodeobs_display.cpp +++ b/src/nodeobs_display.cpp @@ -77,11 +77,11 @@ OBS::Display::Display() { obs_enter_graphics(); m_gsSolidEffect = obs_get_base_effect(OBS_EFFECT_SOLID); - m_lines = new VertexBufferHelper(); - m_triangles = new VertexBufferHelper(); + m_lines = new GS::VertexBuffer(65535); + m_triangles = new GS::VertexBuffer(65535); // Text - m_textVertices = new VertexBufferHelper(); + m_textVertices = new GS::VertexBuffer(65535); m_textEffect = obs_get_base_effect(OBS_EFFECT_DEFAULT); m_textTexture = gs_texture_create_from_file((g_moduleDirectory + "/resources/roboto.png").c_str()); if (!m_textTexture) { @@ -268,7 +268,7 @@ void OBS::Display::SetResizeBoxInnerColor(uint8_t r, uint8_t g, uint8_t b, uint8 m_resizeInnerColor = a << 24 | b << 16 | g << 8 | r; } -static void DrawGlyph(OBS::VertexBufferHelper* vb, float_t x, float_t y, float_t scale, float_t depth, char glyph, uint32_t color) { +static void DrawGlyph(GS::VertexBuffer* vb, float_t x, float_t y, float_t scale, float_t depth, char glyph, uint32_t color) { // I'll be fully honest here, this code is pretty much shit. It works but // it is far from ideal and can just render very basic text. It does the // job but, well, lets just say it shouldn't be used for other things. @@ -328,104 +328,112 @@ static void DrawGlyph(OBS::VertexBufferHelper* vb, float_t x, float_t y, float_t break; } + GS::Vertex v; + size_t bs = vb->Size(); + vb->Resize(bs + 6); + // Top Left - OBS::VertexHelper* v = vb->add(); - vec3_set(&v->pos, x, y, depth); - vec2_set(&v->uv0, uvX, uvY); - v->color = color; + v = vb->At(bs + 0); + vec3_set(v.position, x, y, depth); + vec4_set(v.uv[0], uvX, uvY, 0, 0); + *v.color = color; // Top Right - v = vb->add(); - vec3_set(&v->pos, x + scale, y, depth); - vec2_set(&v->uv0, uvX + uvO, uvY); - v->color = color; + v = vb->At(bs + 1); + vec3_set(v.position, x + scale, y, depth); + vec4_set(v.uv[0], uvX + uvO, uvY, 0, 0); + *v.color = color; // Bottom Left - v = vb->add(); - vec3_set(&v->pos, x, y + scale * 2, depth); - vec2_set(&v->uv0, uvX, uvY + uvO); - v->color = color; + v = vb->At(bs + 2); + vec3_set(v.position, x, y + scale * 2, depth); + vec4_set(v.uv[0], uvX, uvY + uvO, 0, 0); + *v.color = color; // Top Right - v = vb->add(); - vec3_set(&v->pos, x + scale, y, depth); - vec2_set(&v->uv0, uvX + uvO, uvY); - v->color = color; + v = vb->At(bs + 3); + vec3_set(v.position, x + scale, y, depth); + vec4_set(v.uv[0], uvX + uvO, uvY, 0, 0); + *v.color = color; // Bottom Left - v = vb->add(); - vec3_set(&v->pos, x, y + scale * 2, depth); - vec2_set(&v->uv0, uvX, uvY + uvO); - v->color = color; + v = vb->At(bs + 4); + vec3_set(v.position, x, y + scale * 2, depth); + vec4_set(v.uv[0], uvX, uvY + uvO, 0, 0); + *v.color = color; // Bottom Right - v = vb->add(); - vec3_set(&v->pos, x + scale, y + scale * 2, depth); - vec2_set(&v->uv0, uvX + uvO, uvY + uvO); - v->color = color; + v = vb->At(bs + 5); + vec3_set(v.position, x + scale, y + scale * 2, depth); + vec4_set(v.uv[0], uvX + uvO, uvY + uvO, 0, 0); + *v.color = color; } -inline void DrawBox(float_t x, float_t y, float_t w, float_t h, float_t depth, uint32_t color, OBS::VertexBufferHelper* vbh) { - OBS::VertexHelper* v; +inline void DrawBox(float_t x, float_t y, float_t w, float_t h, float_t depth, uint32_t color, GS::VertexBuffer* vbh) { + GS::Vertex v; + size_t bs = vbh->Size(); + vbh->Resize(bs + 6); - v = vbh->add(); - vec3_set(&v->pos, x, y, depth); - v->color = color; + v = vbh->At(bs + 0); + vec3_set(v.position, x, y, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y, depth); - v->color = color; + v = vbh->At(bs + 1); + vec3_set(v.position, x + w, y, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x, y + h, depth); - v->color = color; + v = vbh->At(bs + 2); + vec3_set(v.position, x, y + h, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x, y + h, depth); - v->color = color; + v = vbh->At(bs + 3); + vec3_set(v.position, x, y + h, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y, depth); - v->color = color; + v = vbh->At(bs + 4); + vec3_set(v.position, x + w, y, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y + h, depth); - v->color = color; + v = vbh->At(bs + 5); + vec3_set(v.position, x + w, y + h, depth); + *v.color = color; } -inline void DrawBoxOutline(float_t x, float_t y, float_t w, float_t h, float_t depth, uint32_t color, OBS::VertexBufferHelper* vbh) { - OBS::VertexHelper* v; +inline void DrawBoxOutline(float_t x, float_t y, float_t w, float_t h, float_t depth, uint32_t color, GS::VertexBuffer* vbh) { + GS::Vertex v; + size_t bs = vbh->Size(); + vbh->Resize(bs + 8); - v = vbh->add(); - vec3_set(&v->pos, x, y, depth); - v->color = color; + v = vbh->At(bs + 0); + vec3_set(v.position, x, y, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y, depth); - v->color = color; + v = vbh->At(bs + 1); + vec3_set(v.position, x + w, y, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y, depth); - v->color = color; + v = vbh->At(bs + 2); + vec3_set(v.position, x + w, y, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y + h, depth); - v->color = color; + v = vbh->At(bs + 3); + vec3_set(v.position, x + w, y + h, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x + w, y + h, depth); - v->color = color; + v = vbh->At(bs + 4); + vec3_set(v.position, x + w, y + h, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x, y + h, depth); - v->color = color; + v = vbh->At(bs + 5); + vec3_set(v.position, x, y + h, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x, y + h, depth); - v->color = color; + v = vbh->At(bs + 6); + vec3_set(v.position, x, y + h, depth); + *v.color = color; - v = vbh->add(); - vec3_set(&v->pos, x, y, depth); - v->color = color; + v = vbh->At(bs + 7); + vec3_set(v.position, x, y, depth); + *v.color = color; } bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, void *param) { @@ -441,8 +449,8 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, uint32_t flags = obs_source_get_output_flags(itemSource); bool isOnlyAudio = (flags & OBS_SOURCE_VIDEO) == 0; + GS::Vertex v(nullptr, nullptr, nullptr, nullptr, nullptr); if (obs_sceneitem_selected(item) && !isOnlyAudio && ((itemWidth > 0) && (itemHeight > 0))) { - VertexHelper* v; matrix4 itemMatrix, sceneToView; obs_sceneitem_get_box_transform(item, &itemMatrix); @@ -486,12 +494,16 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, float_t pt = 8; for (size_t n = 0; n < 4; n++) { + bool isIn = (edge[n].x >= 0) && (edge[n].x < sceneWidth * dp->m_worldToPreviewScale.x) && (edge[n].y >= 0) && (edge[n].y < sceneHeight * dp->m_worldToPreviewScale.y); if (!isIn) continue; + size_t bs = dp->m_lines->Size(); + dp->m_lines->Resize(bs + 2); + vec3 alignLeft = { -1, 0, 0 }; vec3 alignTop = { 0, -1, 0 }; @@ -501,13 +513,13 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, float left = vec3_dot(&temp, &alignLeft), top = vec3_dot(&temp, &alignTop); if (left > 0.5) { // LEFT - v = dp->m_lines->add(); - vec3_set(&v->pos, 0, edge[n].y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 0); + vec3_set(v.position, 0, edge[n].y, 0); + *v.color = dp->m_guidelineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, edge[n].x, edge[n].y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 1); + vec3_set(v.position, edge[n].x, edge[n].y, 0); + *v.color = dp->m_guidelineColor; float_t dist = edge[n].x; if (dist > (pt * 4)) { @@ -524,13 +536,13 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, } } } else if (left < -0.5) { // RIGHT - v = dp->m_lines->add(); - vec3_set(&v->pos, sceneWidth * dp->m_worldToPreviewScale.x, edge[n].y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 0); + vec3_set(v.position, sceneWidth * dp->m_worldToPreviewScale.x, edge[n].y, 0); + *v.color = dp->m_guidelineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, edge[n].x, edge[n].y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 1); + vec3_set(v.position, edge[n].x, edge[n].y, 0); + *v.color = dp->m_guidelineColor; float_t dist = sceneWidth * dp->m_worldToPreviewScale.x - edge[n].x; if (dist > (pt * 4)) { @@ -547,13 +559,13 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, } } } else if (top > 0.5) { // UP - v = dp->m_lines->add(); - vec3_set(&v->pos, edge[n].x, 0, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 0); + vec3_set(v.position, edge[n].x, 0, 0); + *v.color = dp->m_guidelineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, edge[n].x, edge[n].y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 1); + vec3_set(v.position, edge[n].x, edge[n].y, 0); + *v.color = dp->m_guidelineColor; float_t dist = edge[n].y; if (dist > pt) { @@ -570,13 +582,13 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, } } } else if (top < -0.5) { // DOWN - v = dp->m_lines->add(); - vec3_set(&v->pos, edge[n].x, sceneHeight * dp->m_worldToPreviewScale.y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 0); + vec3_set(v.position, edge[n].x, sceneHeight * dp->m_worldToPreviewScale.y, 0); + *v.color = dp->m_guidelineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, edge[n].x, edge[n].y, 0); - v->color = dp->m_guidelineColor; + v = dp->m_lines->At(bs + 1); + vec3_set(v.position, edge[n].x, edge[n].y, 0); + *v.color = dp->m_guidelineColor; float_t dist = sceneHeight * dp->m_worldToPreviewScale.y - edge[n].y; if (dist > (pt * 4)) { @@ -594,36 +606,38 @@ bool OBS::Display::DrawSelectedSource(obs_scene_t *scene, obs_sceneitem_t *item, } } } + size_t bs = dp->m_lines->Size(); + dp->m_lines->Resize(bs + 8); // Drawing /// Outline - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[0].x, corner[0].y, 0); - v->color = dp->m_outlineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[1].x, corner[1].y, 0); - v->color = dp->m_outlineColor; - - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[1].x, corner[1].y, 0); - v->color = dp->m_outlineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[2].x, corner[2].y, 0); - v->color = dp->m_outlineColor; - - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[2].x, corner[2].y, 0); - v->color = dp->m_outlineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[3].x, corner[3].y, 0); - v->color = dp->m_outlineColor; - - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[3].x, corner[3].y, 0); - v->color = dp->m_outlineColor; - v = dp->m_lines->add(); - vec3_set(&v->pos, corner[0].x, corner[0].y, 0); - v->color = dp->m_outlineColor; + v = dp->m_lines->At(bs + 0); + vec3_set(v.position, corner[0].x, corner[0].y, 0); + *v.color = dp->m_outlineColor; + v = dp->m_lines->At(bs + 1); + vec3_set(v.position, corner[1].x, corner[1].y, 0); + *v.color = dp->m_outlineColor; + + v = dp->m_lines->At(bs + 2); + vec3_set(v.position, corner[1].x, corner[1].y, 0); + *v.color = dp->m_outlineColor; + v = dp->m_lines->At(bs + 3); + vec3_set(v.position, corner[2].x, corner[2].y, 0); + *v.color = dp->m_outlineColor; + + v = dp->m_lines->At(bs + 4); + vec3_set(v.position, corner[2].x, corner[2].y, 0); + *v.color = dp->m_outlineColor; + v = dp->m_lines->At(bs + 5); + vec3_set(v.position, corner[3].x, corner[3].y, 0); + *v.color = dp->m_outlineColor; + + v = dp->m_lines->At(bs + 6); + vec3_set(v.position, corner[3].x, corner[3].y, 0); + *v.color = dp->m_outlineColor; + v = dp->m_lines->At(bs + 7); + vec3_set(v.position, corner[0].x, corner[0].y, 0); + *v.color = dp->m_outlineColor; /// Resize Boxes DrawBox(corner[0].x - 5, corner[0].y - 5, 10, 10, 0, dp->m_resizeOuterColor, dp->m_triangles); @@ -680,30 +694,30 @@ void OBS::Display::DisplayCallback(OBS::Display* dp, uint32_t cx, uint32_t cy) { dp->m_previewSize.first, dp->m_previewSize.second); #pragma region Background - dp->m_triangles->clear(); + dp->m_triangles->Resize(4); { - VertexHelper* v = dp->m_triangles->add(); - vec3_set(&v->pos, 0, 0, 0); - v->color = dp->m_backgroundColor; + GS::Vertex v = dp->m_triangles->At(0); + vec3_set(v.position, 0, 0, 0); + *v.color = dp->m_backgroundColor; - v = dp->m_triangles->add(); - vec3_set(&v->pos, float(sourceW), 0, 0); - v->color = dp->m_backgroundColor; + v = dp->m_triangles->At(1); + vec3_set(v.position, float(sourceW), 0, 0); + *v.color = dp->m_backgroundColor; - v = dp->m_triangles->add(); - vec3_set(&v->pos, 0, float(sourceH), 0); - v->color = dp->m_backgroundColor; + v = dp->m_triangles->At(2); + vec3_set(v.position, 0, float(sourceH), 0); + *v.color = dp->m_backgroundColor; - v = dp->m_triangles->add(); - vec3_set(&v->pos, float(sourceW), float(sourceH), 0); - v->color = dp->m_backgroundColor; + v = dp->m_triangles->At(3); + vec3_set(v.position, float(sourceW), float(sourceH), 0); + *v.color = dp->m_backgroundColor; } - gs_vertbuffer_t *vb = dp->m_triangles->update(); + gs_vertbuffer_t *vb = dp->m_triangles->Update(); while (gs_effect_loop(dp->m_gsSolidEffect, "SolidColored")) { gs_load_vertexbuffer(vb); gs_load_indexbuffer(nullptr); - gs_draw(GS_TRISTRIP, 0, (uint32_t)dp->m_triangles->size()); + gs_draw(GS_TRISTRIP, 0, (uint32_t)dp->m_triangles->Size()); } #pragma endregion Background @@ -720,9 +734,9 @@ void OBS::Display::DisplayCallback(OBS::Display* dp, uint32_t cx, uint32_t cy) { -100.0f, 100.0f); // Clear Buffers - dp->m_lines->clear(); - dp->m_triangles->clear(); - dp->m_textVertices->clear(); + dp->m_lines->Resize(0); + dp->m_triangles->Resize(0); + dp->m_textVertices->Resize(0); /* Here we assume that channel 0 holds the one and only transition. * We also assume that the active source within that transition is @@ -736,35 +750,35 @@ void OBS::Display::DisplayCallback(OBS::Display* dp, uint32_t cx, uint32_t cy) { obs_source_release(source); // Lines - if (dp->m_lines->size() > 0) { - gs_vertbuffer_t* vb = dp->m_lines->update(); + if (dp->m_lines->Size() > 0) { + gs_vertbuffer_t* vb = dp->m_lines->Update(); while (gs_effect_loop(dp->m_gsSolidEffect, "SolidColored")) { gs_load_vertexbuffer(vb); gs_load_indexbuffer(nullptr); - gs_draw(GS_LINES, 0, (uint32_t)dp->m_lines->size()); + gs_draw(GS_LINES, 0, (uint32_t)dp->m_lines->Size()); } } // Triangles - if (dp->m_triangles->size() > 0) { - gs_vertbuffer_t* vb = dp->m_triangles->update(); + if (dp->m_triangles->Size() > 0) { + gs_vertbuffer_t* vb = dp->m_triangles->Update(); while (gs_effect_loop(dp->m_gsSolidEffect, "SolidColored")) { gs_load_vertexbuffer(vb); gs_load_indexbuffer(nullptr); - gs_draw(GS_TRIS, 0, (uint32_t)dp->m_triangles->size()); + gs_draw(GS_TRIS, 0, (uint32_t)dp->m_triangles->Size()); } } // Text Rendering - if (dp->m_textVertices->size() > 0) { - gs_vertbuffer_t* vb = dp->m_textVertices->update(); + if (dp->m_textVertices->Size() > 0) { + gs_vertbuffer_t* vb = dp->m_textVertices->Update(); while (gs_effect_loop(dp->m_textEffect, "Draw")) { gs_effect_set_texture( gs_effect_get_param_by_name(dp->m_textEffect, "image"), dp->m_textTexture); gs_load_vertexbuffer(vb); gs_load_indexbuffer(nullptr); - gs_draw(GS_TRIS, 0, (uint32_t)dp->m_textVertices->size()); + gs_draw(GS_TRIS, 0, (uint32_t)dp->m_textVertices->Size()); } } } @@ -860,97 +874,3 @@ LRESULT CALLBACK OBS::Display::DisplayWndProc(_In_ HWND hwnd, _In_ UINT uMsg, _I } #endif - -OBS::VertexHelper::VertexHelper() { - vec3_set(&pos, 0, 0, 0); - vec3_set(&normal, 0, 0, 0); - vec3_set(&tangent, 0, 0, 0); - color = 0xFFFFFFFF; - vec2_set(&uv0, 0, 0); - vec2_set(&uv1, 0, 0); -} - -OBS::VertexBufferHelper::VertexBufferHelper(size_t initialSize) { - t_vertices.reserve(initialSize); - t_normals.reserve(initialSize); - t_tangents.reserve(initialSize); - t_colors.reserve(initialSize); - t_uv0.reserve(initialSize); - t_uv1.reserve(initialSize); - - vbdata = gs_vbdata_create(); - std::memset(vbdata, 0, sizeof(gs_vb_data)); - vbdata->num = t_vertices.capacity(); - vbdata->points = t_vertices.data(); - vbdata->colors = t_colors.data(); - vbdata->normals = t_normals.data(); - vbdata->tangents = t_tangents.data(); - vbdata->num_tex = 2; - vbuvdata.resize(2); - vbdata->tvarray = vbuvdata.data(); - - vbuvdata[0].width = 2; - vbuvdata[0].array = t_uv0.data(); - vbuvdata[1].width = 2; - vbuvdata[1].array = t_uv1.data(); - - vb = gs_vertexbuffer_create(vbdata, GS_DYNAMIC); -} - -OBS::VertexBufferHelper::~VertexBufferHelper() { - if (vb) { - std::memset(vbdata, 0, sizeof(gs_vb_data)); - gs_vertexbuffer_destroy(vb); - } - if (vbdata) { - gs_vbdata_destroy(vbdata); - } -} - -void OBS::VertexBufferHelper::clear() { - vertices.clear(); -} - -OBS::VertexHelper* OBS::VertexBufferHelper::add() { - vertices.emplace_back(); - return &vertices.back(); -} - -gs_vertbuffer_t* OBS::VertexBufferHelper::update() { - size_t verts = vertices.size(); - t_vertices.resize(verts); - t_normals.resize(verts); - t_tangents.resize(verts); - t_colors.resize(verts); - t_uv0.resize(verts); - t_uv1.resize(verts); - - for (size_t n = 0; n < verts; n++) { - VertexHelper& v = vertices[n]; - vec3_copy(&t_vertices[n], &v.pos); - vec3_copy(&t_normals[n], &v.normal); - vec3_copy(&t_tangents[n], &v.tangent); - t_colors[n] = v.color; - vec2_copy(&t_uv0[n], &v.uv0); - vec2_copy(&t_uv1[n], &v.uv1); - } - - vbdata->num = verts; - vbdata->points = t_vertices.data(); - vbdata->normals = t_normals.data(); - vbdata->tangents = t_tangents.data(); - vbdata->colors = t_colors.data(); - vbdata->tvarray = vbuvdata.data(); - vbdata->num_tex = 2; - vbuvdata[0].width = 2; - vbuvdata[0].array = t_uv0.data(); - vbuvdata[1].width = 2; - vbuvdata[1].array = t_uv1.data(); - - gs_vertexbuffer_flush(vb); - return vb; -} - -size_t OBS::VertexBufferHelper::size() { - return vertices.size(); -} diff --git a/src/nodeobs_display.h b/src/nodeobs_display.h index a63286862..b05b495bd 100644 --- a/src/nodeobs_display.h +++ b/src/nodeobs_display.h @@ -5,6 +5,7 @@ #include #include #include +#include "gs-vertexbuffer.h" #if defined(_WIN32) #ifdef NOWINOFFSETS @@ -21,34 +22,6 @@ EXTERN_C IMAGE_DOS_HEADER __ImageBase; #endif namespace OBS { - struct VertexHelper { - VertexHelper(); - - vec3 pos, normal, tangent; - uint32_t color; - vec2 uv0, uv1; - }; - - class VertexBufferHelper { - private: - gs_vertbuffer_t* vb; - gs_vb_data* vbdata; - std::vector vertices; - std::vector vbuvdata; - std::vector t_vertices, t_normals, t_tangents; - std::vector t_colors; - std::vector t_uv0, t_uv1; - - public: - VertexBufferHelper(size_t initialSize = 65535); - virtual ~VertexBufferHelper(); - - void clear(); - VertexHelper* add(); - gs_vertbuffer_t* update(); - size_t size(); - }; - class Display { #pragma region Constructors & Finalizer private: @@ -105,7 +78,7 @@ namespace OBS { *m_textEffect; gs_texture_t *m_textTexture; - VertexBufferHelper + GS::VertexBuffer *m_lines, *m_triangles, *m_textVertices; diff --git a/src/util-memory.cpp b/src/util-memory.cpp new file mode 100644 index 000000000..cbe702414 --- /dev/null +++ b/src/util-memory.cpp @@ -0,0 +1,43 @@ +/* +* Modern effects for a modern Streamer +* Copyright (C) 2017 Michael Fabian Dirks +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#include "util-memory.h" +#include + +void* util::malloc_aligned(size_t align, size_t size) { + // Ensure that we have space for the pointer and the data. + size_t asize = aligned_offset(align, size + sizeof(void*)); + + // Allocate memory and store integer representation of pointer. + void* ptr = malloc(asize); + + // Calculate actual aligned position + intptr_t ptr_off = aligned_offset(align, reinterpret_cast(ptr)+sizeof(void*)); + + // Store actual pointer at ptr_off - sizeof(void*). + *reinterpret_cast(ptr_off - sizeof(void*)) = reinterpret_cast(ptr); + + // Return aligned pointer + return reinterpret_cast(ptr_off); +} + +void util::free_aligned(void* mem) { + void* ptr = reinterpret_cast(*reinterpret_cast(static_cast(mem)-sizeof(void*))); + free(ptr); +} diff --git a/src/util-memory.h b/src/util-memory.h new file mode 100644 index 000000000..f7b15dc44 --- /dev/null +++ b/src/util-memory.h @@ -0,0 +1,98 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include +#include + +namespace util { + inline size_t aligned_offset(size_t align, size_t pos) { + return ((pos / align) + 1) * align; + } + void* malloc_aligned(size_t align, size_t size); + void free_aligned(void* mem); + + template + class AlignmentAllocator { + public: + typedef T value_type; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef T * pointer; + typedef const T * const_pointer; + + typedef T & reference; + typedef const T & const_reference; + + public: + inline AlignmentAllocator() throw () {} + + template + inline AlignmentAllocator(const AlignmentAllocator &) throw () {} + + inline ~AlignmentAllocator() throw () {} + + inline pointer adress(reference r) { + return &r; + } + + inline const_pointer adress(const_reference r) const { + return &r; + } + + inline pointer allocate(size_type n) { + return (pointer)malloc_aligned(n*sizeof(value_type), N); + } + + inline void deallocate(pointer p, size_type) { + free_aligned(p); + } + + inline void construct(pointer p, const value_type & wert) { + new (p)value_type(wert); + } + + inline void destroy(pointer p) { + p->~value_type(); + p; + } + + inline size_type max_size() const throw () { + return size_type(-1) / sizeof(value_type); + } + + template + struct rebind { + typedef AlignmentAllocator other; + }; + + bool operator!=(const AlignmentAllocator& other) const { + return !(*this == other); + } + + // Returns true if and only if storage allocated from *this + // can be deallocated from other, and vice versa. + // Always returns true for stateless allocators. + bool operator==(const AlignmentAllocator& other) const { + return true; + } + }; +}; +