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
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)
all: $(TARGET)
$(LIBS): lib/
@>&2 echo "You need to put FNA.dll{,.config} and libmojoshader.so in the" \
"'lib/' directory."; false
"\`lib/' directory."; false
debug: CSFLAGS += -debug+
debug: all
......
......@@ -15,13 +15,33 @@ using Microsoft.Xna.Framework.Graphics;
* -> glEffect{Begin,End}Pass: bind shader! | state mgmt
* * GD draw calls: ok
* * 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
* * samplers, textures
*/
namespace PoroCYon.FNAGLSL {
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 glprgm;
......@@ -30,8 +50,18 @@ namespace PoroCYon.FNAGLSL {
: base(/*UGLY hack*/new BasicEffect(gd)) {
GL.Init(gd);
// TODO: gd.GLDevice.DeleteEffect(base.glEffect),
// set base.glEffect.{GL,}EffectData to IntPtr.Zero
// this basically makes FNA think this effect is a noop, so binding
// 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];
bool ok = false;
......@@ -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() {
for (int i = 0; i < glshdrs.Length; ++i)
if (shdrs[i] != 0)
GL.DeleteShader(shdrs[i]);
if (glshdrs[i] != 0)
GL.DeleteShader(glshdrs[i]);
if (prgm != 0)
GL.DeleteProgram(prgm);
if (glprgm != 0)
GL.DeleteProgram(glprgm);
}
protected override void Dispose(bool disposing) {
......
......@@ -43,11 +43,10 @@ namespace PoroCYon.FNAGLSL {
CheckFNA();
if (inited) return;
var gldev = gd.GetType().GetField("GLDevice",
BindingFlags.GetField|BindingFlags.NonPublic|BindingFlags.Instance
).GetValue(gd);
if (gldev.GetType().Name.EndsWith("MetalDevice"))
throw new NotSupportedException("Metal isn't supported, need OpenGL!");
var nam = gd.GLDevice().GetType().Name;
if (!nam.Contains("GLDevice"))
throw new NotSupportedException("need OpenGL, but FNA is using"+
" the " + nam + " backend!");
InitProcs();
......
......@@ -24,7 +24,8 @@ namespace PoroCYon.FNAGLSL {
public const GLenum
COMPILE_STATUS = 0x8B81,
INFO_LOG_LENGTH = 0x8B84,
LINK_STATUS = 0x8B82;
LINK_STATUS = 0x8B82,
CURRENT_PROGRAM = 0x8B8D;
static void InitProcs() {
_GetError = GetProcAddress<Func<GLenum>>("GetError");
......@@ -40,6 +41,8 @@ namespace PoroCYon.FNAGLSL {
_GetProgramInfoLog = GetProcAddress<Action<GLuint, GLsizei, IntPtr, IntPtr>>("GetProgramInfoLog");
_DeleteShader = GetProcAddress<Action<GLuint>>("DeleteShader");
_DeleteProgram = GetProcAddress<Action<GLuint>>("DeleteProgram");
_UseProgram = GetProcAddress<Action<GLuint>>("UseProgram");
_GetIntegerv = GetProcAddress<Action<GLenum, IntPtr>>("GetIntegerv");
}
static void DeinitProcs() {
_GetError = null;
......@@ -55,6 +58,8 @@ namespace PoroCYon.FNAGLSL {
_GetProgramInfoLog = null;
_DeleteShader = null;
_DeleteProgram = null;
_UseProgram = null;
_GetIntegerv = null;
}
static Func<GLenum> _GetError;
......@@ -118,6 +123,17 @@ namespace PoroCYon.FNAGLSL {
static Action<GLuint> _DeleteProgram;
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