Commit 2b5850e5 authored by pcy's avatar pcy
Browse files

textures work

parent f6156952
......@@ -23,6 +23,10 @@ using Microsoft.Xna.Framework.Graphics;
* * samplers, textures
* -> https://www.khronos.org/opengl/wiki/Program_Introspection
* -> https://stackoverflow.com/questions/440144/in-opengl-is-there-a-way-to-get-a-list-of-all-uniforms-attribs-used-by-a-shade#442819
* -> https://www.khronos.org/opengl/wiki/Basic_Type_(GLSL)
*
* -> https://www.khronos.org/opengl/wiki/Sampler_(GLSL)
* -> https://www.khronos.org/opengl/wiki/Texture
* * vertex format verification!
*/
......@@ -43,33 +47,58 @@ namespace PoroCYon.FNAGLSL {
cols = c; epclass = epc; eptype = ept; bytesize = bsz;
}
}
struct TexT {
public uint slot, getn, setn, texid;
public TexT(uint sl, uint g, uint s, uint t) {
slot = sl; getn = g; setn = s; texid = t;
}
};
public partial class GLSLEffect : Effect {
public struct ActiveEffect : IDisposable {
internal uint oldprgm;
internal List<uint> texs;
internal List<TexT> texs;
bool disposed;
internal ActiveEffect(uint old, List<uint> ts) {
internal ActiveEffect(uint old, List<TexT> ts) {
oldprgm = old; disposed = false; texs = ts;
}
public void Dispose() {
if (disposed) return;
GL.GetError();
GL.UseProgram(oldprgm);
GL.Throw();
oldprgm = 0;
// TODO: release textures
/*for (int i = 0; i < texs.Length; ++i) {
}*/
texs.Clear();
uint actSlot = unchecked((uint)GL.GetIntegerv(GL.ACTIVE_TEXTURE));
GL.Throw();
try {
for (int i = 0; i < texs.Count; ++i) {
GL.ActiveTexture(GL.TEXTURE0 + texs[i].slot);
GL.Throw();
GL.BindTexture(texs[i].setn, 0);
GL.Throw();
/*Console.WriteLine("clear slot " + texs[i].slot + " texid " + texs[i].texid
+ " getn 0x" + texs[i].getn.ToString("X") + " setn 0x" + texs[i].setn.ToString("X"));*/
}
} finally {
GL.ActiveTexture(actSlot);
//GL.Throw();
texs.Clear();
}
disposed = true;
}
}
static int maxTextureSlots = -1;
uint[] glshdrs;
uint glprgm;
......@@ -91,6 +120,11 @@ namespace PoroCYon.FNAGLSL {
GL.Init(gd);
GL.GetError(); // ignore errors from FNA/mojoshader
if (maxTextureSlots < 0) {
maxTextureSlots = GL.GetIntegerv(GL.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
GL.Throw();
}
// 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
......@@ -228,31 +262,30 @@ namespace PoroCYon.FNAGLSL {
}
}
List<uint> usedTextures = new List<uint>();
List<TexT> usedTextures = new List<TexT>();
void ApplyUnifs() {
usedTextures.Clear();
// TODO: get active texture to restore later -> glGetIntegerv(GL_ACTIVE_TEXTURE)
// TODO: make list to hold used texture slots
IntPtr data = unifDataBacking;
for (int i = 0; i < unifs.Length; ++i) {
var u = unifs[i];
var p = Parameters[i];
// TODO:
/*if (it's a texture) {
find empty texture slot, put texture in it
-> GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
-> GL_TEXTURE_BINDING_[123]D / _BINDING_CUBE_MAP
bind uniform to texture slot
add texture slot to the used slot list
}
else*/ SetUniform(ref u, data);
uint actSlot = unchecked((uint)GL.GetIntegerv(GL.ACTIVE_TEXTURE));
GL.Throw();
try {
IntPtr data = unifDataBacking;
uint firstEmptySlot = 0;
for (int i = 0; i < unifs.Length; ++i) {
var u = unifs[i];
var p = Parameters[i];
data = (IntPtr)((long)data + u.bytesize);
}
if (Array.IndexOf(GL.samplerTypes, (uint)u.type) >= 0) // it's a texture
SetTexture(ref firstEmptySlot, ref u, p);
else SetUniform(ref u, data);
// TODO: restore active texture
data = (IntPtr)((long)data + u.bytesize);
}
} finally {
GL.ActiveTexture(actSlot);
}
}
// TODO: find out a better (i.e. more API-conform) way to do this!
......@@ -306,6 +339,50 @@ namespace PoroCYon.FNAGLSL {
base.Dispose(disposing);
}
unsafe void SetTexture(ref uint firstEmpty, ref UnifData u, EffectParameter p) {
uint getn = typ2getn[u.type]/*,
setn = typ2setn[u.type]*/;
// find a free texture slot
bool foundSlot = false;
for (uint j = firstEmpty; j < maxTextureSlots; ++j) {
GL.ActiveTexture(GL.TEXTURE0 + j);
GL.Throw();
uint curbound = unchecked((uint)GL.GetIntegerv(getn));
GL.Throw();
if (curbound == 0) { // free!
var tar = p.GetValueTexture();
if (tar == null)
throw new InvalidOperationException("texture of param '"
+ u.name + "'is null?!");
uint setn = unchecked((uint)tar.GetGLTexTarget());
uint texn = tar.GetGLTexID();
/*Console.WriteLine("set slot " + j + " texid " + texn
+ " getn 0x" + getn.ToString("X") + " setn 0x" + setn.ToString("X")
+ " -> to unif. " + u.name);*/
// bind the uniform to the texture slot
GL.Uniform1i(u.location, unchecked((int)j));
GL.Throw();
// bind the texture to the texture slot!
GL.BindTexture(setn, texn);
GL.Throw();
usedTextures.Add(new TexT(j, getn, setn, texn));
firstEmpty = j+1;
foundSlot = true;
break;
}
}
if (!foundSlot)
throw new InvalidOperationException("param '" + u.name
+ "': can't find a free texture slot...");
}
}
}
......@@ -17,6 +17,7 @@ namespace PoroCYon.FNAGLSL {
readonly static Dictionary<GLSLType, int > typ2size ;
readonly static Dictionary<GLSLType, EffectParameterClass> typ2class;
readonly static Dictionary<GLSLType, EffectParameterType > typ2type ;
readonly static Dictionary<GLSLType, uint> typ2getn, typ2setn;
static GLSLEffect() {
typ2size = new Dictionary<GLSLType, int>() {
......@@ -139,6 +140,56 @@ namespace PoroCYon.FNAGLSL {
{ UNSIGNED_INT_SAMPLER_3D, T.Texture3D },
{ UNSIGNED_INT_SAMPLER_CUBE, T.TextureCube },
};
typ2getn = new Dictionary<GLSLType, uint>() {
{ SAMPLER_1D, GL.TEXTURE_BINDING_1D },
{ SAMPLER_2D, GL.TEXTURE_BINDING_2D },
{ SAMPLER_3D, GL.TEXTURE_BINDING_3D },
{ SAMPLER_CUBE, GL.TEXTURE_BINDING_CUBE },
{ INT_SAMPLER_1D, GL.TEXTURE_BINDING_1D },
{ INT_SAMPLER_2D, GL.TEXTURE_BINDING_2D },
{ INT_SAMPLER_3D, GL.TEXTURE_BINDING_3D },
{ INT_SAMPLER_CUBE, GL.TEXTURE_BINDING_CUBE },
{ UNSIGNED_INT_SAMPLER_1D, GL.TEXTURE_BINDING_1D },
{ UNSIGNED_INT_SAMPLER_2D, GL.TEXTURE_BINDING_2D },
{ UNSIGNED_INT_SAMPLER_3D, GL.TEXTURE_BINDING_3D },
{ UNSIGNED_INT_SAMPLER_CUBE, GL.TEXTURE_BINDING_CUBE },
/*GL_TEXTURE_BINDING_1D,
GL_TEXTURE_BINDING_1D_ARRAY,
GL_TEXTURE_BINDING_2D,
GL_TEXTURE_BINDING_2D_ARRAY,
GL_TEXTURE_BINDING_2D_MULTISAMPLE,
GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY,
GL_TEXTURE_BINDING_3D,
GL_TEXTURE_BINDING_BUFFER,
GL_TEXTURE_BINDING_CUBE_MAP,
GL_TEXTURE_BINDING_RECTANGLE*/
};
typ2setn = new Dictionary<GLSLType, uint>() {
{ SAMPLER_1D, GL.TEXTURE_1D },
{ SAMPLER_2D, GL.TEXTURE_2D },
{ SAMPLER_3D, GL.TEXTURE_3D },
{ SAMPLER_CUBE, GL.TEXTURE_CUBE_MAP },
{ INT_SAMPLER_1D, GL.TEXTURE_1D },
{ INT_SAMPLER_2D, GL.TEXTURE_2D },
{ INT_SAMPLER_3D, GL.TEXTURE_3D },
{ INT_SAMPLER_CUBE, GL.TEXTURE_CUBE_MAP },
{ UNSIGNED_INT_SAMPLER_1D, GL.TEXTURE_1D },
{ UNSIGNED_INT_SAMPLER_2D, GL.TEXTURE_2D },
{ UNSIGNED_INT_SAMPLER_3D, GL.TEXTURE_3D },
{ UNSIGNED_INT_SAMPLER_CUBE, GL.TEXTURE_CUBE_MAP },
/* GL_TEXTURE_1D,
* GL_TEXTURE_2D,
* GL_TEXTURE_3D,
* GL_TEXTURE_1D_ARRAY,
* GL_TEXTURE_2D_ARRAY,
* GL_TEXTURE_RECTANGLE,
* GL_TEXTURE_CUBE_MAP,
* GL_TEXTURE_CUBE_MAP_ARRAY,
* GL_TEXTURE_BUFFER,
* GL_TEXTURE_2D_MULTISAMPLE
* GL_TEXTURE_2D_MULTISAMPLE_ARRAY.*/
};
}
static int GetRows(GLSLType t) {
......@@ -351,6 +402,7 @@ namespace PoroCYon.FNAGLSL {
default:
throw new NotSupportedException(u.type+"");
}
GL.Throw();
}
}
}
......
......@@ -14,6 +14,21 @@ namespace PoroCYon.FNAGLSL {
ACTIVE_UNIFORMS = 0x8B86,
INVALID_INDEX = 0xFFFFFFFFu,
MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D,
ACTIVE_TEXTURE = 0x84E0,
TEXTURE0 = 0x84C0,
TEXTURE_1D = 0x0DE0,
TEXTURE_2D = 0x0DE1,
TEXTURE_3D = 0x806F,
TEXTURE_CUBE_MAP = 0x8513,
TEXTURE_BINDING_1D = 0x8068,
TEXTURE_BINDING_2D = 0x8069,
TEXTURE_BINDING_3D = 0x806A,
TEXTURE_BINDING_CUBE = 0X8514,
UNIFORM_TYPE = 0x8A37,
UNIFORM_SIZE = 0x8A38,
UNIFORM_NAME_LENGTH = 0x8A39,
......@@ -36,6 +51,45 @@ namespace PoroCYon.FNAGLSL {
UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x84F1;
public const byte FALSE = 0, TRUE = 1;
public readonly static uint/*GLSLType*/[] samplerTypes = {
(uint)GLSLType.SAMPLER_1D,
(uint)GLSLType.SAMPLER_2D,
(uint)GLSLType.SAMPLER_3D,
(uint)GLSLType.SAMPLER_CUBE,
/*SAMPLER_1D_SHADOW,
SAMPLER_2D_SHADOW,
SAMPLER_1D_ARRAY,
SAMPLER_2D_ARRAY,
SAMPLER_1D_ARRAY_SHADOW,
SAMPLER_2D_ARRAY_SHADOW,
SAMPLER_CUBE_SHADOW,
SAMPLER_2D_MULTISAMPLE,
SAMPLER_2D_MULTISAMPLE_ARRAY,
SAMPLER_2D_RECT,
SAMPLER_2D_RECT_SHADOW,
SAMPLER_BUFFER,*/
(uint)GLSLType.INT_SAMPLER_1D,
(uint)GLSLType.INT_SAMPLER_2D,
(uint)GLSLType.INT_SAMPLER_3D,
(uint)GLSLType.INT_SAMPLER_CUBE,
/*INT_SAMPLER_1D_ARRAY,
INT_SAMPLER_2D_ARRAY,
INT_SAMPLER_2D_MULTISAMPLE ,
INT_SAMPLER_2D_MULTISAMPLE_ARRAY,
INT_SAMPLER_BUFFER ,
INT_SAMPLER_2D_RECT,*/
(uint)GLSLType.UNSIGNED_INT_SAMPLER_1D,
(uint)GLSLType.UNSIGNED_INT_SAMPLER_2D,
(uint)GLSLType.UNSIGNED_INT_SAMPLER_3D,
(uint)GLSLType.UNSIGNED_INT_SAMPLER_CUBE
/*,UNSIGNED_INT_SAMPLER_1D_ARRAY,
UNSIGNED_INT_SAMPLER_2D_ARRAY,
UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE ,
UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,
UNSIGNED_INT_SAMPLER_BUFFER ,
UNSIGNED_INT_SAMPLER_2D_RECT*/
};
}
}
......@@ -47,6 +47,9 @@ namespace PoroCYon.FNAGLSL {
_GetActiveUniformsiv = GetProcAddress<GetActiveUniformsiv_T>("GetActiveUniformsiv");
_GetActiveUniform = GetProcAddress<GetActiveUniform_T>("GetActiveUniform");
_ActiveTexture = GetProcAddress<ActiveTexture_T>("ActiveTexture");
_BindTexture = GetProcAddress<BindTexture_T>("BindTexture");
_Uniform1fv = GetProcAddress<Uniform1fv_T>("Uniform1fv");
_Uniform2fv = GetProcAddress<Uniform2fv_T>("Uniform2fv");
_Uniform3fv = GetProcAddress<Uniform3fv_T>("Uniform3fv");
......@@ -585,6 +588,16 @@ namespace PoroCYon.FNAGLSL {
public static void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) {
_Uniform4ui(location, v0, v1, v2, v3);
}
delegate void ActiveTexture_T(GLenum tex);
static ActiveTexture_T _ActiveTexture;
public static void ActiveTexture(GLenum tex) { _ActiveTexture(tex); }
delegate void BindTexture_T(GLenum tar, GLuint tex);
static BindTexture_T _BindTexture;
public static void BindTexture(GLenum tar, GLuint tex) {
_BindTexture(tar, tex);
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
......@@ -35,6 +36,7 @@ class TestGame : Game {
KeyboardState ks;
BasicEffect hlsl;
GLSLEffect glsl;
Texture2D thetex;
public TestGame() : base() {
gdm = new GraphicsDeviceManager(this);
......@@ -66,6 +68,11 @@ class TestGame : Game {
protected override void LoadContent() {
sb = new SpriteBatch(GraphicsDevice);
using (var fs = File.OpenRead("checker.png")) {
thetex = Texture2D.FromStream(GraphicsDevice, fs);
}
hlsl = new BasicEffect(GraphicsDevice);
hlsl.LightingEnabled = false;
......@@ -102,6 +109,7 @@ class TestGame : Game {
"\n"+
"uniform float fGlobalTime;\n"+
"uniform vec2 v2Resolution;\n"+
"uniform sampler2D mytex;\n"+
"\n"+
"layout(location = 0) out vec4 C;\n"+
"\n"+
......@@ -118,6 +126,7 @@ class TestGame : Game {
" vec2 uv = vec2(gl_FragCoord.x/v2Resolution.x, gl_FragCoord.y/v2Resolution.y);\n"+
" uv -= 0.5;\n"+
" uv /= vec2(v2Resolution.y/v2Resolution.x, 1.);\n"+
" vec2 ouv = uv;\n"+
"\n"+
" vec2 m;\n"+
" m.x = atan(uv.x / uv.y) / pi;\n"+
......@@ -127,7 +136,7 @@ class TestGame : Game {
" m.y += fGlobalTime * 0.25;\n"+
"\n"+
" vec4 t = plas(fGlobalTime, m * pi) / d;\n"+
" C = clamp(t, 0.0, 1.0);\n"+
" C = clamp(t, 0.0, 1.0)*texture2D(mytex, ouv);\n"+
" /*gl_FragColor = vec4(0);*/\n"+
"}\n"}
});
......@@ -137,6 +146,23 @@ class TestGame : Game {
protected override void UnloadContent() {
base.UnloadContent();
if (thetex != null) {
thetex.Dispose();
thetex = null;
}
if (hlsl != null) {
hlsl.Dispose();
hlsl = null;
}
if (glsl != null) {
glsl.Dispose();
glsl = null;
}
if (sb != null) {
sb.Dispose();
sb = null;
}
}
TimeSpan totalTime = TimeSpan.Zero;
......@@ -178,6 +204,7 @@ class TestGame : Game {
var vp = GraphicsDevice.Viewport;
glsl.Parameters["fGlobalTime" ].SetValue((float)totalTime.TotalSeconds);
glsl.Parameters["v2Resolution"].SetValue(new Vector2(vp.Width, vp.Height));
glsl.Parameters["mytex" ].SetValue(thetex);
using (var act = glsl.Bind()) {
GraphicsDevice.DrawUserPrimitives<VertexType>(
......
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