metal: handle HiDPI scaling

This commit is contained in:
Mitchell Hashimoto
2022-10-30 11:04:15 -07:00
parent fb49595904
commit 0058906035
3 changed files with 27 additions and 13 deletions

View File

@ -1,4 +1,11 @@
//! Renderer implementation for Metal. //! 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(); pub const Metal = @This();
const std = @import("std"); const std = @import("std");
@ -64,7 +71,16 @@ const GPUCell = extern struct {
}; };
const GPUUniforms = 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, 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, cell_size: [2]f32,
}; };
@ -292,11 +308,8 @@ pub fn render(
@floatCast(f32, bounds.size.height), @floatCast(f32, bounds.size.height),
0, 0,
), ),
.px_scale = .{ scaleX, scaleY },
.cell_size = .{ .cell_size = .{ self.cell_size.width, self.cell_size.height },
self.cell_size.width * scaleX,
self.cell_size.height * scaleY,
},
}; };
} }

View File

@ -8,6 +8,7 @@ enum Mode : uint8_t {
struct Uniforms { struct Uniforms {
float4x4 projection_matrix; float4x4 projection_matrix;
float2 px_scale;
float2 cell_size; float2 cell_size;
}; };
@ -45,8 +46,11 @@ vertex VertexOut uber_vertex(
VertexIn input [[ stage_in ]], VertexIn input [[ stage_in ]],
constant Uniforms &uniforms [[ buffer(1) ]] 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 // 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 // Turn the cell position into a vertex point depending on the
// vertex ID. Since we use instanced drawing, we have 4 vertices // 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.x = (vid == 0 || vid == 1) ? 1.0f : 0.0f;
position.y = (vid == 0 || vid == 3) ? 0.0f : 1.0f; position.y = (vid == 0 || vid == 3) ? 0.0f : 1.0f;
// TODO: scale
float2 cell_size = uniforms.cell_size;
VertexOut out; VertexOut out;
out.mode = input.mode; out.mode = input.mode;
out.color = float4(input.color) / 255.0f; 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. // Calculate the final position of our cell in world space.
// We have to add our cell size since our vertices are offset // 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) // 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); out.position = uniforms.projection_matrix * float4(cell_pos.x, cell_pos.y, 0.0f, 1.0f);
break; break;
case MODE_FG: case MODE_FG:
float2 glyph_size = float2(input.glyph_size); float2 glyph_size = float2(input.glyph_size) * uniforms.px_scale;
float2 glyph_offset = float2(input.glyph_offset); float2 glyph_offset = float2(input.glyph_offset) * uniforms.px_scale;
// TODO: downsampling // TODO: downsampling

View File

@ -147,7 +147,7 @@ void main() {
glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y; glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y;
// Calculate the final position of the cell. // 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); gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
// We need to convert our texture position and size to normalized // We need to convert our texture position and size to normalized