Intel GPU detection tweaks

This commit is contained in:
Anuken
2025-09-11 18:56:05 -04:00
parent f089e38994
commit 5f58adb764
5 changed files with 243 additions and 9 deletions

View File

@@ -54,12 +54,12 @@ 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 @ context.", gl30 != null ? "OpenGL 3" : "OpenGL 2");
Log.info("[GL] Using @ API.", gl30 != null ? "OpenGL 3" : "OpenGL 2");
if(GpuDetect.gpus.size > 0) Log.info("[GL] Detected GPU: @", GpuDetect.gpus.toString(", "));
if(GpuDetect.isIntel) Log.warn("[GL] Intel GPU detected. Due to memory corruption issues, OpenGL 3 support has been disabled for Intel GPUs. See issue #11041.");
if(GpuDetect.hasIntel && !graphics.isGL30Available()) Log.warn("[GL] Intel GPU detected. Due to memory corruption issues, OpenGL 3 support has been disabled for Intel GPUs. See issue #11041.");
if(gl30 == null && !GpuDetect.isIntel) Log.warn("[GL] Your device or video drivers do not support OpenGL 3. This will cause performance issues.");
if(gl30 == null && !GpuDetect.hasIntel) 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);

View File

@@ -9,7 +9,7 @@ import java.util.*;
public class GpuDetect{
public static String rawGpuString = "";
public static Seq<String> gpus = new Seq<>();
public static boolean isIntel, isNvidia, isAMD;
public static boolean hasIntel, hasNvidia, hasAMD;
public static void init(){
if(OS.isWindows){
@@ -17,9 +17,9 @@ public class GpuDetect{
rawGpuString = OS.exec("wmic", "path", "win32_VideoController", "get", "name");
gpus = Seq.with(rawGpuString.split("\n")).map(s -> s.trim()).removeAll(s -> s.isEmpty() || s.equalsIgnoreCase("name"));
isIntel = rawGpuString.toLowerCase(Locale.ROOT).contains("intel");
isNvidia = rawGpuString.toLowerCase(Locale.ROOT).contains("nvidia");
isAMD = rawGpuString.toLowerCase(Locale.ROOT).contains("amd") || rawGpuString.toLowerCase(Locale.ROOT).contains("radeon");
hasIntel = rawGpuString.toLowerCase(Locale.ROOT).contains("intel");
hasNvidia = rawGpuString.toLowerCase(Locale.ROOT).contains("nvidia");
hasAMD = rawGpuString.toLowerCase(Locale.ROOT).contains("amd") || rawGpuString.toLowerCase(Locale.ROOT).contains("radeon");
}catch(Exception e){
Log.err(e);
}

View File

@@ -0,0 +1,233 @@
package mindustry.graphics;
import arc.*;
import arc.graphics.*;
import arc.graphics.gl.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import mindustry.*;
import java.util.concurrent.*;
/** WIP experimental point-sprite based particle renderer. */
public class ParticleRenderer{
static final boolean useAsync = true;
static final int maxParticles = 100_000, maxParticlesPerFrame = 25_000;
static final int particleSize =
1 + //time
1 + //total lifetime
2 + //position xy
2 + //velocity xy
1 + //sizeFrom
1 + //sizeTo
1 //color
; //TODO fade color?
static final int particleVertexSize =
2 + //xy
1 + //size
1 //color
;
static final float globalDrag = 0.05f;
static final float cullPadding = 8f*3f;
static final VertexAttribute[] attributes = {VertexAttribute.position, new VertexAttribute(1, "a_size"), VertexAttribute.color};
static Shader shader;
float[] data = new float[maxParticles * particleSize];
volatile int count;
float[] addBuffer = new float[maxParticlesPerFrame * particleSize]; //TODO should be smaller than data
int addCount;
Mesh mesh = new Mesh(false, maxParticles, 0, attributes);
float[] vertexBuffer = new float[maxParticles * particleVertexSize];
volatile int vertexBufferLength;
@Nullable Future<?> asyncTask;
public int count(){
return count;
}
public void updateAndRender(){
if(!Vars.state.isPaused()){
update();
}
render();
}
public void update(){
if(useAsync && asyncTask != null){
try{
asyncTask.get();
}catch(Exception e){
Log.err(e);
}
}
//append added particles to the queue
int maxAdded = Math.min(maxParticles - count, addCount);
//if maxAdded is less than addCount, prioritize particles at the end of the array (most recent)
int addOffset = addCount - maxAdded;
if(maxAdded > 0){
System.arraycopy(addBuffer, addOffset * particleSize, data, count * particleSize, maxAdded * particleSize);
}
count += maxAdded;
addCount = 0;
//uses data calculated from previous frame
uploadMeshData(mesh);
if(useAsync){
asyncTask = Vars.mainExecutor.submit(this::updateAsync);
}else{
updateAsync();
}
}
void updateAsync(){
count = update(data, count, Time.delta);
buildVertices();
}
public void render(){
if(shader == null) makeShader();
Gl.enable(Gl.programPointSize);
shader.bind();
shader.setUniformMatrix4("u_mat", Core.camera.mat);
shader.setUniformf("u_scaling", Core.graphics.getWidth() / Core.camera.width);
mesh.render(shader, Gl.points);
}
public void add(float x, float y, float lifetime, float vx, float vy, float sizeFrom, float sizeTo, float color){
if(addCount * particleSize >= addBuffer.length ||
//ignore particles added not in the camera viewport
//TODO fast-moving offscreen particles won't show up.
!Rect.contains(
x - Core.camera.width/2f - sizeFrom - cullPadding,
y - Core.camera.height/2f - sizeFrom - cullPadding,
Core.camera.width + sizeFrom*2f + cullPadding*2f,
Core.camera.height + sizeFrom*2f + cullPadding*2f, x, y)) return;
float[] buf = addBuffer;
int i = addCount * particleSize;
buf[i + 0] = 0f;
buf[i + 1] = lifetime;
buf[i + 2] = x;
buf[i + 3] = y;
buf[i + 4] = vx;
buf[i + 5] = vy;
buf[i + 6] = sizeFrom * 2f;
buf[i + 7] = sizeTo * 2f;
buf[i + 8] = color;
addCount ++;
}
void buildVertices(){
//TODO: cull based on camera viewport
float[] data = this.data;
float count = this.count * particleSize;
float[] vertices = vertexBuffer;
int bufferIndex = 0;
for(int i = 0; i < count; i += particleSize){
float color = data[i + 8]; //TODO: colorTo
float size = Mathf.lerp(data[i + 6], data[i + 7], Mathf.clamp(data[i] / data[i + 1]));
//xy
vertices[bufferIndex + 0] = data[i + 2];
vertices[bufferIndex + 1] = data[i + 3];
//size
vertices[bufferIndex + 2] = size;
//color
vertices[bufferIndex + 3] = color;
bufferIndex += particleVertexSize;
}
vertexBufferLength = bufferIndex;
}
void uploadMeshData(Mesh mesh){
var buffer = mesh.getVerticesBuffer();
buffer.position(0);
buffer.limit(vertexBufferLength);
buffer.put(vertexBuffer, 0, vertexBufferLength);
buffer.position(0);
}
static int update(float[] data, int count, float delta){
int head = count * particleSize;
float dragValue = Math.max(1f - globalDrag * delta, 0f);
for(int i = 0; i < head; i += particleSize){
data[i] += delta;
if(data[i] >= data[i + 1]){
if(head > particleSize){
//swap head
System.arraycopy(data, head - particleSize, data, i, particleSize);
}
head -= particleSize;
i -= particleSize;
}else{
//velocity
data[i + 2] += data[i + 4] * delta;
data[i + 3] += data[i + 5] * delta;
data[i + 4] *= dragValue;
data[i + 5] *= dragValue;
}
}
return head / particleSize;
}
static void makeShader(){
shader = new Shader(
"""
uniform mat4 u_mat;
uniform float u_scaling;
attribute vec4 a_position;
attribute float a_size;
attribute vec4 a_color;
varying vec4 v_color;
void main(){
v_color = a_color;
gl_Position = u_mat * a_position;
gl_PointSize = a_size * u_scaling;
}
""",
"""
varying lowp vec4 v_color;
#define RAD1 0.43
#define RAD2 0.5
void main(){
vec2 delta = gl_PointCoord - vec2(0.5);
gl_FragColor = vec4(v_color.rgb, v_color.a * (1.0-smoothstep(RAD1*RAD1, RAD2*RAD2, delta.x * delta.x + delta.y * delta.y)));
}
"""
);
}
}