1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-06 06:32:56 +01:00

reinstate hardware display

This commit is contained in:
Ted John
2016-06-05 23:14:54 +01:00
parent 3b627651aa
commit 313110ab8d
3 changed files with 196 additions and 59 deletions

View File

@@ -43,7 +43,7 @@ extern "C"
_drawingEngine = DrawingEngineFactory::CreateSoftware();
break;
case DRAWING_ENGINE_SOFTWARE_WITH_HARDWARE_DISPLAY:
_drawingEngine = DrawingEngineFactory::CreateSoftware();
_drawingEngine = DrawingEngineFactory::CreateSoftwareWithHardwareDisplay();
break;
case DRAWING_ENGINE_OPENGL:
_drawingEngine = DrawingEngineFactory::CreateOpenGL();

View File

@@ -23,6 +23,7 @@
extern "C"
{
#include "../../config.h"
#include "../../game.h"
#include "../../interface/screenshot.h"
#include "../../interface/window.h"
#include "../../intro.h"
@@ -185,6 +186,18 @@ private:
SDL_Surface * _RGBASurface = nullptr;
SDL_Palette * _palette = nullptr;
// For hardware display only
SDL_Renderer * _sdlRenderer = nullptr;
SDL_Texture * _screenTexture = nullptr;
SDL_PixelFormat * _screenTextureFormat = nullptr;
uint32 _paletteHWMapped[256] = { 0 };
// Steam overlay checking
uint32 _pixelBeforeOverlay = 0;
uint32 _pixelAfterOverlay = 0;
bool _overlayActive = false;
bool _pausedBeforeOverlay = false;
uint32 _width = 0;
uint32 _height = 0;
uint32 _pitch = 0;
@@ -213,6 +226,9 @@ public:
SDL_FreeSurface(_surface);
SDL_FreeSurface(_RGBASurface);
SDL_FreePalette(_palette);
SDL_DestroyTexture(_screenTexture);
SDL_FreeFormat(_screenTextureFormat);
SDL_DestroyRenderer(_sdlRenderer);
}
void Initialise(SDL_Window * window) override
@@ -225,42 +241,88 @@ public:
SDL_FreeSurface(_surface);
SDL_FreeSurface(_RGBASurface);
SDL_FreePalette(_palette);
SDL_DestroyTexture(_screenTexture);
SDL_FreeFormat(_screenTextureFormat);
SDL_DestroyRenderer(_sdlRenderer);
_surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);
_RGBASurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
SDL_SetSurfaceBlendMode(_RGBASurface, SDL_BLENDMODE_NONE);
_palette = SDL_AllocPalette(256);
if (_surface == nullptr ||
_palette == nullptr ||
_RGBASurface == nullptr)
if (_hardwareDisplay)
{
log_fatal("%p || %p || %p == NULL %s", _surface, _palette, _RGBASurface, SDL_GetError());
exit(-1);
}
_sdlRenderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (SDL_SetSurfacePalette(_surface, _palette))
SDL_RendererInfo rendererInfo;
SDL_GetRendererInfo(_sdlRenderer, &rendererInfo);
uint32 pixelFormat = SDL_PIXELFORMAT_UNKNOWN;
for (uint32 i = 0; i < rendererInfo.num_texture_formats; i++)
{
uint32 format = rendererInfo.texture_formats[i];
if (!SDL_ISPIXELFORMAT_FOURCC(format) &&
!SDL_ISPIXELFORMAT_INDEXED(format) &&
(pixelFormat == SDL_PIXELFORMAT_UNKNOWN || SDL_BYTESPERPIXEL(format) < SDL_BYTESPERPIXEL(pixelFormat)))
{
pixelFormat = format;
}
}
_screenTexture = SDL_CreateTexture(_sdlRenderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, width, height);
uint32 format;
SDL_QueryTexture(_screenTexture, &format, 0, 0, 0);
_screenTextureFormat = SDL_AllocFormat(format);
ConfigureBits(width, height, width);
}
else
{
log_fatal("SDL_SetSurfacePalette failed %s", SDL_GetError());
exit(-1);
}
_surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);
_RGBASurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
SDL_SetSurfaceBlendMode(_RGBASurface, SDL_BLENDMODE_NONE);
_palette = SDL_AllocPalette(256);
ConfigureBits(width, height, _surface->pitch);
if (_surface == nullptr ||
_palette == nullptr ||
_RGBASurface == nullptr)
{
log_fatal("%p || %p || %p == NULL %s", _surface, _palette, _RGBASurface, SDL_GetError());
exit(-1);
}
if (SDL_SetSurfacePalette(_surface, _palette))
{
log_fatal("SDL_SetSurfacePalette failed %s", SDL_GetError());
exit(-1);
}
ConfigureBits(width, height, _surface->pitch);
}
}
void SetPalette(SDL_Color * palette) override
{
SDL_Surface * windowSurface = SDL_GetWindowSurface(gWindow);
if (windowSurface == nullptr)
if (_hardwareDisplay)
{
log_fatal("SDL_GetWindowSurface failed %s", SDL_GetError());
exit(1);
if (_screenTextureFormat != nullptr)
{
for (int i = 0; i < 256; i++)
{
_paletteHWMapped[i] = SDL_MapRGB(_screenTextureFormat, palette[i].r, palette[i].g, palette[i].b);
}
}
}
if (_palette != nullptr && SDL_SetPaletteColors(_palette, gPalette, 0, 256))
else
{
log_fatal("SDL_SetPaletteColors failed %s", SDL_GetError());
exit(1);
SDL_Surface * windowSurface = SDL_GetWindowSurface(gWindow);
if (windowSurface == nullptr)
{
log_fatal("SDL_GetWindowSurface failed %s", SDL_GetError());
exit(1);
}
if (_palette != nullptr && SDL_SetPaletteColors(_palette, palette, 0, 256))
{
log_fatal("SDL_SetPaletteColors failed %s", SDL_GetError());
exit(1);
}
}
}
@@ -317,7 +379,15 @@ public:
rct2_draw(&_bitsDPI);
}
Display();
if (_hardwareDisplay)
{
DisplayViaTexture();
}
else
{
Display();
}
}
void CopyRect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) override
@@ -588,6 +658,106 @@ private:
exit(1);
}
}
void DisplayViaTexture()
{
void * pixels;
int pitch;
if (SDL_LockTexture(_screenTexture, nullptr, &pixels, &pitch) == 0)
{
uint8 * src = _bits;
int padding = pitch - (_width * 4);
if (pitch == _width * 4) {
uint32 * dst = (uint32 *)pixels;
for (int i = _width * _height; i > 0; i--)
{
*dst++ = *(uint32 *)(&_paletteHWMapped[*src++]);
}
}
else
{
if (pitch == (_width * 2) + padding)
{
uint16 * dst = (uint16 *)pixels;
for (sint32 y = (sint32)_height; y > 0; y--) {
for (sint32 x = (sint32)_width; x > 0; x--) {
const uint8 lower = *(uint8 *)(&_paletteHWMapped[*src++]);
const uint8 upper = *(uint8 *)(&_paletteHWMapped[*src++]);
*dst++ = (lower << 8) | upper;
}
dst = (uint16*)(((uint8 *)dst) + padding);
}
}
else
{
if (pitch == _width + padding)
{
uint8 * dst = (uint8 *)pixels;
for (sint32 y = (sint32)_height; y > 0; y--) {
for (sint32 x = (sint32)_width; x > 0; x--)
{
*dst++ = *(uint8 *)(&_paletteHWMapped[*src++]);
}
dst += padding;
}
}
}
}
SDL_UnlockTexture(_screenTexture);
}
SDL_RenderCopy(_sdlRenderer, _screenTexture, NULL, NULL);
if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause)
{
OverlayPreRenderCheck();
}
SDL_RenderPresent(_sdlRenderer);
if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause)
{
OverlayPostRenderCheck();
}
}
void ReadCentrePixel(uint32 * pixel)
{
SDL_Rect centrePixelRegion = { (sint32)(_width / 2), (sint32)(_height / 2), 1, 1 };
SDL_RenderReadPixels(_sdlRenderer, &centrePixelRegion, SDL_PIXELFORMAT_RGBA8888, pixel, sizeof(uint32));
}
// Should be called before SDL_RenderPresent to capture frame buffer before Steam overlay is drawn.
void OverlayPreRenderCheck()
{
ReadCentrePixel(&_pixelBeforeOverlay);
}
// Should be called after SDL_RenderPresent, when Steam overlay has had the chance to be drawn.
void OverlayPostRenderCheck()
{
ReadCentrePixel(&_pixelAfterOverlay);
// Detect an active Steam overlay by checking if the center pixel is changed by the gray fade.
// Will not be triggered by applications rendering to corners, like FRAPS, MSI Afterburner and Friends popups.
bool newOverlayActive = _pixelBeforeOverlay != _pixelAfterOverlay;
// Toggle game pause state consistently with base pause state
if (!_overlayActive && newOverlayActive)
{
_pausedBeforeOverlay = gGamePaused & GAME_PAUSED_NORMAL;
if (!_pausedBeforeOverlay)
{
pause_toggle();
}
}
else if (_overlayActive && !newOverlayActive && !_pausedBeforeOverlay)
{
pause_toggle();
}
_overlayActive = newOverlayActive;
}
};
IDrawingEngine * DrawingEngineFactory::CreateSoftware()

View File

@@ -171,39 +171,6 @@ void platform_get_closest_resolution(int inWidth, int inHeight, int *outWidth, i
}
}
static void read_center_pixel(int width, int height, uint32 *pixel) {
SDL_Rect centerPixelRegion = {width / 2, height / 2, 1, 1};
SDL_RenderReadPixels(gRenderer, &centerPixelRegion, SDL_PIXELFORMAT_RGBA8888, pixel, sizeof(uint32));
}
// Should be called before SDL_RenderPresent to capture frame buffer before Steam overlay is drawn.
static void overlay_pre_render_check(int width, int height) {
read_center_pixel(width, height, &_pixelBeforeOverlay);
}
// Should be called after SDL_RenderPresent, when Steam overlay has had the chance to be drawn.
static void overlay_post_render_check(int width, int height) {
static bool overlayActive = false;
static bool pausedBeforeOverlay = false;
read_center_pixel(width, height, &_pixelAfterOverlay);
// Detect an active Steam overlay by checking if the center pixel is changed by the gray fade.
// Will not be triggered by applications rendering to corners, like FRAPS, MSI Afterburner and Friends popups.
bool newOverlayActive = _pixelBeforeOverlay != _pixelAfterOverlay;
// Toggle game pause state consistently with base pause state
if (!overlayActive && newOverlayActive) {
pausedBeforeOverlay = gGamePaused & GAME_PAUSED_NORMAL;
if (!pausedBeforeOverlay) pause_toggle();
} else if (overlayActive && !newOverlayActive && !pausedBeforeOverlay) {
pause_toggle();
}
overlayActive = newOverlayActive;
}
void platform_draw()
{
if (!gOpenRCT2Headless) {