- use TextureItem.bind()/.upload()

- keep track of which texture is bound in GLState
- add workaround for issue with line-distance-texture on desktop
This commit is contained in:
Hannes Janetzek 2013-08-04 14:27:38 +02:00
parent 29b70ecf5b
commit b433ca6dff
14 changed files with 153 additions and 101 deletions

View File

@ -16,9 +16,12 @@ package org.oscim.backend;
public class GLAdapter {
public static GL20 g;
public static boolean GDX_DESKTOP_QUIRKS;
public static boolean GDX_WEBGL_QUIRKS;
public static boolean NON_PREMUL_CANVAS;
public static GL20 get(){

View File

@ -66,15 +66,11 @@ public class TileRenderer {
mProjMatrix.setValue(14, 0);
mProjMatrix.multiplyRhs(m.view);
//GL.glDepthMask(true);
GL.glDepthMask(true);
GL.glClear(GL20.GL_DEPTH_BUFFER_BIT);
GL.glDepthFunc(GL20.GL_LESS);
// load texture for line caps
LineRenderer.beginLines();
// Draw visible tiles
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
@ -105,8 +101,7 @@ public class TileRenderer {
// make sure stencil buffer write is disabled
GL.glStencilMask(0x00);
LineRenderer.endLines();
GL.glDepthMask(false);
mDrawSerial++;
@ -189,6 +184,17 @@ public class TileRenderer {
}
for (Layer l = t.layers.textureLayers; l != null;) {
if (!clipped) {
// draw stencil buffer clip region
PolygonRenderer.draw(pos, null, m, true, div, true);
clipped = true;
}
// if (!clipped) {
// // draw stencil buffer clip region
// PolygonRenderer.clip(m);
// clipped = true;
// }
//GLState.test(false, false);
switch (l.type) {
case Layer.BITMAP:
l = BitmapRenderer.draw(l, 1, m);

View File

@ -275,6 +275,9 @@ public class GLRenderer {
| GL20.GL_DEPTH_BUFFER_BIT
| GL20.GL_STENCIL_BUFFER_BIT);
GLState.blend(false);
GL.glDisable(GL20.GL_BLEND);
boolean changed = false;
MapPosition pos = mMapPosition;
@ -297,6 +300,10 @@ public class GLRenderer {
}
}
//Log.d(TAG, "begin frame");
GLState.bindTex2D(0);
//GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
/* update layers */
RenderLayer[] layers = mMapView.getLayerManager().getRenderLayers();

View File

@ -29,6 +29,8 @@ public class GLState {
private static boolean stencil = false;
private static int shader;
private static int currentTexId;
public static void init() {
vertexArray[0] = false;
vertexArray[1] = false;
@ -36,8 +38,14 @@ public class GLState {
depth = false;
stencil = false;
shader = -1;
GL.glDisable(GL20.GL_STENCIL_TEST);
GL.glDisable(GL20.GL_DEPTH_TEST);
// if (currentTexId != 0) {
// GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
// currentTexId = 0;
// }
}
public static boolean useProgram(int shaderProgram) {
@ -110,4 +118,17 @@ public class GLState {
}
}
}
public static void bindTex2D(int id) {
// if (GLAdapter.GDX_DESKTOP_QUIRKS){
// GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
//if (GLAdapter.GDX_DESKTOP_QUIRKS && id != 0)
// GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
// } else
if (currentTexId != id) {
GL.glBindTexture(GL20.GL_TEXTURE_2D, id);
currentTexId = id;
}
}
}

View File

@ -92,11 +92,9 @@ public class TextureAtlas extends Inlist<TextureAtlas> {
/**
* only call in GL-Thread
*/
public TextureItem compileTexture() {
public TextureItem loadTexture() {
if (texture != null) {
if (texture.id < 1) {
TextureItem.uploadTexture(texture);
}
texture.upload();
return texture;
}

View File

@ -115,9 +115,7 @@ public class BitmapLayer extends TextureLayer {
setVertices(sbuf);
//for (TextureItem to = textures; to != null; to = to.next)
TextureItem.uploadTexture(textures);
textures.upload();
if (!mReuseBitmap) {
mBitmap.recycle();

View File

@ -56,7 +56,7 @@ public final class BitmapRenderer {
}
public static Layer draw(Layer layer, float scale, Matrices m) {
GLState.test(false, false);
//GLState.test(false, false);
GLState.blend(true);
GLState.useProgram(mTextureProgram);
@ -79,9 +79,9 @@ public final class BitmapRenderer {
GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, GLRenderer.mQuadIndicesID);
for (TextureItem ti = tl.textures; ti != null; ti = ti.next) {
//Log.d(TAG, "render texture " + ti.id);
GL.glBindTexture(GL20.GL_TEXTURE_2D, ti.id);
ti.bind();
int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE;
// draw up to maxVertices in each iteration

View File

@ -43,7 +43,7 @@ public final class LineRenderer {
private static int[] hLineScale = new int[2];
private static int[] hLineWidth = new int[2];
private static int[] hLineMode = new int[2];
private static int mTexID;
public static int mTexID;
static boolean init() {
GL = GLAdapter.get();
@ -93,33 +93,31 @@ public final class LineRenderer {
GL20.GL_NEAREST, GL20.GL_NEAREST,
GL20.GL_MIRRORED_REPEAT, GL20.GL_MIRRORED_REPEAT);
Log.d(TAG, "TEX ID: " + mTexID);
return true;
}
public static void beginLines() {
GL.glBindTexture(GL20.GL_TEXTURE_2D, mTexID);
}
public static void endLines() {
GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
}
public static Layer draw(Layers layers, Layer curLayer, MapPosition pos,
Matrices m, float div, int mode) {
beginLines();
if (curLayer == null)
return null;
GLState.blend(true);
// FIXME HACK: fallback to simple shader
if (lineProgram[mode] == 0)
mode = 1;
GLState.useProgram(lineProgram[mode]);
GLState.blend(true);
// Somehow we loose the texture after an indefinite
// time, when label/symbol textures are used.
// Debugging gl on Desktop is most fun imaginable,
// so for now:
if (!GLAdapter.GDX_DESKTOP_QUIRKS)
GLState.bindTex2D(mTexID);
int uLineScale = hLineScale[mode];
int uLineMode = hLineMode[mode];
int uLineColor = hLineColor[mode];
@ -291,17 +289,19 @@ public final class LineRenderer {
//+ " len = texture2D(tex, v_st).a;"
//+ " len = u_mode * length(v_st);"
// this avoids branching, need to check performance
+ " float len = max((1.0 - u_mode) * abs(v_st.s), u_mode * texture2D(tex, v_st).a);"
//+ " float len = max((1.0 - u_mode) * abs(v_st.s), u_mode * length(v_st));"
+ (GLAdapter.GDX_DESKTOP_QUIRKS
? " float len = max((1.0 - u_mode) * abs(v_st.s), u_mode * length(v_st));"
: " float len = max((1.0 - u_mode) * abs(v_st.s), u_mode * texture2D(tex, v_st).a);")
// interpolate alpha between: 0.0 < 1.0 - len < u_wscale
// where wscale is 'filter width' / 'line width' and 0 <= len <= sqrt(2)
//+ " gl_FragColor = u_color * smoothstep(0.0, u_wscale, 1.0 - len);"
//+ " gl_FragColor = mix(vec4(1.0,0.0,0.0,1.0), u_color, smoothstep(0.0, u_wscale, 1.0 - len));"
+ " float alpha = min(1.0, (1.0 - len) / u_wscale);"
+ " if (alpha > 0.2)"
+ " if (alpha > 0.1)"
+ " gl_FragColor = u_color * alpha;"
+ " else"
+ " discard;"
// + "gl_FragColor = vec4(texture2D(tex, v_st).a);"
+ "}";
private final static String lineFragmentShader = ""
@ -319,8 +319,9 @@ public final class LineRenderer {
+ " len = abs(v_st.s);"
+ " fuzz = fwidth(v_st.s);"
+ " } else {"
+ " len = texture2D(tex, v_st).a;"
//+ " len = length(v_st);"
+ (GLAdapter.GDX_DESKTOP_QUIRKS
? " len = length(v_st);"
: " len = texture2D(tex, v_st).a;")
+ " vec2 st_width = fwidth(v_st);"
+ " fuzz = max(st_width.s, st_width.t);"
+ " }"

View File

@ -57,10 +57,7 @@ public final class PolygonRenderer {
private static int[] hPolygonColor = new int[numShaders];
private static int[] hPolygonScale = new int[numShaders];
//private static boolean enableTexture = true;
//private static int mTexWater;
//private static int mTexWood;
//private static int mTexGrass;
private static boolean enableTexture = false;
static boolean init() {
GL = GLAdapter.get();
@ -110,7 +107,7 @@ public final class PolygonRenderer {
for (int c = start; c < end; c++) {
Area a = mFillPolys[c].area;
if (a.texture != null){
if (enableTexture && a.texture != null){
shader = texShader;
setShader(texShader, m);
GL.glUniform2f(hPolygonScale[1], FastMath.clamp(scale - 1, 0, 1), div);
@ -158,6 +155,7 @@ public final class PolygonRenderer {
GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP, 0, 4);
if (shader != polyShader) {
// disable texture shader
setShader(polyShader, m);
shader = polyShader;
}
@ -168,9 +166,7 @@ public final class PolygonRenderer {
private static int mCount;
private static void setShader(int shader, Matrices m) {
//if (
GLState.useProgram(polygonProgram[shader]);
// ) {
GLState.enableVertexArrays(hPolygonVertexPosition[shader], -1);
@ -178,7 +174,6 @@ public final class PolygonRenderer {
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
m.mvp.setAsUniform(hPolygonMatrix[shader]);
//}
}
/**
@ -270,6 +265,15 @@ public final class PolygonRenderer {
return l;
}
public static void clip(Matrices m){
setShader(polyShader, m);
drawStencilRegion(true);
// disable writes to stencil buffer
GL.glStencilMask(0x00);
// enable writes to color buffer
GL.glColorMask(true, true, true, true);
}
/**
* Draw a tile filling rectangle to set stencil- and depth buffer
* appropriately

View File

@ -83,7 +83,7 @@ public final class SymbolLayer extends TextureLayer {
// FIXME this work only with one TextureAtlas per
// SymbolLayer.
if (textures == null) {
to = it.symbol.atlas.compileTexture();
to = it.symbol.atlas.loadTexture();
// clone TextureItem to use same texID with
// multiple TextureItem
to = TextureItem.clone(to);
@ -107,7 +107,7 @@ public final class SymbolLayer extends TextureLayer {
// to.height = it.bitmap.getHeight();
textures = Inlist.append(textures, to);
TextureItem.uploadTexture(to);
to.upload();
}
to.offset = numIndices;
to.vertices = 0;

View File

@ -22,6 +22,7 @@ import org.oscim.backend.GLAdapter;
import org.oscim.backend.Log;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.backend.canvas.Color;
import org.oscim.renderer.GLState;
import org.oscim.utils.GlUtils;
import org.oscim.utils.pool.Inlist;
import org.oscim.utils.pool.SyncPool;
@ -67,6 +68,8 @@ public class TextureItem extends Inlist<TextureItem> {
clone.width = ti.width;
clone.height = ti.height;
clone.isClone = true;
// original texture needs to be loaded
clone.isReady = true;
return clone;
}
@ -87,12 +90,20 @@ public class TextureItem extends Inlist<TextureItem> {
this.repeat = repeat;
}
public void bind() {
public void upload() {
if (!isReady) {
TextureItem.uploadTexture(this);
isReady = true;
}
GL.glBindTexture(GL20.GL_TEXTURE_2D, id);
}
public void bind() {
if (!isReady) {
TextureItem.uploadTexture(this);
isReady = true;
} else {
GLState.bindTex2D(id);
}
}
public synchronized static void releaseAll(TextureItem ti) {
@ -114,16 +125,16 @@ public class TextureItem extends Inlist<TextureItem> {
static class TextureItemPool extends SyncPool<TextureItem> {
public TextureItemPool() {
super(0);
super(10);
}
@Override
public void init(int num) {
if (pool != null){
if (pool != null) {
Log.d(TAG, "still textures in pool! " + fill);
pool = null;
}
int[] textureIds = GlUtils.glGenTextures(num);
for (int i = 0; i < num; i++) {
@ -147,35 +158,37 @@ public class TextureItem extends Inlist<TextureItem> {
/** called when item is added back to pool */
@Override
protected boolean clearItem(TextureItem it) {
protected boolean clearItem(TextureItem t) {
if (it.ownBitmap) {
it.bitmap = null;
it.ownBitmap = false;
releaseTexture(it);
if (t.ownBitmap) {
t.bitmap = null;
t.ownBitmap = false;
releaseTexture(t);
return false;
}
if (it.isClone) {
it.isClone = false;
it.id = -1;
it.width = -1;
it.height = -1;
if (t.isClone) {
t.isClone = false;
t.id = -1;
t.width = -1;
t.height = -1;
return false;
}
releaseBitmap(it);
t.isReady = false;
releaseBitmap(t);
return true;
}
@Override
protected void freeItem(TextureItem it) {
it.width = -1;
it.height = -1;
protected void freeItem(TextureItem t) {
t.width = -1;
t.height = -1;
if (!it.isClone)
releaseTexture(it);
if (!t.isClone)
releaseTexture(t);
}
};
@ -204,19 +217,23 @@ public class TextureItem extends Inlist<TextureItem> {
/**
* This function may only be used in GLRenderer Thread.
*
* @param to
* @param t
* the TextureObjet to compile and upload
*/
public static void uploadTexture(TextureItem to) {
private static void uploadTexture(TextureItem t) {
GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
if (t.bitmap == null) {
throw new RuntimeException("Missing bitmap for texture");
}
// free unused textures -> TODO find a better place for this
synchronized (mTextures) {
int size = mTextures.size();
if (size > 0) {
int[] tmp = new int[size];
for (int i = 0; i < size; i++)
for (int i = 0; i < size; i++){
tmp[i] = mTextures.get(i).intValue();
}
mTextures.clear();
GlUtils.glDeleteTextures(size, tmp);
@ -224,62 +241,64 @@ public class TextureItem extends Inlist<TextureItem> {
}
}
if (to.id < 0) {
if (t.id < 0) {
mTexCnt++;
int[] textureIds = GlUtils.glGenTextures(1);
to.id = textureIds[0];
initTexture(to);
t.id = textureIds[0];
initTexture(t);
if (TextureRenderer.debug)
Log.d(TAG, "poolFill:" + pool.getFill()
+ " texCnt:" + mTexCnt
+ " new texture " + to.id);
Log.d(TAG, "fill:" + pool.getFill()
+ " count:" + mTexCnt
+ " new texture " + t.id);
}
uploadTexture(to, to.bitmap,
//Log.d(TAG, "UPLOAD ID: " + t.id);
uploadTexture(t, t.bitmap,
mBitmapFormat, mBitmapType,
TEXTURE_WIDTH, TEXTURE_HEIGHT);
if (!to.ownBitmap)
TextureItem.releaseBitmap(to);
if (!t.ownBitmap)
TextureItem.releaseBitmap(t);
else {
// FIXME when in doubt
// to.bitmap = null;
}
}
public static void uploadTexture(TextureItem to, Bitmap bitmap,
public static void uploadTexture(TextureItem t, Bitmap bitmap,
int format, int type, int w, int h) {
if (to == null) {
if (t == null) {
Log.d(TAG, "no texture!");
return;
}
GL.glBindTexture(GL20.GL_TEXTURE_2D, to.id);
GLState.bindTex2D(t.id);
if (to.ownBitmap) {
if (t.ownBitmap) {
bitmap.uploadToTexture(false);
} else if (to.width == w && to.height == h) {
} else if (t.width == w && t.height == h) {
bitmap.uploadToTexture(true);
} else {
bitmap.uploadToTexture(false);
to.width = w;
to.height = h;
t.width = w;
t.height = h;
}
if (TextureRenderer.debug)
GlUtils.checkGlError(TAG);
}
static void initTexture(TextureItem it) {
GL.glBindTexture(GL20.GL_TEXTURE_2D, it.id);
private static void initTexture(TextureItem t) {
GLState.bindTex2D(t.id);
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER,
GL20.GL_LINEAR);
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER,
GL20.GL_LINEAR);
if (it.repeat) {
if (t.repeat) {
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S,
GL20.GL_REPEAT);
GL.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T,
@ -342,7 +361,6 @@ public class TextureItem extends Inlist<TextureItem> {
mBitmaps.add(it.bitmap);
it.bitmap = null;
}
it.ownBitmap = false;
}
}
}

View File

@ -31,7 +31,7 @@ public abstract class TextureLayer extends Layer {
protected void compile(ShortBuffer sbuf) {
for (TextureItem to = textures; to != null; to = to.next)
TextureItem.uploadTexture(to);
to.upload();
// add vertices to vbo
Layers.addPoolItems(this, sbuf);

View File

@ -58,8 +58,6 @@ public final class TextureRenderer {
}
public static Layer draw(Layer layer, float scale, Matrices m) {
if (GLAdapter.NON_PREMUL_CANVAS)
GL.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
GLState.test(false, false);
GLState.blend(true);
@ -84,7 +82,7 @@ public final class TextureRenderer {
for (TextureItem ti = tl.textures; ti != null; ti = ti.next) {
GL.glBindTexture(GL20.GL_TEXTURE_2D, ti.id);
ti.bind();
int maxVertices = GLRenderer.maxQuads * INDICES_PER_SPRITE;
@ -114,11 +112,6 @@ public final class TextureRenderer {
GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
//GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
if (GLAdapter.NON_PREMUL_CANVAS)
GL.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
return layer.next;
}

View File

@ -23,6 +23,7 @@ import org.oscim.backend.GL20;
import org.oscim.backend.GLAdapter;
import org.oscim.backend.Log;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLState;
/**
* Utility functions
@ -114,7 +115,8 @@ public class GlUtils {
int min_filter, int mag_filter, int wrap_s, int wrap_t) {
int[] textureIds = GlUtils.glGenTextures(1);
GL = GLAdapter.get();
GL.glBindTexture(GL20.GL_TEXTURE_2D, textureIds[0]);
GLState.bindTex2D(textureIds[0]);
setTextureParameter(min_filter, mag_filter, wrap_s, wrap_t);
@ -125,7 +127,8 @@ public class GlUtils {
GL.glTexImage2D(GL20.GL_TEXTURE_2D, 0, format, width, height, 0, format,
GL20.GL_UNSIGNED_BYTE, intBuf);
GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
GLState.bindTex2D(0);
return textureIds[0];
}