Browse Source
When rendering directly to the output buffer, we need to maintain the state of what has been drawn and what needs redrawing per-buffer. We previously tried to do it implicitly by checking `SDL_DOUBLEBUF` and other flags. The previous implementation was broken in several ways, resulting in rendering issues on devices that support 8-bit output directly. Changes this mechanism to explicitly maintain buffer state per output buffer. The new mechanism doesn't require knowledge of the number of buffers, and thus also works correctly with triple-buffering. Fixes #5447pull/5458/head
31 changed files with 386 additions and 245 deletions
@ -0,0 +1,98 @@
|
||||
#include "engine/backbuffer_state.hpp" |
||||
|
||||
#include <unordered_map> |
||||
|
||||
#include "engine/dx.h" |
||||
#include "utils/enum_traits.h" |
||||
|
||||
namespace devilution { |
||||
namespace { |
||||
|
||||
struct RedrawState { |
||||
enum { |
||||
RedrawNone, |
||||
RedrawViewportOnly, |
||||
RedrawAll |
||||
} Redraw; |
||||
std::array<bool, enum_size<PanelDrawComponent>::value> redrawComponents; |
||||
}; |
||||
|
||||
struct BackbufferState { |
||||
RedrawState redrawState; |
||||
DrawnCursor cursor; |
||||
}; |
||||
|
||||
std::unordered_map<void *, BackbufferState> States; |
||||
|
||||
BackbufferState &GetBackbufferState() |
||||
{ |
||||
// `PalSurface` is null in headless mode.
|
||||
void *ptr = PalSurface != nullptr ? PalSurface->pixels : nullptr; |
||||
auto result = States.emplace(std::piecewise_construct, std::forward_as_tuple(ptr), std::forward_as_tuple()); |
||||
BackbufferState &state = result.first->second; |
||||
if (result.second) |
||||
state.redrawState.Redraw = RedrawState::RedrawAll; |
||||
return state; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
bool IsRedrawEverything() |
||||
{ |
||||
return GetBackbufferState().redrawState.Redraw == RedrawState::RedrawAll; |
||||
} |
||||
|
||||
void RedrawViewport() |
||||
{ |
||||
for (auto &&it : States) { |
||||
if (it.second.redrawState.Redraw != RedrawState::RedrawAll) { |
||||
it.second.redrawState.Redraw = RedrawState::RedrawViewportOnly; |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool IsRedrawViewport() |
||||
{ |
||||
return GetBackbufferState().redrawState.Redraw == RedrawState::RedrawViewportOnly; |
||||
} |
||||
|
||||
void RedrawComplete() |
||||
{ |
||||
GetBackbufferState().redrawState.Redraw = RedrawState::RedrawNone; |
||||
} |
||||
|
||||
void RedrawEverything() |
||||
{ |
||||
for (auto &&it : States) { |
||||
it.second.redrawState.Redraw = RedrawState::RedrawAll; |
||||
} |
||||
} |
||||
|
||||
void InitBackbufferState() |
||||
{ |
||||
States.clear(); |
||||
} |
||||
|
||||
void RedrawComponent(PanelDrawComponent component) |
||||
{ |
||||
for (auto &&it : States) { |
||||
it.second.redrawState.redrawComponents[static_cast<size_t>(component)] = true; |
||||
} |
||||
} |
||||
|
||||
bool IsRedrawComponent(PanelDrawComponent component) |
||||
{ |
||||
return GetBackbufferState().redrawState.redrawComponents[static_cast<size_t>(component)]; |
||||
} |
||||
|
||||
void RedrawComponentComplete(PanelDrawComponent component) |
||||
{ |
||||
GetBackbufferState().redrawState.redrawComponents[static_cast<size_t>(component)] = false; |
||||
} |
||||
|
||||
DrawnCursor &GetDrawnCursor() |
||||
{ |
||||
return GetBackbufferState().cursor; |
||||
} |
||||
|
||||
} // namespace devilution
|
||||
@ -0,0 +1,40 @@
|
||||
#pragma once |
||||
|
||||
#include <cstdint> |
||||
|
||||
#include "engine/rectangle.hpp" |
||||
#include "engine/surface.hpp" |
||||
|
||||
namespace devilution { |
||||
|
||||
enum class PanelDrawComponent { |
||||
Health, |
||||
Mana, |
||||
ControlButtons, |
||||
Belt, |
||||
ChatInput, |
||||
|
||||
FIRST = Health, |
||||
LAST = ChatInput |
||||
}; |
||||
|
||||
struct DrawnCursor { |
||||
Rectangle rect; |
||||
uint8_t behindBuffer[8192]; |
||||
}; |
||||
|
||||
void InitBackbufferState(); |
||||
|
||||
void RedrawEverything(); |
||||
bool IsRedrawEverything(); |
||||
void RedrawViewport(); |
||||
bool IsRedrawViewport(); |
||||
void RedrawComplete(); |
||||
|
||||
void RedrawComponent(PanelDrawComponent component); |
||||
bool IsRedrawComponent(PanelDrawComponent component); |
||||
void RedrawComponentComplete(PanelDrawComponent component); |
||||
|
||||
DrawnCursor &GetDrawnCursor(); |
||||
|
||||
} // namespace devilution
|
||||
Loading…
Reference in new issue