mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-15 14:27:29 +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:
@@ -191,7 +191,8 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
// Pipelines.
|
// Pipelines.
|
||||||
id<MTLRenderPipelineState> _composePipeline; // For rendering to the composition texture.
|
id<MTLRenderPipelineState> _composePipeline; // For rendering to the composition texture.
|
||||||
id<MTLRenderPipelineState> _outputPipeline; // For drawing to the frame buffer.
|
id<MTLRenderPipelineState> _outputPipeline; // For drawing to the frame buffer.
|
||||||
id<MTLRenderPipelineState> _copyPipeline; // For copying the frame buffer to the visible surface.
|
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).
|
id<MTLRenderPipelineState> _clearPipeline; // For applying additional inter-frame clearing (cf. the stencil).
|
||||||
|
|
||||||
// Buffers.
|
// Buffers.
|
||||||
@@ -315,6 +316,9 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"copyFragment"];
|
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"copyFragment"];
|
||||||
_copyPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
|
_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.fragmentFunction = [library newFunctionWithName:@"clearFragment"];
|
||||||
pipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormatStencil8;
|
pipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormatStencil8;
|
||||||
_clearPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
|
_clearPipeline = [_view.device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:nil];
|
||||||
@@ -360,8 +364,9 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateSizeBuffersToSize:(CGSize)size {
|
- (void)updateSizeBuffersToSize:(CGSize)size {
|
||||||
const NSUInteger frameBufferWidth = NSUInteger(size.width * _view.layer.contentsScale);
|
// TODO: above what size threshold is supersampling no longer desired?
|
||||||
const NSUInteger frameBufferHeight = NSUInteger(size.height * _view.layer.contentsScale);
|
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.
|
// Generate a framebuffer and a stencil.
|
||||||
MTLTextureDescriptor *const textureDescriptor = [MTLTextureDescriptor
|
MTLTextureDescriptor *const textureDescriptor = [MTLTextureDescriptor
|
||||||
@@ -1080,7 +1085,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
view.currentRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionDontCare;
|
view.currentRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionDontCare;
|
||||||
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:view.currentRenderPassDescriptor];
|
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:view.currentRenderPassDescriptor];
|
||||||
|
|
||||||
[encoder setRenderPipelineState:_copyPipeline];
|
[encoder setRenderPipelineState:_supersamplePipeline];
|
||||||
[encoder setVertexTexture:_frameBuffer atIndex:0];
|
[encoder setVertexTexture:_frameBuffer atIndex:0];
|
||||||
[encoder setFragmentTexture:_frameBuffer atIndex:0];
|
[encoder setFragmentTexture:_frameBuffer atIndex:0];
|
||||||
|
|
||||||
|
@@ -390,6 +390,19 @@ DeclareShaders(Red4Green4Blue4, ushort)
|
|||||||
DeclareShaders(Red2Green2Blue2, ushort)
|
DeclareShaders(Red2Green2Blue2, ushort)
|
||||||
DeclareShaders(Red1Green1Blue1, 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)]]) {
|
fragment half4 copyFragment(CopyInterpolator vert [[stage_in]], texture2d<half> texture [[texture(0)]]) {
|
||||||
return texture.sample(standardSampler, vert.textureCoordinates);
|
return texture.sample(standardSampler, vert.textureCoordinates);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user