Render via an intermediate frame buffer.
This commit is contained in:
@@ -41,6 +41,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
Size WindowSize { get; }
|
Size WindowSize { get; }
|
||||||
float WindowScale { get; }
|
float WindowScale { get; }
|
||||||
|
Size SurfaceSize { get; }
|
||||||
|
|
||||||
event Action<float, float> OnWindowScaleChanged;
|
event Action<float, float> OnWindowScaleChanged;
|
||||||
|
|
||||||
void PumpInput(IInputHandler inputHandler);
|
void PumpInput(IInputHandler inputHandler);
|
||||||
@@ -62,7 +64,7 @@ namespace OpenRA
|
|||||||
IFrameBuffer CreateFrameBuffer(Size s);
|
IFrameBuffer CreateFrameBuffer(Size s);
|
||||||
IFrameBuffer CreateFrameBuffer(Size s, Color clearColor);
|
IFrameBuffer CreateFrameBuffer(Size s, Color clearColor);
|
||||||
IShader CreateShader(string name);
|
IShader CreateShader(string name);
|
||||||
void EnableScissor(int left, int top, int width, int height);
|
void EnableScissor(int x, int y, int width, int height);
|
||||||
void DisableScissor();
|
void DisableScissor();
|
||||||
void SaveScreenshot(string path);
|
void SaveScreenshot(string path);
|
||||||
void Present();
|
void Present();
|
||||||
|
|||||||
@@ -160,9 +160,9 @@ namespace OpenRA.Graphics
|
|||||||
shader.SetVec("Scroll", scroll.X, scroll.Y, scroll.Y);
|
shader.SetVec("Scroll", scroll.X, scroll.Y, scroll.Y);
|
||||||
shader.SetVec("r1",
|
shader.SetVec("r1",
|
||||||
zoom * 2f / screen.Width,
|
zoom * 2f / screen.Width,
|
||||||
-zoom * 2f / screen.Height,
|
zoom * 2f / screen.Height,
|
||||||
-depthScale * zoom / screen.Height);
|
-depthScale * zoom / screen.Height);
|
||||||
shader.SetVec("r2", -1, 1, 1 - depthOffset);
|
shader.SetVec("r2", -1, -1, 1 - depthOffset);
|
||||||
|
|
||||||
// Texture index is sampled as a float, so convert to pixels then scale
|
// Texture index is sampled as a float, so convert to pixels then scale
|
||||||
shader.SetVec("DepthTextureScale", 128 * depthScale * zoom / screen.Height);
|
shader.SetVec("DepthTextureScale", 128 * depthScale * zoom / screen.Height);
|
||||||
|
|||||||
@@ -38,13 +38,16 @@ namespace OpenRA
|
|||||||
readonly IVertexBuffer<Vertex> tempBuffer;
|
readonly IVertexBuffer<Vertex> tempBuffer;
|
||||||
readonly Stack<Rectangle> scissorState = new Stack<Rectangle>();
|
readonly Stack<Rectangle> scissorState = new Stack<Rectangle>();
|
||||||
|
|
||||||
|
IFrameBuffer screenBuffer;
|
||||||
|
Sprite screenSprite;
|
||||||
|
|
||||||
SheetBuilder fontSheetBuilder;
|
SheetBuilder fontSheetBuilder;
|
||||||
readonly IPlatform platform;
|
readonly IPlatform platform;
|
||||||
|
|
||||||
float depthScale;
|
float depthScale;
|
||||||
float depthOffset;
|
float depthOffset;
|
||||||
|
|
||||||
Size lastResolution = new Size(-1, -1);
|
Size lastBufferSize = new Size(-1, -1);
|
||||||
int2 lastScroll = new int2(-1, -1);
|
int2 lastScroll = new int2(-1, -1);
|
||||||
float lastZoom = -1f;
|
float lastZoom = -1f;
|
||||||
ITexture currentPaletteTexture;
|
ITexture currentPaletteTexture;
|
||||||
@@ -123,26 +126,55 @@ namespace OpenRA
|
|||||||
public void BeginFrame(int2 scroll, float zoom)
|
public void BeginFrame(int2 scroll, float zoom)
|
||||||
{
|
{
|
||||||
Context.Clear();
|
Context.Clear();
|
||||||
|
|
||||||
|
var surfaceSize = Window.SurfaceSize;
|
||||||
|
var surfaceBufferSize = surfaceSize.NextPowerOf2();
|
||||||
|
|
||||||
|
if (screenSprite == null || screenSprite.Sheet.Size != surfaceBufferSize)
|
||||||
|
{
|
||||||
|
if (screenBuffer != null)
|
||||||
|
screenBuffer.Dispose();
|
||||||
|
|
||||||
|
// Render the screen into a frame buffer to simplify reading back screenshots
|
||||||
|
screenBuffer = Context.CreateFrameBuffer(surfaceBufferSize, Color.FromArgb(0xFF, 0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screenSprite == null || surfaceSize.Width != screenSprite.Bounds.Width || -surfaceSize.Height != screenSprite.Bounds.Height)
|
||||||
|
{
|
||||||
|
var screenSheet = new Sheet(SheetType.BGRA, screenBuffer.Texture);
|
||||||
|
|
||||||
|
// Flip sprite in Y to match OpenGL's bottom-left origin
|
||||||
|
var screenBounds = Rectangle.FromLTRB(0, surfaceSize.Height, surfaceSize.Width, 0);
|
||||||
|
screenSprite = new Sprite(screenSheet, screenBounds, TextureChannel.RGBA);
|
||||||
|
}
|
||||||
|
|
||||||
|
screenBuffer.Bind();
|
||||||
SetViewportParams(scroll, zoom);
|
SetViewportParams(scroll, zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetViewportParams(int2 scroll, float zoom)
|
public void SetViewportParams(int2 scroll, float zoom)
|
||||||
{
|
{
|
||||||
// PERF: Calling SetViewportParams on each renderer is slow. Only call it when things change.
|
// In HiDPI windows we follow Apple's convention of defining window coordinates as for standard resolution windows
|
||||||
var resolutionChanged = lastResolution != Resolution;
|
// but to have a higher resolution backing surface with more than 1 texture pixel per viewport pixel.
|
||||||
if (resolutionChanged)
|
// We must convert the surface buffer size to a viewport size - in general this is NOT just the window size
|
||||||
{
|
// rounded to the next power of two, as the NextPowerOf2 calculation is done in the surface pixel coordinates
|
||||||
lastResolution = Resolution;
|
var scale = Window.WindowScale;
|
||||||
SpriteRenderer.SetViewportParams(lastResolution, 0f, 0f, 1f, int2.Zero);
|
var surfaceBufferSize = Window.SurfaceSize.NextPowerOf2();
|
||||||
}
|
var bufferSize = new Size((int)(surfaceBufferSize.Width / scale), (int)(surfaceBufferSize.Height / scale));
|
||||||
|
|
||||||
// If zoom evaluates as different due to floating point weirdness that's OK, setting the parameters again is harmless.
|
// PERF: Calling SetViewportParams on each renderer is slow. Only call it when things change.
|
||||||
if (resolutionChanged || lastScroll != scroll || lastZoom != zoom)
|
// If zoom evaluates as different due to floating point weirdness that's OK, it will be going away soon
|
||||||
|
if (lastBufferSize != bufferSize || lastScroll != scroll || lastZoom != zoom)
|
||||||
{
|
{
|
||||||
|
if (lastBufferSize != bufferSize)
|
||||||
|
SpriteRenderer.SetViewportParams(bufferSize, 0f, 0f, 1f, int2.Zero);
|
||||||
|
|
||||||
|
WorldSpriteRenderer.SetViewportParams(bufferSize, depthScale, depthOffset, zoom, scroll);
|
||||||
|
WorldModelRenderer.SetViewportParams(bufferSize, zoom, scroll);
|
||||||
|
|
||||||
|
lastBufferSize = bufferSize;
|
||||||
lastScroll = scroll;
|
lastScroll = scroll;
|
||||||
lastZoom = zoom;
|
lastZoom = zoom;
|
||||||
WorldSpriteRenderer.SetViewportParams(lastResolution, depthScale, depthOffset, zoom, scroll);
|
|
||||||
WorldModelRenderer.SetViewportParams(lastResolution, zoom, scroll);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +194,15 @@ namespace OpenRA
|
|||||||
public void EndFrame(IInputHandler inputHandler)
|
public void EndFrame(IInputHandler inputHandler)
|
||||||
{
|
{
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
|
screenBuffer.Unbind();
|
||||||
|
|
||||||
|
// Render the compositor buffer to the screen
|
||||||
|
// HACK / PERF: Fudge the coordinates to cover the actual window while keeping the buffer viewport parameters
|
||||||
|
// This saves us two redundant (and expensive) SetViewportParams each frame
|
||||||
|
RgbaSpriteRenderer.DrawSprite(screenSprite, new float3(0, lastBufferSize.Height, 0), new float3(lastBufferSize.Width, -lastBufferSize.Height, 0));
|
||||||
|
Flush();
|
||||||
|
|
||||||
Window.PumpInput(inputHandler);
|
Window.PumpInput(inputHandler);
|
||||||
Context.Present();
|
Context.Present();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace OpenRA.Platforms.Default
|
|||||||
return new Shader(name);
|
return new Shader(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnableScissor(int left, int top, int width, int height)
|
public void EnableScissor(int x, int y, int width, int height)
|
||||||
{
|
{
|
||||||
VerifyThreadAffinity();
|
VerifyThreadAffinity();
|
||||||
|
|
||||||
@@ -97,16 +97,15 @@ namespace OpenRA.Platforms.Default
|
|||||||
var windowScale = window.WindowScale;
|
var windowScale = window.WindowScale;
|
||||||
var surfaceSize = window.SurfaceSize;
|
var surfaceSize = window.SurfaceSize;
|
||||||
|
|
||||||
var bottom = windowSize.Height - (top + height);
|
|
||||||
if (windowSize != surfaceSize)
|
if (windowSize != surfaceSize)
|
||||||
{
|
{
|
||||||
left = (int)Math.Round(windowScale * left);
|
x = (int)Math.Round(windowScale * x);
|
||||||
bottom = (int)Math.Round(windowScale * bottom);
|
y = (int)Math.Round(windowScale * y);
|
||||||
width = (int)Math.Round(windowScale * width);
|
width = (int)Math.Round(windowScale * width);
|
||||||
height = (int)Math.Round(windowScale * height);
|
height = (int)Math.Round(windowScale * height);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGL.glScissor(left, bottom, width, height);
|
OpenGL.glScissor(x, y, width, height);
|
||||||
OpenGL.CheckGLError();
|
OpenGL.CheckGLError();
|
||||||
OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST);
|
OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST);
|
||||||
OpenGL.CheckGLError();
|
OpenGL.CheckGLError();
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace OpenRA.Platforms.Default
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Size SurfaceSize
|
public Size SurfaceSize
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user