iOS lock step keyboard + metal
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#import "modules/gpu/types.sx";
|
||||
#import "modules/gpu/api.sx";
|
||||
#import "modules/stb_truetype.sx";
|
||||
#import "modules/stb.sx";
|
||||
#import "modules/ui/types.sx";
|
||||
|
||||
// Cached glyph data with UV coordinates into the atlas texture
|
||||
@@ -426,17 +427,26 @@ GlyphCache :: struct {
|
||||
context.allocator.dealloc(old_vals);
|
||||
}
|
||||
|
||||
// Upload dirty atlas to GPU
|
||||
// Upload dirty atlas to GPU. On the Metal path, defer the upload to
|
||||
// end-of-frame (`upload_atlas_to_gpu`) — calling `replaceRegion:` against
|
||||
// the same R8 MTLTexture multiple times within one frame garbles the
|
||||
// contents on iOS-sim Metal. The dirty flag carries over so the final
|
||||
// end-of-frame upload picks up every rasterization that happened during
|
||||
// the frame's render pass.
|
||||
flush :: (self: *GlyphCache) {
|
||||
if self.dirty == false { return; }
|
||||
if self.has_gpu {
|
||||
self.gpu.update_texture_region(self.texture_id, 0, 0,
|
||||
self.atlas_width, self.atlas_height, xx self.bitmap);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, self.texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, self.atlas_width, self.atlas_height, GL_RED, GL_UNSIGNED_BYTE, self.bitmap);
|
||||
}
|
||||
if self.has_gpu { return; }
|
||||
glBindTexture(GL_TEXTURE_2D, self.texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, self.atlas_width, self.atlas_height, GL_RED, GL_UNSIGNED_BYTE, self.bitmap);
|
||||
self.dirty = false;
|
||||
}
|
||||
|
||||
upload_atlas_to_gpu :: (self: *GlyphCache) {
|
||||
if self.has_gpu == false { return; }
|
||||
if self.dirty == false { return; }
|
||||
self.gpu.update_texture_region(self.texture_id, 0, 0,
|
||||
self.atlas_width, self.atlas_height, xx self.bitmap);
|
||||
self.dirty = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,11 @@ UIPipeline :: struct {
|
||||
|
||||
self.renderer.begin(self.screen_width, self.screen_height, self.font.texture_id);
|
||||
self.renderer.process(@self.render_tree);
|
||||
// Push any glyphs rasterized during process() to the GPU atlas BEFORE
|
||||
// the final draw is recorded. On Metal we deferred per-render_text
|
||||
// uploads so this is the single point where the atlas reaches the
|
||||
// GPU. On the GL path it's a no-op (uploads already happened inline).
|
||||
self.font.upload_atlas_to_gpu();
|
||||
self.renderer.flush();
|
||||
|
||||
if !self.has_gpu {
|
||||
|
||||
@@ -375,6 +375,7 @@ UIRenderer :: struct {
|
||||
u1 := cached.uv_x + cached.uv_w;
|
||||
v1 := cached.uv_y + cached.uv_h;
|
||||
|
||||
|
||||
if self.vertex_count + 6 > MAX_UI_VERTICES {
|
||||
self.flush();
|
||||
}
|
||||
@@ -619,12 +620,7 @@ fragment float4 fmain(VOut in [[stage_in]],
|
||||
// Image mode (mode == -2.0): sample texture
|
||||
return tex.sample(s, in.uv) * in.color;
|
||||
} else if (mode < 0.0) {
|
||||
// Text mode (mode == -1.0): the glyph atlas stores R8 alpha
|
||||
// coverage from stbtt_MakeGlyphBitmap. Use the sampled value
|
||||
// directly as alpha (no smoothstep — those were for SDFs and
|
||||
// thinned anti-aliased coverage strokes). Small-size text renders
|
||||
// dim on dark backgrounds because most glyph pixels sit in 0.1-0.5
|
||||
// coverage; tracked as the "faint text" follow-up.
|
||||
// Text mode (mode == -1.0): the glyph atlas stores R8 alpha coverage.
|
||||
float alpha = tex.sample(s, in.uv).r;
|
||||
return float4(in.color.rgb, in.color.a * alpha);
|
||||
} else if (mode > 0.0 || border > 0.0) {
|
||||
|
||||
Reference in New Issue
Block a user