diff --git a/.gitmodules b/.gitmodules index 20dff78..6195055 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,9 @@ [submodule "logvisor"] path = logvisor url = ../logvisor.git -[submodule "lib/graphicsdev/NX/mesa"] +[submodule "lib/graphicsdev/nx/mesa"] path = lib/graphicsdev/nx/mesa url = ../mesa.git -[submodule "lib/graphicsdev/NX/libdrm_nouveau"] +[submodule "lib/graphicsdev/nx/libdrm_nouveau"] path = lib/graphicsdev/nx/libdrm_nouveau url = https://github.com/devkitPro/libdrm_nouveau.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 23f1579..68364f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if(TARGET nx_compiler) list(APPEND _BOO_SYS_DEFINES -DHECL_NOUVEAU_NX=1) endif() -if(NOT GEKKO AND NOT CAFE AND NOT WINDOWS_STORE AND NOT NX) +if(NOT GEKKO AND NOT CAFE AND NOT WINDOWS_STORE AND NOT NX AND NOT APPLE) list(APPEND PLAT_SRCS lib/graphicsdev/GL.cpp lib/graphicsdev/glew.c) @@ -137,7 +137,6 @@ elseif(APPLE) find_library(APPKIT_LIBRARY AppKit) find_library(IOKIT_LIBRARY IOKit) - find_library(OPENGL_LIBRARY OpenGL) unset(BOO_HAS_METAL CACHE) if (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.11) set(BOO_HAS_METAL ON CACHE BOOL "Metal is available in this OS X version" FORCE) @@ -151,10 +150,11 @@ elseif(APPLE) find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox) find_library(COREAUDIO_LIBRARY CoreAudio) find_library(COREMIDI_LIBRARY CoreMIDI) - list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY} ${METAL_LIBRARY} + list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY} ${COREVIDEO_LIBRARY} ${AUDIOTOOLBOX_LIBRARY} ${COREAUDIO_LIBRARY} ${COREMIDI_LIBRARY}) + add_library(glew lib/graphicsdev/glew.c) elseif(NX) list(APPEND _BOO_SYS_DEFINES -DBOO_HAS_NX=1) list(APPEND PLAT_SRCS diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp index f282080..5191460 100644 --- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp +++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "boo/System.hpp" #include "boo/ThreadLocalPtr.hpp" #include "boo/BooObject.hpp" diff --git a/include/boo/graphicsdev/Metal.hpp b/include/boo/graphicsdev/Metal.hpp index 0cbdb55..c7e5cdf 100644 --- a/include/boo/graphicsdev/Metal.hpp +++ b/include/boo/graphicsdev/Metal.hpp @@ -37,36 +37,15 @@ public: ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, size_t colorBindCount, size_t depthBindCount); - bool bindingNeedsVertexFormat() const { return false; } - ObjToken newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, - size_t baseVert = 0, size_t baseInst = 0); + ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); - ObjToken newShaderPipeline(const char* vertSource, const char* fragSource, - std::vector* vertBlobOut, - std::vector* fragBlobOut, - const ObjToken& vtxFmt, - BlendFactor srcFac, BlendFactor dstFac, Primitive prim, - ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, - bool overwriteAlpha = true, - bool depthAttachment = true); - - ObjToken newTessellationShaderPipeline( - const char* computeSource, const char* fragSource, - const char* evaluationSource, - std::vector* computeBlobOut, - std::vector* fragBlobOut, - std::vector* evaluationBlobOut, - const ObjToken& vtxFmt, - BlendFactor srcFac, BlendFactor dstFac, uint32_t patchSize, - ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, - bool overwriteAlpha = true, - bool depthAttachment = true); + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo); ObjToken newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vtxFormat, const ObjToken& vbo, const ObjToken& instVbo, const ObjToken& ibo, @@ -76,6 +55,8 @@ public: const int* texBindIdxs, const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0); }; + + static std::vector CompileMetal(const char* source, PipelineStage stage); }; } diff --git a/include/boo/inputdev/DeviceSignature.hpp b/include/boo/inputdev/DeviceSignature.hpp index b3d1b88..9945fd1 100644 --- a/include/boo/inputdev/DeviceSignature.hpp +++ b/include/boo/inputdev/DeviceSignature.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace boo { diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 844b0b6..ffa5113 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -67,19 +67,11 @@ static logvisor::Module Log("boo::Metal"); struct MetalCommandQueue; class MetalDataFactoryImpl; -struct MetalShareableShader : IShareableShader -{ - id m_shader; - MetalShareableShader(MetalDataFactoryImpl& fac, uint64_t srcKey, uint64_t binKey, id s) - : IShareableShader(fac, srcKey, binKey), m_shader(s) {} -}; - class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactoryHead { friend struct MetalCommandQueue; friend class MetalDataFactory::Context; IGraphicsContext* m_parent; - std::unordered_map> m_sharedShaders; struct MetalContext* m_ctx; bool m_hasTessellation = false; @@ -88,7 +80,6 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory ObjToken m_gammaShader; ObjToken m_gammaLUT; ObjToken m_gammaVBO; - ObjToken m_gammaVFMT; ObjToken m_gammaBinding; void SetupGammaResources() { @@ -96,14 +87,20 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory commitTransaction([this](IGraphicsDataFactory::Context& ctx) { + auto vertexMetal = MetalDataFactory::CompileMetal(GammaVS, PipelineStage::Vertex); + auto vertexShader = ctx.newShaderStage(vertexMetal, PipelineStage::Vertex); + auto fragmentMetal = MetalDataFactory::CompileMetal(GammaFS, PipelineStage::Fragment); + auto fragmentShader = ctx.newShaderStage(fragmentMetal, PipelineStage::Fragment); const VertexElementDescriptor vfmt[] = { - {nullptr, nullptr, VertexSemantic::Position4}, - {nullptr, nullptr, VertexSemantic::UV4} + {VertexSemantic::Position4}, + {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, true, false); + AdditionalPipelineInfo info = + { + BlendFactor::One, BlendFactor::Zero, + Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None + }; + m_gammaShader = ctx.newShaderPipeline(vertexShader, fragmentShader, vfmt, info); m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); setDisplayGamma(1.f); const struct Vert { @@ -117,242 +114,22 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory }; 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(), {}, {}, + m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, 0, nullptr, nullptr, 2, texs, nullptr, nullptr); return true; } BooTrace); } public: - std::unordered_map m_sourceToBinary; - char m_libfile[MAXPATHLEN]; - bool m_hasCompiler = false; MetalDataFactoryImpl(IGraphicsContext* parent, MetalContext* ctx) - : m_parent(parent), m_ctx(ctx) - { - snprintf(m_libfile, MAXPATHLEN, "%sboo_metal_shader.metallib", getenv("TMPDIR")); - for (auto& arg : APP->getArgs()) - if (arg == "--metal-compile") - { - m_hasCompiler = CheckForMetalCompiler(); - break; - } - } + : m_parent(parent), m_ctx(ctx) {} ~MetalDataFactoryImpl() = default; Platform platform() const { return Platform::Metal; } const char* platformName() const { return "Metal"; } void commitTransaction(const std::function& __BooTraceArgs); ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); - void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) { m_sharedShaders.erase(srcKey); } - - static bool CheckForMetalCompiler() - { - pid_t pid = fork(); - if (!pid) - { - execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", NULL); - /* xcrun returns 72 if metal command not found; - * emulate that if xcrun not found */ - exit(72); - } - - int status, ret; - while ((ret = waitpid(pid, &status, 0)) < 0 && errno == EINTR) {} - if (ret < 0) - return false; - return WEXITSTATUS(status) == 1; - } - - uint64_t CompileLib(std::vector& blobOut, const char* source, uint64_t srcKey) - { - if (!m_hasCompiler) - { - /* Cache the source if there's no compiler */ - size_t sourceLen = strlen(source); - - /* First byte unset to indicate source data */ - blobOut.resize(sourceLen + 2); - memcpy(&blobOut[1], source, sourceLen); - } - else - { - /* Cache the binary otherwise */ - int compilerOut[2]; - int compilerIn[2]; - pipe(compilerOut); - pipe(compilerIn); - - /* Pipe source write to compiler */ - pid_t compilerPid = fork(); - if (!compilerPid) - { - dup2(compilerIn[0], STDIN_FILENO); - dup2(compilerOut[1], STDOUT_FILENO); - - close(compilerOut[0]); - close(compilerOut[1]); - close(compilerIn[0]); - close(compilerIn[1]); - - execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "-o", "/dev/stdout", "-Wno-unused-variable", - "-Wno-unused-const-variable", "-Wno-unused-function", "-x", "metal", "-", NULL); - fprintf(stderr, "execlp fail %s\n", strerror(errno)); - exit(1); - } - close(compilerIn[0]); - close(compilerOut[1]); - - /* Pipe compiler to linker */ - pid_t linkerPid = fork(); - if (!linkerPid) - { - dup2(compilerOut[0], STDIN_FILENO); - - close(compilerOut[0]); - close(compilerIn[1]); - - /* metallib doesn't like outputting to a pipe, so temp file will have to do */ - execlp("xcrun", "xcrun", "-sdk", "macosx", "metallib", "-", "-o", m_libfile, NULL); - fprintf(stderr, "execlp fail %s\n", strerror(errno)); - exit(1); - } - close(compilerOut[0]); - - /* Stream in source */ - const char* inPtr = source; - size_t inRem = strlen(source); - while (inRem) - { - ssize_t writeRes = write(compilerIn[1], inPtr, inRem); - if (writeRes < 0) - { - fprintf(stderr, "write fail %s\n", strerror(errno)); - break; - } - inPtr += writeRes; - inRem -= writeRes; - } - close(compilerIn[1]); - - /* Wait for completion */ - int compilerStat, linkerStat; - if (waitpid(compilerPid, &compilerStat, 0) < 0 || waitpid(linkerPid, &linkerStat, 0) < 0) - { - fprintf(stderr, "waitpid fail %s\n", strerror(errno)); - return 0; - } - - if (WEXITSTATUS(compilerStat) || WEXITSTATUS(linkerStat)) - return 0; - - /* Copy temp file into buffer with first byte set to indicate binary data */ - FILE* fin = fopen(m_libfile, "rb"); - fseek(fin, 0, SEEK_END); - long libLen = ftell(fin); - fseek(fin, 0, SEEK_SET); - blobOut.resize(libLen + 1); - blobOut[0] = 1; - fread(&blobOut[1], 1, libLen, fin); - fclose(fin); - } - - XXH64_state_t hashState; - XXH64_reset(&hashState, 0); - XXH64_update(&hashState, blobOut.data(), blobOut.size()); - uint64_t binKey = XXH64_digest(&hashState); - m_sourceToBinary[srcKey] = binKey; - return binKey; - } - - uint64_t CompileLib(__strong id& libOut, const char* source, uint64_t srcKey, - MTLCompileOptions* compOpts, NSError * _Nullable *err) - { - libOut = [m_ctx->m_dev newLibraryWithSource:@(source) - options:compOpts - error:err]; - - if (srcKey) - { - XXH64_state_t hashState; - XXH64_reset(&hashState, 0); - uint8_t zero = 0; - XXH64_update(&hashState, &zero, 1); - XXH64_update(&hashState, source, strlen(source) + 1); - uint64_t binKey = XXH64_digest(&hashState); - m_sourceToBinary[srcKey] = binKey; - return binKey; - } - return 0; - } - - MetalShareableShader::Token PrepareShaderStage(const char* source, std::vector* blobOut, NSString* funcName) - { - MTLCompileOptions* compOpts = [MTLCompileOptions new]; - compOpts.languageVersion = MTLLanguageVersion1_2; - NSError* err = nullptr; - - XXH64_state_t hashState; - uint64_t srcHash = 0; - uint64_t binHash = 0; - XXH64_reset(&hashState, 0); - if (source) - { - XXH64_update(&hashState, source, strlen(source)); - srcHash = XXH64_digest(&hashState); - auto binSearch = m_sourceToBinary.find(srcHash); - if (binSearch != m_sourceToBinary.cend()) - binHash = binSearch->second; - } - else if (blobOut && !blobOut->empty()) - { - XXH64_update(&hashState, blobOut->data(), blobOut->size()); - binHash = XXH64_digest(&hashState); - } - - if (blobOut && blobOut->empty()) - binHash = CompileLib(*blobOut, source, srcHash); - - MetalShareableShader::Token shader; - auto search = binHash ? m_sharedShaders.find(binHash) : m_sharedShaders.end(); - if (search != m_sharedShaders.end()) - { - return search->second->lock(); - } - else - { - id shaderLib; - if (blobOut && !blobOut->empty()) - { - if ((*blobOut)[0] == 1) - { - dispatch_data_t data = dispatch_data_create(blobOut->data() + 1, blobOut->size() - 1, nullptr, nullptr); - shaderLib = [m_ctx->m_dev newLibraryWithData:data error:&err]; - if (!shaderLib) - Log.report(logvisor::Fatal, "error loading library: %s", [[err localizedDescription] UTF8String]); - } - else - { - CompileLib(shaderLib, (char*)blobOut->data() + 1, 0, compOpts, &err); - } - } - else - binHash = CompileLib(shaderLib, source, srcHash, compOpts, &err); - - if (!shaderLib) - { - printf("%s\n", source); - Log.report(logvisor::Fatal, "error compiling shader: %s", [[err localizedDescription] UTF8String]); - } - id func = [shaderLib newFunctionWithName:funcName]; - - auto it = - m_sharedShaders.emplace(std::make_pair(binHash, - std::make_unique(*this, srcHash, binHash, func))).first; - return it->second->lock(); - } - } void setDisplayGamma(float gamma) { @@ -855,15 +632,14 @@ static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] = MTLVertexFormatFloat4 }; -struct MetalVertexFormat : GraphicsDataNode +struct MetalVertexFormat { size_t m_elementCount; MTLVertexDescriptor* m_vdesc; size_t m_stride = 0; size_t m_instStride = 0; - MetalVertexFormat(const ObjToken& parent, - size_t elementCount, const VertexElementDescriptor* elements) - : GraphicsDataNode(parent), m_elementCount(elementCount) + MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements) + : m_elementCount(elementCount) { for (size_t i=0 ; i } } - MTLStageInputOutputDescriptor* makeTessellationComputeLayout() + MTLStageInputOutputDescriptor* makeTessellationComputeLayout() const { MTLStageInputOutputDescriptor* ret = [MTLStageInputOutputDescriptor stageInputOutputDescriptor]; @@ -930,7 +706,7 @@ struct MetalVertexFormat : GraphicsDataNode return ret; } - MTLVertexDescriptor* makeTessellationVertexLayout() + MTLVertexDescriptor* makeTessellationVertexLayout() const { MTLVertexDescriptor* ret = [MTLVertexDescriptor vertexDescriptor]; @@ -982,6 +758,56 @@ static const MTLPrimitiveType PRIMITIVE_TABLE[] = #define COLOR_WRITE_MASK (MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue) +class MetalShaderStage : public GraphicsDataNode +{ + friend class MetalDataFactory; + id m_shader; + MetalShaderStage(const boo::ObjToken& parent, MetalContext* ctx, + const uint8_t* data, size_t size, PipelineStage stage) + : GraphicsDataNode(parent) + { + NSError* err = nullptr; + + id shaderLib; + if (data[0] == 1) + { + dispatch_data_t d = dispatch_data_create(data + 1, size - 1, nullptr, nullptr); + shaderLib = [ctx->m_dev newLibraryWithData:d error:&err]; + } + else + { + MTLCompileOptions* compOpts = [MTLCompileOptions new]; + compOpts.languageVersion = MTLLanguageVersion1_2; + shaderLib = [ctx->m_dev newLibraryWithSource:@((const char*)(data + 1)) + options:compOpts + error:&err]; + if (!shaderLib) + printf("%s\n", data + 1); + } + if (!shaderLib) + Log.report(logvisor::Fatal, "error creating library: %s", [[err localizedDescription] UTF8String]); + + NSString* funcName; + switch (stage) + { + case PipelineStage::Vertex: + default: + funcName = @"vmain"; break; + case PipelineStage::Fragment: + funcName = @"fmain"; break; + case PipelineStage::Geometry: + funcName = @"gmain"; break; + case PipelineStage::Control: + funcName = @"cmain"; break; + case PipelineStage::Evaluation: + funcName = @"emain"; break; + } + m_shader = [shaderLib newFunctionWithName:funcName]; + } +public: + id shader() const { return m_shader; } +}; + class MetalShaderPipeline : public GraphicsDataNode { protected: @@ -990,17 +816,13 @@ protected: friend struct MetalShaderDataBinding; MTLCullMode m_cullMode = MTLCullModeNone; MTLPrimitiveType m_drawPrim; - MetalShareableShader::Token m_vert; - MetalShareableShader::Token m_frag; + uint32_t m_patchSize; - MetalShaderPipeline(const ObjToken& parent, - MetalShareableShader::Token&& vert, - MetalShareableShader::Token&& frag) - : GraphicsDataNode(parent), - m_vert(std::move(vert)), m_frag(std::move(frag)) - {} + MetalShaderPipeline(const boo::ObjToken& parent) + : GraphicsDataNode(parent) {} - virtual void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc, MetalVertexFormat& cVtxFmt) {} + virtual void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc, + ObjToken compute, const MetalVertexFormat& cVtxFmt) {} virtual void draw(MetalCommandQueue& q, size_t start, size_t count); virtual void drawIndexed(MetalCommandQueue& q, size_t start, size_t count); @@ -1008,15 +830,17 @@ protected: virtual void drawInstancesIndexed(MetalCommandQueue& q, size_t start, size_t count, size_t instCount); void setup(MetalContext* ctx, - const ObjToken& vtxFmt, NSUInteger targetSamples, - BlendFactor srcFac, BlendFactor dstFac, Primitive prim, - ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, bool overwriteAlpha, CullMode culling, - bool depthAttachment = true) + NSUInteger targetSamples, + ObjToken vertex, + ObjToken fragment, + ObjToken compute, + const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& info) { - m_drawPrim = PRIMITIVE_TABLE[int(prim)]; + m_drawPrim = PRIMITIVE_TABLE[int(info.prim)]; + m_patchSize = info.patchSize; - switch (culling) + switch (info.culling) { case CullMode::None: default: @@ -1031,22 +855,22 @@ protected: } MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new]; - desc.vertexFunction = m_vert.get().m_shader; - desc.fragmentFunction = m_frag.get().m_shader; - MetalVertexFormat& cVtxFmt = *vtxFmt.cast(); + desc.vertexFunction = vertex.cast()->shader(); + desc.fragmentFunction = fragment.cast()->shader(); + MetalVertexFormat cVtxFmt(vtxFmt.elementCount, vtxFmt.elements); desc.vertexDescriptor = cVtxFmt.m_vdesc; - setupExtraStages(ctx, desc, cVtxFmt); + setupExtraStages(ctx, desc, compute, cVtxFmt); desc.sampleCount = targetSamples; desc.colorAttachments[0].pixelFormat = ctx->m_pixelFormat; - desc.colorAttachments[0].writeMask = (colorWrite ? COLOR_WRITE_MASK : 0) | - (alphaWrite ? MTLColorWriteMaskAlpha : 0); - desc.colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero; - if (srcFac == BlendFactor::Subtract || dstFac == BlendFactor::Subtract) + desc.colorAttachments[0].writeMask = (info.colorWrite ? COLOR_WRITE_MASK : 0) | + (info.alphaWrite ? MTLColorWriteMaskAlpha : 0); + desc.colorAttachments[0].blendingEnabled = info.dstFac != BlendFactor::Zero; + if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract) { desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationReverseSubtract; - if (overwriteAlpha) + if (info.overwriteAlpha) { desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; @@ -1061,22 +885,22 @@ protected: } else { - desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; - desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; + desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(info.srcFac)]; + desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(info.dstFac)]; desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - if (overwriteAlpha) + if (info.overwriteAlpha) { desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; } else { - desc.colorAttachments[0].sourceAlphaBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; - desc.colorAttachments[0].destinationAlphaBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; + desc.colorAttachments[0].sourceAlphaBlendFactor = BLEND_FACTOR_TABLE[int(info.srcFac)]; + desc.colorAttachments[0].destinationAlphaBlendFactor = BLEND_FACTOR_TABLE[int(info.dstFac)]; } desc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; } - desc.depthAttachmentPixelFormat = depthAttachment ? MTLPixelFormatDepth32Float : MTLPixelFormatInvalid; + desc.depthAttachmentPixelFormat = info.depthAttachment ? MTLPixelFormatDepth32Float : MTLPixelFormatInvalid; desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle; NSError* err = nullptr; m_state = [ctx->m_dev newRenderPipelineStateWithDescriptor:desc error:&err]; @@ -1085,7 +909,7 @@ protected: [[err localizedDescription] UTF8String]); MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; - switch (depthTest) + switch (info.depthTest) { case ZTest::None: default: @@ -1105,7 +929,7 @@ protected: break; } - dsDesc.depthWriteEnabled = depthWrite; + dsDesc.depthWriteEnabled = info.depthWrite; m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc]; } @@ -1129,20 +953,12 @@ class MetalTessellationShaderPipeline : public MetalShaderPipeline friend class MetalDataFactory; friend struct MetalCommandQueue; friend struct MetalShaderDataBinding; - MetalShareableShader::Token m_compute; - uint32_t m_patchSize; - MetalTessellationShaderPipeline( - const ObjToken& parent, - MetalShareableShader::Token&& compute, - MetalShareableShader::Token&& frag, - MetalShareableShader::Token&& evaluation, - uint32_t patchSize) - : MetalShaderPipeline(parent, std::move(evaluation), std::move(frag)), - m_compute(std::move(compute)), m_patchSize(patchSize) - {} + MetalTessellationShaderPipeline(const ObjToken& parent) + : MetalShaderPipeline(parent) {} - void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc, MetalVertexFormat& cVtxFmt) + void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc, + ObjToken compute, const MetalVertexFormat& cVtxFmt) { desc.maxTessellationFactor = 16; desc.tessellationFactorScaleEnabled = NO; @@ -1154,7 +970,7 @@ class MetalTessellationShaderPipeline : public MetalShaderPipeline desc.vertexDescriptor = cVtxFmt.makeTessellationVertexLayout(); MTLComputePipelineDescriptor* compDesc = [MTLComputePipelineDescriptor new]; - compDesc.computeFunction = m_compute.get().m_shader; + compDesc.computeFunction = compute.cast()->shader(); compDesc.stageInputDescriptor = cVtxFmt.makeTessellationComputeLayout(); NSError* err = nullptr; @@ -1980,77 +1796,39 @@ MetalDataFactory::Context::newRenderTexture(size_t width, size_t height, Texture } } -ObjToken -MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, - size_t baseVert, size_t baseInst) +ObjToken +MetalDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) { @autoreleasepool { - return {new struct MetalVertexFormat(m_data, elementCount, elements)}; + MetalDataFactoryImpl& factory = static_cast(m_parent); + return {new MetalShaderStage(m_data, factory.m_ctx, data, size, stage)}; } } ObjToken -MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource, - std::vector* vertBlobOut, - std::vector* fragBlobOut, - const ObjToken& vtxFmt, - BlendFactor srcFac, BlendFactor dstFac, Primitive prim, - ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, bool overwriteAlpha, - bool depthAttachment) +MetalDataFactory::Context::newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo) { @autoreleasepool { MetalDataFactoryImpl& factory = static_cast(m_parent); - MetalShareableShader::Token vertShader = factory.PrepareShaderStage(vertSource, vertBlobOut, @"vmain"); - MetalShareableShader::Token fragShader = factory.PrepareShaderStage(fragSource, fragBlobOut, @"fmain"); - - MetalShaderPipeline* ret = new MetalShaderPipeline(m_data, std::move(vertShader), std::move(fragShader)); - ret->setup(factory.m_ctx, vtxFmt, depthAttachment ? factory.m_ctx->m_sampleCount : 1, - srcFac, dstFac, prim, depthTest, depthWrite, - colorWrite, alphaWrite, overwriteAlpha, culling, depthAttachment); - return {ret}; - } -} - -ObjToken MetalDataFactory::Context::newTessellationShaderPipeline( - const char* computeSource, const char* fragSource, - const char* evaluationSource, - std::vector* computeBlobOut, - std::vector* fragBlobOut, - std::vector* evaluationBlobOut, - const ObjToken& vtxFmt, - BlendFactor srcFac, BlendFactor dstFac, uint32_t patchSize, - ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, - bool overwriteAlpha, - bool depthAttachment) -{ - @autoreleasepool - { - MetalDataFactoryImpl& factory = static_cast(m_parent); - - if (!factory.m_hasTessellation) - Log.report(logvisor::Fatal, "Device does not support tessellation"); - - MetalShareableShader::Token computeShader = factory.PrepareShaderStage(computeSource, computeBlobOut, @"cmain"); - MetalShareableShader::Token fragShader = factory.PrepareShaderStage(fragSource, fragBlobOut, @"fmain"); - MetalShareableShader::Token evaluationShader = factory.PrepareShaderStage(evaluationSource, evaluationBlobOut, @"emain"); - - MetalTessellationShaderPipeline* ret = new MetalTessellationShaderPipeline(m_data, - std::move(computeShader), std::move(fragShader), std::move(evaluationShader), patchSize); - ret->setup(factory.m_ctx, vtxFmt, depthAttachment ? factory.m_ctx->m_sampleCount : 1, - srcFac, dstFac, Primitive::Patches, depthTest, depthWrite, - colorWrite, alphaWrite, overwriteAlpha, culling, depthAttachment); + MetalShaderPipeline* ret; + if (evaluation) + ret = new MetalTessellationShaderPipeline(m_data); + else + ret = new MetalShaderPipeline(m_data); + ret->setup(factory.m_ctx, additionalInfo.depthAttachment ? factory.m_ctx->m_sampleCount : 1, + vertex, fragment, evaluation, vtxFmt, additionalInfo); return {ret}; } } ObjToken MetalDataFactory::Context::newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vtxFormat, const ObjToken& vbo, const ObjToken& instVbo, const ObjToken& ibo, @@ -2095,6 +1873,14 @@ std::unique_ptr _NewMetalDataFactory(IGraphicsContext* par return std::make_unique(parent, ctx); } +std::vector MetalDataFactory::CompileMetal(const char* source, PipelineStage stage) +{ + size_t strSz = strlen(source) + 1; + std::vector ret(strSz + 1); + memcpy(ret.data() + 1, source, strSz); + return ret; +} + } #endif diff --git a/lib/mac/ApplicationCocoa.mm b/lib/mac/ApplicationCocoa.mm index e9d3631..813594d 100644 --- a/lib/mac/ApplicationCocoa.mm +++ b/lib/mac/ApplicationCocoa.mm @@ -3,7 +3,6 @@ #include "boo/IApplication.hpp" #include "boo/graphicsdev/Metal.hpp" -#include "boo/graphicsdev/GL.hpp" #include "CocoaCommon.hpp" #include "../Common.hpp" @@ -32,8 +31,7 @@ namespace boo { static logvisor::Module Log("boo::ApplicationCocoa"); -std::shared_ptr _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx, - MetalContext* metalCtx, GLContext* glCtx); +std::shared_ptr _WindowCocoaNew(SystemStringView title, MetalContext* metalCtx); class ApplicationCocoa : public IApplication { @@ -52,7 +50,9 @@ private: std::unordered_map> m_windows; MetalContext m_metalCtx; +#if 0 GLContext m_glCtx; +#endif void _deletedWindow(IWindow* window) { @@ -78,9 +78,11 @@ public: m_metalCtx.m_sampleCount = samples; m_metalCtx.m_anisotropy = anisotropy; m_metalCtx.m_pixelFormat = deepColor ? MTLPixelFormatRGBA16Float : MTLPixelFormatBGRA8Unorm; +#if 0 m_glCtx.m_sampleCount = samples; m_glCtx.m_anisotropy = anisotropy; m_glCtx.m_deepColor = deepColor; +#endif [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; @@ -104,38 +106,13 @@ public: action:nil keyEquivalent:@""] setSubmenu:appMenu]; [[NSApplication sharedApplication] setMainMenu:rootMenu]; - /* Determine which graphics API to use */ -#if BOO_HAS_METAL - bool useGL = false; - if (!gfxApi.compare("OpenGL")) - useGL = true; - for (const SystemString& arg : args) - { - if (!arg.compare("--gl")) - { - useGL = true; - break; - } - else if (!arg.compare("--metal")) - { - useGL = false; - break; - } - } - if (!useGL) - m_metalCtx.m_dev = MTLCreateSystemDefaultDevice(); - if (m_metalCtx.m_dev) - { - m_metalCtx.m_q = [m_metalCtx.m_dev newCommandQueue]; - while (![m_metalCtx.m_dev supportsTextureSampleCount:m_metalCtx.m_sampleCount]) - m_metalCtx.m_sampleCount = flp2(m_metalCtx.m_sampleCount - 1); - Log.report(logvisor::Info, "using Metal renderer"); - } - else - Log.report(logvisor::Info, "using OpenGL renderer"); -#else - Log.report(logvisor::Info, "using OpenGL renderer"); -#endif + m_metalCtx.m_dev = MTLCreateSystemDefaultDevice(); + if (!m_metalCtx.m_dev) + Log.report(logvisor::Fatal, "Unable to create metal device"); + m_metalCtx.m_q = [m_metalCtx.m_dev newCommandQueue]; + while (![m_metalCtx.m_dev supportsTextureSampleCount:m_metalCtx.m_sampleCount]) + m_metalCtx.m_sampleCount = flp2(m_metalCtx.m_sampleCount - 1); + Log.report(logvisor::Info, "using Metal renderer"); } EPlatformType getPlatformType() const @@ -214,19 +191,23 @@ public: std::shared_ptr newWindow(std::string_view title) { - auto newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx, &m_glCtx); + auto newWindow = _WindowCocoaNew(title, &m_metalCtx); m_windows[newWindow->getPlatformHandle()] = newWindow; return newWindow; } /* Last GL context */ +#if 0 NSOpenGLContext* m_lastGLCtx = nullptr; +#endif }; +#if 0 void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx) { static_cast(APP)->m_lastGLCtx = lastGLCtx; } +#endif IApplication* APP = nullptr; int ApplicationRun(IApplication::EPlatformType platform, diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index 9d72cf6..0714110 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -1,5 +1,3 @@ -#include "boo/graphicsdev/GL.hpp" -#include "boo/graphicsdev/glew.h" #include "boo/graphicsdev/Metal.hpp" #include "CocoaCommon.hpp" #import @@ -26,6 +24,7 @@ namespace boo {class WindowCocoa; class GraphicsContextCocoa;} - (void)setTouchBarProvider:(id)provider; @end +#if 0 /* AppKit applies OpenGL much differently than other platforms * the NSOpenGLView class composes together all necessary * OGL context members and provides the necessary event hooks @@ -95,6 +94,7 @@ static const NSOpenGLPixelFormatAttribute* PF_TABLE[] = PF_RGBAF32_ATTRS, PF_RGBAF32_Z24_ATTRS }; +#endif @interface BooCocoaResponder : NSResponder { @@ -155,10 +155,13 @@ public: } virtual BooCocoaResponder* responder() const=0; }; +#if 0 class GraphicsContextCocoaGL; +#endif class GraphicsContextCocoaMetal; } +#if 0 @interface GraphicsContextCocoaGLInternal : NSOpenGLView { @public @@ -166,6 +169,7 @@ class GraphicsContextCocoaMetal; } - (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx; @end +#endif @interface GraphicsContextCocoaMetalInternal : NSView { @@ -181,11 +185,14 @@ class GraphicsContextCocoaMetal; namespace boo { static logvisor::Module Log("boo::WindowCocoa"); +#if 0 std::unique_ptr _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx); std::unique_ptr _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx); +#endif std::unique_ptr _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsContext* parent); std::unique_ptr _NewMetalDataFactory(IGraphicsContext* parent, MetalContext* ctx); +#if 0 void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx); class GraphicsContextCocoaGL : public GraphicsContextCocoa @@ -349,6 +356,7 @@ IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api, return new GraphicsContextCocoaGL(api, parentWindow, lastGLCtx, glCtx); } +#endif #if BOO_HAS_METAL class GraphicsContextCocoaMetal : public GraphicsContextCocoa @@ -1147,6 +1155,7 @@ static boo::ESpecialKey translateKeycode(short code) @end +#if 0 @implementation GraphicsContextCocoaGLInternal - (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx { @@ -1203,6 +1212,7 @@ static boo::ESpecialKey translateKeycode(short code) } @end +#endif #if BOO_HAS_METAL @implementation GraphicsContextCocoaMetalInternal @@ -1299,23 +1309,16 @@ class WindowCocoa : public IWindow public: - void setup(std::string_view title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx, GLContext* glCtx) + void setup(std::string_view title, MetalContext* metalCtx) { dispatch_sync(dispatch_get_main_queue(), ^{ std::shared_ptr windowPtr = std::static_pointer_cast(shared_from_this()); m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:windowPtr title:title]; -#if BOO_HAS_METAL - if (metalCtx->m_dev) - m_gfxCtx = static_cast( - _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal, - this, metalCtx)); - else -#endif - m_gfxCtx = static_cast( - _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3, - this, lastGLCtx, glCtx)); + m_gfxCtx = static_cast( + _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal, + this, metalCtx)); m_gfxCtx->initializeContext(nullptr); }); m_gfxCtx->getMainContextDataFactory(); @@ -1587,11 +1590,10 @@ public: }; -std::shared_ptr _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx, - MetalContext* metalCtx, GLContext* glCtx) +std::shared_ptr _WindowCocoaNew(SystemStringView title, MetalContext* metalCtx) { auto ret = std::make_shared(); - ret->setup(title, lastGLCtx, metalCtx, glCtx); + ret->setup(title, metalCtx); return ret; }