From 5f48359cc72977e63f041e680c0fe8b9ff3833dc Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 21 Jan 2018 13:07:34 -1000 Subject: [PATCH] macOS fixes --- lib/graphicsdev/Common.cpp | 1 + lib/graphicsdev/GL.cpp | 2 - lib/graphicsdev/Metal.mm | 269 ++++++++++++++++++++++++++++--------- lib/mac/WindowCocoa.mm | 5 +- test/main.cpp | 2 +- 5 files changed, 212 insertions(+), 67 deletions(-) diff --git a/lib/graphicsdev/Common.cpp b/lib/graphicsdev/Common.cpp index 0105056..e0a696e 100644 --- a/lib/graphicsdev/Common.cpp +++ b/lib/graphicsdev/Common.cpp @@ -1,4 +1,5 @@ #include "Common.hpp" +#include namespace boo { diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index e9ed53a..117b964 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -1321,8 +1321,6 @@ struct GLCommandQueue : IGraphicsCommandQueue { std::unique_lock lk(self->m_initmt); self->m_parent->makeCurrent(); - //if (glewInit() != GLEW_OK) - // Log.report(logvisor::Fatal, "unable to init glew"); const GLubyte* version = glGetString(GL_VERSION); Log.report(logvisor::Info, "OpenGL Version: %s", version); self->m_parent->postInit(); diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 7864340..f622ad1 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -17,6 +17,50 @@ #define MAX_UNIFORM_COUNT 8 #define MAX_TEXTURE_COUNT 8 +static const char* GammaVS = +"#include \n" +"using namespace metal;\n" +"struct VertData\n" +"{\n" +" float4 posIn [[ attribute(0) ]];\n" +" float4 uvIn [[ attribute(1) ]];\n" +"};\n" +"\n" +"struct VertToFrag\n" +"{\n" +" float4 pos [[ position ]];\n" +" float2 uv;\n" +"};\n" +"\n" +"vertex VertToFrag vmain(VertData v [[ stage_in ]])\n" +"{\n" +" VertToFrag vtf;\n" +" vtf.uv = v.uvIn.xy;\n" +" vtf.pos = v.posIn;\n" +" return vtf;\n" +"}\n"; + +static const char* GammaFS = +"#include \n" +"using namespace metal;\n" +"struct VertToFrag\n" +"{\n" +" float4 pos [[ position ]];\n" +" float2 uv;\n" +"};\n" +"\n" +"fragment float4 fmain(VertToFrag vtf [[ stage_in ]],\n" +" sampler clampSamp [[ sampler(2) ]],\n" +" texture2d screenTex [[ texture(0) ]],\n" +" texture2d gammaLUT [[ texture(1) ]])\n" +"{\n" +" uint4 tex = uint4(saturate(screenTex.sample(clampSamp, vtf.uv)) * float4(65535.0));\n" +" float4 colorOut;\n" +" for (int i=0 ; i<3 ; ++i)\n" +" colorOut[i] = gammaLUT.read(uint2(tex[i] % 256, tex[i] / 256)).r;\n" +" return colorOut;\n" +"}\n"; + namespace boo { static logvisor::Module Log("boo::Metal"); @@ -38,6 +82,43 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory std::unordered_map> m_sharedShaders; struct MetalContext* m_ctx; + float m_gamma = 1.f; + ObjToken m_gammaShader; + ObjToken m_gammaLUT; + ObjToken m_gammaVBO; + ObjToken m_gammaVFMT; + ObjToken m_gammaBinding; + void SetupGammaResources() + { + commitTransaction([this](IGraphicsDataFactory::Context& ctx) + { + const VertexElementDescriptor vfmt[] = { + {nullptr, nullptr, VertexSemantic::Position4}, + {nullptr, nullptr, VertexSemantic::UV4} + }; + m_gammaVFMT = ctx.newVertexFormat(2, vfmt); + m_gammaShader = static_cast(ctx).newShaderPipeline(GammaVS, GammaFS, + nullptr, nullptr, m_gammaVFMT, BlendFactor::One, BlendFactor::Zero, + Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None); + m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); + setDisplayGamma(1.f); + const struct Vert { + float pos[4]; + float uv[4]; + } verts[4] = { + {{-1.f, -1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, + {{ 1.f, -1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, + {{-1.f, 1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, + {{ 1.f, 1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}} + }; + m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); + ObjToken texs[] = {{}, m_gammaLUT.get()}; + m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVFMT, m_gammaVBO.get(), {}, {}, + 0, nullptr, nullptr, 2, texs, nullptr, nullptr); + return true; + }); + } + public: std::unordered_map m_sourceToBinary; char m_libfile[MAXPATHLEN]; @@ -201,6 +282,16 @@ public: } return 0; } + + void setDisplayGamma(float gamma) + { + if (m_ctx->m_pixelFormat == MTLPixelFormatRGBA16Float) + m_gamma = gamma * 2.2f; + else + m_gamma = gamma; + if (m_gamma != 1.f) + UpdateGammaLUT(m_gammaLUT.get(), m_gamma); + } }; #define MTL_STATIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeManaged @@ -296,6 +387,11 @@ class MetalTextureS : public GraphicsDataNode ppitchNum = 1; bytesPerRow = width * ppitchNum; break; + case TextureFormat::I16: + pfmt = MTLPixelFormatR16Unorm; + ppitchNum = 2; + bytesPerRow = width * ppitchNum; + break; case TextureFormat::DXT1: pfmt = MTLPixelFormatBC1_RGBA; ppitchNum = 1; @@ -352,6 +448,10 @@ class MetalTextureSA : public GraphicsDataNode pfmt = MTLPixelFormatR8Unorm; ppitch = 1; break; + case TextureFormat::I16: + pfmt = MTLPixelFormatR16Unorm; + ppitch = 2; + break; default: break; } @@ -417,6 +517,10 @@ class MetalTextureD : public GraphicsDataNode format = MTLPixelFormatR8Unorm; m_pxPitch = 1; break; + case TextureFormat::I16: + format = MTLPixelFormatR16Unorm; + m_pxPitch = 2; + break; default: Log.report(logvisor::Fatal, "unsupported tex format"); } @@ -1061,6 +1165,11 @@ struct MetalCommandQueue : IGraphicsCommandQueue } } + void startRenderer() + { + static_cast(m_parent->getDataFactory())->SetupGammaResources(); + } + void stopRenderer() { m_running = false; @@ -1212,6 +1321,54 @@ struct MetalCommandQueue : IGraphicsCommandQueue baseInstance:m_boundData->m_baseInst]; } + void _resolveBindTexture(MetalTextureR* tex, const SWindowRect& rect, bool tlOrigin, + int bindIdx, bool color, bool depth) + { + if (tex->samples() > 1) + { + if (color && tex->m_colorBindTex[bindIdx]) + [[m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_blitColor[bindIdx]] endEncoding]; + if (depth && tex->m_depthBindTex[bindIdx]) + [[m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_blitDepth[bindIdx]] endEncoding]; + } + else + { + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height)); + NSUInteger y = tlOrigin ? intersectRect.location[1] : int(tex->m_height) - + intersectRect.location[1] - intersectRect.size[1]; + MTLOrigin origin = {NSUInteger(intersectRect.location[0]), y, 0}; + id blitEnc = [m_cmdBuf blitCommandEncoder]; + + if (color && tex->m_colorBindTex[bindIdx]) + { + [blitEnc copyFromTexture:tex->m_colorTex + sourceSlice:0 + sourceLevel:0 + sourceOrigin:origin + sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1) + toTexture:tex->m_colorBindTex[bindIdx] + destinationSlice:0 + destinationLevel:0 + destinationOrigin:origin]; + } + + if (depth && tex->m_depthBindTex[bindIdx]) + { + [blitEnc copyFromTexture:tex->m_depthTex + sourceSlice:0 + sourceLevel:0 + sourceOrigin:origin + sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1) + toTexture:tex->m_depthBindTex[bindIdx] + destinationSlice:0 + destinationLevel:0 + destinationOrigin:origin]; + } + + [blitEnc endEncoding]; + } + } + void resolveBindTexture(const ObjToken& texture, const SWindowRect& rect, bool tlOrigin, int bindIdx, bool color, bool depth, bool clearDepth) { @@ -1220,49 +1377,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue { [m_enc endEncoding]; - if (tex->samples() > 1) - { - if (color && tex->m_colorBindTex[bindIdx]) - [[m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_blitColor[bindIdx]] endEncoding]; - if (depth && tex->m_depthBindTex[bindIdx]) - [[m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_blitDepth[bindIdx]] endEncoding]; - } - else - { - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height)); - NSUInteger y = tlOrigin ? intersectRect.location[1] : int(tex->m_height) - - intersectRect.location[1] - intersectRect.size[1]; - MTLOrigin origin = {NSUInteger(intersectRect.location[0]), y, 0}; - id blitEnc = [m_cmdBuf blitCommandEncoder]; - - if (color && tex->m_colorBindTex[bindIdx]) - { - [blitEnc copyFromTexture:tex->m_colorTex - sourceSlice:0 - sourceLevel:0 - sourceOrigin:origin - sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1) - toTexture:tex->m_colorBindTex[bindIdx] - destinationSlice:0 - destinationLevel:0 - destinationOrigin:origin]; - } - - if (depth && tex->m_depthBindTex[bindIdx]) - { - [blitEnc copyFromTexture:tex->m_depthTex - sourceSlice:0 - sourceLevel:0 - sourceOrigin:origin - sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1) - toTexture:tex->m_depthBindTex[bindIdx] - destinationSlice:0 - destinationLevel:0 - destinationOrigin:origin]; - } - - [blitEnc endEncoding]; - } + _resolveBindTexture(tex, rect, tlOrigin, bindIdx, color, depth); m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:clearDepth ? tex->m_clearDepthPassDesc : tex->m_passDesc]; [m_enc setFrontFacingWinding:MTLWindingCounterClockwise]; @@ -1282,6 +1397,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue bool m_inProgress = false; std::unordered_map m_resolvePasses; + std::unordered_map m_gammaPasses; void execute() { if (!m_running) @@ -1357,34 +1473,61 @@ struct MetalCommandQueue : IGraphicsCommandQueue if (src->m_colorTex.width == dest.width && src->m_colorTex.height == dest.height) { - if (src->samples() > 1) + if (gfxF->m_gamma != 1.f) { - uintptr_t key = uintptr_t(src->m_colorTex) ^ uintptr_t(dest); - auto passSearch = m_resolvePasses.find(key); - if (passSearch == m_resolvePasses.end()) + SWindowRect rect(0, 0, src->m_width, src->m_height); + _resolveBindTexture(src, rect, true, 0, true, false); + + uintptr_t key = uintptr_t(dest); + auto passSearch = m_gammaPasses.find(key); + if (passSearch == m_gammaPasses.end()) { MTLRenderPassDescriptor* desc = [MTLRenderPassDescriptor renderPassDescriptor]; - desc.colorAttachments[0].texture = src->m_colorTex; + desc.colorAttachments[0].texture = dest; desc.colorAttachments[0].loadAction = MTLLoadActionLoad; - desc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve; - desc.colorAttachments[0].resolveTexture = dest; - passSearch = m_resolvePasses.insert(std::make_pair(key, desc)).first; + desc.colorAttachments[0].storeAction = MTLStoreActionStore; + passSearch = m_gammaPasses.insert(std::make_pair(key, desc)).first; } - [[m_cmdBuf renderCommandEncoderWithDescriptor:passSearch->second] endEncoding]; + + id enc = [m_cmdBuf renderCommandEncoderWithDescriptor:passSearch->second]; + MetalShaderDataBinding* gammaBinding = gfxF->m_gammaBinding.cast(); + gammaBinding->m_texs[0].tex = m_needsDisplay.get(); + gammaBinding->bind(enc, m_drawBuf); + [enc drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4]; + gammaBinding->m_texs[0].tex.reset(); + [enc endEncoding]; } else { - id blitEnc = [m_cmdBuf blitCommandEncoder]; - [blitEnc copyFromTexture:src->m_colorTex - sourceSlice:0 - sourceLevel:0 - sourceOrigin:MTLOriginMake(0, 0, 0) - sourceSize:MTLSizeMake(dest.width, dest.height, 1) - toTexture:dest - destinationSlice:0 - destinationLevel:0 - destinationOrigin:MTLOriginMake(0, 0, 0)]; - [blitEnc endEncoding]; + if (src->samples() > 1) + { + uintptr_t key = uintptr_t(src->m_colorTex) ^ uintptr_t(dest); + auto passSearch = m_resolvePasses.find(key); + if (passSearch == m_resolvePasses.end()) + { + MTLRenderPassDescriptor* desc = [MTLRenderPassDescriptor renderPassDescriptor]; + desc.colorAttachments[0].texture = src->m_colorTex; + desc.colorAttachments[0].loadAction = MTLLoadActionLoad; + desc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve; + desc.colorAttachments[0].resolveTexture = dest; + passSearch = m_resolvePasses.insert(std::make_pair(key, desc)).first; + } + [[m_cmdBuf renderCommandEncoderWithDescriptor:passSearch->second] endEncoding]; + } + else + { + id blitEnc = [m_cmdBuf blitCommandEncoder]; + [blitEnc copyFromTexture:src->m_colorTex + sourceSlice:0 + sourceLevel:0 + sourceOrigin:MTLOriginMake(0, 0, 0) + sourceSize:MTLSizeMake(dest.width, dest.height, 1) + toTexture:dest + destinationSlice:0 + destinationLevel:0 + destinationOrigin:MTLOriginMake(0, 0, 0)]; + [blitEnc endEncoding]; + } } [m_cmdBuf presentDrawable:drawable]; } diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index 81dbcea..cdb06fd 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -266,6 +266,7 @@ public: CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkStart(m_dispLink); m_commandQueue = _NewGLCommandQueue(this, m_glCtx); + m_commandQueue->startRenderer(); return true; } @@ -351,6 +352,8 @@ IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api, major = glVersion[0] - '0'; minor = glVersion[2] - '0'; } + if (glewInit() != GLEW_OK) + Log.report(logvisor::Fatal, "glewInit failed"); [NSOpenGLContext clearCurrentContext]; if (!glVersion) return NULL; @@ -428,6 +431,7 @@ public: CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkStart(m_dispLink); m_commandQueue = _NewMetalCommandQueue(m_metalCtx, m_parentWindow, this); + m_commandQueue->startRenderer(); return true; } @@ -1244,7 +1248,6 @@ static boo::ESpecialKey translateKeycode(short code) CAMetalLayer* layer = [CAMetalLayer new]; layer.device = m_ctx->m_dev; layer.pixelFormat = m_ctx->m_pixelFormat; - layer.colorspace = CGColorSpaceCreateDeviceRGB(); layer.framebufferOnly = NO; return layer; } diff --git a/test/main.cpp b/test/main.cpp index 1896a87..1ffc3de 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -463,7 +463,7 @@ struct TestApplicationCallback : IApplicationCallback "using namespace metal;\n" "struct VertToFrag {float4 out_pos [[ position ]]; float2 out_uv;};\n" "fragment float4 fmain(VertToFrag d [[ stage_in ]],\n" - " sampler samp [[ sampler(0) ]],\n" + " sampler samp [[ sampler(2) ]],\n" " texture2d tex [[ texture(0) ]])\n" "{\n" " return tex.sample(samp, d.out_uv);\n"