change pipelines

This commit is contained in:
2025-08-01 06:35:25 -05:00
parent 625503e654
commit 8033c161d0

View File

@@ -276,15 +276,37 @@ function make_shader(sh_file)
return shader return shader
} }
var usepipe def material_pipeline_cache = {};
function get_pipeline_for_material(mat = {}) {
def key = json.encode({
vert: mat.vertex || sprite_pipeline.vertex,
frag: mat.fragment || sprite_pipeline.fragment,
blend: mat.blend || sprite_pipeline.blend,
cull: mat.cull || sprite_pipeline.cull,
});
if (!material_pipeline_cache[key]) {
def cfg = Object.assign({}, sprite_pipeline, {
vertex: mat.vertex || sprite_pipeline.vertex,
fragment: mat.fragment || sprite_pipeline.fragment,
blend: mat.blend || sprite_pipeline.blend,
cull: mat.cull || sprite_pipeline.cull,
});
cfg.__proto__ = sprite_pipeline
material_pipeline_cache[key] = load_pipeline(cfg)
log.console(`created pipeline for ${json.encode(cfg)}`)
}
return material_pipeline_cache[key];
}
function load_pipeline(config) function load_pipeline(config)
{ {
if (usepipe) return usepipe
config.vertex = make_shader(config.vertex)[GPU] config.vertex = make_shader(config.vertex)[GPU]
config.fragment = make_shader(config.fragment)[GPU] config.fragment = make_shader(config.fragment)[GPU]
usepipe = new sdl_gpu.graphics_pipeline(device, config) return new sdl_gpu.graphics_pipeline(device, config)
log.console(usepipe)
return usepipe
} }
// Initialize ImGui with the window and renderer // Initialize ImGui with the window and renderer
@@ -483,8 +505,6 @@ var sprite_pipeline = {
blend: alpha_blend_state blend: alpha_blend_state
} }
var pipey = load_pipeline(sprite_pipeline)
var GPU = Symbol() var GPU = Symbol()
var cur_cam var cur_cam
@@ -562,7 +582,7 @@ var draw_queue = []
var index_count = 0 var index_count = 0
var vertex_count = 0 var vertex_count = 0
function render_geom(geom, img) function render_geom(geom, img, pipeline = get_pipeline_for_material(null))
{ {
if (!img[GPU]) { if (!img[GPU]) {
if (img.surface) if (img.surface)
@@ -579,7 +599,7 @@ function render_geom(geom, img)
index_blob.write_blob(geom.indices) index_blob.write_blob(geom.indices)
draw_queue.push({ draw_queue.push({
pipeline:pipey, pipeline,
texture: img[GPU], texture: img[GPU],
num_indices: geom.num_indices, num_indices: geom.num_indices,
first_index: index_count, first_index: index_count,
@@ -605,7 +625,8 @@ cmd_fns.draw_image = function(cmd)
geom.indices = geometry.make_quad_indices(1) geom.indices = geometry.make_quad_indices(1)
geom.num_indices = 6 geom.num_indices = 6
render_geom(geom, img) var pipeline = get_pipeline_for_material(cmd.material)
render_geom(geom, img, pipeline)
} }
cmd_fns.draw_text = function(cmd) cmd_fns.draw_text = function(cmd)
@@ -623,31 +644,36 @@ cmd_fns.draw_text = function(cmd)
font font
) )
render_geom(mesh, font) var pipeline = get_pipeline_for_material(cmd.material)
render_geom(mesh, font, pipeline)
} }
cmd_fns.tilemap = function(cmd) cmd_fns.tilemap = function(cmd)
{ {
var geometryCommands = cmd.tilemap.draw() var geometryCommands = cmd.tilemap.draw()
var pipeline = get_pipeline_for_material(cmd.material)
for (var geomCmd of geometryCommands) { for (var geomCmd of geometryCommands) {
var img = graphics.texture(geomCmd.image) var img = graphics.texture(geomCmd.image)
if (!img) continue if (!img) continue
render_geom(geomCmd.geometry, img) render_geom(geomCmd.geometry, img, pipeline)
} }
} }
cmd_fns.geometry = function(cmd) cmd_fns.geometry = function(cmd)
{ {
var pipeline = get_pipeline_for_material(cmd.material)
if (typeof cmd.image == 'object') { if (typeof cmd.image == 'object') {
render_geom(cmd.geometry, cmd.image) render_geom(cmd.geometry, cmd.image, pipeline)
return return
} }
var img = graphics.texture(cmd.image) var img = graphics.texture(cmd.image)
if (!img) return if (!img) return
render_geom(cmd.geometry, img) render_geom(cmd.geometry, img, pipeline)
} }
cmd_fns.draw_slice9 = function(cmd) cmd_fns.draw_slice9 = function(cmd)
@@ -678,22 +704,23 @@ cmd_fns.draw_slice9 = function(cmd)
var mesh = geometry.slice9(img, cmd.rect, slice_lrtb, slice_info) var mesh = geometry.slice9(img, cmd.rect, slice_lrtb, slice_info)
render_geom(mesh, img) var pipeline = get_pipeline_for_material(cmd.material)
render_geom(mesh, img, pipeline)
} }
cmd_fns.draw_rect = function(cmd) cmd_fns.draw_rect = function(cmd)
{ {
// Create geometry for a rectangle quad // Create geometry for a rectangle quad
var geom = geometry.make_rect_quad(cmd.rect, null, cmd.material.color || [1,1,1,1]) var geom = geometry.make_rect_quad(cmd.rect, null, cmd.material.color)
geom.indices = geometry.make_quad_indices(1) geom.indices = geometry.make_quad_indices(1)
geom.num_indices = 6 geom.num_indices = 6
// Use white_pixel as the texture so the color modulation works // Use white_pixel as the texture so the color modulation works
if (!white_pixel[GPU]) { if (!white_pixel[GPU])
white_pixel[GPU] = get_img_gpu(white_pixel) white_pixel[GPU] = get_img_gpu(white_pixel)
}
render_geom(geom, {[GPU]: white_pixel[GPU]}) var pipeline = get_pipeline_for_material(cmd.material)
render_geom(geom, {[GPU]: white_pixel[GPU]}, pipeline)
} }
var copy_pass var copy_pass
@@ -733,6 +760,11 @@ prosperon.create_batch = function create_batch(draw_cmds, done) {
var render_pass var render_pass
var render_target var render_target
// State tracking for optimization
var current_pipeline = null
var current_camera_blob = null
var buffers_bound = false
for (var cmd of draw_queue) { for (var cmd of draw_queue) {
if (cmd.camera) { if (cmd.camera) {
if (!cmd.camera.surface && render_target != "swap") { if (!cmd.camera.surface && render_target != "swap") {
@@ -740,6 +772,9 @@ prosperon.create_batch = function create_batch(draw_cmds, done) {
render_pass.end() render_pass.end()
render_target = "swap" render_target = "swap"
render_pass = render_queue.swapchain_pass(window) render_pass = render_queue.swapchain_pass(window)
// Reset state tracking when render pass changes
current_pipeline = null
buffers_bound = false
} else if (cmd.camera.surface && render_target != cmd.camera.surface) { } else if (cmd.camera.surface && render_target != cmd.camera.surface) {
if (render_pass) if (render_pass)
render_pass.end() render_pass.end()
@@ -754,18 +789,11 @@ prosperon.create_batch = function create_batch(draw_cmds, done) {
store: "store", store: "store",
}] }]
}) })
// Reset state tracking when render pass changes
current_pipeline = null
buffers_bound = false
} }
render_pass.bind_pipeline(pipey)
render_pass.bind_buffers(0, [
{ buffer: pos_buffer, offset: 0 },
{ buffer: uv_buffer, offset: 0 },
{ buffer: color_buffer, offset: 0 }
])
render_pass.bind_index_buffer(
{ buffer: index_buffer, offset: 0 }, // the binding itself is in bytes
16 // 16 = Uint32 indices
);
var vpW, vpH var vpW, vpH
if (render_target == "swap") { if (render_target == "swap") {
@@ -783,10 +811,45 @@ prosperon.create_batch = function create_batch(draw_cmds, done) {
height: cmd.camera.viewport.height * vpH height: cmd.camera.viewport.height * vpH
}) })
cur_cam = make_camera_pblob(cmd.camera) var new_cam_blob = make_camera_pblob(cmd.camera)
render_queue.push_vertex_uniform_data(0, cur_cam) // Only update camera uniform if it changed
if (current_camera_blob != new_cam_blob) {
render_queue.push_vertex_uniform_data(0, new_cam_blob)
current_camera_blob = new_cam_blob
}
continue continue
} }
// Only bind pipeline if it changed
if (current_pipeline != cmd.pipeline) {
render_pass.bind_pipeline(cmd.pipeline)
current_pipeline = cmd.pipeline
// When pipeline changes, we need to rebind buffers and uniforms
buffers_bound = false
current_camera_blob = null
}
// Only bind buffers if not already bound or pipeline changed
if (!buffers_bound) {
render_pass.bind_buffers(0, [
{ buffer: pos_buffer, offset: 0 },
{ buffer: uv_buffer, offset: 0 },
{ buffer: color_buffer, offset: 0 }
])
render_pass.bind_index_buffer(
{ buffer: index_buffer, offset: 0 }, // the binding itself is in bytes
16 // 16 = Uint32 indices
);
buffers_bound = true
}
// Rebind camera uniform if needed after pipeline change
if (!current_camera_blob && cur_cam) {
render_queue.push_vertex_uniform_data(0, cur_cam)
current_camera_blob = cur_cam
}
// Use texture's sampler if it has one, otherwise use standard sampler // Use texture's sampler if it has one, otherwise use standard sampler
var sampler_to_use = std_sampler var sampler_to_use = std_sampler
if (cmd.texture && cmd.texture.sampler_desc) { if (cmd.texture && cmd.texture.sampler_desc) {