diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index ff096fef0..cb9609e31 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1,4 +1,11 @@ //! Renderer implementation for Metal. +//! +//! Open questions: +//! +//! - This requires a "px_scale" uniform to account for pixel scaling +//! issues with Retina. I'm not 100% sure why this is necessary and why +//! this doesn't happen with OpenGL. +//! pub const Metal = @This(); const std = @import("std"); @@ -64,7 +71,16 @@ const GPUCell = extern struct { }; const GPUUniforms = extern struct { + /// The projection matrix for turning world coordinates to normalized. + /// This is calculated based on the size of the screen. projection_matrix: math.Mat, + + /// A scale factor to apply to all pixels given as input (including + /// in this uniform i.e. cell_size). This is due to HiDPI screens (Retina) + /// mismatch with the window. + px_scale: [2]f32, + + /// Size of a single cell in pixels, unscaled. cell_size: [2]f32, }; @@ -292,11 +308,8 @@ pub fn render( @floatCast(f32, bounds.size.height), 0, ), - - .cell_size = .{ - self.cell_size.width * scaleX, - self.cell_size.height * scaleY, - }, + .px_scale = .{ scaleX, scaleY }, + .cell_size = .{ self.cell_size.width, self.cell_size.height }, }; } diff --git a/src/shaders/cell.metal b/src/shaders/cell.metal index 560fffa3e..6e7eeebcb 100644 --- a/src/shaders/cell.metal +++ b/src/shaders/cell.metal @@ -8,6 +8,7 @@ enum Mode : uint8_t { struct Uniforms { float4x4 projection_matrix; + float2 px_scale; float2 cell_size; }; @@ -45,8 +46,11 @@ vertex VertexOut uber_vertex( VertexIn input [[ stage_in ]], constant Uniforms &uniforms [[ buffer(1) ]] ) { + // TODO: scale with cell width + float2 cell_size = uniforms.cell_size * uniforms.px_scale; + // Convert the grid x,y into world space x, y by accounting for cell size - float2 cell_pos = uniforms.cell_size * input.grid_pos; + float2 cell_pos = cell_size * input.grid_pos; // Turn the cell position into a vertex point depending on the // vertex ID. Since we use instanced drawing, we have 4 vertices @@ -62,9 +66,6 @@ vertex VertexOut uber_vertex( position.x = (vid == 0 || vid == 1) ? 1.0f : 0.0f; position.y = (vid == 0 || vid == 3) ? 0.0f : 1.0f; - // TODO: scale - float2 cell_size = uniforms.cell_size; - VertexOut out; out.mode = input.mode; out.color = float4(input.color) / 255.0f; @@ -73,14 +74,14 @@ vertex VertexOut uber_vertex( // Calculate the final position of our cell in world space. // We have to add our cell size since our vertices are offset // one cell up and to the left. (Do the math to verify yourself) - cell_pos = cell_pos + uniforms.cell_size * position; + cell_pos = cell_pos + cell_size * position; out.position = uniforms.projection_matrix * float4(cell_pos.x, cell_pos.y, 0.0f, 1.0f); break; case MODE_FG: - float2 glyph_size = float2(input.glyph_size); - float2 glyph_offset = float2(input.glyph_offset); + float2 glyph_size = float2(input.glyph_size) * uniforms.px_scale; + float2 glyph_offset = float2(input.glyph_offset) * uniforms.px_scale; // TODO: downsampling diff --git a/src/shaders/cell.v.glsl b/src/shaders/cell.v.glsl index 756b0ecd7..b0c94a31f 100644 --- a/src/shaders/cell.v.glsl +++ b/src/shaders/cell.v.glsl @@ -147,7 +147,7 @@ void main() { glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y; // Calculate the final position of the cell. - cell_pos = cell_pos + glyph_size_downsampled * position + glyph_offset_calc; + cell_pos = cell_pos + (glyph_size_downsampled * position) + glyph_offset_calc; gl_Position = projection * vec4(cell_pos, cell_z, 1.0); // We need to convert our texture position and size to normalized