Fix T98449: Cycles crash changing frame after recent changes

Subdivision did not properly update when evaluating first without and then with
orco coordinates. Now update the subdivision evaluator settings every time, and
reallocate the vertex data buffer when needed.

there is an additional issue in this file where orco coordinates are not
available immediately on the first frame when they should be, and only appear
on the second frame. However that is an old limitation related to the depsgraph
not getting re-evaluated on viewport display mode changes, here we just fix the
crash.
This commit is contained in:
Brecht Van Lommel 2022-05-30 13:28:38 +02:00
parent f1c29b9bd3
commit 24e74f8bef
Notes: blender-bot 2023-02-13 15:19:58 +01:00
Referenced by commit a9a4bcc3d1, Fix building: stub for OpenSubdiv
Referenced by issue #98449, Regression: Crash on frame change while in Cycles render preview
9 changed files with 59 additions and 44 deletions

View File

@ -27,6 +27,8 @@
#include "internal/base/type.h"
#include "internal/evaluator/evaluator_impl.h"
#include "opensubdiv_evaluator_capi.h"
using OpenSubdiv::Far::PatchTable;
using OpenSubdiv::Far::StencilTable;
using OpenSubdiv::Osd::BufferDescriptor;
@ -42,6 +44,8 @@ class EvalOutputAPI::EvalOutput {
public:
virtual ~EvalOutput() = default;
virtual void updateSettings(const OpenSubdiv_EvaluatorSettings *settings) = 0;
virtual void updateData(const float *src, int start_vertex, int num_vertices) = 0;
virtual void updateVaryingData(const float *src, int start_vertex, int num_vertices) = 0;
@ -338,13 +342,13 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const int vertex_data_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL,
DEVICE_CONTEXT *device_context = NULL)
: src_desc_(0, 3, 3),
: src_vertex_data_(NULL),
src_desc_(0, 3, 3),
src_varying_desc_(0, 3, 3),
src_vertex_data_desc_(0, vertex_data_width, vertex_data_width),
src_vertex_data_desc_(0, 0, 0),
face_varying_width_(face_varying_width),
evaluator_cache_(evaluator_cache),
device_context_(device_context)
@ -362,15 +366,6 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
device_context_);
// Optionally allocate additional data to be subdivided like vertex coordinates.
if (vertex_data_width > 0) {
src_vertex_data_ = SRC_VERTEX_BUFFER::Create(
vertex_data_width, num_total_vertices, device_context_);
}
else {
src_vertex_data_ = NULL;
}
// Create evaluators for every face varying channel.
face_varying_evaluators.reserve(all_face_varying_stencils.size());
int face_varying_channel = 0;
@ -398,6 +393,23 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
}
}
void updateSettings(const OpenSubdiv_EvaluatorSettings *settings) override
{
// Optionally allocate additional data to be subdivided like vertex coordinates.
if (settings->num_vertex_data != src_vertex_data_desc_.length) {
delete src_vertex_data_;
if (settings->num_vertex_data > 0) {
src_vertex_data_ = SRC_VERTEX_BUFFER::Create(
settings->num_vertex_data, src_data_->GetNumVertices(), device_context_);
}
else {
src_vertex_data_ = NULL;
}
src_vertex_data_desc_ = BufferDescriptor(
0, settings->num_vertex_data, settings->num_vertex_data);
}
}
// TODO(sergey): Implement binding API.
void updateData(const float *src, int start_vertex, int num_vertices) override

View File

@ -44,7 +44,6 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const int vertex_data_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL)
: VolatileEvalOutput<CpuVertexBuffer,
@ -55,7 +54,6 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
varying_stencils,
all_face_varying_stencils,
face_varying_width,
vertex_data_width,
patch_table,
evaluator_cache)
{

View File

@ -45,7 +45,6 @@ GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const int vertex_data_width,
const PatchTable *patch_table,
VolatileEvalOutput::EvaluatorCache *evaluator_cache)
: VolatileEvalOutput<GLVertexBuffer,
@ -56,7 +55,6 @@ GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
varying_stencils,
all_face_varying_stencils,
face_varying_width,
vertex_data_width,
patch_table,
evaluator_cache)
{

View File

@ -40,7 +40,6 @@ class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
const int vertex_data_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL);

View File

@ -28,6 +28,12 @@
namespace {
void setSettings(struct OpenSubdiv_Evaluator *evaluator,
const OpenSubdiv_EvaluatorSettings *settings)
{
evaluator->impl->eval_output->setSettings(settings);
}
void setCoarsePositions(OpenSubdiv_Evaluator *evaluator,
const float *positions,
const int start_vertex_index,
@ -222,6 +228,8 @@ void wrapFVarSrcBuffer(struct OpenSubdiv_Evaluator *evaluator,
void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
{
evaluator->setSettings = setSettings;
evaluator->setCoarsePositions = setCoarsePositions;
evaluator->setVertexData = setVertexData;
evaluator->setVaryingData = setVaryingData;
@ -258,16 +266,12 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache,
const OpenSubdiv_EvaluatorSettings *settings)
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
OpenSubdiv_Evaluator *evaluator = MEM_new<OpenSubdiv_Evaluator>(__func__);
assignFunctionPointers(evaluator);
evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner,
evaluator_type,
evaluator_cache ? evaluator_cache->impl :
nullptr,
settings);
evaluator->impl = openSubdiv_createEvaluatorInternal(
topology_refiner, evaluator_type, evaluator_cache ? evaluator_cache->impl : nullptr);
evaluator->type = evaluator->impl ? evaluator_type : static_cast<eOpenSubdivEvaluator>(0);
return evaluator;
}

View File

@ -166,6 +166,11 @@ EvalOutputAPI::~EvalOutputAPI()
delete implementation_;
}
void EvalOutputAPI::setSettings(const OpenSubdiv_EvaluatorSettings *settings)
{
implementation_->updateSettings(settings);
}
void EvalOutputAPI::setCoarsePositions(const float *positions,
const int start_vertex_index,
const int num_vertices)
@ -425,8 +430,7 @@ OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl()
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr,
const OpenSubdiv_EvaluatorSettings *settings)
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
{
// Only CPU and GLCompute are implemented at the moment.
if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU &&
@ -445,7 +449,6 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
const bool has_face_varying_data = (num_face_varying_channels != 0);
const int level = topology_refiner->getSubdivisionLevel(topology_refiner);
const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner);
const int vertex_data_width = settings->num_vertex_data;
// Common settings for stencils and patches.
const bool stencil_generate_intermediate_levels = is_adaptive;
const bool stencil_generate_offsets = true;
@ -550,17 +553,12 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
varying_stencils,
all_face_varying_stencils,
2,
vertex_data_width,
patch_table,
evaluator_cache);
}
else {
eval_output = new blender::opensubdiv::CpuEvalOutput(vertex_stencils,
varying_stencils,
all_face_varying_stencils,
2,
vertex_data_width,
patch_table);
eval_output = new blender::opensubdiv::CpuEvalOutput(
vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
}
blender::opensubdiv::PatchMap *patch_map = new blender::opensubdiv::PatchMap(*patch_table);

View File

@ -57,6 +57,9 @@ class EvalOutputAPI {
~EvalOutputAPI();
// Set settings for data buffers.
void setSettings(const OpenSubdiv_EvaluatorSettings *settings);
// Set coarse positions from a continuous array of coordinates.
void setCoarsePositions(const float *positions,
const int start_vertex_index,
@ -204,8 +207,7 @@ struct OpenSubdiv_EvaluatorImpl {
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
struct OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr,
const OpenSubdiv_EvaluatorSettings *settings);
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr);
void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator);

View File

@ -31,6 +31,11 @@ struct OpenSubdiv_EvaluatorInternal;
struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
typedef struct OpenSubdiv_EvaluatorSettings {
// Number of smoothly interpolated vertex data channels.
int num_vertex_data;
} OpenSubdiv_EvaluatorSettings;
// Callback type for doing input/output operations on buffers.
// Useful to abstract GPU buffers.
typedef struct OpenSubdiv_Buffer {
@ -64,6 +69,10 @@ typedef struct OpenSubdiv_Buffer {
} OpenSubdiv_Buffer;
typedef struct OpenSubdiv_Evaluator {
// Set settings for data buffers used.
void (*setSettings)(struct OpenSubdiv_Evaluator *evaluator,
const OpenSubdiv_EvaluatorSettings *settings);
// Set coarse positions from a continuous array of coordinates.
void (*setCoarsePositions)(struct OpenSubdiv_Evaluator *evaluator,
const float *positions,
@ -227,16 +236,10 @@ typedef struct OpenSubdiv_EvaluatorCache {
struct OpenSubdiv_EvaluatorCacheImpl *impl;
} OpenSubdiv_EvaluatorCache;
typedef struct OpenSubdiv_EvaluatorSettings {
// Number of smoothly interpolated vertex data channels.
int num_vertex_data;
} OpenSubdiv_EvaluatorSettings;
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
struct OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache,
const OpenSubdiv_EvaluatorSettings *settings);
OpenSubdiv_EvaluatorCache *evaluator_cache);
void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator);

View File

@ -58,7 +58,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type);
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache, settings);
subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->evaluator == NULL) {
return false;
@ -67,6 +67,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
else {
/* TODO(sergey): Check for topology change. */
}
subdiv->evaluator->setSettings(subdiv->evaluator, settings);
BKE_subdiv_eval_init_displacement(subdiv);
return true;
}