Work on MSAA support

This commit is contained in:
Jack Andersen 2018-01-06 19:17:14 -10:00
parent db82ba674b
commit 1dc69c3468
12 changed files with 242 additions and 123 deletions

View File

@ -51,8 +51,7 @@ public:
virtual const std::vector<SystemString>& getArgs() const=0;
/* Constructors/initializers for sub-objects */
virtual std::shared_ptr<IWindow> newWindow(SystemStringView title, uint32_t drawSamples)=0;
virtual std::shared_ptr<IWindow> newWindow(SystemStringView title)=0;
};
int
@ -62,6 +61,8 @@ ApplicationRun(IApplication::EPlatformType platform,
SystemStringView friendlyName,
SystemStringView pname,
const std::vector<SystemString>& args,
uint32_t samples = 1,
uint32_t anisotropy = 1,
bool singleInstance=true);
extern IApplication* APP;
@ -71,6 +72,8 @@ ApplicationRun(IApplication::EPlatformType platform,
SystemStringView uniqueName,
SystemStringView friendlyName,
int argc, const SystemChar** argv,
uint32_t samples = 1,
uint32_t anisotropy = 1,
bool singleInstance=true)
{
if (APP)
@ -78,7 +81,8 @@ ApplicationRun(IApplication::EPlatformType platform,
std::vector<SystemString> args;
for (int i=1 ; i<argc ; ++i)
args.push_back(argv[i]);
return ApplicationRun(platform, cb, uniqueName, friendlyName, argv[0], args, singleInstance);
return ApplicationRun(platform, cb, uniqueName, friendlyName, argv[0], args,
samples, anisotropy, singleInstance);
}
}

View File

@ -11,6 +11,12 @@ namespace boo
{
struct BaseGraphicsData;
struct GLContext
{
uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1;
};
class GLDataFactory : public IGraphicsDataFactory
{
public:

View File

@ -45,7 +45,7 @@ public:
ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource,
std::vector<uint8_t>* vertBlobOut,
std::vector<uint8_t>* fragBlobOut,
const ObjToken<IVertexFormat>& vtxFmt, unsigned targetSamples,
const ObjToken<IVertexFormat>& vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling);

View File

@ -66,6 +66,16 @@ protected:
}
};
static inline uint32_t flp2(uint32_t x)
{
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
return x - (x >> 1);
}
}
#endif // BOO_INTERNAL_COMMON_HPP

View File

@ -36,11 +36,11 @@ class GLDataFactoryImpl : public GLDataFactory, public GraphicsDataFactoryHead
friend struct GLCommandQueue;
friend class GLDataFactory::Context;
IGraphicsContext* m_parent;
uint32_t m_drawSamples;
GLContext* m_glCtx;
std::unordered_map<uint64_t, std::unique_ptr<GLShareableShader>> m_sharedShaders;
public:
GLDataFactoryImpl(IGraphicsContext* parent, uint32_t drawSamples)
: m_parent(parent), m_drawSamples(drawSamples) {}
GLDataFactoryImpl(IGraphicsContext* parent, GLContext* glCtx)
: m_parent(parent), m_glCtx(glCtx) {}
Platform platform() const { return Platform::OpenGL; }
const SystemChar* platformName() const { return _S("OpenGL"); }
@ -187,7 +187,7 @@ class GLTextureS : public GraphicsDataNode<ITextureS>
friend class GLDataFactory;
GLuint m_tex;
GLTextureS(const ObjToken<BaseGraphicsData>& parent, size_t width, size_t height, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz)
TextureFormat fmt, TextureClampMode clampMode, GLint aniso, const void* data, size_t sz)
: GraphicsDataNode<ITextureS>(parent)
{
const uint8_t* dataIt = static_cast<const uint8_t*>(data);
@ -196,12 +196,15 @@ class GLTextureS : public GraphicsDataNode<ITextureS>
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (mips > 1)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mips-1);
}
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (GLEW_EXT_texture_filter_anisotropic)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
SetClampMode(GL_TEXTURE_2D, clampMode);
GLenum intFormat, format;
@ -274,7 +277,7 @@ class GLTextureSA : public GraphicsDataNode<ITextureSA>
friend class GLDataFactory;
GLuint m_tex;
GLTextureSA(const ObjToken<BaseGraphicsData>& parent, size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz)
TextureFormat fmt, TextureClampMode clampMode, GLint aniso, const void* data, size_t sz)
: GraphicsDataNode<ITextureSA>(parent)
{
const uint8_t* dataIt = static_cast<const uint8_t*>(data);
@ -289,6 +292,9 @@ class GLTextureSA : public GraphicsDataNode<ITextureSA>
else
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (GLEW_EXT_texture_filter_anisotropic)
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
SetClampMode(GL_TEXTURE_2D_ARRAY, clampMode);
GLenum intFormat, format;
@ -433,13 +439,13 @@ class GLTextureR : public GraphicsDataNode<ITextureR>
struct GLCommandQueue* m_q;
GLuint m_texs[2] = {};
GLuint m_bindTexs[2][MAX_BIND_TEXS] = {};
GLuint m_bindFBOs[2][MAX_BIND_TEXS] = {};
GLuint m_fbo = 0;
size_t m_width = 0;
size_t m_height = 0;
size_t m_samples = 0;
size_t m_colorBindCount;
size_t m_depthBindCount;
GLenum m_target;
GLTextureR(const ObjToken<BaseGraphicsData>& parent, GLCommandQueue* q, size_t width, size_t height, size_t samples,
TextureClampMode clampMode, size_t colorBindCount, size_t depthBindCount);
public:
@ -447,6 +453,8 @@ public:
{
glDeleteTextures(2, m_texs);
glDeleteTextures(MAX_BIND_TEXS * 2, m_bindTexs[0]);
if (m_samples > 1)
glDeleteFramebuffers(MAX_BIND_TEXS * 2, m_bindFBOs[0]);
glDeleteFramebuffers(1, &m_fbo);
}
@ -467,7 +475,7 @@ public:
void bind(size_t idx, int bindIdx, bool depth) const
{
glActiveTexture(GL_TEXTURE0 + idx);
glBindTexture(m_target, m_bindTexs[depth][bindIdx]);
glBindTexture(GL_TEXTURE_2D, m_bindTexs[depth][bindIdx]);
}
void resize(size_t width, size_t height)
@ -518,7 +526,9 @@ ObjToken<ITextureS>
GLDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz)
{
return {new GLTextureS(m_data, width, height, mips, fmt, clampMode, data, sz)};
GLDataFactoryImpl& factory = static_cast<GLDataFactoryImpl&>(m_parent);
return {new GLTextureS(m_data, width, height, mips, fmt, clampMode,
factory.m_glCtx->m_anisotropy, data, sz)};
}
ObjToken<ITextureSA>
@ -526,7 +536,9 @@ GLDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_
TextureFormat fmt, TextureClampMode clampMode,
const void *data, size_t sz)
{
return {new GLTextureSA(m_data, width, height, layers, mips, fmt, clampMode, data, sz)};
GLDataFactoryImpl& factory = static_cast<GLDataFactoryImpl&>(m_parent);
return {new GLTextureSA(m_data, width, height, layers, mips, fmt, clampMode,
factory.m_glCtx->m_anisotropy, data, sz)};
}
class GLShaderPipeline : public GraphicsDataNode<IShaderPipeline>
@ -1028,6 +1040,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
Platform platform() const { return IGraphicsDataFactory::Platform::OpenGL; }
const SystemChar* platformName() const { return _S("OpenGL"); }
IGraphicsContext* m_parent = nullptr;
GLContext* m_glCtx = nullptr;
std::mutex m_mt;
std::condition_variable m_cv;
@ -1167,8 +1180,31 @@ struct GLCommandQueue : IGraphicsCommandQueue
{
glGenFramebuffers(1, &tex->m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, tex->m_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->m_texs[0], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex->m_texs[1], 0);
GLenum target = tex->m_samples > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex->m_texs[0], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, tex->m_texs[1], 0);
if (tex->m_samples > 1)
{
if (tex->m_colorBindCount)
{
glGenFramebuffers(tex->m_colorBindCount, tex->m_bindFBOs[0]);
for (int i=0 ; i<tex->m_colorBindCount ; ++i)
{
glBindFramebuffer(GL_FRAMEBUFFER, tex->m_bindFBOs[0][i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->m_bindTexs[0][i], 0);
}
}
if (tex->m_depthBindCount)
{
glGenFramebuffers(tex->m_depthBindCount, tex->m_bindFBOs[1]);
for (int i=0 ; i<tex->m_depthBindCount ; ++i)
{
glBindFramebuffer(GL_FRAMEBUFFER, tex->m_bindFBOs[1][i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex->m_bindTexs[1][i], 0);
}
}
}
}
static void RenderingWorker(GLCommandQueue* self)
@ -1188,6 +1224,17 @@ struct GLCommandQueue : IGraphicsCommandQueue
Log.report(logvisor::Info, "OpenGL Version: %s", version);
self->m_parent->postInit();
glClearColor(0.f, 0.f, 0.f, 0.f);
if (GLEW_EXT_texture_filter_anisotropic)
{
GLint maxAniso;
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso);
self->m_glCtx->m_anisotropy = std::min(uint32_t(maxAniso), self->m_glCtx->m_anisotropy);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso);
}
GLint maxSamples;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
self->m_glCtx->m_sampleCount =
flp2(std::min(uint32_t(maxSamples), std::max(uint32_t(1), self->m_glCtx->m_sampleCount)) - 1);
}
self->m_initcv.notify_one();
while (self->m_running)
@ -1229,6 +1276,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
std::vector<Command>& cmds = self->m_cmdBufs[self->m_drawBuf];
GLenum currentPrim = GL_TRIANGLES;
const GLShaderDataBinding* curBinding = nullptr;
GLuint curFBO = 0;
for (const Command& cmd : cmds)
{
switch (cmd.m_op)
@ -1244,10 +1292,8 @@ struct GLCommandQueue : IGraphicsCommandQueue
case Command::Op::SetRenderTarget:
{
const GLTextureR* tex = cmd.target.cast<GLTextureR>();
if (!tex)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
else
glBindFramebuffer(GL_FRAMEBUFFER, tex->m_fbo);
curFBO = (!tex) ? 0 : tex->m_fbo;
glBindFramebuffer(GL_FRAMEBUFFER, curFBO);
break;
}
case Command::Op::SetViewport:
@ -1291,23 +1337,49 @@ struct GLCommandQueue : IGraphicsCommandQueue
break;
case Command::Op::ResolveBindTexture:
{
const SWindowRect& rect = cmd.viewport.rect;
const GLTextureR* tex = cmd.resolveTex.cast<GLTextureR>();
GLenum target = (tex->m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo);
glActiveTexture(GL_TEXTURE9);
if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx])
if (tex->m_samples <= 1)
{
glBindTexture(target, tex->m_bindTexs[0][cmd.bindIdx]);
glCopyTexSubImage2D(target, 0, cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.size[0], cmd.viewport.rect.size[1]);
glActiveTexture(GL_TEXTURE9);
if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx])
{
glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[0][cmd.bindIdx]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
rect.location[0], rect.location[1],
rect.location[0], rect.location[1],
rect.size[0], rect.size[1]);
}
if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx])
{
glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[1][cmd.bindIdx]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
rect.location[0], rect.location[1],
rect.location[0], rect.location[1],
rect.size[0], rect.size[1]);
}
}
if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx])
else
{
glBindTexture(target, tex->m_bindTexs[1][cmd.bindIdx]);
glCopyTexSubImage2D(target, 0, cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.location[0], cmd.viewport.rect.location[1],
cmd.viewport.rect.size[0], cmd.viewport.rect.size[1]);
if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx])
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[0][cmd.bindIdx]);
glBlitFramebuffer(rect.location[0], rect.location[1],
rect.location[0] + rect.size[0], rect.location[1] + rect.size[1],
rect.location[0], rect.location[1],
rect.location[0] + rect.size[0], rect.location[1] + rect.size[1],
GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx])
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[1][cmd.bindIdx]);
glBlitFramebuffer(rect.location[0], rect.location[1],
rect.location[0] + rect.size[0], rect.location[1] + rect.size[1],
rect.location[0], rect.location[1],
rect.location[0] + rect.size[0], rect.location[1] + rect.size[1],
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
}
if (cmd.clearDepth)
{
@ -1315,6 +1387,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
}
glBindFramebuffer(GL_FRAMEBUFFER, curFBO);
break;
}
case Command::Op::Present:
@ -1338,8 +1411,9 @@ struct GLCommandQueue : IGraphicsCommandQueue
}
}
GLCommandQueue(IGraphicsContext* parent)
GLCommandQueue(IGraphicsContext* parent, GLContext* glCtx)
: m_parent(parent),
m_glCtx(glCtx),
m_initlk(m_initmt),
m_thr(RenderingWorker, this)
{
@ -1585,7 +1659,6 @@ GLTextureR::GLTextureR(const ObjToken<BaseGraphicsData>& parent, GLCommandQueue*
if (samples > 1)
{
m_target = GL_TEXTURE_2D_MULTISAMPLE;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, width, height, GL_FALSE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]);
@ -1593,7 +1666,6 @@ GLTextureR::GLTextureR(const ObjToken<BaseGraphicsData>& parent, GLCommandQueue*
}
else
{
m_target = GL_TEXTURE_2D;
glBindTexture(GL_TEXTURE_2D, m_texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, m_texs[1]);
@ -1626,7 +1698,7 @@ GLDataFactory::Context::newRenderTexture(size_t width, size_t height, TextureCla
{
GLDataFactoryImpl& factory = static_cast<GLDataFactoryImpl&>(m_parent);
GLCommandQueue* q = static_cast<GLCommandQueue*>(factory.m_parent->getCommandQueue());
ObjToken<ITextureR> retval(new GLTextureR(m_data, q, width, height, factory.m_drawSamples, clampMode,
ObjToken<ITextureR> retval(new GLTextureR(m_data, q, width, height, factory.m_glCtx->m_sampleCount, clampMode,
colorBindingCount, depthBindingCount));
q->resizeRenderTexture(retval, width, height);
return retval;
@ -1653,14 +1725,14 @@ ObjToken<IVertexFormat> GLDataFactory::Context::newVertexFormat
return {new GLVertexFormat(m_data, q, elementCount, elements, baseVert, baseInst)};
}
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent)
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx)
{
return new struct GLCommandQueue(parent);
return new struct GLCommandQueue(parent, glCtx);
}
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, uint32_t drawSamples)
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx)
{
return new class GLDataFactoryImpl(parent, drawSamples);
return new class GLDataFactoryImpl(parent, glCtx);
}
}

View File

@ -37,15 +37,14 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory
IGraphicsContext* m_parent;
std::unordered_map<uint64_t, std::unique_ptr<MetalShareableShader>> m_sharedShaders;
struct MetalContext* m_ctx;
uint32_t m_sampleCount;
public:
std::unordered_map<uint64_t, uint64_t> m_sourceToBinary;
char m_libfile[MAXPATHLEN];
bool m_hasCompiler = false;
MetalDataFactoryImpl(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount)
: m_parent(parent), m_ctx(ctx), m_sampleCount(sampleCount)
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())
@ -524,14 +523,28 @@ class MetalTextureR : public GraphicsDataNode<ITextureR>
{
desc.pixelFormat = MTLPixelFormatBGRA8Unorm;
for (int i=0 ; i<m_colorBindCount ; ++i)
{
m_colorBindTex[i] = [ctx->m_dev newTextureWithDescriptor:desc];
m_blitColor[i] = [MTLRenderPassDescriptor renderPassDescriptor];
m_blitColor[i].colorAttachments[0].texture = m_colorTex;
m_blitColor[i].colorAttachments[0].loadAction = MTLLoadActionLoad;
m_blitColor[i].colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
m_blitColor[i].colorAttachments[0].resolveTexture = m_colorBindTex[i];
}
}
if (m_depthBindCount)
{
desc.pixelFormat = MTLPixelFormatDepth32Float;
for (int i=0 ; i<m_depthBindCount ; ++i)
{
m_depthBindTex[i] = [ctx->m_dev newTextureWithDescriptor:desc];
m_blitDepth[i] = [MTLRenderPassDescriptor renderPassDescriptor];
m_blitDepth[i].depthAttachment.texture = m_colorTex;
m_blitDepth[i].depthAttachment.loadAction = MTLLoadActionLoad;
m_blitDepth[i].depthAttachment.storeAction = MTLStoreActionMultisampleResolve;
m_blitDepth[i].depthAttachment.resolveTexture = m_depthBindTex[i];
}
}
{
@ -609,6 +622,8 @@ public:
MTLRenderPassDescriptor* m_clearDepthPassDesc;
MTLRenderPassDescriptor* m_clearColorPassDesc;
MTLRenderPassDescriptor* m_clearBothPassDesc;
MTLRenderPassDescriptor* m_blitColor[MAX_BIND_TEXS] = {};
MTLRenderPassDescriptor* m_blitDepth[MAX_BIND_TEXS] = {};
~MetalTextureR() = default;
void resize(MetalContext* ctx, size_t width, size_t height)
@ -1004,6 +1019,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
IGraphicsContext* m_parent;
id<MTLCommandBuffer> m_cmdBuf;
id<MTLRenderCommandEncoder> m_enc;
id<MTLSamplerState> m_samplers[3];
bool m_running = true;
int m_fillBuf = 0;
@ -1015,6 +1031,27 @@ struct MetalCommandQueue : IGraphicsCommandQueue
@autoreleasepool
{
m_cmdBuf = [ctx->m_q commandBuffer];
MTLSamplerDescriptor* sampDesc = [MTLSamplerDescriptor new];
sampDesc.rAddressMode = MTLSamplerAddressModeRepeat;
sampDesc.sAddressMode = MTLSamplerAddressModeRepeat;
sampDesc.tAddressMode = MTLSamplerAddressModeRepeat;
sampDesc.minFilter = MTLSamplerMinMagFilterLinear;
sampDesc.magFilter = MTLSamplerMinMagFilterLinear;
sampDesc.mipFilter = MTLSamplerMipFilterLinear;
sampDesc.maxAnisotropy = ctx->m_anisotropy;
sampDesc.borderColor = MTLSamplerBorderColorOpaqueWhite;
m_samplers[0] = [ctx->m_dev newSamplerStateWithDescriptor:sampDesc];
sampDesc.rAddressMode = MTLSamplerAddressModeClampToBorderColor;
sampDesc.sAddressMode = MTLSamplerAddressModeClampToBorderColor;
sampDesc.tAddressMode = MTLSamplerAddressModeClampToBorderColor;
m_samplers[1] = [ctx->m_dev newSamplerStateWithDescriptor:sampDesc];
sampDesc.rAddressMode = MTLSamplerAddressModeClampToEdge;
sampDesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
sampDesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
m_samplers[2] = [ctx->m_dev newSamplerStateWithDescriptor:sampDesc];
}
}
@ -1040,6 +1077,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
cbind->bind(m_enc, m_fillBuf);
m_boundData = cbind;
m_currentPrimitive = cbind->m_pipeline.cast<MetalShaderPipeline>()->m_drawPrim;
[m_enc setFragmentSamplerStates:m_samplers withRange:NSMakeRange(0, 3)];
}
}
@ -1175,39 +1213,11 @@ struct MetalCommandQueue : IGraphicsCommandQueue
@autoreleasepool
{
[m_enc endEncoding];
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<MTLBlitCommandEncoder> 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];
}
[[m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_blitColor[bindIdx]] endEncoding];
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];
}
[[m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_blitDepth[bindIdx]] endEncoding];
[blitEnc endEncoding];
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:clearDepth ? tex->m_clearDepthPassDesc : tex->m_passDesc];
[m_enc setFrontFacingWinding:MTLWindingCounterClockwise];
@ -1225,6 +1235,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
}
bool m_inProgress = false;
std::unordered_map<uintptr_t, MTLRenderPassDescriptor*> m_resolvePasses;
void execute()
{
if (!m_running)
@ -1297,20 +1308,21 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{
MetalTextureR* src = m_needsDisplay.cast<MetalTextureR>();
id<MTLTexture> dest = drawable.texture;
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;
}
if (src->m_colorTex.width == dest.width &&
src->m_colorTex.height == dest.height)
{
id<MTLBlitCommandEncoder> 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 renderCommandEncoderWithDescriptor:passSearch->second] endEncoding];
[m_cmdBuf presentDrawable:drawable];
}
}
@ -1392,7 +1404,7 @@ MetalDataFactory::Context::newRenderTexture(size_t width, size_t height, Texture
@autoreleasepool
{
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
return {new MetalTextureR(m_data, factory.m_ctx, width, height, factory.m_sampleCount,
return {new MetalTextureR(m_data, factory.m_ctx, width, height, factory.m_ctx->m_sampleCount,
colorBindCount, depthBindCount)};
}
}
@ -1411,7 +1423,7 @@ ObjToken<IShaderPipeline>
MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource,
std::vector<uint8_t>* vertBlobOut,
std::vector<uint8_t>* fragBlobOut,
const ObjToken<IVertexFormat>& vtxFmt, unsigned targetSamples,
const ObjToken<IVertexFormat>& vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
@ -1420,7 +1432,7 @@ MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char*
{
MetalDataFactoryImpl& factory = static_cast<MetalDataFactoryImpl&>(m_parent);
MTLCompileOptions* compOpts = [MTLCompileOptions new];
compOpts.languageVersion = MTLLanguageVersion1_2;
compOpts.languageVersion = MTLLanguageVersion1_1;
NSError* err = nullptr;
XXH64_state_t hashState;
@ -1541,7 +1553,7 @@ MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char*
}
return {new MetalShaderPipeline(m_data, factory.m_ctx, std::move(vertShader), std::move(fragShader),
vtxFmt, targetSamples, srcFac, dstFac, prim, depthTest, depthWrite,
vtxFmt, factory.m_ctx->m_sampleCount, srcFac, dstFac, prim, depthTest, depthWrite,
colorWrite, alphaWrite, culling)};
}
}
@ -1588,9 +1600,9 @@ IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentW
return new struct MetalCommandQueue(ctx, parentWindow, parent);
}
IGraphicsDataFactory* _NewMetalDataFactory(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount)
IGraphicsDataFactory* _NewMetalDataFactory(IGraphicsContext* parent, MetalContext* ctx)
{
return new class MetalDataFactoryImpl(parent, ctx, sampleCount);
return new class MetalDataFactoryImpl(parent, ctx);
}
}

View File

@ -3,7 +3,9 @@
#include "boo/IApplication.hpp"
#include "boo/graphicsdev/Metal.hpp"
#include "boo/graphicsdev/GL.hpp"
#include "CocoaCommon.hpp"
#include "../Common.hpp"
#include "logvisor/logvisor.hpp"
@ -31,7 +33,7 @@ namespace boo
static logvisor::Module Log("boo::ApplicationCocoa");
std::shared_ptr<IWindow> _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx,
MetalContext* metalCtx, uint32_t sampleCount);
MetalContext* metalCtx, GLContext* glCtx);
class ApplicationCocoa : public IApplication
{
@ -50,6 +52,7 @@ private:
std::unordered_map<uintptr_t, std::weak_ptr<IWindow>> m_windows;
MetalContext m_metalCtx;
GLContext m_glCtx;
void _deletedWindow(IWindow* window)
{
@ -61,13 +64,20 @@ public:
SystemStringView uniqueName,
SystemStringView friendlyName,
SystemStringView pname,
const std::vector<SystemString>& args)
const std::vector<SystemString>& args,
uint32_t samples,
uint32_t anisotropy)
: m_callback(callback),
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args)
{
m_metalCtx.m_sampleCount = samples;
m_metalCtx.m_anisotropy = anisotropy;
m_glCtx.m_sampleCount = samples;
m_glCtx.m_anisotropy = anisotropy;
[[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular];
/* Delegate (OS X callbacks) */
@ -104,6 +114,8 @@ public:
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
@ -187,9 +199,9 @@ public:
return m_args;
}
std::shared_ptr<IWindow> newWindow(std::string_view title, uint32_t sampleCount)
std::shared_ptr<IWindow> newWindow(std::string_view title)
{
auto newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx, sampleCount);
auto newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx, &m_glCtx);
m_windows[newWindow->getPlatformHandle()] = newWindow;
return newWindow;
}
@ -210,6 +222,8 @@ int ApplicationRun(IApplication::EPlatformType platform,
SystemStringView friendlyName,
SystemStringView pname,
const std::vector<SystemString>& args,
uint32_t samples,
uint32_t anisotropy,
bool singleInstance)
{
std::string thrName = std::string(friendlyName) + " Main Thread";
@ -222,7 +236,7 @@ int ApplicationRun(IApplication::EPlatformType platform,
platform != IApplication::EPlatformType::Auto)
return 1;
/* Never deallocated to ensure window destructors have access */
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args);
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args, samples, anisotropy);
}
[NSApp run];
ApplicationCocoa* appCocoa = static_cast<ApplicationCocoa*>(APP);

View File

@ -28,6 +28,8 @@ struct MetalContext
CGSize m_size;
};
std::unordered_map<IWindow*, Window> m_windows;
uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1;
};
}

View File

@ -185,12 +185,11 @@ class GraphicsContextCocoaMetal;
namespace boo
{
static logvisor::Module Log("boo::WindowCocoa");
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, uint32_t drawSamples);
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx);
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx);
IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow,
IGraphicsContext* parent);
IGraphicsDataFactory* _NewMetalDataFactory(IGraphicsContext* parent,
MetalContext* ctx, uint32_t sampleCount);
IGraphicsDataFactory* _NewMetalDataFactory(IGraphicsContext* parent, MetalContext* ctx);
void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx);
class GraphicsContextCocoaGL : public GraphicsContextCocoa
@ -203,14 +202,15 @@ class GraphicsContextCocoaGL : public GraphicsContextCocoa
NSOpenGLContext* m_loadCtx = nullptr;
public:
NSOpenGLContext* m_lastCtx = nullptr;
NSOpenGLContext* m_lastCtx;
GLContext* m_glCtx;
GraphicsContextCocoaGL(EGraphicsAPI api, IWindow* parentWindow,
NSOpenGLContext* lastGLCtx, uint32_t sampleCount)
NSOpenGLContext* lastGLCtx, GLContext* glCtx)
: GraphicsContextCocoa(api, EPixelFormat::RGBA8, parentWindow),
m_lastCtx(lastGLCtx)
m_lastCtx(lastGLCtx), m_glCtx(glCtx)
{
m_dataFactory = _NewGLDataFactory(this, sampleCount);
m_dataFactory = _NewGLDataFactory(this, glCtx);
}
~GraphicsContextCocoaGL()
@ -253,7 +253,7 @@ public:
CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink);
CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this);
CVDisplayLinkStart(m_dispLink);
m_commandQueue = _NewGLCommandQueue(this);
m_commandQueue = _NewGLCommandQueue(this, m_glCtx);
return true;
}
@ -318,7 +318,7 @@ public:
IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow, NSOpenGLContext* lastGLCtx,
uint32_t sampleCount)
GLContext* glCtx)
{
if (api != IGraphicsContext::EGraphicsAPI::OpenGL3_3 && api != IGraphicsContext::EGraphicsAPI::OpenGL4_2)
return NULL;
@ -349,7 +349,7 @@ IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api,
if (api == IGraphicsContext::EGraphicsAPI::OpenGL4_2)
return NULL;
return new GraphicsContextCocoaGL(api, parentWindow, lastGLCtx, sampleCount);
return new GraphicsContextCocoaGL(api, parentWindow, lastGLCtx, glCtx);
}
#if BOO_HAS_METAL
@ -364,12 +364,11 @@ public:
IWindow* m_parentWindow;
MetalContext* m_metalCtx;
GraphicsContextCocoaMetal(EGraphicsAPI api, IWindow* parentWindow,
MetalContext* metalCtx, uint32_t sampleCount)
GraphicsContextCocoaMetal(EGraphicsAPI api, IWindow* parentWindow, MetalContext* metalCtx)
: GraphicsContextCocoa(api, EPixelFormat::RGBA8, parentWindow),
m_parentWindow(parentWindow), m_metalCtx(metalCtx)
{
m_dataFactory = _NewMetalDataFactory(this, metalCtx, sampleCount);
m_dataFactory = _NewMetalDataFactory(this, metalCtx);
}
~GraphicsContextCocoaMetal()
@ -461,12 +460,11 @@ public:
IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow,
MetalContext* metalCtx,
uint32_t sampleCount)
MetalContext* metalCtx)
{
if (api != IGraphicsContext::EGraphicsAPI::Metal)
return nullptr;
return new GraphicsContextCocoaMetal(api, parentWindow, metalCtx, sampleCount);
return new GraphicsContextCocoaMetal(api, parentWindow, metalCtx);
}
#endif
@ -1302,7 +1300,7 @@ class WindowCocoa : public IWindow
public:
void setup(std::string_view title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx, uint32_t sampleCount)
void setup(std::string_view title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx, GLContext* glCtx)
{
dispatch_sync(dispatch_get_main_queue(),
^{
@ -1313,12 +1311,12 @@ public:
if (metalCtx->m_dev)
m_gfxCtx = static_cast<GraphicsContextCocoa*>(
_GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal,
this, metalCtx, sampleCount));
this, metalCtx));
else
#endif
m_gfxCtx = static_cast<GraphicsContextCocoa*>(
_GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
this, lastGLCtx, sampleCount));
this, lastGLCtx, glCtx));
m_gfxCtx->initializeContext(nullptr);
});
m_gfxCtx->getMainContextDataFactory();
@ -1591,10 +1589,10 @@ public:
};
std::shared_ptr<IWindow> _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx,
MetalContext* metalCtx, uint32_t sampleCount)
MetalContext* metalCtx, GLContext* glCtx)
{
auto ret = std::make_shared<WindowCocoa>();
ret->setup(title, lastGLCtx, metalCtx, sampleCount);
ret->setup(title, lastGLCtx, metalCtx, glCtx);
return ret;
}

View File

@ -35,8 +35,8 @@ IGraphicsDataFactory* _NewD3D12DataFactory(D3D12Context* ctx, IGraphicsContext*
#endif
IGraphicsCommandQueue* _NewD3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, IGraphicsContext* parent);
IGraphicsDataFactory* _NewD3D11DataFactory(D3D11Context* ctx, IGraphicsContext* parent, uint32_t sampleCount);
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, uint32_t drawSamples);
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx);
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx);
#if BOO_HAS_VULKAN
IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx,
VulkanContext::Window* windowCtx,

View File

@ -110,8 +110,8 @@ extern "C" const size_t MAINICON_NETWM_SZ;
namespace boo
{
static logvisor::Module Log("boo::WindowXlib");
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, uint32_t drawSamples);
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx);
IGraphicsDataFactory* _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx);
#if BOO_HAS_VULKAN
IGraphicsCommandQueue* _NewVulkanCommandQueue(VulkanContext* ctx,
VulkanContext::Window* windowCtx,

View File

@ -458,9 +458,10 @@ struct TestApplicationCallback : IApplicationCallback
static const char* FS =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"constexpr sampler samp(address::repeat);\n"
"struct VertToFrag {float4 out_pos [[ position ]]; float2 out_uv;};\n"
"fragment float4 fmain(VertToFrag d [[ stage_in ]], texture2d<float> tex [[ texture(0) ]])\n"
"fragment float4 fmain(VertToFrag d [[ stage_in ]],\n"
" sampler samp [[ sampler(0) ]],\n"
" texture2d<float> tex [[ texture(0) ]])\n"
"{\n"
" return tex.sample(samp, d.out_uv);\n"
"}\n";