[OpenTK] Use ASCII encoding
Most OpenGL versions work with single-byte ASCII strings exclusively. OpenGL 4.2 adds UTF8 encoded comments to GLSL shaders. Unfortunately, UTF16 (.Net) to UTF8 conversions will usually modify the length of the resulting byte array. This is not currently possible to implement inside OpenTK, since the binding generator does not know which length parameter corresponds to a string parameter. For this reason, and to maintain compatibility with older OpenGL versions, we perform a destructive UTF16-to-ASCII encoding, which replaces unsupported characters by '?'. This allows multi-byte post-4.2. GLSL shaders to work as expected. If non-destructive round-tripping of strings is required, the user will have to use the IntPtr overload for string parameters and perform the UTF16-to-UTF8 encoding/decoding manually. This need is very unlikely to arise in practice.
This commit is contained in:
parent
606b4ddcd1
commit
b9f57ba4d2
1 changed files with 8 additions and 8 deletions
|
@ -146,7 +146,7 @@ namespace OpenTK
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marshal a <c>System.String</c> to unmanaged memory.
|
/// Marshal a <c>System.String</c> to unmanaged memory.
|
||||||
/// The resulting string is encoded in UTF-8 and must be freed
|
/// The resulting string is encoded in ASCII and must be freed
|
||||||
/// with <c>FreeStringPtr</c>.
|
/// with <c>FreeStringPtr</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str">The <c>System.String</c> to marshal.</param>
|
/// <param name="str">The <c>System.String</c> to marshal.</param>
|
||||||
|
@ -162,23 +162,23 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a buffer big enough to hold the marshalled string.
|
// Allocate a buffer big enough to hold the marshalled string.
|
||||||
// We use GetMaxByteCount() as it is faster than GetByteCount().
|
// GetMaxByteCount() appears to allocate space for the final NUL
|
||||||
// The downside is that it may allocate up to 3x more memory than
|
// character, but allocate an extra one just in case (who knows
|
||||||
// strictly necessary.
|
// what old Mono version would do here.)
|
||||||
int max_count = Encoding.UTF8.GetMaxByteCount(str.Length) + 1;
|
int max_count = Encoding.ASCII.GetMaxByteCount(str.Length) + 1;
|
||||||
IntPtr ptr = Marshal.AllocHGlobal(max_count);
|
IntPtr ptr = Marshal.AllocHGlobal(max_count);
|
||||||
if (ptr == IntPtr.Zero)
|
if (ptr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
throw new OutOfMemoryException();
|
throw new OutOfMemoryException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pin the managed string and convert it to UTF-8 using
|
// Pin the managed string and convert it to ASCII using
|
||||||
// the pointer overload of System.Encoding.UTF8.GetBytes().
|
// the pointer overload of System.Encoding.ASCII.GetBytes().
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (char* pstr = str)
|
fixed (char* pstr = str)
|
||||||
{
|
{
|
||||||
int actual_count = Encoding.UTF8.GetBytes(pstr, str.Length, (byte*)ptr, max_count);
|
int actual_count = Encoding.ASCII.GetBytes(pstr, str.Length, (byte*)ptr, max_count);
|
||||||
Marshal.WriteByte(ptr, actual_count, 0); // Append '\0' at the end of the string
|
Marshal.WriteByte(ptr, actual_count, 0); // Append '\0' at the end of the string
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue