macOS API sync

This commit is contained in:
Jack Andersen 2018-10-15 17:13:57 -10:00
parent 592ffa1372
commit 65c99ad769
8 changed files with 177 additions and 425 deletions

4
.gitmodules vendored
View File

@ -4,9 +4,9 @@
[submodule "logvisor"] [submodule "logvisor"]
path = logvisor path = logvisor
url = ../logvisor.git url = ../logvisor.git
[submodule "lib/graphicsdev/NX/mesa"] [submodule "lib/graphicsdev/nx/mesa"]
path = lib/graphicsdev/nx/mesa path = lib/graphicsdev/nx/mesa
url = ../mesa.git url = ../mesa.git
[submodule "lib/graphicsdev/NX/libdrm_nouveau"] [submodule "lib/graphicsdev/nx/libdrm_nouveau"]
path = lib/graphicsdev/nx/libdrm_nouveau path = lib/graphicsdev/nx/libdrm_nouveau
url = https://github.com/devkitPro/libdrm_nouveau.git url = https://github.com/devkitPro/libdrm_nouveau.git

View File

@ -39,7 +39,7 @@ if(TARGET nx_compiler)
list(APPEND _BOO_SYS_DEFINES -DHECL_NOUVEAU_NX=1) list(APPEND _BOO_SYS_DEFINES -DHECL_NOUVEAU_NX=1)
endif() 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 list(APPEND PLAT_SRCS
lib/graphicsdev/GL.cpp lib/graphicsdev/GL.cpp
lib/graphicsdev/glew.c) lib/graphicsdev/glew.c)
@ -137,7 +137,6 @@ elseif(APPLE)
find_library(APPKIT_LIBRARY AppKit) find_library(APPKIT_LIBRARY AppKit)
find_library(IOKIT_LIBRARY IOKit) find_library(IOKIT_LIBRARY IOKit)
find_library(OPENGL_LIBRARY OpenGL)
unset(BOO_HAS_METAL CACHE) unset(BOO_HAS_METAL CACHE)
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.11) 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) 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(AUDIOTOOLBOX_LIBRARY AudioToolbox)
find_library(COREAUDIO_LIBRARY CoreAudio) find_library(COREAUDIO_LIBRARY CoreAudio)
find_library(COREMIDI_LIBRARY CoreMIDI) 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} ${QUARTZCORE_LIBRARY} ${COREVIDEO_LIBRARY} ${AUDIOTOOLBOX_LIBRARY}
${COREAUDIO_LIBRARY} ${COREMIDI_LIBRARY}) ${COREAUDIO_LIBRARY} ${COREMIDI_LIBRARY})
add_library(glew lib/graphicsdev/glew.c)
elseif(NX) elseif(NX)
list(APPEND _BOO_SYS_DEFINES -DBOO_HAS_NX=1) list(APPEND _BOO_SYS_DEFINES -DBOO_HAS_NX=1)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS

View File

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <cstdint> #include <cstdint>
#include <vector>
#include "boo/System.hpp" #include "boo/System.hpp"
#include "boo/ThreadLocalPtr.hpp" #include "boo/ThreadLocalPtr.hpp"
#include "boo/BooObject.hpp" #include "boo/BooObject.hpp"

View File

@ -37,36 +37,15 @@ public:
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount); size_t colorBindCount, size_t depthBindCount);
bool bindingNeedsVertexFormat() const { return false; } ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IVertexFormat> newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0);
ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource, ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
std::vector<uint8_t>* vertBlobOut, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
std::vector<uint8_t>* fragBlobOut, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const ObjToken<IVertexFormat>& vtxFmt, const AdditionalPipelineInfo& additionalInfo);
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling,
bool overwriteAlpha = true,
bool depthAttachment = true);
ObjToken<IShaderPipeline> newTessellationShaderPipeline(
const char* computeSource, const char* fragSource,
const char* evaluationSource,
std::vector<uint8_t>* computeBlobOut,
std::vector<uint8_t>* fragBlobOut,
std::vector<uint8_t>* evaluationBlobOut,
const ObjToken<IVertexFormat>& 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<IShaderDataBinding> ObjToken<IShaderDataBinding>
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IVertexFormat>& vtxFormat,
const ObjToken<IGraphicsBuffer>& vbo, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo, const ObjToken<IGraphicsBuffer>& ibo,
@ -76,6 +55,8 @@ public:
const int* texBindIdxs, const bool* depthBind, const int* texBindIdxs, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0); size_t baseVert = 0, size_t baseInst = 0);
}; };
static std::vector<uint8_t> CompileMetal(const char* source, PipelineStage stage);
}; };
} }

View File

@ -4,6 +4,7 @@
#include <functional> #include <functional>
#include <typeindex> #include <typeindex>
#include <memory> #include <memory>
#include <string>
namespace boo namespace boo
{ {

View File

@ -67,19 +67,11 @@ static logvisor::Module Log("boo::Metal");
struct MetalCommandQueue; struct MetalCommandQueue;
class MetalDataFactoryImpl; class MetalDataFactoryImpl;
struct MetalShareableShader : IShareableShader<MetalDataFactoryImpl, MetalShareableShader>
{
id<MTLFunction> m_shader;
MetalShareableShader(MetalDataFactoryImpl& fac, uint64_t srcKey, uint64_t binKey, id<MTLFunction> s)
: IShareableShader(fac, srcKey, binKey), m_shader(s) {}
};
class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactoryHead class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactoryHead
{ {
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
friend class MetalDataFactory::Context; friend class MetalDataFactory::Context;
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
std::unordered_map<uint64_t, std::unique_ptr<MetalShareableShader>> m_sharedShaders;
struct MetalContext* m_ctx; struct MetalContext* m_ctx;
bool m_hasTessellation = false; bool m_hasTessellation = false;
@ -88,7 +80,6 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory
ObjToken<IShaderPipeline> m_gammaShader; ObjToken<IShaderPipeline> m_gammaShader;
ObjToken<ITextureD> m_gammaLUT; ObjToken<ITextureD> m_gammaLUT;
ObjToken<IGraphicsBufferS> m_gammaVBO; ObjToken<IGraphicsBufferS> m_gammaVBO;
ObjToken<IVertexFormat> m_gammaVFMT;
ObjToken<IShaderDataBinding> m_gammaBinding; ObjToken<IShaderDataBinding> m_gammaBinding;
void SetupGammaResources() void SetupGammaResources()
{ {
@ -96,14 +87,20 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory
commitTransaction([this](IGraphicsDataFactory::Context& ctx) 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[] = { const VertexElementDescriptor vfmt[] = {
{nullptr, nullptr, VertexSemantic::Position4}, {VertexSemantic::Position4},
{nullptr, nullptr, VertexSemantic::UV4} {VertexSemantic::UV4}
}; };
m_gammaVFMT = ctx.newVertexFormat(2, vfmt); AdditionalPipelineInfo info =
m_gammaShader = static_cast<Context&>(ctx).newShaderPipeline(GammaVS, GammaFS, {
nullptr, nullptr, m_gammaVFMT, BlendFactor::One, BlendFactor::Zero, BlendFactor::One, BlendFactor::Zero,
Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None, true, false); 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); m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge);
setDisplayGamma(1.f); setDisplayGamma(1.f);
const struct Vert { const struct Vert {
@ -117,242 +114,22 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory
}; };
m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4);
ObjToken<ITexture> texs[] = {{}, m_gammaLUT.get()}; ObjToken<ITexture> 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); 0, nullptr, nullptr, 2, texs, nullptr, nullptr);
return true; return true;
} BooTrace); } BooTrace);
} }
public: public:
std::unordered_map<uint64_t, uint64_t> m_sourceToBinary;
char m_libfile[MAXPATHLEN];
bool m_hasCompiler = false;
MetalDataFactoryImpl(IGraphicsContext* parent, MetalContext* ctx) MetalDataFactoryImpl(IGraphicsContext* parent, MetalContext* ctx)
: m_parent(parent), m_ctx(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;
}
}
~MetalDataFactoryImpl() = default; ~MetalDataFactoryImpl() = default;
Platform platform() const { return Platform::Metal; } Platform platform() const { return Platform::Metal; }
const char* platformName() const { return "Metal"; } const char* platformName() const { return "Metal"; }
void commitTransaction(const std::function<bool(IGraphicsDataFactory::Context& ctx)>& __BooTraceArgs); void commitTransaction(const std::function<bool(IGraphicsDataFactory::Context& ctx)>& __BooTraceArgs);
ObjToken<IGraphicsBufferD> newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); ObjToken<IGraphicsBufferD> 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<uint8_t>& 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<MTLLibrary>& 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<uint8_t>* 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<MTLLibrary> 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<MTLFunction> func = [shaderLib newFunctionWithName:funcName];
auto it =
m_sharedShaders.emplace(std::make_pair(binHash,
std::make_unique<MetalShareableShader>(*this, srcHash, binHash, func))).first;
return it->second->lock();
}
}
void setDisplayGamma(float gamma) void setDisplayGamma(float gamma)
{ {
@ -855,15 +632,14 @@ static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] =
MTLVertexFormatFloat4 MTLVertexFormatFloat4
}; };
struct MetalVertexFormat : GraphicsDataNode<IVertexFormat> struct MetalVertexFormat
{ {
size_t m_elementCount; size_t m_elementCount;
MTLVertexDescriptor* m_vdesc; MTLVertexDescriptor* m_vdesc;
size_t m_stride = 0; size_t m_stride = 0;
size_t m_instStride = 0; size_t m_instStride = 0;
MetalVertexFormat(const ObjToken<BaseGraphicsData>& parent, MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
size_t elementCount, const VertexElementDescriptor* elements) : m_elementCount(elementCount)
: GraphicsDataNode<IVertexFormat>(parent), m_elementCount(elementCount)
{ {
for (size_t i=0 ; i<elementCount ; ++i) for (size_t i=0 ; i<elementCount ; ++i)
{ {
@ -909,7 +685,7 @@ struct MetalVertexFormat : GraphicsDataNode<IVertexFormat>
} }
} }
MTLStageInputOutputDescriptor* makeTessellationComputeLayout() MTLStageInputOutputDescriptor* makeTessellationComputeLayout() const
{ {
MTLStageInputOutputDescriptor* ret = [MTLStageInputOutputDescriptor stageInputOutputDescriptor]; MTLStageInputOutputDescriptor* ret = [MTLStageInputOutputDescriptor stageInputOutputDescriptor];
@ -930,7 +706,7 @@ struct MetalVertexFormat : GraphicsDataNode<IVertexFormat>
return ret; return ret;
} }
MTLVertexDescriptor* makeTessellationVertexLayout() MTLVertexDescriptor* makeTessellationVertexLayout() const
{ {
MTLVertexDescriptor* ret = [MTLVertexDescriptor vertexDescriptor]; MTLVertexDescriptor* ret = [MTLVertexDescriptor vertexDescriptor];
@ -982,6 +758,56 @@ static const MTLPrimitiveType PRIMITIVE_TABLE[] =
#define COLOR_WRITE_MASK (MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue) #define COLOR_WRITE_MASK (MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue)
class MetalShaderStage : public GraphicsDataNode<IShaderStage>
{
friend class MetalDataFactory;
id<MTLFunction> m_shader;
MetalShaderStage(const boo::ObjToken<BaseGraphicsData>& parent, MetalContext* ctx,
const uint8_t* data, size_t size, PipelineStage stage)
: GraphicsDataNode<IShaderStage>(parent)
{
NSError* err = nullptr;
id<MTLLibrary> 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<MTLFunction> shader() const { return m_shader; }
};
class MetalShaderPipeline : public GraphicsDataNode<IShaderPipeline> class MetalShaderPipeline : public GraphicsDataNode<IShaderPipeline>
{ {
protected: protected:
@ -990,17 +816,13 @@ protected:
friend struct MetalShaderDataBinding; friend struct MetalShaderDataBinding;
MTLCullMode m_cullMode = MTLCullModeNone; MTLCullMode m_cullMode = MTLCullModeNone;
MTLPrimitiveType m_drawPrim; MTLPrimitiveType m_drawPrim;
MetalShareableShader::Token m_vert; uint32_t m_patchSize;
MetalShareableShader::Token m_frag;
MetalShaderPipeline(const ObjToken<BaseGraphicsData>& parent, MetalShaderPipeline(const boo::ObjToken<BaseGraphicsData>& parent)
MetalShareableShader::Token&& vert, : GraphicsDataNode<IShaderPipeline>(parent) {}
MetalShareableShader::Token&& frag)
: GraphicsDataNode<IShaderPipeline>(parent),
m_vert(std::move(vert)), m_frag(std::move(frag))
{}
virtual void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc, MetalVertexFormat& cVtxFmt) {} virtual void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc,
ObjToken<IShaderStage> compute, const MetalVertexFormat& cVtxFmt) {}
virtual void draw(MetalCommandQueue& q, size_t start, size_t count); virtual void draw(MetalCommandQueue& q, size_t start, size_t count);
virtual void drawIndexed(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); virtual void drawInstancesIndexed(MetalCommandQueue& q, size_t start, size_t count, size_t instCount);
void setup(MetalContext* ctx, void setup(MetalContext* ctx,
const ObjToken<IVertexFormat>& vtxFmt, NSUInteger targetSamples, NSUInteger targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ObjToken<IShaderStage> vertex,
ZTest depthTest, bool depthWrite, bool colorWrite, ObjToken<IShaderStage> fragment,
bool alphaWrite, bool overwriteAlpha, CullMode culling, ObjToken<IShaderStage> compute,
bool depthAttachment = true) 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: case CullMode::None:
default: default:
@ -1031,22 +855,22 @@ protected:
} }
MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new]; MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
desc.vertexFunction = m_vert.get().m_shader; desc.vertexFunction = vertex.cast<MetalShaderStage>()->shader();
desc.fragmentFunction = m_frag.get().m_shader; desc.fragmentFunction = fragment.cast<MetalShaderStage>()->shader();
MetalVertexFormat& cVtxFmt = *vtxFmt.cast<MetalVertexFormat>(); MetalVertexFormat cVtxFmt(vtxFmt.elementCount, vtxFmt.elements);
desc.vertexDescriptor = cVtxFmt.m_vdesc; desc.vertexDescriptor = cVtxFmt.m_vdesc;
setupExtraStages(ctx, desc, cVtxFmt); setupExtraStages(ctx, desc, compute, cVtxFmt);
desc.sampleCount = targetSamples; desc.sampleCount = targetSamples;
desc.colorAttachments[0].pixelFormat = ctx->m_pixelFormat; desc.colorAttachments[0].pixelFormat = ctx->m_pixelFormat;
desc.colorAttachments[0].writeMask = (colorWrite ? COLOR_WRITE_MASK : 0) | desc.colorAttachments[0].writeMask = (info.colorWrite ? COLOR_WRITE_MASK : 0) |
(alphaWrite ? MTLColorWriteMaskAlpha : 0); (info.alphaWrite ? MTLColorWriteMaskAlpha : 0);
desc.colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero; desc.colorAttachments[0].blendingEnabled = info.dstFac != BlendFactor::Zero;
if (srcFac == BlendFactor::Subtract || dstFac == BlendFactor::Subtract) if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract)
{ {
desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne;
desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationReverseSubtract; desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationReverseSubtract;
if (overwriteAlpha) if (info.overwriteAlpha)
{ {
desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero;
@ -1061,22 +885,22 @@ protected:
} }
else else
{ {
desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(info.srcFac)];
desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(info.dstFac)];
desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
if (overwriteAlpha) if (info.overwriteAlpha)
{ {
desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero;
} }
else else
{ {
desc.colorAttachments[0].sourceAlphaBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; desc.colorAttachments[0].sourceAlphaBlendFactor = BLEND_FACTOR_TABLE[int(info.srcFac)];
desc.colorAttachments[0].destinationAlphaBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; desc.colorAttachments[0].destinationAlphaBlendFactor = BLEND_FACTOR_TABLE[int(info.dstFac)];
} }
desc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; desc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
} }
desc.depthAttachmentPixelFormat = depthAttachment ? MTLPixelFormatDepth32Float : MTLPixelFormatInvalid; desc.depthAttachmentPixelFormat = info.depthAttachment ? MTLPixelFormatDepth32Float : MTLPixelFormatInvalid;
desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle; desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
NSError* err = nullptr; NSError* err = nullptr;
m_state = [ctx->m_dev newRenderPipelineStateWithDescriptor:desc error:&err]; m_state = [ctx->m_dev newRenderPipelineStateWithDescriptor:desc error:&err];
@ -1085,7 +909,7 @@ protected:
[[err localizedDescription] UTF8String]); [[err localizedDescription] UTF8String]);
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new];
switch (depthTest) switch (info.depthTest)
{ {
case ZTest::None: case ZTest::None:
default: default:
@ -1105,7 +929,7 @@ protected:
break; break;
} }
dsDesc.depthWriteEnabled = depthWrite; dsDesc.depthWriteEnabled = info.depthWrite;
m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc]; m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc];
} }
@ -1129,20 +953,12 @@ class MetalTessellationShaderPipeline : public MetalShaderPipeline
friend class MetalDataFactory; friend class MetalDataFactory;
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
friend struct MetalShaderDataBinding; friend struct MetalShaderDataBinding;
MetalShareableShader::Token m_compute;
uint32_t m_patchSize;
MetalTessellationShaderPipeline( MetalTessellationShaderPipeline(const ObjToken<BaseGraphicsData>& parent)
const ObjToken<BaseGraphicsData>& parent, : MetalShaderPipeline(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)
{}
void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc, MetalVertexFormat& cVtxFmt) void setupExtraStages(MetalContext* ctx, MTLRenderPipelineDescriptor* desc,
ObjToken<IShaderStage> compute, const MetalVertexFormat& cVtxFmt)
{ {
desc.maxTessellationFactor = 16; desc.maxTessellationFactor = 16;
desc.tessellationFactorScaleEnabled = NO; desc.tessellationFactorScaleEnabled = NO;
@ -1154,7 +970,7 @@ class MetalTessellationShaderPipeline : public MetalShaderPipeline
desc.vertexDescriptor = cVtxFmt.makeTessellationVertexLayout(); desc.vertexDescriptor = cVtxFmt.makeTessellationVertexLayout();
MTLComputePipelineDescriptor* compDesc = [MTLComputePipelineDescriptor new]; MTLComputePipelineDescriptor* compDesc = [MTLComputePipelineDescriptor new];
compDesc.computeFunction = m_compute.get().m_shader; compDesc.computeFunction = compute.cast<MetalShaderStage>()->shader();
compDesc.stageInputDescriptor = cVtxFmt.makeTessellationComputeLayout(); compDesc.stageInputDescriptor = cVtxFmt.makeTessellationComputeLayout();
NSError* err = nullptr; NSError* err = nullptr;
@ -1980,77 +1796,39 @@ MetalDataFactory::Context::newRenderTexture(size_t width, size_t height, Texture
} }
} }
ObjToken<IVertexFormat> ObjToken<IShaderStage>
MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, MetalDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage)
size_t baseVert, size_t baseInst)
{ {
@autoreleasepool @autoreleasepool
{ {
return {new struct MetalVertexFormat(m_data, elementCount, elements)}; MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
return {new MetalShaderStage(m_data, factory.m_ctx, data, size, stage)};
} }
} }
ObjToken<IShaderPipeline> ObjToken<IShaderPipeline>
MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource, MetalDataFactory::Context::newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
std::vector<uint8_t>* vertBlobOut, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
std::vector<uint8_t>* fragBlobOut, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const ObjToken<IVertexFormat>& vtxFmt, const AdditionalPipelineInfo& additionalInfo)
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling, bool overwriteAlpha,
bool depthAttachment)
{ {
@autoreleasepool @autoreleasepool
{ {
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent); MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MetalShareableShader::Token vertShader = factory.PrepareShaderStage(vertSource, vertBlobOut, @"vmain"); MetalShaderPipeline* ret;
MetalShareableShader::Token fragShader = factory.PrepareShaderStage(fragSource, fragBlobOut, @"fmain"); if (evaluation)
ret = new MetalTessellationShaderPipeline(m_data);
MetalShaderPipeline* ret = new MetalShaderPipeline(m_data, std::move(vertShader), std::move(fragShader)); else
ret->setup(factory.m_ctx, vtxFmt, depthAttachment ? factory.m_ctx->m_sampleCount : 1, ret = new MetalShaderPipeline(m_data);
srcFac, dstFac, prim, depthTest, depthWrite, ret->setup(factory.m_ctx, additionalInfo.depthAttachment ? factory.m_ctx->m_sampleCount : 1,
colorWrite, alphaWrite, overwriteAlpha, culling, depthAttachment); vertex, fragment, evaluation, vtxFmt, additionalInfo);
return {ret};
}
}
ObjToken<IShaderPipeline> MetalDataFactory::Context::newTessellationShaderPipeline(
const char* computeSource, const char* fragSource,
const char* evaluationSource,
std::vector<uint8_t>* computeBlobOut,
std::vector<uint8_t>* fragBlobOut,
std::vector<uint8_t>* evaluationBlobOut,
const ObjToken<IVertexFormat>& 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<MetalDataFactoryImpl&>(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);
return {ret}; return {ret};
} }
} }
ObjToken<IShaderDataBinding> ObjToken<IShaderDataBinding>
MetalDataFactory::Context::newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, MetalDataFactory::Context::newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IVertexFormat>& vtxFormat,
const ObjToken<IGraphicsBuffer>& vbo, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo, const ObjToken<IGraphicsBuffer>& ibo,
@ -2095,6 +1873,14 @@ std::unique_ptr<IGraphicsDataFactory> _NewMetalDataFactory(IGraphicsContext* par
return std::make_unique<MetalDataFactoryImpl>(parent, ctx); return std::make_unique<MetalDataFactoryImpl>(parent, ctx);
} }
std::vector<uint8_t> MetalDataFactory::CompileMetal(const char* source, PipelineStage stage)
{
size_t strSz = strlen(source) + 1;
std::vector<uint8_t> ret(strSz + 1);
memcpy(ret.data() + 1, source, strSz);
return ret;
}
} }
#endif #endif

View File

@ -3,7 +3,6 @@
#include "boo/IApplication.hpp" #include "boo/IApplication.hpp"
#include "boo/graphicsdev/Metal.hpp" #include "boo/graphicsdev/Metal.hpp"
#include "boo/graphicsdev/GL.hpp"
#include "CocoaCommon.hpp" #include "CocoaCommon.hpp"
#include "../Common.hpp" #include "../Common.hpp"
@ -32,8 +31,7 @@ namespace boo
{ {
static logvisor::Module Log("boo::ApplicationCocoa"); static logvisor::Module Log("boo::ApplicationCocoa");
std::shared_ptr<IWindow> _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx, std::shared_ptr<IWindow> _WindowCocoaNew(SystemStringView title, MetalContext* metalCtx);
MetalContext* metalCtx, GLContext* glCtx);
class ApplicationCocoa : public IApplication class ApplicationCocoa : public IApplication
{ {
@ -52,7 +50,9 @@ private:
std::unordered_map<uintptr_t, std::weak_ptr<IWindow>> m_windows; std::unordered_map<uintptr_t, std::weak_ptr<IWindow>> m_windows;
MetalContext m_metalCtx; MetalContext m_metalCtx;
#if 0
GLContext m_glCtx; GLContext m_glCtx;
#endif
void _deletedWindow(IWindow* window) void _deletedWindow(IWindow* window)
{ {
@ -78,9 +78,11 @@ public:
m_metalCtx.m_sampleCount = samples; m_metalCtx.m_sampleCount = samples;
m_metalCtx.m_anisotropy = anisotropy; m_metalCtx.m_anisotropy = anisotropy;
m_metalCtx.m_pixelFormat = deepColor ? MTLPixelFormatRGBA16Float : MTLPixelFormatBGRA8Unorm; m_metalCtx.m_pixelFormat = deepColor ? MTLPixelFormatRGBA16Float : MTLPixelFormatBGRA8Unorm;
#if 0
m_glCtx.m_sampleCount = samples; m_glCtx.m_sampleCount = samples;
m_glCtx.m_anisotropy = anisotropy; m_glCtx.m_anisotropy = anisotropy;
m_glCtx.m_deepColor = deepColor; m_glCtx.m_deepColor = deepColor;
#endif
[[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular];
@ -104,39 +106,14 @@ public:
action:nil keyEquivalent:@""] setSubmenu:appMenu]; action:nil keyEquivalent:@""] setSubmenu:appMenu];
[[NSApplication sharedApplication] setMainMenu:rootMenu]; [[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(); m_metalCtx.m_dev = MTLCreateSystemDefaultDevice();
if (m_metalCtx.m_dev) if (!m_metalCtx.m_dev)
{ Log.report(logvisor::Fatal, "Unable to create metal device");
m_metalCtx.m_q = [m_metalCtx.m_dev newCommandQueue]; m_metalCtx.m_q = [m_metalCtx.m_dev newCommandQueue];
while (![m_metalCtx.m_dev supportsTextureSampleCount:m_metalCtx.m_sampleCount]) while (![m_metalCtx.m_dev supportsTextureSampleCount:m_metalCtx.m_sampleCount])
m_metalCtx.m_sampleCount = flp2(m_metalCtx.m_sampleCount - 1); m_metalCtx.m_sampleCount = flp2(m_metalCtx.m_sampleCount - 1);
Log.report(logvisor::Info, "using Metal renderer"); Log.report(logvisor::Info, "using Metal renderer");
} }
else
Log.report(logvisor::Info, "using OpenGL renderer");
#else
Log.report(logvisor::Info, "using OpenGL renderer");
#endif
}
EPlatformType getPlatformType() const EPlatformType getPlatformType() const
{ {
@ -214,19 +191,23 @@ public:
std::shared_ptr<IWindow> newWindow(std::string_view title) std::shared_ptr<IWindow> 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; m_windows[newWindow->getPlatformHandle()] = newWindow;
return newWindow; return newWindow;
} }
/* Last GL context */ /* Last GL context */
#if 0
NSOpenGLContext* m_lastGLCtx = nullptr; NSOpenGLContext* m_lastGLCtx = nullptr;
#endif
}; };
#if 0
void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx) void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx)
{ {
static_cast<ApplicationCocoa*>(APP)->m_lastGLCtx = lastGLCtx; static_cast<ApplicationCocoa*>(APP)->m_lastGLCtx = lastGLCtx;
} }
#endif
IApplication* APP = nullptr; IApplication* APP = nullptr;
int ApplicationRun(IApplication::EPlatformType platform, int ApplicationRun(IApplication::EPlatformType platform,

View File

@ -1,5 +1,3 @@
#include "boo/graphicsdev/GL.hpp"
#include "boo/graphicsdev/glew.h"
#include "boo/graphicsdev/Metal.hpp" #include "boo/graphicsdev/Metal.hpp"
#include "CocoaCommon.hpp" #include "CocoaCommon.hpp"
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
@ -26,6 +24,7 @@ namespace boo {class WindowCocoa; class GraphicsContextCocoa;}
- (void)setTouchBarProvider:(id)provider; - (void)setTouchBarProvider:(id)provider;
@end @end
#if 0
/* AppKit applies OpenGL much differently than other platforms /* AppKit applies OpenGL much differently than other platforms
* the NSOpenGLView class composes together all necessary * the NSOpenGLView class composes together all necessary
* OGL context members and provides the necessary event hooks * OGL context members and provides the necessary event hooks
@ -95,6 +94,7 @@ static const NSOpenGLPixelFormatAttribute* PF_TABLE[] =
PF_RGBAF32_ATTRS, PF_RGBAF32_ATTRS,
PF_RGBAF32_Z24_ATTRS PF_RGBAF32_Z24_ATTRS
}; };
#endif
@interface BooCocoaResponder : NSResponder <NSTextInputClient> @interface BooCocoaResponder : NSResponder <NSTextInputClient>
{ {
@ -155,10 +155,13 @@ public:
} }
virtual BooCocoaResponder* responder() const=0; virtual BooCocoaResponder* responder() const=0;
}; };
#if 0
class GraphicsContextCocoaGL; class GraphicsContextCocoaGL;
#endif
class GraphicsContextCocoaMetal; class GraphicsContextCocoaMetal;
} }
#if 0
@interface GraphicsContextCocoaGLInternal : NSOpenGLView @interface GraphicsContextCocoaGLInternal : NSOpenGLView
{ {
@public @public
@ -166,6 +169,7 @@ class GraphicsContextCocoaMetal;
} }
- (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx; - (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx;
@end @end
#endif
@interface GraphicsContextCocoaMetalInternal : NSView @interface GraphicsContextCocoaMetalInternal : NSView
{ {
@ -181,11 +185,14 @@ class GraphicsContextCocoaMetal;
namespace boo namespace boo
{ {
static logvisor::Module Log("boo::WindowCocoa"); static logvisor::Module Log("boo::WindowCocoa");
#if 0
std::unique_ptr<IGraphicsCommandQueue> _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx); std::unique_ptr<IGraphicsCommandQueue> _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx);
std::unique_ptr<IGraphicsDataFactory> _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx); std::unique_ptr<IGraphicsDataFactory> _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx);
#endif
std::unique_ptr<IGraphicsCommandQueue> _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, std::unique_ptr<IGraphicsCommandQueue> _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow,
IGraphicsContext* parent); IGraphicsContext* parent);
std::unique_ptr<IGraphicsDataFactory> _NewMetalDataFactory(IGraphicsContext* parent, MetalContext* ctx); std::unique_ptr<IGraphicsDataFactory> _NewMetalDataFactory(IGraphicsContext* parent, MetalContext* ctx);
#if 0
void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx); void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx);
class GraphicsContextCocoaGL : public GraphicsContextCocoa class GraphicsContextCocoaGL : public GraphicsContextCocoa
@ -349,6 +356,7 @@ IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api,
return new GraphicsContextCocoaGL(api, parentWindow, lastGLCtx, glCtx); return new GraphicsContextCocoaGL(api, parentWindow, lastGLCtx, glCtx);
} }
#endif
#if BOO_HAS_METAL #if BOO_HAS_METAL
class GraphicsContextCocoaMetal : public GraphicsContextCocoa class GraphicsContextCocoaMetal : public GraphicsContextCocoa
@ -1147,6 +1155,7 @@ static boo::ESpecialKey translateKeycode(short code)
@end @end
#if 0
@implementation GraphicsContextCocoaGLInternal @implementation GraphicsContextCocoaGLInternal
- (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx - (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx
{ {
@ -1203,6 +1212,7 @@ static boo::ESpecialKey translateKeycode(short code)
} }
@end @end
#endif
#if BOO_HAS_METAL #if BOO_HAS_METAL
@implementation GraphicsContextCocoaMetalInternal @implementation GraphicsContextCocoaMetalInternal
@ -1299,23 +1309,16 @@ class WindowCocoa : public IWindow
public: 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(), dispatch_sync(dispatch_get_main_queue(),
^{ ^{
std::shared_ptr<boo::WindowCocoa> windowPtr = std::shared_ptr<boo::WindowCocoa> windowPtr =
std::static_pointer_cast<boo::WindowCocoa>(shared_from_this()); std::static_pointer_cast<boo::WindowCocoa>(shared_from_this());
m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:windowPtr title:title]; m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:windowPtr title:title];
#if BOO_HAS_METAL
if (metalCtx->m_dev)
m_gfxCtx = static_cast<GraphicsContextCocoa*>( m_gfxCtx = static_cast<GraphicsContextCocoa*>(
_GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal, _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal,
this, metalCtx)); this, metalCtx));
else
#endif
m_gfxCtx = static_cast<GraphicsContextCocoa*>(
_GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
this, lastGLCtx, glCtx));
m_gfxCtx->initializeContext(nullptr); m_gfxCtx->initializeContext(nullptr);
}); });
m_gfxCtx->getMainContextDataFactory(); m_gfxCtx->getMainContextDataFactory();
@ -1587,11 +1590,10 @@ public:
}; };
std::shared_ptr<IWindow> _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx, std::shared_ptr<IWindow> _WindowCocoaNew(SystemStringView title, MetalContext* metalCtx)
MetalContext* metalCtx, GLContext* glCtx)
{ {
auto ret = std::make_shared<WindowCocoa>(); auto ret = std::make_shared<WindowCocoa>();
ret->setup(title, lastGLCtx, metalCtx, glCtx); ret->setup(title, metalCtx);
return ret; return ret;
} }