Codechange: [OSX] Only keep a total dirty rect for drawing.

When drawing an 8bpp screen buffer, palette resolving was done for each
dirty rectangle. In areas with high activity, this would mean a pixel might
have been resolved multiple times. Also, if too many individual updates
were queued, the whole screen would be refreshed, even if unnecessary.

All other drivers only keep one overall dirty rect, so do it here as well.
This commit is contained in:
Michael Lutz 2021-02-20 19:01:45 +01:00
parent 61275df7da
commit f3c192c63d
2 changed files with 25 additions and 43 deletions

View File

@ -32,10 +32,8 @@ private:
void *pixel_buffer; ///< used for direct pixel access void *pixel_buffer; ///< used for direct pixel access
void *window_buffer; ///< Colour translation from palette to screen void *window_buffer; ///< Colour translation from palette to screen
static const int MAX_DIRTY_RECTS = 100; Rect dirty_rect; ///< Region of the screen that needs redrawing.
Rect dirty_rects[MAX_DIRTY_RECTS]; ///< dirty rectangles
uint num_dirty_rects; ///< Number of dirty rectangles
uint32 palette[256]; ///< Colour Palette uint32 palette[256]; ///< Colour Palette
public: public:

View File

@ -26,7 +26,7 @@
#include "../../openttd.h" #include "../../openttd.h"
#include "../../debug.h" #include "../../debug.h"
#include "../../core/geometry_type.hpp" #include "../../core/geometry_func.hpp"
#include "../../core/math_func.hpp" #include "../../core/math_func.hpp"
#include "cocoa_v.h" #include "cocoa_v.h"
#include "cocoa_wnd.h" #include "cocoa_wnd.h"
@ -125,7 +125,7 @@ VideoDriver_Cocoa::VideoDriver_Cocoa()
this->color_space = nullptr; this->color_space = nullptr;
this->cgcontext = nullptr; this->cgcontext = nullptr;
this->num_dirty_rects = lengthof(this->dirty_rects); this->dirty_rect = {};
} }
/** Stop Cocoa video driver. */ /** Stop Cocoa video driver. */
@ -192,13 +192,8 @@ const char *VideoDriver_Cocoa::Start(const StringList &parm)
*/ */
void VideoDriver_Cocoa::MakeDirty(int left, int top, int width, int height) void VideoDriver_Cocoa::MakeDirty(int left, int top, int width, int height)
{ {
if (this->num_dirty_rects < lengthof(this->dirty_rects)) { Rect r = {left, top, left + width, top + height};
dirty_rects[this->num_dirty_rects].left = left; this->dirty_rect = BoundingRect(this->dirty_rect, r);
dirty_rects[this->num_dirty_rects].top = top;
dirty_rects[this->num_dirty_rects].right = left + width;
dirty_rects[this->num_dirty_rects].bottom = top + height;
}
this->num_dirty_rects++;
} }
/** /**
@ -473,40 +468,29 @@ void VideoDriver_Cocoa::Paint()
PerformanceMeasurer framerate(PFE_VIDEO); PerformanceMeasurer framerate(PFE_VIDEO);
/* Check if we need to do anything */ /* Check if we need to do anything */
if (this->num_dirty_rects == 0 || [ this->window isMiniaturized ]) return; if (IsEmptyRect(this->dirty_rect) || [ this->window isMiniaturized ]) return;
if (this->num_dirty_rects >= lengthof(this->dirty_rects)) { /* We only need to blit in indexed mode since in 32bpp mode the game draws directly to the image. */
this->num_dirty_rects = 1; if (this->buffer_depth == 8) {
this->dirty_rects[0].left = 0; BlitIndexedToView32(
this->dirty_rects[0].top = 0; this->dirty_rect.left,
this->dirty_rects[0].right = this->window_width; this->dirty_rect.top,
this->dirty_rects[0].bottom = this->window_height; this->dirty_rect.right,
this->dirty_rect.bottom
);
} }
/* Build the region of dirty rectangles */ NSRect dirtyrect;
for (uint i = 0; i < this->num_dirty_rects; i++) { dirtyrect.origin.x = this->dirty_rect.left;
/* We only need to blit in indexed mode since in 32bpp mode the game draws directly to the image. */ dirtyrect.origin.y = this->window_height - this->dirty_rect.bottom;
if (this->buffer_depth == 8) { dirtyrect.size.width = this->dirty_rect.right - this->dirty_rect.left;
BlitIndexedToView32( dirtyrect.size.height = this->dirty_rect.bottom - this->dirty_rect.top;
this->dirty_rects[i].left,
this->dirty_rects[i].top,
this->dirty_rects[i].right,
this->dirty_rects[i].bottom
);
}
NSRect dirtyrect; /* Normally drawRect will be automatically called by Mac OS X during next update cycle,
dirtyrect.origin.x = this->dirty_rects[i].left; * and then blitting will occur. */
dirtyrect.origin.y = this->window_height - this->dirty_rects[i].bottom; [ this->cocoaview setNeedsDisplayInRect:[ this->cocoaview getVirtualRect:dirtyrect ] ];
dirtyrect.size.width = this->dirty_rects[i].right - this->dirty_rects[i].left;
dirtyrect.size.height = this->dirty_rects[i].bottom - this->dirty_rects[i].top;
/* Normally drawRect will be automatically called by Mac OS X during next update cycle, this->dirty_rect = {};
* and then blitting will occur. */
[ this->cocoaview setNeedsDisplayInRect:[ this->cocoaview getVirtualRect:dirtyrect ] ];
}
this->num_dirty_rects = 0;
} }
/** Update the palette. */ /** Update the palette. */
@ -522,7 +506,7 @@ void VideoDriver_Cocoa::UpdatePalette(uint first_color, uint num_colors)
this->palette[i] = clr; this->palette[i] = clr;
} }
this->num_dirty_rects = lengthof(this->dirty_rects); this->MakeDirty(0, 0, _screen.width, _screen.height);
} }
/** Clear buffer to opaque black. */ /** Clear buffer to opaque black. */
@ -580,8 +564,8 @@ void VideoDriver_Cocoa::AllocateBackingStore()
} }
/* Redraw screen */ /* Redraw screen */
this->num_dirty_rects = lengthof(this->dirty_rects);
this->GameSizeChanged(); this->GameSizeChanged();
this->MakeDirty(0, 0, _screen.width, _screen.height);
} }
/** Check if palette updates need to be performed. */ /** Check if palette updates need to be performed. */