Files
test/source/blender/compositor/cached_resources/intern/cached_texture.cc

166 lines
5.4 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include <cstdint>
#include <memory>
#include "BLI_array.hh"
#include "BLI_hash.hh"
#include "BLI_index_range.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
#include "BLI_task.hh"
#include "GPU_texture.hh"
#include "BKE_image.hh"
#include "BKE_texture.h"
#include "DNA_ID.h"
#include "DNA_texture_types.h"
#include "RE_texture.h"
#include "COM_cached_texture.hh"
#include "COM_context.hh"
#include "COM_result.hh"
namespace blender::compositor {
/* --------------------------------------------------------------------
* Cached Texture Key.
*/
CachedTextureKey::CachedTextureKey(int2 size, float3 offset, float3 scale)
: size(size), offset(offset), scale(scale)
{
}
uint64_t CachedTextureKey::hash() const
{
return get_default_hash(size, offset, scale);
}
bool operator==(const CachedTextureKey &a, const CachedTextureKey &b)
{
return a.size == b.size && a.offset == b.offset && a.scale == b.scale;
}
/* --------------------------------------------------------------------
* Cached Texture.
*/
CachedTexture::CachedTexture(Context &context,
Tex *texture,
bool use_color_management,
int2 size,
float3 offset,
float3 scale)
: color_result(context.create_result(ResultType::Color)),
value_result(context.create_result(ResultType::Float))
{
ImagePool *image_pool = BKE_image_pool_new();
BKE_texture_fetch_images_for_pool(texture, image_pool);
color_pixels_ = Array<float4>(size.x * size.y);
value_pixels_ = Array<float>(size.x * size.y);
threading::parallel_for(IndexRange(size.y), 1, [&](const IndexRange sub_y_range) {
for (const int64_t y : sub_y_range) {
for (const int64_t x : IndexRange(size.x)) {
/* Compute the coordinates in the [-1, 1] range and add 0.5 to evaluate the texture at the
* center of pixels in case it was interpolated. */
const float2 pixel_coordinates = ((float2(x, y) + 0.5f) / float2(size)) * 2.0f - 1.0f;
/* Note that it is expected that the offset is scaled by the scale. */
const float3 coordinates = (float3(pixel_coordinates, 0.0f) + offset) * scale;
TexResult texture_result;
const int result_type = multitex_ext_safe(
texture, coordinates, &texture_result, image_pool, use_color_management, false);
float4 color = float4(texture_result.trgba);
color.w = texture_result.talpha ? color.w : texture_result.tin;
if (!(result_type & TEX_RGB)) {
copy_v3_fl(color, color.w);
}
color_pixels_[y * size.x + x] = color;
value_pixels_[y * size.x + x] = color.w;
}
}
});
BKE_image_pool_free(image_pool);
if (context.use_gpu()) {
this->color_result.allocate_texture(Domain(size), false);
this->value_result.allocate_texture(Domain(size), false);
GPU_texture_update(this->color_result, GPU_DATA_FLOAT, color_pixels_.data());
GPU_texture_update(this->value_result, GPU_DATA_FLOAT, value_pixels_.data());
/* CPU-side data no longer needed, so free it. */
color_pixels_ = Array<float4>();
value_pixels_ = Array<float>();
}
else {
this->color_result.wrap_external(&color_pixels_.data()[0].x, size);
this->value_result.wrap_external(value_pixels_.data(), size);
}
}
CachedTexture::~CachedTexture()
{
this->color_result.release();
this->value_result.release();
}
/* --------------------------------------------------------------------
* Cached Texture Container.
*/
void CachedTextureContainer::reset()
{
/* First, delete all cached textures that are no longer needed. */
for (auto &cached_textures_for_id : map_.values()) {
cached_textures_for_id.remove_if([](auto item) { return !item.value->needed; });
}
map_.remove_if([](auto item) { return item.value.is_empty(); });
/* Second, reset the needed status of the remaining cached textures to false to ready them to
* track their needed status for the next evaluation. */
for (auto &cached_textures_for_id : map_.values()) {
for (auto &value : cached_textures_for_id.values()) {
value->needed = false;
}
}
}
CachedTexture &CachedTextureContainer::get(Context &context,
Tex *texture,
bool use_color_management,
int2 size,
float3 offset,
float3 scale)
{
const CachedTextureKey key(size, offset, scale);
const std::string library_key = texture->id.lib ? texture->id.lib->id.name : "";
const std::string id_key = std::string(texture->id.name) + library_key;
auto &cached_textures_for_id = map_.lookup_or_add_default(id_key);
/* Invalidate the cache for that texture ID if it was changed and reset the recalculate flag. */
if (context.query_id_recalc_flag(reinterpret_cast<ID *>(texture)) & ID_RECALC_ALL) {
cached_textures_for_id.clear();
}
auto &cached_texture = *cached_textures_for_id.lookup_or_add_cb(key, [&]() {
return std::make_unique<CachedTexture>(
context, texture, use_color_management, size, offset, scale);
});
cached_texture.needed = true;
return cached_texture;
}
} // namespace blender::compositor