realized past me realized that aliasing buffers isn't foolproof and added a system to fetch buffer descriptors by name from a source, yet never used it (re-bind buffer descriptors on mesh updates, need to fix the crash for graph storage when it resizes...)

This commit is contained in:
ecker 2025-08-19 19:18:12 -05:00
parent 6d4837e3cc
commit 0a29063869
14 changed files with 603 additions and 471 deletions

View File

@ -78,8 +78,8 @@
"stream": {
"tag": "worldspawn",
"player": "info_player_spawn",
"enabled": "auto",
"radius": 32,
"enabled": true, // "auto",
"radius": 16,
"every": 1
}
}

View File

@ -17,7 +17,7 @@
}
},
"graph": {
"initial buffer elements": 256
"initial buffer elements": 128
},
"ext": {
"opengl": {

View File

@ -161,7 +161,7 @@ namespace uf {
void UF_API initialize( uf::Object&, size_t = uf::graph::initialBufferElements );
void UF_API initialize( pod::Graph::Storage&, size_t = uf::graph::initialBufferElements );
void UF_API tick( uf::Object& );
void UF_API tick( pod::Graph::Storage& );
bool UF_API tick( pod::Graph::Storage& );
void UF_API render( uf::Object& );
void UF_API render( pod::Graph::Storage& );
void UF_API destroy( uf::Object&, bool soft = false );

View File

@ -13,6 +13,7 @@ namespace ext {
struct Device;
struct UF_API Buffer {
bool aliased = false;
Device* device;
GLuint buffer = 0;

View File

@ -38,6 +38,10 @@ namespace ext {
} textures, buffers;
struct {
uf::stl::vector<Buffer> buffers;
} transient;
void initialize();
void destroy();

View File

@ -110,6 +110,11 @@ namespace ext {
void destroy();
bool validate();
bool hasBuffer( const uf::stl::string& name );
void aliasBuffer( const Metadata::BufferDescriptor& descriptor );
void aliasBuffer( const ext::opengl::Buffer& buffer );
void aliasBuffer( const uf::stl::string& name, const ext::opengl::Buffer& = {}, const ext::opengl::RenderMode* renderMode = NULL, GLenum = 0 );
bool hasUniform( const uf::stl::string& name ) const;
Buffer& getUniformBuffer( const uf::stl::string& name );

View File

@ -144,6 +144,7 @@ namespace ext {
bool hasBuffer( const uf::stl::string& name );
void aliasBuffer( const Metadata::BufferDescriptor& descriptor );
void aliasBuffer( const ext::vulkan::Buffer& buffer );
void aliasBuffer( const uf::stl::string& name, const ext::vulkan::Buffer& = {}, const ext::vulkan::RenderMode* renderMode = NULL, VkBufferUsageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT );
bool hasUniform( const uf::stl::string& name ) const;

File diff suppressed because it is too large Load Diff

View File

@ -12,15 +12,14 @@ ext::opengl::Buffer ext::opengl::Buffer::alias() const {
return buffer;
}
void ext::opengl::Buffer::aliasBuffer( const ext::opengl::Buffer& buffer ) {
*this = {
.device = NULL,
.buffer = buffer.buffer,
.descriptor = buffer.descriptor,
.size = buffer.size,
.alignment = buffer.alignment,
.usage = buffer.usage,
.allocationInfo = buffer.allocationInfo,
};
this->aliased = true;
this->device = NULL;
this->buffer = buffer.buffer;
this->descriptor = buffer.descriptor;
this->size = buffer.size;
this->alignment = buffer.alignment;
this->usage = buffer.usage;
this->allocationInfo = buffer.allocationInfo;
}
void* ext::opengl::Buffer::map( GLsizeiptr size, GLsizeiptr offset ) {
@ -52,9 +51,18 @@ void ext::opengl::Buffer::initialize( const void* data, GLsizeiptr length, GLenu
} );
if ( !alias ) this->update( data, length );
}
bool ext::opengl::Buffer::update( const void* data, GLsizeiptr len ) const {
bool ext::opengl::Buffer::update( const void* data, GLsizeiptr length ) const {
if ( !buffer || !data ) return false;
if ( len >= size ) len = size;
if ( length > allocationInfo.size ) {
UF_MSG_WARNING("Buffer update of {} exceeds buffer size of {}", length, allocationInfo.size);
auto savedUsage = usage;
Buffer& self = const_cast<Buffer&>(*this);
self.destroy(true);
self.initialize(data, length, savedUsage);
return true;
}
#if !UF_USE_OPENGL_FIXED_FUNCTION
// GPU-bound buffer
GLenum usage;
@ -74,12 +82,12 @@ bool ext::opengl::Buffer::update( const void* data, GLsizeiptr len ) const {
if ( usage & enums::Buffer::COPY ) usage = GL_DYNAMIC_COPY;
}
GL_ERROR_CHECK(glBindBuffer(GL_COPY_WRITE_BUFFER, buffer));
GL_ERROR_CHECK(glBufferData(GL_COPY_WRITE_BUFFER, len, data, usage));
GL_ERROR_CHECK(glBufferData(GL_COPY_WRITE_BUFFER, length, data, usage));
GL_ERROR_CHECK(glBindBuffer(GL_COPY_WRITE_BUFFER, 0));
#else
// CPU-bound buffer
void* pointer = device->getBuffer( buffer );
if ( pointer && pointer != data ) memcpy( pointer, data, len );
if ( pointer && pointer != data ) memcpy( pointer, data, length );
#endif
return false;
}
@ -113,7 +121,15 @@ void ext::opengl::Buffer::initialize( Device& device ) {
this->device = &device;
}
void ext::opengl::Buffer::destroy( bool defer ) {
if ( device && buffer ) device->destroyBuffer( buffer );
if ( !device || aliased ) return;
if ( defer ) {
ext::opengl::mutex.lock();
device->transient.buffers.emplace_back(*this);
ext::opengl::mutex.unlock();
} else if ( buffer ) {
device->destroyBuffer( buffer );
}
device = NULL;
buffer = NULL;
}

View File

@ -410,6 +410,7 @@ void ext::opengl::render(){
#if !UF_ENV_DREAMCAST
ext::opengl::device.activateContext();
#endif
auto transient = std::move(ext::opengl::device.transient);
{
auto& scene = uf::scene::getCurrentScene();
@ -470,6 +471,11 @@ void ext::opengl::render(){
#if UF_USE_OPENVR
// if ( ext::openvr::context ) ext::openvr::postSubmit();
#endif
// cleanup in-flight buffers
for ( auto& buffer : transient.buffers ) buffer.destroy(false);
transient.buffers.clear();
ext::opengl::mutex.unlock();
}
void ext::opengl::destroy() {

View File

@ -116,6 +116,19 @@ bool ext::opengl::Shader::hasUniform( const uf::stl::string& name ) const {
// return metadata.definitions.uniforms.count(name) > 0;
return true;
}
void ext::opengl::Shader::aliasBuffer( const ext::opengl::Shader::Metadata::BufferDescriptor& descriptor ) {
metadata.aliases.buffers.emplace_back(descriptor);
}
// aliases by name
void ext::opengl::Shader::aliasBuffer( const uf::stl::string& name, const ext::opengl::Buffer& fallback, const ext::opengl::RenderMode* renderMode, GLenum flags ) {
return aliasBuffer({ name, fallback.alias(), renderMode, flags });
}
// aliases directly
void ext::opengl::Shader::aliasBuffer( const ext::opengl::Buffer& buffer ) {
return aliasBuffer({ "", buffer.alias(), NULL, buffer.usage });
}
ext::opengl::Buffer& ext::opengl::Shader::getUniformBuffer( const uf::stl::string& name ) {
UF_ASSERT( hasUniform(name) );
size_t uniformIndex = 0; // metadata.definitions.uniforms[name].index;

View File

@ -195,14 +195,11 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
auto savedMemProps = memoryProperties;
auto savedAlignment = alignment;
Buffer& oldBuffer = *const_cast<Buffer*>(this);
Buffer newBuffer = {};
Buffer& self = const_cast<Buffer&>(*this);
oldBuffer.swap(newBuffer);
newBuffer.destroy(true);
oldBuffer.initialize(*device, savedAlignment);
oldBuffer.initialize(data, length, savedUsage, savedMemProps, stage);
self.destroy(true);
self.initialize(*device, savedAlignment);
self.initialize(data, length, savedUsage, savedMemProps, stage);
return true;
}

View File

@ -516,6 +516,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
auto& infos = INFOS.emplace_back();
uf::stl::vector<ext::vulkan::enums::Image::viewType_t> types;
// add aliased-by-name buffers
for ( auto& descriptor : shader->metadata.aliases.buffers ) {
auto matches = uf::string::match(descriptor.name, R"(/^(.+?)\[(\d+)\]$/)");
auto name = matches.size() == 2 ? matches[0] : descriptor.name;

View File

@ -881,9 +881,14 @@ bool ext::vulkan::Shader::hasBuffer( const uf::stl::string& name ) {
void ext::vulkan::Shader::aliasBuffer( const ext::vulkan::Shader::Metadata::BufferDescriptor& descriptor ) {
metadata.aliases.buffers.emplace_back(descriptor);
}
// aliases by name
void ext::vulkan::Shader::aliasBuffer( const uf::stl::string& name, const ext::vulkan::Buffer& fallback, const ext::vulkan::RenderMode* renderMode, VkBufferUsageFlags flags ) {
return aliasBuffer({ name, fallback.alias(), renderMode, flags });
}
// aliases directly
void ext::vulkan::Shader::aliasBuffer( const ext::vulkan::Buffer& buffer ) {
return aliasBuffer({ "", buffer.alias(), NULL, buffer.usage });
}
bool ext::vulkan::Shader::hasUniform( const uf::stl::string& name ) const {
return metadata.definitions.uniforms.count(name) > 0;