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
59 lines
2.2 KiB
C++
59 lines
2.2 KiB
C++
/* SPDX-FileCopyrightText: 2021 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*
|
|
* Author: Sergey Sharybin. */
|
|
|
|
#include "internal/evaluator/eval_output_gpu.h"
|
|
|
|
#include "opensubdiv_evaluator.hh"
|
|
|
|
#include "gpu_patch_table.hh"
|
|
|
|
using OpenSubdiv::Osd::PatchArray;
|
|
using OpenSubdiv::Osd::PatchArrayVector;
|
|
|
|
namespace blender::opensubdiv {
|
|
|
|
static GPUStorageBuf *create_patch_array_buffer(const PatchArrayVector &patch_arrays)
|
|
{
|
|
const size_t patch_array_size = sizeof(PatchArray);
|
|
const size_t patch_array_byte_size = patch_array_size * patch_arrays.size();
|
|
GPUStorageBuf *storage_buf = GPU_storagebuf_create_ex(
|
|
patch_array_byte_size, patch_arrays.data(), GPU_USAGE_STATIC, "osd_patch_array");
|
|
return storage_buf;
|
|
}
|
|
|
|
GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
|
|
const StencilTable *varying_stencils,
|
|
const std::vector<const StencilTable *> &all_face_varying_stencils,
|
|
const int face_varying_width,
|
|
const PatchTable *patch_table,
|
|
VolatileEvalOutput::EvaluatorCache *evaluator_cache)
|
|
: VolatileEvalOutput<GPUVertexBuffer,
|
|
GPUVertexBuffer,
|
|
GPUStencilTableSSBO,
|
|
GPUPatchTable,
|
|
GPUComputeEvaluator>(vertex_stencils,
|
|
varying_stencils,
|
|
all_face_varying_stencils,
|
|
face_varying_width,
|
|
patch_table,
|
|
evaluator_cache)
|
|
{
|
|
}
|
|
|
|
GPUStorageBuf *GpuEvalOutput::create_patch_arrays_buf()
|
|
{
|
|
GPUPatchTable *patch_table = getPatchTable();
|
|
return create_patch_array_buffer(patch_table->GetPatchArrays());
|
|
}
|
|
|
|
GPUStorageBuf *GpuEvalOutput::create_face_varying_patch_array_buf(const int face_varying_channel)
|
|
{
|
|
GPUPatchTable *patch_table = getFVarPatchTable(face_varying_channel);
|
|
return create_patch_array_buffer(patch_table->GetFVarPatchArrays(face_varying_channel));
|
|
}
|
|
|
|
} // namespace blender::opensubdiv
|