1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-09 01:29:44 +00:00

Enforces across-the-board supersampling.

I'm damned if I can figure out how to talk an MTKView, or Metal in general, into supersampling so as a first effort this does it in software.
This commit is contained in:
Thomas Harte 2020-09-13 19:30:26 -04:00
parent 7dd4c67304
commit d7972a7b86
2 changed files with 25 additions and 7 deletions

View File

@ -189,10 +189,11 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
id<MTLCommandQueue> _commandQueue;
// Pipelines.
id<MTLRenderPipelineState> _composePipeline; // For rendering to the composition texture.
id<MTLRenderPipelineState> _outputPipeline; // For drawing to the frame buffer.
id<MTLRenderPipelineState> _copyPipeline; // For copying the frame buffer to the visible surface.
id<MTLRenderPipelineState> _clearPipeline; // For applying additional inter-frame clearing (cf. the stencil).
id<MTLRenderPipelineState> _composePipeline; // For rendering to the composition texture.
id<MTLRenderPipelineState> _outputPipeline; // For drawing to the frame buffer.
id<MTLRenderPipelineState> _copyPipeline; // For copying from one texture to another.
id<MTLRenderPipelineState> _supersamplePipeline; // For resampling from one texture to one that is 1/4 as large.
id<MTLRenderPipelineState> _clearPipeline; // For applying additional inter-frame clearing (cf. the stencil).
// Buffers.
id<MTLBuffer> _uniformsBuffer; // A static buffer, containing a copy of the Uniforms struct.
@ -315,6 +316,9 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"copyFragment"];
_copyPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"supersampleFragment"];
_supersamplePipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"clearFragment"];
pipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormatStencil8;
_clearPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
@ -360,8 +364,9 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
}
- (void)updateSizeBuffersToSize:(CGSize)size {
const NSUInteger frameBufferWidth = NSUInteger(size.width * _view.layer.contentsScale);
const NSUInteger frameBufferHeight = NSUInteger(size.height * _view.layer.contentsScale);
// TODO: above what size threshold is supersampling no longer desired?
const NSUInteger frameBufferWidth = NSUInteger(size.width * _view.layer.contentsScale) * 2;
const NSUInteger frameBufferHeight = NSUInteger(size.height * _view.layer.contentsScale) * 2;
// Generate a framebuffer and a stencil.
MTLTextureDescriptor *const textureDescriptor = [MTLTextureDescriptor
@ -1080,7 +1085,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
view.currentRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionDontCare;
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:view.currentRenderPassDescriptor];
[encoder setRenderPipelineState:_copyPipeline];
[encoder setRenderPipelineState:_supersamplePipeline];
[encoder setVertexTexture:_frameBuffer atIndex:0];
[encoder setFragmentTexture:_frameBuffer atIndex:0];

View File

@ -390,6 +390,19 @@ DeclareShaders(Red4Green4Blue4, ushort)
DeclareShaders(Red2Green2Blue2, ushort)
DeclareShaders(Red1Green1Blue1, ushort)
// Assumes a 2 -> 1 scaling on both axes; if ever I figure out how to get Metal to do hardware supersampling
// then this fragment shader can be removed.
fragment half4 supersampleFragment(CopyInterpolator vert [[stage_in]], texture2d<half> texture [[texture(0)]]) {
// TODO: can't I do better than this by being careful about positioning and using the linearSampler?
return (
texture.sample(standardSampler, vert.textureCoordinates + float2(0.5f, -1.0f)) +
texture.sample(standardSampler, vert.textureCoordinates + float2(0.5f, 1.0f)) +
texture.sample(standardSampler, vert.textureCoordinates + float2(-1.0f, 0.5f)) +
texture.sample(standardSampler, vert.textureCoordinates + float2(1.0f, -0.5f))
) * half(0.25f);
}
fragment half4 copyFragment(CopyInterpolator vert [[stage_in]], texture2d<half> texture [[texture(0)]]) {
return texture.sample(standardSampler, vert.textureCoordinates);
}