diff --git a/include/boo/IApplication.hpp b/include/boo/IApplication.hpp index 25f792e..ac1a3bd 100644 --- a/include/boo/IApplication.hpp +++ b/include/boo/IApplication.hpp @@ -51,8 +51,7 @@ public: virtual const std::vector& getArgs() const=0; /* Constructors/initializers for sub-objects */ - virtual std::shared_ptr newWindow(SystemStringView title, uint32_t drawSamples)=0; - + virtual std::shared_ptr newWindow(SystemStringView title)=0; }; int @@ -62,6 +61,8 @@ ApplicationRun(IApplication::EPlatformType platform, SystemStringView friendlyName, SystemStringView pname, const std::vector& 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 args; for (int i=1 ; i newShaderPipeline(const char* vertSource, const char* fragSource, std::vector* vertBlobOut, std::vector* fragBlobOut, - const ObjToken& vtxFmt, unsigned targetSamples, + const ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, bool alphaWrite, CullMode culling); diff --git a/lib/Common.hpp b/lib/Common.hpp index f1f4bf4..7115c82 100644 --- a/lib/Common.hpp +++ b/lib/Common.hpp @@ -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 diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index 2ab580a..c23fa70 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -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> 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 friend class GLDataFactory; GLuint m_tex; GLTextureS(const ObjToken& 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(parent) { const uint8_t* dataIt = static_cast(data); @@ -196,12 +196,15 @@ class GLTextureS : public GraphicsDataNode 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 friend class GLDataFactory; GLuint m_tex; GLTextureSA(const ObjToken& 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(parent) { const uint8_t* dataIt = static_cast(data); @@ -289,6 +292,9 @@ class GLTextureSA : public GraphicsDataNode 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 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& 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 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(m_parent); + return {new GLTextureS(m_data, width, height, mips, fmt, clampMode, + factory.m_glCtx->m_anisotropy, data, sz)}; } ObjToken @@ -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(m_parent); + return {new GLTextureSA(m_data, width, height, layers, mips, fmt, clampMode, + factory.m_glCtx->m_anisotropy, data, sz)}; } class GLShaderPipeline : public GraphicsDataNode @@ -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 ; im_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 ; im_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& 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(); - 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(); - 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& 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& 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(m_parent); GLCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - ObjToken retval(new GLTextureR(m_data, q, width, height, factory.m_drawSamples, clampMode, + ObjToken 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 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); } } diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 9e6610c..e179415 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -37,15 +37,14 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory IGraphicsContext* m_parent; std::unordered_map> m_sharedShaders; struct MetalContext* m_ctx; - uint32_t m_sampleCount; public: std::unordered_map 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 { desc.pixelFormat = MTLPixelFormatBGRA8Unorm; for (int i=0 ; im_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 ; im_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 m_cmdBuf; id m_enc; + id 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()->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 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 m_resolvePasses; void execute() { if (!m_running) @@ -1297,20 +1308,21 @@ struct MetalCommandQueue : IGraphicsCommandQueue { MetalTextureR* src = m_needsDisplay.cast(); id 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 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(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 MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource, std::vector* vertBlobOut, std::vector* fragBlobOut, - const ObjToken& vtxFmt, unsigned targetSamples, + const ObjToken& 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(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); } } diff --git a/lib/mac/ApplicationCocoa.mm b/lib/mac/ApplicationCocoa.mm index 40be38e..2313a64 100644 --- a/lib/mac/ApplicationCocoa.mm +++ b/lib/mac/ApplicationCocoa.mm @@ -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 _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> 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& args) + const std::vector& 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 newWindow(std::string_view title, uint32_t sampleCount) + std::shared_ptr 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& 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(APP); diff --git a/lib/mac/CocoaCommon.hpp b/lib/mac/CocoaCommon.hpp index 9a0beaa..e62a143 100644 --- a/lib/mac/CocoaCommon.hpp +++ b/lib/mac/CocoaCommon.hpp @@ -28,6 +28,8 @@ struct MetalContext CGSize m_size; }; std::unordered_map m_windows; + uint32_t m_sampleCount = 1; + uint32_t m_anisotropy = 1; }; } diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index 525e623..e9f973e 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -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( _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal, - this, metalCtx, sampleCount)); + this, metalCtx)); else #endif m_gfxCtx = static_cast( _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 _WindowCocoaNew(SystemStringView title, NSOpenGLContext* lastGLCtx, - MetalContext* metalCtx, uint32_t sampleCount) + MetalContext* metalCtx, GLContext* glCtx) { auto ret = std::make_shared(); - ret->setup(title, lastGLCtx, metalCtx, sampleCount); + ret->setup(title, lastGLCtx, metalCtx, glCtx); return ret; } diff --git a/lib/win/WindowWin32.cpp b/lib/win/WindowWin32.cpp index b6dfeed..f70f965 100644 --- a/lib/win/WindowWin32.cpp +++ b/lib/win/WindowWin32.cpp @@ -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, diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index d782b52..bb087de 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -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, diff --git a/test/main.cpp b/test/main.cpp index 8e8dbb4..3b4b90c 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -458,9 +458,10 @@ struct TestApplicationCallback : IApplicationCallback static const char* FS = "#include \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 tex [[ texture(0) ]])\n" + "fragment float4 fmain(VertToFrag d [[ stage_in ]],\n" + " sampler samp [[ sampler(0) ]],\n" + " texture2d tex [[ texture(0) ]])\n" "{\n" " return tex.sample(samp, d.out_uv);\n" "}\n";