Fix #106773: resolve Metal grease pencil fill #106857

Merged
Jeroen Bakker merged 2 commits from Jason-Fielder/blender:Fix_106773 into main 2023-04-13 08:23:46 +02:00
3 changed files with 87 additions and 45 deletions

View File

@ -949,20 +949,23 @@ bool MTLContext::ensure_render_pipeline_state(MTLPrimitiveType mtl_prim_type)
/* Some scissor assignments exceed the bounds of the viewport due to implicitly added /* Some scissor assignments exceed the bounds of the viewport due to implicitly added
* padding to the width/height - Clamp width/height. */ * padding to the width/height - Clamp width/height. */
BLI_assert(scissor.x >= 0 && scissor.x < render_fb->get_width()); BLI_assert(scissor.x >= 0 && scissor.x < render_fb->get_default_width());
BLI_assert(scissor.y >= 0 && scissor.y < render_fb->get_height()); BLI_assert(scissor.y >= 0 && scissor.y < render_fb->get_default_height());
scissor.width = min_ii(scissor.width, render_fb->get_width() - scissor.x); scissor.width = (uint)min_ii(scissor.width,
scissor.height = min_ii(scissor.height, render_fb->get_height() - scissor.y); max_ii(render_fb->get_default_width() - (int)(scissor.x), 0));
BLI_assert(scissor.width > 0 && (scissor.x + scissor.width <= render_fb->get_width())); scissor.height = (uint)min_ii(
BLI_assert(scissor.height > 0 && (scissor.height <= render_fb->get_height())); scissor.height, max_ii(render_fb->get_default_height() - (int)(scissor.y), 0));
BLI_assert(scissor.width > 0 &&
(scissor.x + scissor.width <= render_fb->get_default_width()));
BLI_assert(scissor.height > 0 && (scissor.height <= render_fb->get_default_height()));
} }
else { else {
/* Scissor is disabled, reset to default size as scissor state may have been previously /* Scissor is disabled, reset to default size as scissor state may have been previously
* assigned on this encoder. */ * assigned on this encoder. */
scissor.x = 0; scissor.x = 0;
scissor.y = 0; scissor.y = 0;
scissor.width = render_fb->get_width(); scissor.width = render_fb->get_default_width();
scissor.height = render_fb->get_height(); scissor.height = render_fb->get_default_height();
} }
/* Scissor state can still be flagged as changed if it is toggled on and off, without /* Scissor state can still be flagged as changed if it is toggled on and off, without

View File

@ -104,6 +104,16 @@ class MTLFrameBuffer : public FrameBuffer {
/** Whether the primary Frame-buffer attachment is an SRGB target or not. */ /** Whether the primary Frame-buffer attachment is an SRGB target or not. */
bool srgb_; bool srgb_;
/** Default width/height represent raw size of active framebuffer attachments.
* For consistency with OpenGL backend, as width_/height_ can affect viewport and scissor
* size, we need to track this differently to ensure viewport state does not get reset.
* This size is only used to reset viewport/scissor regions when viewports and scissor are
* disabled, as Metal does not provide a utility to fully disable either without manually
* specifying the size.
*/
int default_width_ = 0;
int default_height_ = 0;
public: public:
/** /**
* Create a conventional framebuffer to attach texture to. * Create a conventional framebuffer to attach texture to.
@ -157,6 +167,7 @@ class MTLFrameBuffer : public FrameBuffer {
/* Attachment management. */ /* Attachment management. */
/* When dirty_attachments_ is true, we need to reprocess attachments to extract Metal /* When dirty_attachments_ is true, we need to reprocess attachments to extract Metal
* information. */ * information. */
void ensure_attachments_and_viewport();
void update_attachments(bool update_viewport); void update_attachments(bool update_viewport);
bool add_color_attachment(gpu::MTLTexture *texture, uint slot, int miplevel, int layer); bool add_color_attachment(gpu::MTLTexture *texture, uint slot, int miplevel, int layer);
bool add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer); bool add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer);
@ -211,6 +222,9 @@ class MTLFrameBuffer : public FrameBuffer {
int get_width(); int get_width();
int get_height(); int get_height();
int get_default_width();
int get_default_height();
bool get_dirty() bool get_dirty()
{ {
return is_dirty_ || is_loadstore_dirty_; return is_dirty_ || is_loadstore_dirty_;
@ -231,6 +245,12 @@ class MTLFrameBuffer : public FrameBuffer {
return srgb_; return srgb_;
} }
inline void default_size_set(int w, int h)
{
default_width_ = w;
default_height_ = h;
}
private: private:
/* Clears a render target by force-opening a render pass. */ /* Clears a render target by force-opening a render pass. */
void force_clear(); void force_clear();

View File

@ -90,6 +90,18 @@ MTLFrameBuffer::~MTLFrameBuffer()
} }
} }
void MTLFrameBuffer::ensure_attachments_and_viewport()
{
/* Ensure local MTLAttachment data is up to date.
* NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
* This is to ensure state is consistent with the OpenGL backend. */
if (dirty_attachments_) {
this->update_attachments(true);
this->viewport_reset();
this->scissor_reset();
}
}
void MTLFrameBuffer::bind(bool enabled_srgb) void MTLFrameBuffer::bind(bool enabled_srgb)
{ {
@ -102,11 +114,7 @@ void MTLFrameBuffer::bind(bool enabled_srgb)
/* Ensure local MTLAttachment data is up to date. /* Ensure local MTLAttachment data is up to date.
* NOTE: We only refresh viewport/scissor region when attachments are updated during bind. * NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
* This is to ensure state is consistent with the OpenGL backend. */ * This is to ensure state is consistent with the OpenGL backend. */
if (dirty_attachments_) { this->ensure_attachments_and_viewport();
this->update_attachments(true);
this->viewport_reset();
this->scissor_reset();
}
/* Ensure SRGB state is up-to-date and valid. */ /* Ensure SRGB state is up-to-date and valid. */
bool srgb_state_changed = enabled_srgb_ != enabled_srgb; bool srgb_state_changed = enabled_srgb_ != enabled_srgb;
@ -134,8 +142,10 @@ void MTLFrameBuffer::bind(bool enabled_srgb)
bool MTLFrameBuffer::check(char err_out[256]) bool MTLFrameBuffer::check(char err_out[256])
{ {
/* Ensure local MTLAttachment data is up to date. */ /* Ensure local MTLAttachment data is up to date.
this->update_attachments(true); * NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
* This is to ensure state is consistent with the OpenGL backend. */
this->ensure_attachments_and_viewport();
/* Ensure there is at least one attachment. */ /* Ensure there is at least one attachment. */
bool valid = (this->get_attachment_count() > 0 || bool valid = (this->get_attachment_count() > 0 ||
@ -543,8 +553,8 @@ void MTLFrameBuffer::blit_to(eGPUFrameBufferBits planes,
int dst_offset_x, int dst_offset_x,
int dst_offset_y) int dst_offset_y)
{ {
this->update_attachments(true); this->ensure_attachments_and_viewport();
static_cast<MTLFrameBuffer *>(dst)->update_attachments(true); static_cast<MTLFrameBuffer *>(dst)->ensure_attachments_and_viewport();
BLI_assert(planes != 0); BLI_assert(planes != 0);
@ -773,8 +783,8 @@ void MTLFrameBuffer::apply_state()
if (viewport_w == 0 || viewport_h == 0) { if (viewport_w == 0 || viewport_h == 0) {
MTL_LOG_WARNING( MTL_LOG_WARNING(
"Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check\n"); "Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check\n");
viewport_w = width_; viewport_w = default_width_;
viewport_h = height_; viewport_h = default_height_;
} }
/* Update Context State. */ /* Update Context State. */
@ -892,7 +902,7 @@ bool MTLFrameBuffer::add_color_attachment(gpu::MTLTexture *texture,
break; break;
} }
/* Update Frame-buffer Resolution. */ /* Update default attachment size and ensure future attachments match the same size. */
int width_of_miplayer, height_of_miplayer; int width_of_miplayer, height_of_miplayer;
if (miplevel <= 0) { if (miplevel <= 0) {
width_of_miplayer = texture->width_get(); width_of_miplayer = texture->width_get();
@ -903,14 +913,14 @@ bool MTLFrameBuffer::add_color_attachment(gpu::MTLTexture *texture,
height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1); height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
} }
if (width_ == 0 || height_ == 0) { if (default_width_ == 0 || default_height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer); this->default_size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(width_ > 0); BLI_assert(default_width_ > 0);
BLI_assert(height_ > 0); BLI_assert(default_height_ > 0);
} }
else { else {
BLI_assert(width_ == width_of_miplayer); BLI_assert(default_width_ == width_of_miplayer);
BLI_assert(height_ == height_of_miplayer); BLI_assert(default_height_ == height_of_miplayer);
} }
/* Flag as dirty. */ /* Flag as dirty. */
@ -1011,7 +1021,7 @@ bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel
break; break;
} }
/* Update Frame-buffer Resolution. */ /* Update default attachment size and ensure future attachments match the same size. */
int width_of_miplayer, height_of_miplayer; int width_of_miplayer, height_of_miplayer;
if (miplevel <= 0) { if (miplevel <= 0) {
width_of_miplayer = texture->width_get(); width_of_miplayer = texture->width_get();
@ -1022,15 +1032,14 @@ bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel
height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1); height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
} }
/* Update Frame-buffer Resolution. */ if (default_width_ == 0 || default_height_ == 0) {
if (width_ == 0 || height_ == 0) { this->default_size_set(width_of_miplayer, height_of_miplayer);
this->size_set(width_of_miplayer, height_of_miplayer); BLI_assert(default_width_ > 0);
BLI_assert(width_ > 0); BLI_assert(default_height_ > 0);
BLI_assert(height_ > 0);
} }
else { else {
BLI_assert(width_ == texture->width_get()); BLI_assert(default_width_ == width_of_miplayer);
BLI_assert(height_ == texture->height_get()); BLI_assert(default_height_ == height_of_miplayer);
} }
/* Flag as dirty after attachments changed. */ /* Flag as dirty after attachments changed. */
@ -1131,7 +1140,7 @@ bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplev
break; break;
} }
/* Update Frame-buffer Resolution. */ /* Update default attachment size and ensure future attachments match the same size. */
int width_of_miplayer, height_of_miplayer; int width_of_miplayer, height_of_miplayer;
if (miplevel <= 0) { if (miplevel <= 0) {
width_of_miplayer = texture->width_get(); width_of_miplayer = texture->width_get();
@ -1142,15 +1151,14 @@ bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplev
height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1); height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
} }
/* Update Frame-buffer Resolution. */ if (default_width_ == 0 || default_height_ == 0) {
if (width_ == 0 || height_ == 0) { this->default_size_set(width_of_miplayer, height_of_miplayer);
this->size_set(width_of_miplayer, height_of_miplayer); BLI_assert(default_width_ > 0);
BLI_assert(width_ > 0); BLI_assert(default_height_ > 0);
BLI_assert(height_ > 0);
} }
else { else {
BLI_assert(width_ == texture->width_get()); BLI_assert(default_width_ == width_of_miplayer);
BLI_assert(height_ == texture->height_get()); BLI_assert(default_height_ == height_of_miplayer);
} }
/* Flag as dirty after attachments changed. */ /* Flag as dirty after attachments changed. */
@ -1229,8 +1237,8 @@ void MTLFrameBuffer::ensure_render_target_size()
if (colour_attachment_count_ == 0 && !this->has_depth_attachment() && if (colour_attachment_count_ == 0 && !this->has_depth_attachment() &&
!this->has_stencil_attachment()) { !this->has_stencil_attachment()) {
/* Reset size for empty framebuffer. */ /* Reset default size for empty framebuffer. */
this->size_set(0, 0); this->default_size_set(0, 0);
} }
} }
@ -1461,7 +1469,9 @@ bool MTLFrameBuffer::validate_render_pass()
BLI_assert(this); BLI_assert(this);
/* First update attachments if dirty. */ /* First update attachments if dirty. */
this->update_attachments(true); if (dirty_attachments_) {
this->update_attachments(true);
}
/* Verify attachment count. */ /* Verify attachment count. */
int used_attachments = 0; int used_attachments = 0;
@ -1892,4 +1902,13 @@ int MTLFrameBuffer::get_height()
return height_; return height_;
} }
int MTLFrameBuffer::get_default_width()
{
return default_width_;
}
int MTLFrameBuffer::get_default_height()
{
return default_height_;
}
} // namespace blender::gpu } // namespace blender::gpu