WIP texture array sprite batch + gl3 min

This commit is contained in:
Anuken
2026-06-19 03:24:18 -04:00
parent 0672e7f37e
commit 1314db7295
18 changed files with 75 additions and 180 deletions

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<uses-feature android:glEsVersion="0x00030000" android:required="true"/>
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

View File

@@ -1,9 +0,0 @@
{
duplicatePadding: true,
combineSubdirectories: true,
flattenPaths: true,
maxWidth: 2048,
maxHeight: 2048,
fast: true,
stripWhitespaceCenter: false
}

View File

@@ -6,5 +6,5 @@
maxHeight: 4096,
fast: true,
stripWhitespaceCenter: true,
ignoredWhitespaceStrings: ["effects/"]
ignoredWhitespaceStrings: ["effects/", "environment/"]
}

View File

@@ -1,9 +0,0 @@
{
duplicatePadding: true,
combineSubdirectories: true,
flattenPaths: true,
maxWidth: 4096,
maxHeight: 4096,
fast: true,
stripWhitespaceCenter: true
}

View File

@@ -1,9 +0,0 @@
{
duplicatePadding: true,
combineSubdirectories: true,
flattenPaths: true,
maxWidth: 2048,
maxHeight: 2048,
fast: true,
stripWhitespaceCenter: true
}

View File

@@ -61,15 +61,6 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
//debug GL information
Log.info("[GL] Version: @", graphics.getGLVersion());
Log.info("[GL] Max texture size: @", maxTextureSize);
Log.info("[GL] Using @ API.", gl30 != null ? "OpenGL 3" : "OpenGL 2");
IntelGpuCheck.init(graphics.getGLVersion().vendorString);
boolean isIntel = IntelGpuCheck.wasIntel();
if(isIntel && !graphics.isGL30Available()) Log.warn("[GL] Intel GPU detected on previous launch. Due to memory corruption issues, OpenGL 3 support has been disabled for Intel GPUs. See issue #11041.");
if(gl30 == null && !isIntel) Log.warn("[GL] Your device or video drivers do not support OpenGL 3. This will cause performance issues.");
if(NvGpuInfo.hasMemoryInfo()) Log.info("[GL] Total available VRAM: @mb", NvGpuInfo.getMaxMemoryKB()/1024);
@@ -161,7 +152,10 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
Fonts.loadDefaultFont();
//load fallback atlas if max texture size is below 4096
assets.load(new AssetDescriptor<>(maxTextureSize >= 4096 ? "sprites/sprites.aatls" : "sprites/fallback/sprites.aatls", TextureAtlas.class)).loaded = t -> atlas = t;
assets.load(new AssetDescriptor<>("sprites/sprites.aatls", TextureAtlas.class)).loaded = t -> {
atlas = t;
Fonts.mergeFontAtlas(atlas);
};
assets.loadRun("maps", Map.class, () -> maps.loadPreviews());
Musics.load();
@@ -176,7 +170,6 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
});
assets.load(mods);
assets.loadRun("mergeUI", PixmapPacker.class, () -> {}, () -> Fonts.mergeFontAtlas(atlas));
add(logic = new Logic());
add(control = new Control());

View File

@@ -42,7 +42,7 @@ public class EditorSpriteCache implements Disposable{
* @param indices The shared index data in standard quad format, as seen in SpriteBatch.
* Since this data is static, it should be the same across all caches, and be large enough to accommodate all sprites.
* */
public void build(IndexData indices){
public void build(IndexBufferObject indices){
if(mesh != null) mesh.dispose();
mesh = new Mesh(true, index / vertexSize, 0,

View File

@@ -60,8 +60,8 @@ public class CubemapMesh implements Disposable{
this.map = map;
this.map.setFilter(TextureFilter.linear);
this.mesh = new Mesh(true, vertices.length, 0, VertexAttribute.position3);
mesh.getVerticesBuffer().limit(vertices.length);
mesh.getVerticesBuffer().put(vertices, 0, vertices.length);
mesh.getVertices().limit(vertices.length);
mesh.getVertices().put(vertices, 0, vertices.length);
shader = new Shader(Core.files.internal("shaders/cubemap.vert"), Core.files.internal("shaders/cubemap.frag"));
}

View File

@@ -32,11 +32,11 @@ import static mindustry.Vars.*;
public class FloorRenderer{
public static boolean growSprites = true;
private static final VertexAttribute[] attributes = {VertexAttribute.packedPosition, VertexAttribute.color, VertexAttribute.packedTexCoords};
private static final VertexAttribute[] attributes = {VertexAttribute.packedPosition, VertexAttribute.color, VertexAttribute.packedTexCoords, VertexAttribute.depthCoords};
private static final int
chunksize = 30, //todo 32?
chunkunits = chunksize * tilesize,
vertexSize = 1 + 1 + 1,
vertexSize = 1 + 1 + 1 + 1,
spriteSize = vertexSize * 4,
maxSprites = chunksize * chunksize * 9;
private static final float packPad = tilesize * 8f;
@@ -73,25 +73,29 @@ public class FloorRenderer{
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
attribute float a_depth;
uniform mat4 u_projectionViewMatrix;
varying vec4 v_color;
varying vec2 v_texCoords;
varying float v_depth;
void main(){
v_color = a_color;
v_color.a = v_color.a * (255.0/254.0);
v_texCoords = a_texCoord0;
v_depth = a_depth;
gl_Position = u_projectionViewMatrix * a_position;
}
""",
"""
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
varying float v_depth;
uniform sampler2DArray u_texture;
void main(){
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
gl_FragColor = v_color * texture(u_texture, vec3(v_texCoords, v_depth));
}
""");
@@ -456,24 +460,29 @@ public class FloorRenderer{
float v = region.v2;
float u2 = region.u2;
float v2 = region.v;
float depth = region.getDepth();
float color = this.colorPacked;
verts[idx] = pack(x1, y1);
verts[idx + 1] = color;
verts[idx + 2] = Pack.packUv(u, v);
verts[idx] = pack(x1, y1);
verts[idx + 1] = color;
verts[idx + 2] = Pack.packUv(u, v);
verts[idx + 3] = depth;
verts[idx + 3] = pack(x2, y2);
verts[idx + 4] = color;
verts[idx + 5] = Pack.packUv(u, v2);
verts[idx + 4] = pack(x2, y2);
verts[idx + 5] = color;
verts[idx + 6] = Pack.packUv(u, v2);
verts[idx + 7] = depth;
verts[idx + 6] = pack(x3, y3);
verts[idx + 7] = color;
verts[idx + 8] = Pack.packUv(u2, v2);
verts[idx + 8] = pack(x3, y3);
verts[idx + 9] = color;
verts[idx + 10] = Pack.packUv(u2, v2);
verts[idx + 11] = depth;
verts[idx + 9] = pack(x4, y4);
verts[idx + 10] = color;
verts[idx + 11] = Pack.packUv(u2, v);
verts[idx + 12] = pack(x4, y4);
verts[idx + 13] = color;
verts[idx + 14] = Pack.packUv(u2, v);
verts[idx + 15] = depth;
}else{
float fx2 = x + width;
float fy2 = y + height;
@@ -481,24 +490,29 @@ public class FloorRenderer{
float v = region.v2;
float u2 = region.u2;
float v2 = region.v;
float depth = region.getDepth();
float color = this.colorPacked;
verts[idx] = pack(x, y);
verts[idx + 1] = color;
verts[idx + 2] = Pack.packUv(u, v);
verts[idx] = pack(x, y);
verts[idx + 1] = color;
verts[idx + 2] = Pack.packUv(u, v);
verts[idx + 3] = depth;
verts[idx + 3] = pack(x, fy2);
verts[idx + 4] = color;
verts[idx + 5] = Pack.packUv(u, v2);
verts[idx + 4] = pack(x, fy2);
verts[idx + 5] = color;
verts[idx + 6] = Pack.packUv(u, v2);
verts[idx + 7] = depth;
verts[idx + 6] = pack(fx2, fy2);
verts[idx + 7] = color;
verts[idx + 8] = Pack.packUv(u2, v2);
verts[idx + 8] = pack(fx2, fy2);
verts[idx + 9] = color;
verts[idx + 10] = Pack.packUv(u2, v2);
verts[idx + 11] = depth;
verts[idx + 9] = pack(fx2, y);
verts[idx + 10] = color;
verts[idx + 11] = Pack.packUv(u2, v);
verts[idx + 12] = pack(fx2, y);
verts[idx + 13] = color;
verts[idx + 14] = Pack.packUv(u2, v);
verts[idx + 15] = depth;
}
}
@@ -519,6 +533,7 @@ public class FloorRenderer{
@Override
protected void draw(Texture texture, float[] spriteVertices, int offset, int count){
//TODO broken
if(spriteVertices.length != 20){
throw new IllegalArgumentException("cached vertices must be in non-mixcolor format (20 per sprite, 5 per vertex)");
}

View File

@@ -1,44 +0,0 @@
package mindustry.graphics;
import arc.files.*;
import arc.util.*;
import java.util.*;
public class IntelGpuCheck{
private static boolean wasIntel, checkedLastLaunch;
/** initialize intel version check for the next application launch */
public static void init(String vendor){
if(!OS.isWindows) return;
boolean isIntel = vendor.toLowerCase(Locale.ROOT).contains("intel");
try{
Fi file = new Fi(OS.getAppDataDirectoryString("Mindustry")).child("was_intel_gpu");
if(isIntel){
file.writeString("1");
}else if(file.exists()){
file.delete();
}
}catch(Throwable e){
Log.err(e);
}
}
/** @return whether the last launch used an intel GPU on Windows */
public static boolean wasIntel(){
if(!OS.isWindows) return false;
if(checkedLastLaunch) return wasIntel;
checkedLastLaunch = true;
try{
Fi file = new Fi(OS.getAppDataDirectoryString("Mindustry")).child("was_intel_gpu");
if(file.exists() && file.readString().equals("1")){
return wasIntel = true;
}
}catch(Throwable e){
Log.err("Failed to check whether the last launch used an intel GPU.", e);
}
return wasIntel = false;
}
}

View File

@@ -163,7 +163,7 @@ public class ParticleRenderer{
}
void uploadMeshData(Mesh mesh){
var buffer = mesh.getVerticesBuffer();
var buffer = mesh.getVertices();
buffer.position(0);
buffer.limit(vertexBufferLength);

View File

@@ -24,14 +24,14 @@ public class MeshBuilder{
items[i] *= radius;
}
mesh.getVerticesBuffer().put(items, 0, result.vertices.size);
mesh.getVertices().put(items, 0, result.vertices.size);
short[] indices = new short[result.indices.size];
for(int i = 0; i < result.indices.size; i++){
indices[i] = (short)result.indices.items[i];
}
mesh.getIndicesBuffer().put(indices);
mesh.getIndices().put(indices);
return end(mesh);
}
@@ -59,7 +59,7 @@ public class MeshBuilder{
floats[6] = v2.z * scale;
floats[7] = col;
mesh.getVerticesBuffer().put(floats);
mesh.getVertices().put(floats);
}
}
@@ -175,7 +175,7 @@ public class MeshBuilder{
shorts[11] = (short)(position + 5);
}
mesh.getIndicesBuffer().put(shorts, 0, c.length > 5 ? 12 : 9);
mesh.getIndices().put(shorts, 0, c.length > 5 ? 12 : 9);
position += c.length;
}else{
@@ -216,21 +216,21 @@ public class MeshBuilder{
Mesh mesh = new Mesh(true, vertices, indices, attributes.toArray(VertexAttribute.class));
mesh.getVerticesBuffer().limit(mesh.getVerticesBuffer().capacity());
mesh.getVerticesBuffer().position(0);
mesh.getVertices().limit(mesh.getVertices().capacity());
mesh.getVertices().position(0);
if(indices > 0){
mesh.getIndicesBuffer().limit(mesh.getIndicesBuffer().capacity());
mesh.getIndicesBuffer().position(0);
mesh.getIndices().limit(mesh.getIndices().capacity());
mesh.getIndices().position(0);
}
return mesh;
}
private static Mesh end(Mesh mesh){
mesh.getVerticesBuffer().limit(mesh.getVerticesBuffer().position());
mesh.getVertices().limit(mesh.getVertices().position());
if(mesh.getNumIndices() > 0){
mesh.getIndicesBuffer().limit(mesh.getIndicesBuffer().position());
mesh.getIndices().limit(mesh.getIndices().position());
}
return mesh;
@@ -282,7 +282,7 @@ public class MeshBuilder{
if(floats.length > 7) floats[7] = emissive;
}
mesh.getVerticesBuffer().put(floats);
mesh.getVertices().put(floats);
}
private static float packNormals(float x, float y, float z){

View File

@@ -12,7 +12,6 @@ import arc.graphics.Texture.*;
import arc.graphics.g2d.*;
import arc.graphics.g2d.Font.*;
import arc.graphics.g2d.PixmapPacker.*;
import arc.graphics.g2d.TextureAtlas.*;
import arc.math.geom.*;
import arc.scene.style.*;
import arc.scene.ui.layout.*;
@@ -236,9 +235,9 @@ public class Fonts{
/** Called from a static context for use in the loading screen.*/
public static void loadDefaultFont(){
int max = Gl.getInt(Gl.maxTextureSize);
//TOOD: which size to use?
UI.packer = new PixmapPacker(4096, 2048, 2, true);
UI.packer = new PixmapPacker(max >= 4096 ? 4096 : 2048, 2048, 2, true);
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(Core.files::internal));
Core.assets.setLoader(Font.class, null, new FreetypeFontLoader(Core.files::internal){
ObjectSet<FreeTypeFontParameter> scaled = new ObjectSet<>();
@@ -279,37 +278,14 @@ public class Fonts{
}
/** Merges the UI and font atlas together for better performance. */
//TODO: does nothing at the moment.
public static void mergeFontAtlas(TextureAtlas atlas){
//grab all textures from the ui page, remove all the regions assigned to it, then copy them over to UI.packer and replace the texture in this atlas.
//grab old UI texture and regions...
Texture texture = atlas.find("logo").texture;
if(true) return;
Texture texture = atlas.find("ui-page-placeholder").texture;
Page page = UI.packer.getPages().first();
Seq<AtlasRegion> regions = atlas.getRegions().select(t -> t.texture == texture);
for(AtlasRegion region : regions){
//get new pack rect
page.setDirty(false);
Rect rect = UI.packer.pack(region.name, atlas.getPixmap(region), region.splits, region.pads);
//set new texture
region.texture = UI.packer.getPages().first().getTexture();
//set its new position
region.set((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
//add old texture
atlas.getTextures().add(region.texture);
//clear it
region.pixmapRegion = null;
}
//remove old texture, it will no longer be used
atlas.getTextures().remove(texture);
texture.dispose();
atlas.disposePixmap(texture);
page.setDirty(true);
page.updateTexture(TextureFilter.linear, TextureFilter.linear, false);
page.texture = texture;
}
public static TextureRegionDrawable getGlyph(Font font, char glyph){

View File

@@ -142,7 +142,7 @@ public class EffectsDialog extends BaseDialog{
@Override
protected void draw(Texture texture, float[] spriteVertices, int offset, int count){
for(int i = offset; i < count; i += SpriteBatch.VERTEX_SIZE){
for(int i = offset; i < count; i += SpriteBatch.vertexSize){
max(spriteVertices[i], spriteVertices[i + 1]);
}
}

View File

@@ -20,7 +20,6 @@ import mindustry.core.*;
import mindustry.desktop.steam.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.mod.Mods.*;
import mindustry.net.*;
import mindustry.net.Net.*;
@@ -57,17 +56,12 @@ public class DesktopLauncher extends ClientLauncher{
width = 900;
height = 700;
//on Windows, Intel drivers might be buggy with OpenGL 3.x, so only use 2.x. See https://github.com/Anuken/Mindustry/issues/11041
if(IntelGpuCheck.wasIntel()){
allowGl30 = false;
coreProfile = false;
glVersions = new int[][]{{2, 1}, {2, 0}};
}else if(OS.isMac){
if(OS.isMac){
//MacOS supports 4.1 at most
glVersions = new int[][]{{4, 1}, {3, 2}, {2, 1}, {2, 0}};
glVersions = new int[][]{{4, 1}, {3, 2}};
}else{
//try essentially every OpenGL version
glVersions = new int[][]{{4, 6}, {4, 5}, {4, 4}, {4, 1}, {3, 3}, {3, 2}, {3, 1}, {2, 1}, {2, 0}};
glVersions = new int[][]{{4, 6}, {4, 5}, {4, 4}, {4, 1}, {3, 3}, {3, 2}, {3, 1}, {3, 0}};
}
for(int i = 0; i < arg.length; i++){

View File

@@ -26,4 +26,4 @@ org.gradle.caching=true
org.gradle.internal.http.socketTimeout=100000
org.gradle.internal.http.connectionTimeout=100000
android.enableR8.fullMode=false
archash=abb6cc1a11
archash=f4336eefed

View File

@@ -175,18 +175,6 @@ tasks.register('pack'){
//pack normal sprites
TexturePacker.process(new File(rootDir, "core/assets-raw/sprites_out/").absolutePath, new File(rootDir, "core/assets/sprites/").absolutePath, "sprites.aatls")
println("\n\nPacking fallback 2048 sprites...\n\n")
//replace config file contents
fileTree(dir: '../core/assets-raw/sprites_out/', include: "**/*.json").visit{ file ->
if(!file.isDirectory()) file.file.text = file.file.text.replace("4096", "2048")
}
//pack fallback 2048x2048 sprites - disabled when debugging
if(!project.hasProperty("args")){
TexturePacker.process(new File(rootDir, "core/assets-raw/sprites_out/").absolutePath, new File(rootDir, "core/assets/sprites/fallback/").absolutePath, "sprites.aatls")
}
}
}