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
* padding to the width/height - Clamp width/height. */
BLI_assert(scissor.x >= 0 && scissor.x < render_fb->get_width());
BLI_assert(scissor.y >= 0 && scissor.y < render_fb->get_height());
scissor.width = min_ii(scissor.width, render_fb->get_width() - scissor.x);
scissor.height = min_ii(scissor.height, render_fb->get_height() - scissor.y);
BLI_assert(scissor.width > 0 && (scissor.x + scissor.width <= render_fb->get_width()));
BLI_assert(scissor.height > 0 && (scissor.height <= render_fb->get_height()));
BLI_assert(scissor.x >= 0 && scissor.x < render_fb->get_default_width());
BLI_assert(scissor.y >= 0 && scissor.y < render_fb->get_default_height());
scissor.width = (uint)min_ii(scissor.width,
max_ii(render_fb->get_default_width() - (int)(scissor.x), 0));
scissor.height = (uint)min_ii(
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 {
/* Scissor is disabled, reset to default size as scissor state may have been previously
* assigned on this encoder. */
scissor.x = 0;
scissor.y = 0;
scissor.width = render_fb->get_width();
scissor.height = render_fb->get_height();
scissor.width = render_fb->get_default_width();
scissor.height = render_fb->get_default_height();
}
/* 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. */
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:
/**
* Create a conventional framebuffer to attach texture to.
@ -157,6 +167,7 @@ class MTLFrameBuffer : public FrameBuffer {
/* Attachment management. */
/* When dirty_attachments_ is true, we need to reprocess attachments to extract Metal
* information. */
void ensure_attachments_and_viewport();
void update_attachments(bool update_viewport);
bool add_color_attachment(gpu::MTLTexture *texture, uint slot, 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_height();
int get_default_width();
int get_default_height();
bool get_dirty()
{
return is_dirty_ || is_loadstore_dirty_;
@ -231,6 +245,12 @@ class MTLFrameBuffer : public FrameBuffer {
return srgb_;
}
inline void default_size_set(int w, int h)
{
default_width_ = w;
default_height_ = h;
}
private:
/* Clears a render target by force-opening a render pass. */
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)
{
@ -102,11 +114,7 @@ void MTLFrameBuffer::bind(bool enabled_srgb)
/* 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();
}
this->ensure_attachments_and_viewport();
/* Ensure SRGB state is up-to-date and valid. */
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])
{
/* Ensure local MTLAttachment data is up to date. */
this->update_attachments(true);
/* 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. */
this->ensure_attachments_and_viewport();
/* Ensure there is at least one attachment. */
bool valid = (this->get_attachment_count() > 0 ||
@ -543,8 +553,8 @@ void MTLFrameBuffer::blit_to(eGPUFrameBufferBits planes,
int dst_offset_x,
int dst_offset_y)
{
this->update_attachments(true);
static_cast<MTLFrameBuffer *>(dst)->update_attachments(true);
this->ensure_attachments_and_viewport();
static_cast<MTLFrameBuffer *>(dst)->ensure_attachments_and_viewport();
BLI_assert(planes != 0);
@ -773,8 +783,8 @@ void MTLFrameBuffer::apply_state()
if (viewport_w == 0 || viewport_h == 0) {
MTL_LOG_WARNING(
"Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check\n");
viewport_w = width_;
viewport_h = height_;
viewport_w = default_width_;
viewport_h = default_height_;
}
/* Update Context State. */
@ -892,7 +902,7 @@ bool MTLFrameBuffer::add_color_attachment(gpu::MTLTexture *texture,
break;
}
/* Update Frame-buffer Resolution. */
/* Update default attachment size and ensure future attachments match the same size. */
int width_of_miplayer, height_of_miplayer;
if (miplevel <= 0) {
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);
}
if (width_ == 0 || height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(width_ > 0);
BLI_assert(height_ > 0);
if (default_width_ == 0 || default_height_ == 0) {
this->default_size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(default_width_ > 0);
BLI_assert(default_height_ > 0);
}
else {
BLI_assert(width_ == width_of_miplayer);
BLI_assert(height_ == height_of_miplayer);
BLI_assert(default_width_ == width_of_miplayer);
BLI_assert(default_height_ == height_of_miplayer);
}
/* Flag as dirty. */
@ -1011,7 +1021,7 @@ bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel
break;
}
/* Update Frame-buffer Resolution. */
/* Update default attachment size and ensure future attachments match the same size. */
int width_of_miplayer, height_of_miplayer;
if (miplevel <= 0) {
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);
}
/* Update Frame-buffer Resolution. */
if (width_ == 0 || height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(width_ > 0);
BLI_assert(height_ > 0);
if (default_width_ == 0 || default_height_ == 0) {
this->default_size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(default_width_ > 0);
BLI_assert(default_height_ > 0);
}
else {
BLI_assert(width_ == texture->width_get());
BLI_assert(height_ == texture->height_get());
BLI_assert(default_width_ == width_of_miplayer);
BLI_assert(default_height_ == height_of_miplayer);
}
/* Flag as dirty after attachments changed. */
@ -1131,7 +1140,7 @@ bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplev
break;
}
/* Update Frame-buffer Resolution. */
/* Update default attachment size and ensure future attachments match the same size. */
int width_of_miplayer, height_of_miplayer;
if (miplevel <= 0) {
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);
}
/* Update Frame-buffer Resolution. */
if (width_ == 0 || height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(width_ > 0);
BLI_assert(height_ > 0);
if (default_width_ == 0 || default_height_ == 0) {
this->default_size_set(width_of_miplayer, height_of_miplayer);
BLI_assert(default_width_ > 0);
BLI_assert(default_height_ > 0);
}
else {
BLI_assert(width_ == texture->width_get());
BLI_assert(height_ == texture->height_get());
BLI_assert(default_width_ == width_of_miplayer);
BLI_assert(default_height_ == height_of_miplayer);
}
/* 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() &&
!this->has_stencil_attachment()) {
/* Reset size for empty framebuffer. */
this->size_set(0, 0);
/* Reset default size for empty framebuffer. */
this->default_size_set(0, 0);
}
}
@ -1461,7 +1469,9 @@ bool MTLFrameBuffer::validate_render_pass()
BLI_assert(this);
/* First update attachments if dirty. */
this->update_attachments(true);
if (dirty_attachments_) {
this->update_attachments(true);
}
/* Verify attachment count. */
int used_attachments = 0;
@ -1892,4 +1902,13 @@ int MTLFrameBuffer::get_height()
return height_;
}
int MTLFrameBuffer::get_default_width()
{
return default_width_;
}
int MTLFrameBuffer::get_default_height()
{
return default_height_;
}
} // namespace blender::gpu