Since the introduction of storage buffers in Blender, the calling code has been responsible for ensuring the buffer meets allocation requirements. All backends require the allocation size to be divisible by 16 bytes. Until now, this was sufficient, but with GPU subdivision changes, an external library must also adhere to these requirements. For OpenSubdiv (OSD), some buffers are not 16-byte aligned, leading to potential misallocation. Currently, this is mitigated by allocating a few extra bytes, but this approach has the drawback of potentially reading unintended bytes beyond the source buffer. This PR adopts a similar approach to vertex buffers: the backend handles extra byte allocation while ensuring data uploads and downloads function correctly without requiring those additional bytes. No changes were needed for Metal, as its allocation size is already aligned to 256 bytes. **Alternative solutions considered**: - Copying the CPU buffer to a larger buffer when needed (performance impact). - Modifying OSD buffers to allocate extra space (requires changes to an external library). - Implementing GPU_storagebuf_update_sub. Ref #135873 Pull Request: https://projects.blender.org/blender/blender/pulls/135716
69 lines
1.6 KiB
C++
69 lines
1.6 KiB
C++
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_sys_types.h"
|
|
|
|
struct GPUStorageBuf;
|
|
|
|
namespace blender::gpu {
|
|
|
|
class VertBuf;
|
|
|
|
#ifndef NDEBUG
|
|
# define DEBUG_NAME_LEN 64
|
|
#else
|
|
# define DEBUG_NAME_LEN 8
|
|
#endif
|
|
|
|
/**
|
|
* Implementation of Storage Buffers.
|
|
* Base class which is then specialized for each implementation (GL, VK, ...).
|
|
*/
|
|
class StorageBuf {
|
|
protected:
|
|
/** Data size in bytes. Doesn't need to match actual allocation size due to alignment rules. */
|
|
size_t size_in_bytes_;
|
|
/** Continuous memory block to copy to GPU. This data is owned by the StorageBuf. */
|
|
void *data_ = nullptr;
|
|
/** Debugging name */
|
|
char name_[DEBUG_NAME_LEN];
|
|
|
|
public:
|
|
StorageBuf(size_t size, const char *name);
|
|
virtual ~StorageBuf();
|
|
|
|
virtual void update(const void *data) = 0;
|
|
virtual void bind(int slot) = 0;
|
|
virtual void unbind() = 0;
|
|
virtual void clear(uint32_t clear_value) = 0;
|
|
virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0;
|
|
virtual void read(void *data) = 0;
|
|
virtual void async_flush_to_host() = 0;
|
|
virtual void sync_as_indirect_buffer() = 0;
|
|
};
|
|
|
|
/* Syntactic sugar. */
|
|
static inline GPUStorageBuf *wrap(StorageBuf *storage_buf)
|
|
{
|
|
return reinterpret_cast<GPUStorageBuf *>(storage_buf);
|
|
}
|
|
static inline StorageBuf *unwrap(GPUStorageBuf *storage_buf)
|
|
{
|
|
return reinterpret_cast<StorageBuf *>(storage_buf);
|
|
}
|
|
static inline const StorageBuf *unwrap(const GPUStorageBuf *storage_buf)
|
|
{
|
|
return reinterpret_cast<const StorageBuf *>(storage_buf);
|
|
}
|
|
|
|
#undef DEBUG_NAME_LEN
|
|
|
|
} // namespace blender::gpu
|