Refactor: Move tile highlight logic outside of Render

Allows to generalize the API a bit more, getting closer to
a situation when RenderEngine::re points to a baseclass of
the Render.
This commit is contained in:
Sergey Sharybin
2023-07-20 11:19:29 +02:00
committed by Sergey Sharybin
parent 032bcd50f8
commit 76995feea0
7 changed files with 237 additions and 115 deletions

View File

@@ -40,6 +40,7 @@ set(SRC
intern/texture_margin.cc
intern/texture_pointdensity.c
intern/texture_procedural.c
intern/tile_highlight.cc
intern/zbuf.c
RE_bake.h
@@ -54,6 +55,7 @@ set(SRC
intern/render_result.h
intern/render_types.h
intern/texture_common.h
intern/tile_highlight.h
intern/zbuf.h
)

View File

@@ -303,45 +303,6 @@ static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
/* Render Results */
static HighlightedTile highlighted_tile_from_result_get(Render * /*re*/, RenderResult *result)
{
HighlightedTile tile;
tile.rect = result->tilerect;
return tile;
}
static void engine_tile_highlight_set(RenderEngine *engine,
const HighlightedTile *tile,
bool highlight)
{
if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
return;
}
Render *re = engine->re;
BLI_mutex_lock(&re->highlighted_tiles_mutex);
if (re->highlighted_tiles == nullptr) {
re->highlighted_tiles = BLI_gset_new(
BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, "highlighted tiles");
}
if (highlight) {
HighlightedTile **tile_in_set;
if (!BLI_gset_ensure_p_ex(re->highlighted_tiles, tile, (void ***)&tile_in_set)) {
*tile_in_set = MEM_cnew<HighlightedTile>(__func__);
**tile_in_set = *tile;
}
}
else {
BLI_gset_remove(re->highlighted_tiles, tile, MEM_freeN);
}
BLI_mutex_unlock(&re->highlighted_tiles_mutex);
}
RenderResult *RE_engine_begin_result(
RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
@@ -457,9 +418,16 @@ void RE_engine_end_result(
}
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES)) {
const HighlightedTile tile = highlighted_tile_from_result_get(re, result);
blender::render::TilesHighlight *tile_highlight = re->get_tile_highlight();
engine_tile_highlight_set(engine, &tile, highlight);
if (tile_highlight) {
if (highlight) {
tile_highlight->highlight_tile_for_result(result);
}
else {
tile_highlight->unhighlight_tile_for_result(result);
}
}
}
if (!cancel || merge_results) {
@@ -644,50 +612,18 @@ bool RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera)
const rcti *RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free)
{
static rcti tiles_static[BLENDER_MAX_THREADS];
const int allocation_step = BLENDER_MAX_THREADS;
int total_tiles = 0;
rcti *tiles = tiles_static;
int allocation_size = BLENDER_MAX_THREADS;
BLI_mutex_lock(&re->highlighted_tiles_mutex);
*r_needs_free = false;
if (re->highlighted_tiles == nullptr) {
blender::render::TilesHighlight *tiles_highlight = re->get_tile_highlight();
if (!tiles_highlight) {
*r_total_tiles = 0;
BLI_mutex_unlock(&re->highlighted_tiles_mutex);
return nullptr;
}
};
GSET_FOREACH_BEGIN (HighlightedTile *, tile, re->highlighted_tiles) {
if (total_tiles >= allocation_size) {
/* Just in case we're using crazy network rendering with more
* workers than BLENDER_MAX_THREADS.
*/
allocation_size += allocation_step;
if (tiles == tiles_static) {
/* Can not realloc yet, tiles are pointing to a
* stack memory.
*/
tiles = MEM_cnew_array<rcti>(allocation_size, "current engine tiles");
}
else {
tiles = static_cast<rcti *>(MEM_reallocN(tiles, allocation_size * sizeof(rcti)));
}
*r_needs_free = true;
}
tiles[total_tiles] = tile->rect;
blender::Span<rcti> highlighted_tiles = tiles_highlight->get_all_highlighted_tiles();
total_tiles++;
}
GSET_FOREACH_END();
BLI_mutex_unlock(&re->highlighted_tiles_mutex);
*r_total_tiles = total_tiles;
return tiles;
*r_total_tiles = highlighted_tiles.size();
return highlighted_tiles.data();
}
RenderData *RE_engine_get_render_data(Render *re)
@@ -1262,27 +1198,51 @@ void RE_engine_draw_release(Render *re)
void RE_engine_tile_highlight_set(
RenderEngine *engine, int x, int y, int width, int height, bool highlight)
{
HighlightedTile tile;
BLI_rcti_init(&tile.rect, x, x + width, y, y + height);
if (!engine->re) {
/* No render on the engine, so nowhere to store the highlighted tiles information. */
return;
}
if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
/* Engine reported it does not support tiles highlight, but attempted to set the highlight.
* Technically it is a logic error, but there is no good way to inform an external engine about
* it. */
return;
}
engine_tile_highlight_set(engine, &tile, highlight);
blender::render::TilesHighlight *tile_highlight = engine->re->get_tile_highlight();
if (!tile_highlight) {
/* The renderer itself does not support tiles highlight. */
return;
}
if (highlight) {
tile_highlight->highlight_tile(x, y, width, height);
}
else {
tile_highlight->unhighlight_tile(x, y, width, height);
}
}
void RE_engine_tile_highlight_clear_all(RenderEngine *engine)
{
if (!engine->re) {
/* No render on the engine, so nowhere to store the highlighted tiles information. */
return;
}
if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
/* Engine reported it does not support tiles highlight, but attempted to set the highlight.
* Technically it is a logic error, but there is no good way to inform an external engine about
* it. */
return;
}
Render *re = engine->re;
BLI_mutex_lock(&re->highlighted_tiles_mutex);
if (re->highlighted_tiles != nullptr) {
BLI_gset_clear(re->highlighted_tiles, MEM_freeN);
blender::render::TilesHighlight *tile_highlight = engine->re->get_tile_highlight();
if (!tile_highlight) {
/* The renderer itself does not support tiles highlight. */
return;
}
BLI_mutex_unlock(&re->highlighted_tiles_mutex);
tile_highlight->clear();
}
/* -------------------------------------------------------------------- */

View File

@@ -1820,21 +1820,6 @@ static void render_pipeline_free(Render *re)
/* Destroy the opengl context in the correct thread. */
RE_blender_gpu_context_free(re);
RE_system_gpu_context_free(re);
/* In the case the engine did not mark tiles as finished (un-highlight, which could happen in
* the case of cancelled render) ensure the storage is empty. */
if (re->highlighted_tiles != nullptr) {
BLI_mutex_lock(&re->highlighted_tiles_mutex);
/* Rendering is supposed to be finished here, so no new tiles are expected to be written.
* Only make it so possible read-only access to the highlighted tiles is thread-safe. */
BLI_assert(re->highlighted_tiles);
BLI_gset_free(re->highlighted_tiles, MEM_freeN);
re->highlighted_tiles = nullptr;
BLI_mutex_unlock(&re->highlighted_tiles_mutex);
}
}
void RE_RenderFrame(Render *re,

View File

@@ -36,14 +36,9 @@ Render::~Render()
RE_blender_gpu_context_free(this);
RE_system_gpu_context_free(this);
BLI_mutex_end(&highlighted_tiles_mutex);
BLI_mutex_end(&gpu_compositor_mutex);
BKE_curvemapping_free_data(&r.mblur_shutter_curve);
if (highlighted_tiles != nullptr) {
BLI_gset_free(highlighted_tiles, MEM_freeN);
}
render_result_free(pushedresult);
}

View File

@@ -19,6 +19,8 @@
#include "RE_compositor.hh"
#include "RE_pipeline.h"
#include "tile_highlight.h"
struct Depsgraph;
struct GSet;
struct Main;
@@ -26,14 +28,15 @@ struct Object;
struct RenderEngine;
struct ReportList;
struct HighlightedTile {
rcti rect;
};
struct BaseRender {
BaseRender() = default;
virtual ~BaseRender();
/* Get class which manages highlight of tiles.
* Note that it might not exist: for example, viewport render does not support the tile
* highlight. */
virtual blender::render::TilesHighlight *get_tile_highlight() = 0;
/* Result of rendering */
RenderResult *result = nullptr;
@@ -50,6 +53,10 @@ struct BaseRender {
};
struct ViewRender : public BaseRender {
blender::render::TilesHighlight *get_tile_highlight() override
{
return nullptr;
}
};
/* Controls state of render, everything that's read-only during render stage */
@@ -59,6 +66,11 @@ struct Render : public BaseRender {
Render() = default;
virtual ~Render();
blender::render::TilesHighlight *get_tile_highlight() override
{
return &tile_highlight;
}
char name[RE_MAXNAME] = "";
int slot = 0;
@@ -97,8 +109,7 @@ struct Render : public BaseRender {
char single_view_layer[MAX_NAME] = "";
struct Object *camera_override = nullptr;
ThreadMutex highlighted_tiles_mutex = BLI_MUTEX_INITIALIZER;
struct GSet *highlighted_tiles = nullptr;
blender::render::TilesHighlight tile_highlight;
/* NOTE: This is a minimal dependency graph and evaluated scene which is enough to access view
* layer visibility and use for postprocessing (compositor and sequencer). */

View File

@@ -0,0 +1,102 @@
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup render
*/
#include "tile_highlight.h"
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
#include "BLI_hash.hh"
#include "RE_pipeline.h"
namespace blender::render {
TilesHighlight::Tile::Tile(const RenderResult *result) : rect(result->tilerect) {}
TilesHighlight::Tile::Tile(const int x, const int y, const int width, const int height)
{
BLI_rcti_init(&rect, x, x + width, y, y + height);
}
uint64_t TilesHighlight::Tile::hash() const
{
return get_default_hash_4(rect.xmin, rect.xmax, rect.ymin, rect.ymax);
}
void TilesHighlight::highlight_tile_for_result(const RenderResult *result)
{
const Tile tile(result);
highlight_tile(tile);
}
void TilesHighlight::unhighlight_tile_for_result(const RenderResult *result)
{
const Tile tile(result);
unhighlight_tile(tile);
}
void TilesHighlight::highlight_tile(const int x, const int y, const int width, const int height)
{
const Tile tile(x, y, width, height);
highlight_tile(tile);
}
void TilesHighlight::unhighlight_tile(const int x, const int y, const int width, const int height)
{
const Tile tile(x, y, width, height);
unhighlight_tile(tile);
}
void TilesHighlight::highlight_tile(const Tile &tile)
{
std::unique_lock lock(mutex_);
highlighted_tiles_set_.add(tile);
did_tiles_change_ = true;
}
void TilesHighlight::unhighlight_tile(const Tile &tile)
{
std::unique_lock lock(mutex_);
highlighted_tiles_set_.remove(tile);
did_tiles_change_ = true;
}
void TilesHighlight::clear()
{
std::unique_lock lock(mutex_);
highlighted_tiles_set_.clear();
cached_highlighted_tiles_.clear_and_shrink();
}
Span<rcti> TilesHighlight::get_all_highlighted_tiles() const
{
std::unique_lock lock(mutex_);
/* Updated cached flat list if needed. */
if (did_tiles_change_) {
if (highlighted_tiles_set_.is_empty()) {
cached_highlighted_tiles_.clear_and_shrink();
}
else {
cached_highlighted_tiles_.reserve(highlighted_tiles_set_.size());
for (const Tile &tile : highlighted_tiles_set_) {
cached_highlighted_tiles_.append(tile.rect);
}
}
did_tiles_change_ = false;
}
return cached_highlighted_tiles_;
}
} // namespace blender::render

View File

@@ -0,0 +1,67 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup render
*/
#pragma once
#include "BLI_rect.h"
#include "BLI_set.hh"
#include "BLI_vector.hh"
#include <mutex>
struct RenderResult;
namespace blender::render {
class TilesHighlight {
public:
TilesHighlight() = default;
~TilesHighlight() = default;
void highlight_tile_for_result(const RenderResult *result);
void unhighlight_tile_for_result(const RenderResult *result);
void highlight_tile(int x, int y, int width, int height);
void unhighlight_tile(int x, int y, int width, int height);
void clear();
Span<rcti> get_all_highlighted_tiles() const;
private:
struct Tile {
Tile() = default;
explicit Tile(const RenderResult *result);
explicit Tile(int x, int y, int width, int height);
uint64_t hash() const;
inline bool operator==(const Tile &other) const
{
return rect == other.rect;
}
inline bool operator!=(const Tile &other) const
{
return !(*this == other);
}
rcti rect = {0, 0, 0, 0};
};
void highlight_tile(const Tile &tile);
void unhighlight_tile(const Tile &tile);
mutable std::mutex mutex_;
Set<Tile> highlighted_tiles_set_;
/* Cached flat list of currently highlighted tiles for a fast access via API. */
mutable bool did_tiles_change_ = false;
mutable Vector<rcti> cached_highlighted_tiles_;
};
} // namespace blender::render