Render via an intermediate frame buffer.
This commit is contained in:
@@ -41,6 +41,8 @@ namespace OpenRA
|
||||
|
||||
Size WindowSize { get; }
|
||||
float WindowScale { get; }
|
||||
Size SurfaceSize { get; }
|
||||
|
||||
event Action<float, float> OnWindowScaleChanged;
|
||||
|
||||
void PumpInput(IInputHandler inputHandler);
|
||||
@@ -62,7 +64,7 @@ namespace OpenRA
|
||||
IFrameBuffer CreateFrameBuffer(Size s);
|
||||
IFrameBuffer CreateFrameBuffer(Size s, Color clearColor);
|
||||
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 SaveScreenshot(string path);
|
||||
void Present();
|
||||
|
||||
@@ -160,9 +160,9 @@ namespace OpenRA.Graphics
|
||||
shader.SetVec("Scroll", scroll.X, scroll.Y, scroll.Y);
|
||||
shader.SetVec("r1",
|
||||
zoom * 2f / screen.Width,
|
||||
-zoom * 2f / screen.Height,
|
||||
zoom * 2f / 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
|
||||
shader.SetVec("DepthTextureScale", 128 * depthScale * zoom / screen.Height);
|
||||
|
||||
@@ -38,13 +38,16 @@ namespace OpenRA
|
||||
readonly IVertexBuffer<Vertex> tempBuffer;
|
||||
readonly Stack<Rectangle> scissorState = new Stack<Rectangle>();
|
||||
|
||||
IFrameBuffer screenBuffer;
|
||||
Sprite screenSprite;
|
||||
|
||||
SheetBuilder fontSheetBuilder;
|
||||
readonly IPlatform platform;
|
||||
|
||||
float depthScale;
|
||||
float depthOffset;
|
||||
|
||||
Size lastResolution = new Size(-1, -1);
|
||||
Size lastBufferSize = new Size(-1, -1);
|
||||
int2 lastScroll = new int2(-1, -1);
|
||||
float lastZoom = -1f;
|
||||
ITexture currentPaletteTexture;
|
||||
@@ -123,26 +126,55 @@ namespace OpenRA
|
||||
public void BeginFrame(int2 scroll, float zoom)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public void SetViewportParams(int2 scroll, float zoom)
|
||||
{
|
||||
// PERF: Calling SetViewportParams on each renderer is slow. Only call it when things change.
|
||||
var resolutionChanged = lastResolution != Resolution;
|
||||
if (resolutionChanged)
|
||||
{
|
||||
lastResolution = Resolution;
|
||||
SpriteRenderer.SetViewportParams(lastResolution, 0f, 0f, 1f, int2.Zero);
|
||||
}
|
||||
// In HiDPI windows we follow Apple's convention of defining window coordinates as for standard resolution windows
|
||||
// but to have a higher resolution backing surface with more than 1 texture pixel per viewport pixel.
|
||||
// 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
|
||||
var scale = Window.WindowScale;
|
||||
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.
|
||||
if (resolutionChanged || lastScroll != scroll || lastZoom != zoom)
|
||||
// PERF: Calling SetViewportParams on each renderer is slow. Only call it when things change.
|
||||
// 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;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
Context.Present();
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace OpenRA.Platforms.Default
|
||||
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();
|
||||
|
||||
@@ -97,16 +97,15 @@ namespace OpenRA.Platforms.Default
|
||||
var windowScale = window.WindowScale;
|
||||
var surfaceSize = window.SurfaceSize;
|
||||
|
||||
var bottom = windowSize.Height - (top + height);
|
||||
if (windowSize != surfaceSize)
|
||||
{
|
||||
left = (int)Math.Round(windowScale * left);
|
||||
bottom = (int)Math.Round(windowScale * bottom);
|
||||
x = (int)Math.Round(windowScale * x);
|
||||
y = (int)Math.Round(windowScale * y);
|
||||
width = (int)Math.Round(windowScale * width);
|
||||
height = (int)Math.Round(windowScale * height);
|
||||
}
|
||||
|
||||
OpenGL.glScissor(left, bottom, width, height);
|
||||
OpenGL.glScissor(x, y, width, height);
|
||||
OpenGL.CheckGLError();
|
||||
OpenGL.glEnable(OpenGL.GL_SCISSOR_TEST);
|
||||
OpenGL.CheckGLError();
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace OpenRA.Platforms.Default
|
||||
}
|
||||
}
|
||||
|
||||
internal Size SurfaceSize
|
||||
public Size SurfaceSize
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user