ImageEngine: Migrate to new draw manager

Converts the image engine to the new draw manager.
This is an as is migration without just a few tweaks to improve the code.

Pull Request: https://projects.blender.org/blender/blender/pulls/131142
This commit is contained in:
Jeroen Bakker
2024-12-02 16:10:02 +01:00
parent 26b13504d4
commit 53eadcc533
13 changed files with 117 additions and 100 deletions

View File

@@ -11,49 +11,38 @@
namespace blender::image_engine {
DRWPass *ScreenSpaceDrawingMode::create_image_pass() const
{
DRWState state = static_cast<DRWState>(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS |
DRW_STATE_BLEND_ALPHA_PREMUL);
return DRW_pass_create("Image", state);
}
DRWPass *ScreenSpaceDrawingMode::create_depth_pass() const
{
DRWState state = static_cast<DRWState>(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
return DRW_pass_create("Depth", state);
}
void ScreenSpaceDrawingMode::add_shgroups() const
{
const ShaderParameters &sh_params = instance_.state.sh_params;
PassSimple &pass = instance_.state.image_ps;
GPUShader *shader = ShaderModule::module_get().color.get();
const ShaderParameters &sh_params = instance_.state.sh_params;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
DRWShadingGroup *shgrp = DRW_shgroup_create(shader, instance_.state.passes.image_pass);
DRW_shgroup_uniform_vec2_copy(shgrp, "far_near_distances", sh_params.far_near);
DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", sh_params.shuffle);
DRW_shgroup_uniform_int_copy(shgrp, "draw_flags", static_cast<int32_t>(sh_params.flags));
DRW_shgroup_uniform_bool_copy(shgrp, "is_image_premultiplied", sh_params.use_premul_alpha);
DRW_shgroup_uniform_texture(shgrp, "depth_tx", dtxl->depth);
float image_mat[4][4];
unit_m4(image_mat);
pass.shader_set(shader);
pass.push_constant("far_near_distances", sh_params.far_near);
pass.push_constant("shuffle", sh_params.shuffle);
pass.push_constant("draw_flags", int32_t(sh_params.flags));
pass.push_constant("is_image_premultiplied", sh_params.use_premul_alpha);
pass.bind_texture("depth_tx", dtxl->depth);
float4x4 image_mat = float4x4::identity();
ResourceHandle handle = instance_.manager->resource_handle(image_mat);
for (const TextureInfo &info : instance_.state.texture_infos) {
DRWShadingGroup *shgrp_sub = DRW_shgroup_create_sub(shgrp);
DRW_shgroup_uniform_ivec2_copy(shgrp_sub, "offset", info.offset());
DRW_shgroup_uniform_texture_ex(
shgrp_sub, "image_tx", info.texture, GPUSamplerState::default_sampler());
DRW_shgroup_call_obmat(shgrp_sub, info.batch, image_mat);
PassSimple::Sub &sub = pass.sub("Texture");
sub.push_constant("offset", info.offset());
sub.bind_texture("image_tx", info.texture);
sub.draw(info.batch, handle);
}
}
void ScreenSpaceDrawingMode::add_depth_shgroups(Image *image, ImageUser *image_user) const
void ScreenSpaceDrawingMode::add_depth_shgroups(::Image *image, ImageUser *image_user) const
{
PassSimple &pass = instance_.state.depth_ps;
GPUShader *shader = ShaderModule::module_get().depth.get();
DRWShadingGroup *shgrp = DRW_shgroup_create(shader, instance_.state.passes.depth_pass);
pass.shader_set(shader);
float image_mat[4][4];
unit_m4(image_mat);
float4x4 image_mat = float4x4::identity();
ResourceHandle handle = instance_.manager->resource_handle(image_mat);
ImageUser tile_user = {0};
if (image_user) {
@@ -73,18 +62,17 @@ void ScreenSpaceDrawingMode::add_depth_shgroups(Image *image, ImageUser *image_u
ImBuf *tile_buffer = BKE_image_acquire_ibuf(image, &tile_user, &lock);
if (tile_buffer != nullptr) {
instance_.state.float_buffers.mark_used(tile_buffer);
DRWShadingGroup *shsub = DRW_shgroup_create_sub(shgrp);
PassSimple::Sub &sub = pass.sub("Tile");
float4 min_max_uv(tile_x, tile_y, tile_x + 1, tile_y + 1);
DRW_shgroup_uniform_vec4_copy(shsub, "min_max_uv", min_max_uv);
DRW_shgroup_call_obmat(shsub, info.batch, image_mat);
sub.push_constant("min_max_uv", min_max_uv);
sub.draw(info.batch, handle);
}
BKE_image_release_ibuf(image, tile_buffer, lock);
}
}
}
void ScreenSpaceDrawingMode::update_textures(Image *image, ImageUser *image_user) const
void ScreenSpaceDrawingMode::update_textures(::Image *image, ImageUser *image_user) const
{
State &state = instance_.state;
PartialUpdateChecker<ImageTileData> checker(image, image_user, state.partial_update.user);
@@ -273,7 +261,7 @@ void ScreenSpaceDrawingMode::do_full_update_gpu_texture(TextureInfo &info,
void *lock;
Image *image = instance_.state.image;
::Image *image = instance_.state.image;
LISTBASE_FOREACH (ImageTile *, image_tile_ptr, &image->tiles) {
const ImageTileWrapper image_tile(image_tile_ptr);
tile_user.tile = image_tile.get_tile_number();
@@ -337,10 +325,24 @@ void ScreenSpaceDrawingMode::do_full_update_texture_slot(const TextureInfo &text
void ScreenSpaceDrawingMode::begin_sync() const
{
instance_.state.passes.image_pass = create_image_pass();
instance_.state.passes.depth_pass = create_depth_pass();
{
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
instance_.state.depth_fb.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth));
instance_.state.color_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(dtxl->color));
}
{
PassSimple &pass = instance_.state.image_ps;
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA_PREMUL);
}
{
PassSimple &pass = instance_.state.depth_ps;
pass.init();
pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
}
}
void ScreenSpaceDrawingMode::image_sync(Image *image, ImageUser *iuser) const
void ScreenSpaceDrawingMode::image_sync(::Image *image, ImageUser *iuser) const
{
State &state = instance_.state;
@@ -376,21 +378,29 @@ void ScreenSpaceDrawingMode::draw_finish() const
void ScreenSpaceDrawingMode::draw_viewport() const
{
State *instance_data = &instance_.state;
float clear_depth = instance_.state.flags.do_tile_drawing ? 0.75 : 1.0f;
if (GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_ANY, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL)) {
/* OpenGL doesn't support clearing depth stencil via load store actions as the data types
* should match. */
GPU_framebuffer_bind(instance_.state.depth_fb);
instance_.state.depth_fb.clear_depth(clear_depth);
}
else {
GPU_framebuffer_bind_ex(instance_.state.depth_fb,
{
{GPU_LOADACTION_CLEAR, GPU_STOREACTION_STORE, {clear_depth}},
});
}
instance_.manager->submit(instance_.state.depth_ps, instance_.state.view);
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_bind_ex(
instance_.state.color_fb,
{
{GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_DONT_CARE, {0.0f}},
{GPU_LOADACTION_CLEAR, GPU_STOREACTION_STORE, {0.0f, 0.0f, 0.0f, 0.0f}},
static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float clear_depth = instance_data->flags.do_tile_drawing ? 0.75 : 1.0f;
GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, clear_depth);
DRW_view_set_active(instance_data->view);
DRW_draw_pass(instance_data->passes.depth_pass);
GPU_framebuffer_bind(dfbl->color_only_fb);
DRW_draw_pass(instance_data->passes.image_pass);
DRW_view_set_active(nullptr);
GPU_framebuffer_bind(dfbl->default_fb);
});
instance_.manager->submit(instance_.state.image_ps, instance_.state.view);
}
} // namespace blender::image_engine

View File

@@ -274,8 +274,6 @@ class ScreenSpaceDrawingMode : public AbstractDrawingMode {
ScreenSpaceDrawingMode(Instance &instance) : instance_(instance) {}
private:
DRWPass *create_image_pass() const;
DRWPass *create_depth_pass() const;
void add_shgroups() const;
/**
@@ -283,7 +281,7 @@ class ScreenSpaceDrawingMode : public AbstractDrawingMode {
*
* The depth is used to identify if the tile exist or transparent.
*/
void add_depth_shgroups(Image *image, ImageUser *image_user) const;
void add_depth_shgroups(::Image *image, ::ImageUser *image_user) const;
/**
* \brief Update GPUTextures for drawing the image.
@@ -291,7 +289,7 @@ class ScreenSpaceDrawingMode : public AbstractDrawingMode {
* GPUTextures that are marked dirty are rebuild. GPUTextures that aren't marked dirty are
* updated with changed region of the image.
*/
void update_textures(Image *image, ImageUser *image_user) const;
void update_textures(::Image *image, ::ImageUser *image_user) const;
/**
* Update the float buffer in the region given by the partial update checker.
@@ -299,8 +297,8 @@ class ScreenSpaceDrawingMode : public AbstractDrawingMode {
void do_partial_update_float_buffer(
ImBuf *float_buffer, PartialUpdateChecker<ImageTileData>::CollectResult &iterator) const;
void do_partial_update(PartialUpdateChecker<ImageTileData>::CollectResult &iterator) const;
void do_full_update_for_dirty_textures(const ImageUser *image_user) const;
void do_full_update_gpu_texture(TextureInfo &info, const ImageUser *image_user) const;
void do_full_update_for_dirty_textures(const ::ImageUser *image_user) const;
void do_full_update_gpu_texture(TextureInfo &info, const ::ImageUser *image_user) const;
/**
* texture_buffer is the image buffer belonging to the texture_info.
* tile_buffer is the image buffer of the tile.
@@ -312,7 +310,7 @@ class ScreenSpaceDrawingMode : public AbstractDrawingMode {
public:
void begin_sync() const override;
void image_sync(Image *image, ImageUser *iuser) const override;
void image_sync(::Image *image, ::ImageUser *iuser) const override;
void draw_finish() const override;
void draw_viewport() const override;
};

View File

@@ -12,6 +12,8 @@
#include "image_space_image.hh"
#include "image_space_node.hh"
#include "BLI_math_matrix.hh"
#include "DNA_space_types.h"
namespace blender::image_engine {
@@ -41,6 +43,7 @@ class Instance {
public:
const ARegion *region;
State state;
Manager *manager = nullptr;
public:
Instance() : drawing_mode_(*this) {}
@@ -50,6 +53,7 @@ class Instance {
main_ = main;
region = _region;
space_ = space_accessor_from_space(space_link);
manager = DRW_manager_get();
}
virtual ~Instance() = default;
@@ -59,10 +63,10 @@ class Instance {
drawing_mode_.begin_sync();
/* Setup full screen view matrix. */
float winmat[4][4], viewmat[4][4];
orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0);
unit_m4(winmat);
state.view = DRW_view_create(viewmat, winmat, nullptr, nullptr, nullptr);
float4x4 viewmat = math::projection::orthographic(
0.0f, float(region->winx), 0.0f, float(region->winy), 0.0f, 1.0f);
float4x4 winmat = float4x4::identity();
state.view.sync(viewmat, winmat);
}
void image_sync()

View File

@@ -13,7 +13,7 @@
struct PartialImageUpdater {
PartialUpdateUser *user;
const Image *image;
const ::Image *image;
/**
* \brief Ensure that there is a partial update user for the given image.

View File

@@ -34,7 +34,7 @@ class AbstractDrawingMode {
public:
virtual ~AbstractDrawingMode() = default;
virtual void begin_sync() const = 0;
virtual void image_sync(Image *image, ImageUser *iuser) const = 0;
virtual void image_sync(::Image *image, ::ImageUser *iuser) const = 0;
virtual void draw_viewport() const = 0;
virtual void draw_finish() const = 0;
};

View File

@@ -27,7 +27,10 @@ struct ShaderParameters {
float far_near[2];
bool use_premul_alpha = false;
void update(AbstractSpaceAccessor *space, const Scene *scene, Image *image, ImBuf *image_buffer)
void update(AbstractSpaceAccessor *space,
const Scene *scene,
::Image *image,
ImBuf *image_buffer)
{
flags = ImageDrawFlags::DEFAULT;
copy_v4_fl(shuffle, 1.0f);

View File

@@ -29,7 +29,7 @@ class AbstractSpaceAccessor {
*
* The return value is optional.
*/
virtual Image *get_image(Main *bmain) = 0;
virtual ::Image *get_image(Main *bmain) = 0;
/**
* Return the #ImageUser of the space.
@@ -46,12 +46,12 @@ class AbstractSpaceAccessor {
* \param lock: pointer to a lock object.
* \return Image buffer of the given image.
*/
virtual ImBuf *acquire_image_buffer(Image *image, void **lock) = 0;
virtual ImBuf *acquire_image_buffer(::Image *image, void **lock) = 0;
/**
* Release a previous locked image from #acquire_image_buffer.
*/
virtual void release_buffer(Image *image, ImBuf *image_buffer, void *lock) = 0;
virtual void release_buffer(::Image *image, ImBuf *image_buffer, void *lock) = 0;
/**
* Update the r_shader_parameters with space specific settings.

View File

@@ -20,7 +20,7 @@ class SpaceImageAccessor : public AbstractSpaceAccessor {
public:
SpaceImageAccessor(SpaceImage *sima) : sima(sima) {}
Image *get_image(Main * /*bmain*/) override
::Image *get_image(Main * /*bmain*/) override
{
return ED_space_image(sima);
}
@@ -30,12 +30,12 @@ class SpaceImageAccessor : public AbstractSpaceAccessor {
return &sima->iuser;
}
ImBuf *acquire_image_buffer(Image * /*image*/, void **lock) override
ImBuf *acquire_image_buffer(::Image * /*image*/, void **lock) override
{
return ED_space_image_acquire_buffer(sima, lock, 0);
}
void release_buffer(Image * /*image*/, ImBuf *image_buffer, void *lock) override
void release_buffer(::Image * /*image*/, ImBuf *image_buffer, void *lock) override
{
ED_space_image_release_buffer(sima, image_buffer, lock);
}

View File

@@ -18,7 +18,7 @@ class SpaceNodeAccessor : public AbstractSpaceAccessor {
public:
SpaceNodeAccessor(SpaceNode *snode) : snode(snode) {}
Image *get_image(Main *bmain) override
::Image *get_image(Main *bmain) override
{
return BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
}
@@ -28,12 +28,12 @@ class SpaceNodeAccessor : public AbstractSpaceAccessor {
return nullptr;
}
ImBuf *acquire_image_buffer(Image *image, void **lock) override
ImBuf *acquire_image_buffer(::Image *image, void **lock) override
{
return BKE_image_acquire_ibuf(image, nullptr, lock);
}
void release_buffer(Image *image, ImBuf *ibuf, void *lock) override
void release_buffer(::Image *image, ImBuf *ibuf, void *lock) override
{
BKE_image_release_ibuf(image, ibuf, lock);
}

View File

@@ -19,17 +19,21 @@
#include "image_usage.hh"
#include "DRW_render.hh"
#include "draw_command.hh"
#include "draw_manager.hh"
#include "draw_pass.hh"
namespace blender::image_engine {
using namespace blender::draw;
struct State {
Image *image = nullptr;
::Image *image = nullptr;
/** Usage data of the previous time, to identify changes that require a full update. */
ImageUsage last_usage;
PartialImageUpdater partial_update = {};
DRWView *view = nullptr;
View view = {"Image.View"};
ShaderParameters sh_params;
struct {
/**
@@ -41,10 +45,11 @@ struct State {
bool do_tile_drawing : 1;
} flags;
struct {
DRWPass *image_pass = nullptr;
DRWPass *depth_pass = nullptr;
} passes;
Framebuffer depth_fb = {"Image.Depth"};
Framebuffer color_fb = {"Image.Color"};
PassSimple depth_ps = {"Image.Depth"};
PassSimple image_ps = {"Image.Color"};
/**
* Cache containing the float buffers when drawing byte images.

View File

@@ -14,11 +14,13 @@
#include "GPU_batch.hh"
#include "GPU_texture.hh"
#include "DRW_gpu_wrapper.hh"
#include "DRW_render.hh"
namespace blender::image_engine {
using namespace blender::draw;
struct TextureInfo {
struct TextureInfo : NonCopyable {
/**
* \brief does this texture need a full update.
*
@@ -47,21 +49,19 @@ struct TextureInfo {
/**
* \brief GPU Texture for a partial region of the image editor.
*/
GPUTexture *texture = nullptr;
Texture texture = {"Image.Tile"};
int2 last_texture_size = int2(0);
TextureInfo() = default;
TextureInfo(TextureInfo &&other) = default;
~TextureInfo()
{
if (batch != nullptr) {
GPU_batch_discard(batch);
batch = nullptr;
}
if (texture != nullptr) {
GPU_texture_free(texture);
texture = nullptr;
}
}
/**
@@ -77,22 +77,17 @@ struct TextureInfo {
void ensure_gpu_texture(int2 texture_size)
{
const bool is_allocated = texture != nullptr;
const bool is_allocated = texture.is_valid();
const bool resolution_changed = assign_if_different(last_texture_size, texture_size);
const bool should_be_freed = is_allocated && resolution_changed;
const bool should_be_created = !is_allocated || resolution_changed;
if (should_be_freed) {
GPU_texture_free(texture);
texture = nullptr;
texture.free();
}
if (should_be_created) {
texture = DRW_texture_create_2d_ex(UNPACK2(texture_size),
GPU_RGBA16F,
GPU_TEXTURE_USAGE_GENERAL,
static_cast<DRWTextureFlag>(0),
nullptr);
texture.ensure_2d(GPU_RGBA16F, texture_size, GPU_TEXTURE_USAGE_SHADER_READ);
}
need_full_update |= should_be_created;
}

View File

@@ -30,7 +30,7 @@ struct ImageUsage {
const void *last_image = nullptr;
ImageUsage() = default;
ImageUsage(const Image *image, const ImageUser *image_user, bool do_tile_drawing)
ImageUsage(const ::Image *image, const ::ImageUser *image_user, bool do_tile_drawing)
{
pass = image_user ? image_user->pass : 0;
layer = image_user ? image_user->layer : 0;

View File

@@ -21,7 +21,8 @@ SAMPLER(0, FLOAT_2D, image_tx)
SAMPLER(1, DEPTH_2D, depth_tx)
VERTEX_SOURCE("image_engine_color_vert.glsl")
FRAGMENT_SOURCE("image_engine_color_frag.glsl")
ADDITIONAL_INFO(draw_modelmat)
ADDITIONAL_INFO(draw_view)
ADDITIONAL_INFO(draw_modelmat_new)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()
@@ -36,7 +37,8 @@ VERTEX_OUT(image_engine_depth_iface)
PUSH_CONSTANT(VEC4, min_max_uv)
VERTEX_SOURCE("image_engine_depth_vert.glsl")
FRAGMENT_SOURCE("image_engine_depth_frag.glsl")
ADDITIONAL_INFO(draw_modelmat)
ADDITIONAL_INFO(draw_view)
ADDITIONAL_INFO(draw_modelmat_new)
DEPTH_WRITE(DepthWrite::ANY)
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()