NoelFB / Celeste

Celeste Bugs & Issue Tracker + some Source Code
MIT License
3.54k stars 419 forks source link

Texture larger than 4096 being created during Feather Minigame #5

Closed NoelFB closed 6 years ago

NoelFB commented 6 years ago

Shouldn't allow this to happen


==========================================

Ver 1.2.1.5
3/3/2018 4:17:51 PM
System.NotSupportedException: XNA Framework HiDef profile supports a maximum Texture2D size of 4096.
at Microsoft.Xna.Framework.Graphics.ProfileCapabilities.ThrowNotSupportedException(String message, Object arg1, Object arg2)
at Microsoft.Xna.Framework.Graphics.Texture2D.ValidateCreationParameters(ProfileCapabilities profile, Int32 width, Int32 height, SurfaceFormat format, Boolean mipMap)
at Microsoft.Xna.Framework.Graphics.RenderTarget2D.CreateRenderTarget(GraphicsDevice graphicsDevice, Int32 width, Int32 height, Boolean mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, Int32 preferredMultiSampleCount, RenderTargetUsage usage)
at Microsoft.Xna.Framework.Graphics.RenderTarget2D..ctor(GraphicsDevice graphicsDevice, Int32 width, Int32 height, Boolean mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, Int32 preferredMultiSampleCount, RenderTargetUsage usage)
at Monocle.VirtualRenderTarget.Reload()
at Celeste.BreathingMinigame.BeforeRender()
at Celeste.Level.BeforeRender()
at Monocle.Engine.RenderCore()
at Celeste.Celeste.RenderCore()
at Monocle.Engine.Draw(GameTime gameTime)
at Microsoft.Xna.Framework.Game.DrawFrame()
at Microsoft.Xna.Framework.Game.Tick()
at Microsoft.Xna.Framework.Game.HostIdle(Object sender, EventArgs e)
at Microsoft.Xna.Framework.GameHost.OnIdle()
at Microsoft.Xna.Framework.WindowsGameHost.RunOneFrame()
at Microsoft.Xna.Framework.WindowsGameHost.ApplicationIdle(Object sender, EventArgs e)
at System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(Int32 grfidlef)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Microsoft.Xna.Framework.WindowsGameHost.Run()
at Microsoft.Xna.Framework.Game.RunGame(Boolean useBlockingRun)
at Monocle.Engine.RunWithLogging()```
0x0ade commented 6 years ago

Seems like someone is running the game in an absurdly high resolution, which XNA can't deal with out of the box.

Luckily, the person behind RomTerraria documented a hack to create RenderTarget2Ds larger than 4096x4096:

http://romsteady.blogspot.de/2013/11/xna-hack-create-rendertarget2d-greater.html

Problem: XNA's HiDef profile has a maximum Texture2D size of 4096x4096. RenderTarget2D has a backing Texture2D object, and this limitation is enforced at time of construction. Solution: Time to get a bit tricky with reflection. Limitations in XNA are all stored in Microsoft.Xna.Framework.Graphics.ProfileCapabilities, an internal class. Fortunately, they aren't constants... In your Initialize() function...

Assembly xna = Assembly.GetAssembly(typeof(GraphicsProfile));
Type profileCapabilities = xna.GetType("Microsoft.Xna.Framework.Graphics.ProfileCapabilities", true);
if (profileCapabilities != null)
{
FieldInfo maxTextureSize = profileCapabilities.GetField("MaxTextureSize", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo hidefProfile = profileCapabilities.GetField("HiDef", BindingFlags.Static | BindingFlags.NonPublic);
if (maxTextureSize != null && hidefProfile != null)
{
object profile = hidefProfile.GetValue(null);
maxTextureSize.SetValue(hidefProfile.GetValue(null), MaxTextureSize);
}
}

He states that optimally, MaxTextureSize should be determined using the DirectX API, but NextPOT(Math.Max(Engine.ViewWidth, Engine.ViewHeight)) should probably work fine, too, where NextPOT returns the next higher power of two. This assumes that the backbuffer size <= the maximum supported texture size by the player's GPU.

NoelFB commented 6 years ago

Huh that's really interesting, thanks for the info! I think I'll likely just limit the texture size to the virtual game resolution (1920x1080) since everything else is handled that way too, but this is good for the future.

NoelFB commented 6 years ago

Fixed by clamping the texture size in the Breathing Minigame to 1920x1080