Skip to content

Commit c09ea76

Browse files
mmImagePlane2 - Fix bug when there is not enough memory for image.
If the ImageCache is set to zero, we cannot allow that to cause a crash (which it did, prior to this change).
1 parent 3c47650 commit c09ea76

File tree

1 file changed

+95
-6
lines changed

1 file changed

+95
-6
lines changed

src/mmSolver/image/ImageCache.cpp

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,82 @@
5454
namespace mmsolver {
5555
namespace image {
5656

57+
inline bool check_enough_image_cache_capacity(
58+
const ImageCache &image_cache, const size_t pixel_data_byte_count,
59+
const MString &file_path) {
60+
const size_t cpu_capacity_bytes = image_cache.get_cpu_capacity_bytes();
61+
const size_t gpu_capacity_bytes = image_cache.get_gpu_capacity_bytes();
62+
63+
const bool cpu_zero_capacity = cpu_capacity_bytes == 0;
64+
const bool gpu_zero_capacity = gpu_capacity_bytes == 0;
65+
66+
const bool cpu_low_capacity = cpu_capacity_bytes < pixel_data_byte_count;
67+
const bool gpu_low_capacity = gpu_capacity_bytes < pixel_data_byte_count;
68+
69+
if ((cpu_zero_capacity || gpu_zero_capacity) ||
70+
(cpu_low_capacity || gpu_low_capacity)) {
71+
const size_t requested_megabytes =
72+
pixel_data_byte_count / BYTES_TO_MEGABYTES;
73+
std::string requested_megabytes_str =
74+
mmstring::numberToStringWithCommas(requested_megabytes);
75+
76+
// Check CPU capacity.
77+
if (cpu_zero_capacity || cpu_low_capacity) {
78+
const size_t capacity_megabytes =
79+
cpu_capacity_bytes / BYTES_TO_MEGABYTES;
80+
std::string capacity_megabytes_str =
81+
mmstring::numberToStringWithCommas(capacity_megabytes);
82+
83+
if (pixel_data_byte_count == 0) {
84+
MMSOLVER_MAYA_ERR(
85+
"mmsolver::ImageCache: read_texture_image_file:"
86+
<< " Cannot read \"" << file_path.asChar() << "\"."
87+
<< " CPU Cache capacity is zero."
88+
<< " CPU cache capacity = " << capacity_megabytes_str
89+
<< "MB.");
90+
} else {
91+
MMSOLVER_MAYA_ERR(
92+
"mmsolver::ImageCache: read_texture_image_file:"
93+
<< " Cannot read \"" << file_path.asChar() << "\"."
94+
<< " CPU Cache capacity is too low."
95+
<< " CPU cache capacity = " << capacity_megabytes_str
96+
<< "MB, "
97+
<< " requested memory size = " << requested_megabytes_str
98+
<< "MB.");
99+
}
100+
}
101+
102+
// Check GPU capacity.
103+
if (gpu_zero_capacity || gpu_low_capacity) {
104+
const size_t capacity_megabytes =
105+
gpu_capacity_bytes / BYTES_TO_MEGABYTES;
106+
std::string capacity_megabytes_str =
107+
mmstring::numberToStringWithCommas(capacity_megabytes);
108+
109+
if (pixel_data_byte_count == 0) {
110+
MMSOLVER_MAYA_ERR(
111+
"mmsolver::ImageCache: read_texture_image_file:"
112+
<< " Cannot read \"" << file_path.asChar() << "\"."
113+
<< " GPU Cache capacity is zero."
114+
<< " GPU cache capacity = " << capacity_megabytes_str
115+
<< "MB.");
116+
} else {
117+
MMSOLVER_MAYA_ERR(
118+
"mmsolver::ImageCache: read_texture_image_file:"
119+
<< " Cannot read \"" << file_path.asChar() << "\"."
120+
<< " GPU Cache capacity is too low."
121+
<< " GPU cache capacity = " << capacity_megabytes_str
122+
<< "MB, "
123+
<< " requested memory size = " << requested_megabytes_str
124+
<< "MB.");
125+
}
126+
}
127+
128+
return false;
129+
}
130+
return true;
131+
}
132+
57133
MTexture *read_texture_image_file(MHWRender::MTextureManager *texture_manager,
58134
ImageCache &image_cache, MImage &temp_image,
59135
mmimage::ImagePixelBuffer &temp_pixel_buffer,
@@ -65,6 +141,11 @@ MTexture *read_texture_image_file(MHWRender::MTextureManager *texture_manager,
65141
texture_manager != nullptr,
66142
"Texture manager must be valid to read an image into texture memory.");
67143

144+
if (!check_enough_image_cache_capacity(
145+
image_cache, /*pixel_data_byte_count=*/0, file_path)) {
146+
return nullptr;
147+
}
148+
68149
const bool verbose = false;
69150
MMSOLVER_MAYA_VRB("mmsolver::ImageCache: read_texture_image_file:"
70151
<< " file_path=" << file_path.asChar());
@@ -145,12 +226,19 @@ MTexture *read_texture_image_file(MHWRender::MTextureManager *texture_manager,
145226
// // image.verticalFlip();
146227
}
147228

148-
if (!maya_owned_pixel_data) {
229+
if (!static_cast<bool>(maya_owned_pixel_data)) {
149230
MMSOLVER_MAYA_ERR("mmsolver::ImageCache: read_texture_image_file: "
150231
<< "Invalid pixel data!");
151232
return nullptr;
152233
}
153234

235+
const size_t pixel_data_byte_count =
236+
width * height * num_channels * bytes_per_channel;
237+
if (!check_enough_image_cache_capacity(image_cache, pixel_data_byte_count,
238+
resolved_file_path)) {
239+
return nullptr;
240+
}
241+
154242
ImagePixelData gpu_image_pixel_data =
155243
ImagePixelData(static_cast<void *>(maya_owned_pixel_data), width,
156244
height, num_channels, pixel_data_type);
@@ -168,8 +256,6 @@ MTexture *read_texture_image_file(MHWRender::MTextureManager *texture_manager,
168256
<< "gpu_inserted=" << texture_data.texture());
169257

170258
// Duplicate the Maya-owned pixel data for our image cache.
171-
const size_t pixel_data_byte_count =
172-
width * height * num_channels * bytes_per_channel;
173259
image_pixel_data = ImagePixelData();
174260
const bool allocated_ok = image_pixel_data.allocate_pixels(
175261
width, height, num_channels, pixel_data_type);
@@ -523,9 +609,12 @@ ImageCache::GPUCacheValue ImageCache::gpu_insert_item(
523609
}
524610

525611
m_gpu_used_bytes += texture_data.byte_count();
526-
MMSOLVER_ASSERT(m_gpu_used_bytes <= m_gpu_capacity_bytes,
527-
"It is not possible for the used GPU Cache memory to "
528-
"exceed the GPU Cache capacity.");
612+
MMSOLVER_ASSERT(
613+
m_gpu_used_bytes <= m_gpu_capacity_bytes,
614+
"It is not possible for the used GPU Cache memory to "
615+
"exceed the GPU Cache capacity."
616+
<< " m_gpu_used_bytes=" << m_gpu_used_bytes
617+
<< " m_gpu_capacity_bytes=" << m_gpu_capacity_bytes);
529618

530619
// Make 'item_key' the most-recently-used item key, because when we
531620
// insert an item into the cache, it's used most recently.

0 commit comments

Comments
 (0)