Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallbacks if the preferred render target formats are not supported #5340

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
82 changes: 82 additions & 0 deletions MonoGame.Framework/Graphics/GraphicsAdapter.DirectX.cs
Expand Up @@ -129,5 +129,87 @@ protected bool PlatformIsProfileSupported(GraphicsProfile graphicsProfile)
throw new InvalidOperationException();
}
}

static int NextLowestPowerOf2(int x)
{
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
}

bool PlatformQueryBackBufferFormat(
GraphicsProfile graphicsProfile,
SurfaceFormat format,
DepthFormat depthFormat,
int multiSampleCount,
out SurfaceFormat selectedFormat,
out DepthFormat selectedDepthFormat,
out int selectedMultiSampleCount)
{
selectedFormat = format;
selectedDepthFormat = depthFormat;

// 16-bit formats are not supported for displays
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff471325(v=vs.85).aspx
switch (format)
{
case SurfaceFormat.Color:
case SurfaceFormat.Rgba1010102:
break;

default:
selectedFormat = SurfaceFormat.Color;
break;
}

// Direct3D 11 does not support a 24-bit only depth buffer. It has the D24S8 format.
if (depthFormat == DepthFormat.Depth24)
selectedDepthFormat = DepthFormat.Depth24Stencil8;

// Set to a power of two less than or equal to 8
selectedMultiSampleCount = NextLowestPowerOf2(multiSampleCount);
if (selectedMultiSampleCount > 8)
selectedMultiSampleCount = 8;

return (format == selectedFormat) && (depthFormat == selectedDepthFormat) && (multiSampleCount == selectedMultiSampleCount);
}

bool PlatformQueryRenderTargetFormat(
GraphicsProfile graphicsProfile,
SurfaceFormat format,
DepthFormat depthFormat,
int multiSampleCount,
out SurfaceFormat selectedFormat,
out DepthFormat selectedDepthFormat,
out int selectedMultiSampleCount)
{
selectedFormat = format;
selectedDepthFormat = depthFormat;

// 16-bit formats are not supported until DXGI 1.2 (Direct3D 11.1)
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff471325(v=vs.85).aspx
switch (format)
{
case SurfaceFormat.Bgr565:
case SurfaceFormat.Bgra4444:
case SurfaceFormat.Bgra5551:
selectedFormat = SurfaceFormat.Color;
break;
}

// Direct3D 11 does not support a 24-bit only depth buffer. It has the D24S8 format.
if (depthFormat == DepthFormat.Depth24)
selectedDepthFormat = DepthFormat.Depth24Stencil8;

// Set to a power of two less than or equal to 8
selectedMultiSampleCount = NextLowestPowerOf2(multiSampleCount);
if (selectedMultiSampleCount > 8)
selectedMultiSampleCount = 8;

return (format == selectedFormat) && (depthFormat == selectedDepthFormat) && (multiSampleCount == selectedMultiSampleCount);
}
}
}
63 changes: 63 additions & 0 deletions MonoGame.Framework/Graphics/GraphicsAdapter.Legacy.cs
Expand Up @@ -400,5 +400,68 @@ public bool IsProfileSupported(GraphicsProfile graphicsProfile)
private const int HORZRES = 8;
private const int VERTRES = 10;
#endif

static int NextLowestPowerOf2(int x)
{
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
}

public bool QueryBackBufferFormat(
GraphicsProfile graphicsProfile,
SurfaceFormat format,
DepthFormat depthFormat,
int multiSampleCount,
out SurfaceFormat selectedFormat,
out DepthFormat selectedDepthFormat,
out int selectedMultiSampleCount)
{
selectedFormat = format;
selectedDepthFormat = depthFormat;

// Back buffer support for Color, Rgba1010102 and Bgr565 only
switch (format)
{
case SurfaceFormat.Color:
case SurfaceFormat.Rgba1010102:
case SurfaceFormat.Bgr565:
break;

default:
selectedFormat = SurfaceFormat.Color;
break;
}

// Set to a power of two less than or equal to 8
selectedMultiSampleCount = NextLowestPowerOf2(multiSampleCount);
if (selectedMultiSampleCount > 8)
selectedMultiSampleCount = 8;

return (format == selectedFormat) && (depthFormat == selectedDepthFormat) && (multiSampleCount == selectedMultiSampleCount);
}

public bool QueryRenderTargetFormat(
GraphicsProfile graphicsProfile,
SurfaceFormat format,
DepthFormat depthFormat,
int multiSampleCount,
out SurfaceFormat selectedFormat,
out DepthFormat selectedDepthFormat,
out int selectedMultiSampleCount)
{
selectedFormat = format;
selectedDepthFormat = depthFormat;

// Set to a power of two less than or equal to 8
selectedMultiSampleCount = NextLowestPowerOf2(multiSampleCount);
if (selectedMultiSampleCount > 8)
selectedMultiSampleCount = 8;

return (format == selectedFormat) && (depthFormat == selectedDepthFormat) && (multiSampleCount == selectedMultiSampleCount);
}
}
}
46 changes: 46 additions & 0 deletions MonoGame.Framework/Graphics/GraphicsAdapter.cs
Expand Up @@ -144,5 +144,51 @@ public void Dispose()
// We don't keep any resources, so we have
// nothing to do... just here for XNA compatibility.
}

/// <summary>
/// Queries for support of the requested back buffer format on the adaptor.
/// </summary>
/// <param name="graphicsProfile">The graphics profile.</param>
/// <param name="format">The requested surface format.</param>
/// <param name="depthFormat">The requested depth stencil format.</param>
/// <param name="multiSampleCount">The requested multisample count.</param>
/// <param name="selectedFormat">Set to the best format supported by the adaptor for the requested surface format.</param>
/// <param name="selectedDepthFormat">Set to the best format supported by the adaptor for the requested depth stencil format.</param>
/// <param name="selectedMultiSampleCount">Set to the best count supported by the adaptor for the requested multisample count.</param>
/// <returns>True if the requested format is supported by the adaptor. False if one or more of the values was changed.</returns>
public bool QueryBackBufferFormat(
GraphicsProfile graphicsProfile,
SurfaceFormat format,
DepthFormat depthFormat,
int multiSampleCount,
out SurfaceFormat selectedFormat,
out DepthFormat selectedDepthFormat,
out int selectedMultiSampleCount)
{
return PlatformQueryBackBufferFormat(graphicsProfile, format, depthFormat, multiSampleCount, out selectedFormat, out selectedDepthFormat, out selectedMultiSampleCount);
}

/// <summary>
/// Queries for support of the requested render target format on the adaptor.
/// </summary>
/// <param name="graphicsProfile">The graphics profile.</param>
/// <param name="format">The requested surface format.</param>
/// <param name="depthFormat">The requested depth stencil format.</param>
/// <param name="multiSampleCount">The requested multisample count.</param>
/// <param name="selectedFormat">Set to the best format supported by the adaptor for the requested surface format.</param>
/// <param name="selectedDepthFormat">Set to the best format supported by the adaptor for the requested depth stencil format.</param>
/// <param name="selectedMultiSampleCount">Set to the best count supported by the adaptor for the requested multisample count.</param>
/// <returns>True if the requested format is supported by the adaptor. False if one or more of the values was changed.</returns>
public bool QueryRenderTargetFormat(
GraphicsProfile graphicsProfile,
SurfaceFormat format,
DepthFormat depthFormat,
int multiSampleCount,
out SurfaceFormat selectedFormat,
out DepthFormat selectedDepthFormat,
out int selectedMultiSampleCount)
{
return PlatformQueryRenderTargetFormat(graphicsProfile, format, depthFormat, multiSampleCount, out selectedFormat, out selectedDepthFormat, out selectedMultiSampleCount);
}
}
}
2 changes: 2 additions & 0 deletions MonoGame.Framework/Graphics/RenderTarget2D.cs
Expand Up @@ -26,6 +26,8 @@ private bool SuppressEventHandlerWarningsUntilEventsAreProperlyImplemented()
public RenderTarget2D(GraphicsDevice graphicsDevice, int width, int height, bool mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, int preferredMultiSampleCount, RenderTargetUsage usage, bool shared, int arraySize)
: base(graphicsDevice, width, height, mipMap, preferredFormat, SurfaceType.RenderTarget, shared, arraySize)
{
graphicsDevice.Adapter.QueryRenderTargetFormat(graphicsDevice.GraphicsProfile, preferredFormat, preferredDepthFormat, preferredMultiSampleCount,
out preferredFormat, out preferredDepthFormat, out preferredMultiSampleCount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QueryRenderTargetFormat() is called after the base class (Texture2D) is initialized with the preferredFormat.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move this code into the private Texture2D(...) and perform the fallback when SurfaceType == RenderTarget.

We also need to remove the SurfaceFormat & SurfaceType parameters from Texture2D.PlatformConstruct()
https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Graphics/Texture2D.DirectX.cs#L37-L41
When is needed, it has to use the ._format that is already initialized from Texture2D().

DepthStencilFormat = preferredDepthFormat;
MultiSampleCount = preferredMultiSampleCount;
RenderTargetUsage = usage;
Expand Down
6 changes: 4 additions & 2 deletions MonoGame.Framework/Graphics/RenderTarget3D.cs
Expand Up @@ -25,8 +25,10 @@ private bool SuppressEventHandlerWarningsUntilEventsAreProperlyImplemented()

public RenderTarget3D(GraphicsDevice graphicsDevice, int width, int height, int depth, bool mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, int preferredMultiSampleCount, RenderTargetUsage usage)
:base (graphicsDevice, width, height, depth, mipMap, preferredFormat, true)
{
DepthStencilFormat = preferredDepthFormat;
{
graphicsDevice.Adapter.QueryRenderTargetFormat(graphicsDevice.GraphicsProfile, preferredFormat, preferredDepthFormat, preferredMultiSampleCount,
out preferredFormat, out preferredDepthFormat, out preferredMultiSampleCount);
DepthStencilFormat = preferredDepthFormat;
MultiSampleCount = preferredMultiSampleCount;
RenderTargetUsage = usage;

Expand Down
2 changes: 2 additions & 0 deletions MonoGame.Framework/Graphics/RenderTargetCube.cs
Expand Up @@ -65,6 +65,8 @@ public RenderTargetCube(GraphicsDevice graphicsDevice, int size, bool mipMap, Su
public RenderTargetCube(GraphicsDevice graphicsDevice, int size, bool mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, int preferredMultiSampleCount, RenderTargetUsage usage)
: base(graphicsDevice, size, mipMap, preferredFormat, true)
{
graphicsDevice.Adapter.QueryRenderTargetFormat(graphicsDevice.GraphicsProfile, preferredFormat, preferredDepthFormat, preferredMultiSampleCount,
out preferredFormat, out preferredDepthFormat, out preferredMultiSampleCount);
DepthStencilFormat = preferredDepthFormat;
MultiSampleCount = preferredMultiSampleCount;
RenderTargetUsage = usage;
Expand Down