Commit bb441b3e authored by pcy's avatar pcy
Browse files

make it compile again, also half-assed Bind()/Apply() impl. which probably doesn't work yet

parent 865206e0
...@@ -13,14 +13,14 @@ TARGET := bin/fnaglsl.exe ...@@ -13,14 +13,14 @@ TARGET := bin/fnaglsl.exe
LIBS := lib/FNA.dll lib/FNA.dll.config lib/libmojoshader.so LIBS := lib/FNA.dll lib/FNA.dll.config lib/libmojoshader.so
$(TARGET): bin/ $(SOURCES) $(LIBS) $(TARGET): bin/ $(SOURCES) #$(LIBS)
$(CSC) $(CSFLAGS) -target:exe -out:"$@" $(SOURCES) $(CSC) $(CSFLAGS) -target:exe -out:"$@" $(SOURCES)
all: $(TARGET) all: $(TARGET)
$(LIBS): lib/ $(LIBS): lib/
@>&2 echo "You need to put FNA.dll{,.config} and libmojoshader.so in the" \ @>&2 echo "You need to put FNA.dll{,.config} and libmojoshader.so in the" \
"'lib/' directory."; false "\`lib/' directory."; false
debug: CSFLAGS += -debug+ debug: CSFLAGS += -debug+
debug: all debug: all
......
...@@ -15,13 +15,33 @@ using Microsoft.Xna.Framework.Graphics; ...@@ -15,13 +15,33 @@ using Microsoft.Xna.Framework.Graphics;
* -> glEffect{Begin,End}Pass: bind shader! | state mgmt * -> glEffect{Begin,End}Pass: bind shader! | state mgmt
* * GD draw calls: ok * * GD draw calls: ok
* * EXCEPT mojoshader: glProgramReady, glProgramViewportInfo * * EXCEPT mojoshader: glProgramReady, glProgramViewportInfo
* -> set up uniforms! * -> set up uniforms and vertex arrays!
* --> circumvent? --> HOW??
* --> just go with it?? --> glProgramReady ok, glProgramViewportInfo might segfault!
* * uniforms * * uniforms
* * samplers, textures * * samplers, textures
*/ */
namespace PoroCYon.FNAGLSL { namespace PoroCYon.FNAGLSL {
public class GLSLEffect : Effect { public class GLSLEffect : Effect {
public struct ActiveEffect : IDisposable {
internal uint oldprgm;
bool disposed;
internal ActiveEffect(uint old) {
oldprgm = old; disposed = false;
}
public void Dispose() {
if (disposed) return;
GL.UseProgram(oldprgm);
oldprgm = 0;
disposed = true;
}
}
uint[] glshdrs; uint[] glshdrs;
uint glprgm; uint glprgm;
...@@ -30,8 +50,18 @@ namespace PoroCYon.FNAGLSL { ...@@ -30,8 +50,18 @@ namespace PoroCYon.FNAGLSL {
: base(/*UGLY hack*/new BasicEffect(gd)) { : base(/*UGLY hack*/new BasicEffect(gd)) {
GL.Init(gd); GL.Init(gd);
// TODO: gd.GLDevice.DeleteEffect(base.glEffect), // this basically makes FNA think this effect is a noop, so binding
// set base.glEffect.{GL,}EffectData to IntPtr.Zero // this effect will do the same as binding the 0 program in OpenGL,
// so the BasicEffect used won't do much anymore
/*gd.DeleteEffect(this);
eff.SetGLEffectData(IntPtr.Zero);
eff.SetEffectData (IntPtr.Zero);*/
// turns out we can't do this, or libmojoshader will segfault
// because it lacks some null checking in
// glEffectEnd, glEffectBeginPass, glProgramViewportInfo :/ ...
// so we basically have to make sure the usual route of Apply()ing
// the shader happens (unless we can circumvent this *somehow*),
// and then apply the shader manually.
var shdrs = new uint[shaders.Count]; var shdrs = new uint[shaders.Count];
bool ok = false; bool ok = false;
...@@ -95,13 +125,31 @@ namespace PoroCYon.FNAGLSL { ...@@ -95,13 +125,31 @@ namespace PoroCYon.FNAGLSL {
} }
} }
// TODO: find out a better (i.e. more API-conform) way to do this!
///<summary>
///USAGE: using (var eff &eq; glslEffect.Bind()) { ... gd.DrawPrimitives(...); ... }
///</summary>
public ActiveEffect Bind() {
uint oldprgm = unchecked((uint)GL.GetIntegerv(GL.CURRENT_PROGRAM));
GL.Throw();
GL.UseProgram(glprgm);
GL.Throw();
// TODO: apply uniforms and samplers! (XNA API -> OpenGL state)
return new ActiveEffect(oldprgm);
}
[Obsolete("Please use Bind() instead")]
public ActiveEffect Apply() { return Bind(); }
void DelShdrPrgm() { void DelShdrPrgm() {
for (int i = 0; i < glshdrs.Length; ++i) for (int i = 0; i < glshdrs.Length; ++i)
if (shdrs[i] != 0) if (glshdrs[i] != 0)
GL.DeleteShader(shdrs[i]); GL.DeleteShader(glshdrs[i]);
if (prgm != 0) if (glprgm != 0)
GL.DeleteProgram(prgm); GL.DeleteProgram(glprgm);
} }
protected override void Dispose(bool disposing) { protected override void Dispose(bool disposing) {
......
...@@ -43,11 +43,10 @@ namespace PoroCYon.FNAGLSL { ...@@ -43,11 +43,10 @@ namespace PoroCYon.FNAGLSL {
CheckFNA(); CheckFNA();
if (inited) return; if (inited) return;
var gldev = gd.GetType().GetField("GLDevice", var nam = gd.GLDevice().GetType().Name;
BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance if (!nam.Contains("GLDevice"))
).GetValue(gd); throw new NotSupportedException("need OpenGL, but FNA is using"+
if (gldev.GetType().Name.EndsWith("MetalDevice")) " the " + nam + " backend!");
throw new NotSupportedException("Metal isn't supported, need OpenGL!");
InitProcs(); InitProcs();
......
...@@ -24,7 +24,8 @@ namespace PoroCYon.FNAGLSL { ...@@ -24,7 +24,8 @@ namespace PoroCYon.FNAGLSL {
public const GLenum public const GLenum
COMPILE_STATUS = 0x8B81, COMPILE_STATUS = 0x8B81,
INFO_LOG_LENGTH = 0x8B84, INFO_LOG_LENGTH = 0x8B84,
LINK_STATUS = 0x8B82; LINK_STATUS = 0x8B82,
CURRENT_PROGRAM = 0x8B8D;
static void InitProcs() { static void InitProcs() {
_GetError = GetProcAddress<Func<GLenum>>("GetError"); _GetError = GetProcAddress<Func<GLenum>>("GetError");
...@@ -40,6 +41,8 @@ namespace PoroCYon.FNAGLSL { ...@@ -40,6 +41,8 @@ namespace PoroCYon.FNAGLSL {
_GetProgramInfoLog = GetProcAddress<Action<GLuint, GLsizei, IntPtr, IntPtr>>("GetProgramInfoLog"); _GetProgramInfoLog = GetProcAddress<Action<GLuint, GLsizei, IntPtr, IntPtr>>("GetProgramInfoLog");
_DeleteShader = GetProcAddress<Action<GLuint>>("DeleteShader"); _DeleteShader = GetProcAddress<Action<GLuint>>("DeleteShader");
_DeleteProgram = GetProcAddress<Action<GLuint>>("DeleteProgram"); _DeleteProgram = GetProcAddress<Action<GLuint>>("DeleteProgram");
_UseProgram = GetProcAddress<Action<GLuint>>("UseProgram");
_GetIntegerv = GetProcAddress<Action<GLenum, IntPtr>>("GetIntegerv");
} }
static void DeinitProcs() { static void DeinitProcs() {
_GetError = null; _GetError = null;
...@@ -55,6 +58,8 @@ namespace PoroCYon.FNAGLSL { ...@@ -55,6 +58,8 @@ namespace PoroCYon.FNAGLSL {
_GetProgramInfoLog = null; _GetProgramInfoLog = null;
_DeleteShader = null; _DeleteShader = null;
_DeleteProgram = null; _DeleteProgram = null;
_UseProgram = null;
_GetIntegerv = null;
} }
static Func<GLenum> _GetError; static Func<GLenum> _GetError;
...@@ -118,6 +123,17 @@ namespace PoroCYon.FNAGLSL { ...@@ -118,6 +123,17 @@ namespace PoroCYon.FNAGLSL {
static Action<GLuint> _DeleteProgram; static Action<GLuint> _DeleteProgram;
public static void DeleteProgram(GLuint prgm) { _DeleteProgram(prgm); } public static void DeleteProgram(GLuint prgm) { _DeleteProgram(prgm); }
static Action<GLuint> _UseProgram;
public static void UseProgram(GLuint prgm) { _UseProgram(prgm); }
static Action<GLenum, IntPtr> _GetIntegerv;
public static GLint GetIntegerv(GLenum name) {
GLint* parm = stackalloc GLint[4];
parm[3] = parm[2] = parm[1] = parm[0] = 0;
_GetIntegerv(name, (IntPtr)parm);
return parm[0];
}
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace PoroCYon.FNAGLSL {
public static class ReflUtil {
readonly static FieldInfo gd_GLDevice_fi = typeof(GraphicsDevice).GetField(
"GLDevice", BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance);
readonly static FieldInfo ef_glEffect_fi = typeof(Effect).GetField(
"glEffect", BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance);
static MethodInfo gldev_DeleteEffect_mi;
static PropertyInfo ef_GLEffectData_pi, ef_EffectData_pi;
public static object GLDevice(this GraphicsDevice gd) =>
gd_GLDevice_fi.GetValue(gd);
public static object glEffect(this Effect eff) =>
ef_glEffect_fi.GetValue(eff);
static object[] arg1 = new object[1];
public static void DeleteEffect(this GraphicsDevice gd, Effect eff) {
var gldev = gd.GLDevice();
if (gldev_DeleteEffect_mi == null) {
// type of the gldev not known at compile-time!
gldev_DeleteEffect_mi = gldev.GetType().GetMethod("DeleteEffect",
BindingFlags.InvokeMethod|BindingFlags.NonPublic|BindingFlags.Instance);
}
arg1[0] = eff.glEffect();
gldev_DeleteEffect_mi.Invoke(gldev, arg1);
}
public static IntPtr GetGLEffectData(this Effect eff) {
var gleff = eff.glEffect();
if (ef_GLEffectData_pi == null) {
// type of the gleff not known at compile-time!
ef_GLEffectData_pi = gleff.GetType().GetProperty("GLEffectData",
BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance);
}
return (IntPtr)ef_GLEffectData_pi.GetValue(gleff);
}
public static void SetGLEffectData(this Effect eff, IntPtr value) {
var gleff = eff.glEffect();
if (ef_GLEffectData_pi == null) {
// type of the gleff not known at compile-time!
ef_GLEffectData_pi = gleff.GetType().GetProperty("GLEffectData",
BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance);
}
ef_GLEffectData_pi.SetValue(gleff, value);
}
public static IntPtr GetEffectData(this Effect eff) {
var gleff = eff.glEffect();
if (ef_EffectData_pi == null) {
// type of the gleff not known at compile-time!
ef_EffectData_pi = gleff.GetType().GetProperty("EffectData",
BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance);
}
return (IntPtr)ef_EffectData_pi.GetValue(gleff);
}
public static void SetEffectData(this Effect eff, IntPtr value) {
var gleff = eff.glEffect();
if (ef_EffectData_pi == null) {
// type of the gleff not known at compile-time!
ef_EffectData_pi = gleff.GetType().GetProperty("EffectData",
BindingFlags.SetProperty|BindingFlags.NonPublic|BindingFlags.Instance);
}
ef_EffectData_pi.SetValue(gleff, value);
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment