From fa45c6750a0d9d876341017a7e2b4915afa90369 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 9 Dec 2016 16:31:50 -1000 Subject: [PATCH] macOS HIDPI fixes; buffer pools --- include/boo/graphicsdev/GL.hpp | 10 ++- .../boo/graphicsdev/IGraphicsDataFactory.hpp | 77 ++++++++++++++++-- include/boo/graphicsdev/Metal.hpp | 12 ++- lib/graphicsdev/GL.cpp | 62 +++++++++++--- lib/graphicsdev/Metal.mm | 81 +++++++++++++++---- lib/mac/WindowCocoa.mm | 24 ++++-- 6 files changed, 225 insertions(+), 41 deletions(-) diff --git a/include/boo/graphicsdev/GL.hpp b/include/boo/graphicsdev/GL.hpp index 33d7656..c4a65e1 100644 --- a/include/boo/graphicsdev/GL.hpp +++ b/include/boo/graphicsdev/GL.hpp @@ -19,9 +19,13 @@ class GLDataFactory : public IGraphicsDataFactory uint32_t m_drawSamples; static ThreadLocalPtr m_deferredData; std::unordered_set m_committedData; + std::unordered_set m_committedPools; std::mutex m_committedMutex; void destroyData(IGraphicsData*); void destroyAllData(); + void destroyPool(IGraphicsBufferPool*); + IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool* pool, BufferUse use, + size_t stride, size_t count); public: GLDataFactory(IGraphicsContext* parent, uint32_t drawSamples); ~GLDataFactory() {destroyAllData();} @@ -50,7 +54,8 @@ public: bool enableShaderColorBinding, bool enableShaderDepthBinding); bool bindingNeedsVertexFormat() const {return true;} - IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements); + IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, + size_t baseVert = 0, size_t baseInst = 0); IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, size_t texCount, const char** texNames, @@ -64,10 +69,11 @@ public: IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, ITexture** texs); + size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0); }; GraphicsDataToken commitTransaction(const FactoryCommitFunc&); + GraphicsBufferPoolToken newBufferPool(); }; } diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp index a189b14..6278906 100644 --- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp +++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp @@ -152,6 +152,10 @@ struct IShaderDataBinding {}; struct IGraphicsData {}; class GraphicsDataToken; +/** Opaque object for maintaining ownership of factory-created pool buffers */ +struct IGraphicsBufferPool {}; +class GraphicsBufferPoolToken; + /** Used wherever distinction of pipeline stages is needed */ enum class PipelineStage { @@ -226,7 +230,8 @@ struct IGraphicsDataFactory virtual bool bindingNeedsVertexFormat() const=0; virtual IVertexFormat* - newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)=0; + newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, + size_t baseVert = 0, size_t baseInst = 0)=0; virtual IShaderDataBinding* newShaderDataBinding(IShaderPipeline* pipeline, @@ -234,32 +239,39 @@ struct IGraphicsDataFactory IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, ITexture** texs)=0; + size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0)=0; IShaderDataBinding* newShaderDataBinding(IShaderPipeline* pipeline, IVertexFormat* vtxFormat, IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, - size_t texCount, ITexture** texs) + size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0) { return newShaderDataBinding(pipeline, vtxFormat, vbo, instVbo, ibo, - ubufCount, ubufs, ubufStages, nullptr, nullptr, texCount, texs); + ubufCount, ubufs, ubufStages, nullptr, + nullptr, texCount, texs, baseVert, baseInst); } }; virtual GraphicsDataToken commitTransaction(const std::function&)=0; + virtual GraphicsBufferPoolToken newBufferPool()=0; private: friend class GraphicsDataToken; virtual void destroyData(IGraphicsData*)=0; virtual void destroyAllData()=0; + + friend class GraphicsBufferPoolToken; + virtual void destroyPool(IGraphicsBufferPool*)=0; + virtual IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool* pool, BufferUse use, + size_t stride, size_t count)=0; }; using FactoryCommitFunc = std::function; -/** Ownership token for maintaining lifetime of factory-created resources - * deletion of this token triggers mass-deallocation of the factory's +/** Ownership token for maintaining lifetime of factory-created resources. + * Deletion of this token triggers mass-deallocation of the factory's * IGraphicsData (please don't delete and draw contained resources in the same frame). */ class GraphicsDataToken { @@ -305,6 +317,59 @@ public: operator bool() const {return m_factory && m_data;} }; +/** Ownership token for maintaining lifetimes of an appendable list of dynamic buffers. + * Deletion of this token triggers mass-deallocation of the IGraphicsBufferPool + * (please don't delete and draw contained resources in the same frame). */ +class GraphicsBufferPoolToken +{ + friend class GLDataFactory; + friend class D3D12DataFactory; + friend class D3D11DataFactory; + friend class MetalDataFactory; + friend class VulkanDataFactory; + IGraphicsDataFactory* m_factory = nullptr; + IGraphicsBufferPool* m_pool = nullptr; + GraphicsBufferPoolToken(IGraphicsDataFactory* factory, IGraphicsBufferPool* pool) + : m_factory(factory), m_pool(pool) {} +public: + void doDestroy() + { + if (m_factory && m_pool) + { + m_factory->destroyPool(m_pool); + m_factory = nullptr; + m_pool = nullptr; + } + } + GraphicsBufferPoolToken() = default; + GraphicsBufferPoolToken(const GraphicsBufferPoolToken& other) = delete; + GraphicsBufferPoolToken(GraphicsBufferPoolToken&& other) + { + m_factory = other.m_factory; + other.m_factory = nullptr; + m_pool = other.m_pool; + other.m_pool = nullptr; + } + GraphicsBufferPoolToken& operator=(const GraphicsBufferPoolToken& other) = delete; + GraphicsBufferPoolToken& operator=(GraphicsBufferPoolToken&& other) + { + doDestroy(); + m_factory = other.m_factory; + other.m_factory = nullptr; + m_pool = other.m_pool; + other.m_pool = nullptr; + return *this; + } + ~GraphicsBufferPoolToken() {doDestroy();} + operator bool() const {return m_factory && m_pool;} + + IGraphicsBufferD* newPoolBuffer(BufferUse use, + size_t stride, size_t count) + { + return m_factory->newPoolBuffer(m_pool, use, stride, count); + } +}; + } #endif // IGFXDATAFACTORY_HPP diff --git a/include/boo/graphicsdev/Metal.hpp b/include/boo/graphicsdev/Metal.hpp index 1ea7851..d1c957d 100644 --- a/include/boo/graphicsdev/Metal.hpp +++ b/include/boo/graphicsdev/Metal.hpp @@ -21,12 +21,16 @@ class MetalDataFactory : public IGraphicsDataFactory IGraphicsContext* m_parent; static ThreadLocalPtr m_deferredData; std::unordered_set m_committedData; + std::unordered_set m_committedPools; std::mutex m_committedMutex; struct MetalContext* m_ctx; uint32_t m_sampleCount; void destroyData(IGraphicsData*); void destroyAllData(); + void destroyPool(IGraphicsBufferPool*); + IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool* pool, BufferUse use, + size_t stride, size_t count); public: MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount); ~MetalDataFactory() {} @@ -55,7 +59,8 @@ public: bool enableShaderColorBinding, bool enableShaderDepthBinding); bool bindingNeedsVertexFormat() const {return false;} - IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements); + IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, + size_t baseVert = 0, size_t baseInst = 0); IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, IVertexFormat* vtxFmt, unsigned targetSamples, @@ -68,10 +73,11 @@ public: IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, ITexture** texs); + size_t texCount, ITexture** texs, size_t baseVert = 0, size_t baseInst = 0); }; - virtual GraphicsDataToken commitTransaction(const std::function&); + GraphicsDataToken commitTransaction(const std::function&); + GraphicsBufferPoolToken newBufferPool(); }; } diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index 54e906e..5c2e4d8 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -30,6 +30,11 @@ struct GLData : IGraphicsData std::vector> m_VFmts; }; +struct GLPool : IGraphicsBufferPool +{ + std::vector> m_DBufs; +}; + static const GLenum USE_TABLE[] = { GL_INVALID_ENUM, @@ -533,9 +538,11 @@ struct GLVertexFormat : IVertexFormat GLCommandQueue* m_q; GLuint m_vao[3] = {}; size_t m_elementCount; + GLuint m_baseVert, m_baseInst; std::unique_ptr m_elements; GLVertexFormat(GLCommandQueue* q, size_t elementCount, - const VertexElementDescriptor* elements); + const VertexElementDescriptor* elements, + size_t baseVert, size_t baseInst); ~GLVertexFormat(); void bind(int idx) const {glBindVertexArray(m_vao[idx]);} }; @@ -652,10 +659,11 @@ GLDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline, IGraphicsBuffer*, IGraphicsBuffer*, IGraphicsBuffer*, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, ITexture** texs) + size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) { GLShaderDataBinding* retval = - new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs); + new GLShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, + ubufOffs, ubufSizes, texCount, texs); m_deferredData->m_SBinds.emplace_back(retval); return retval; } @@ -690,6 +698,14 @@ GraphicsDataToken GLDataFactory::commitTransaction(const FactoryCommitFunc& tran return GraphicsDataToken(this, retval); } +GraphicsBufferPoolToken GLDataFactory::newBufferPool() +{ + std::unique_lock lk(m_committedMutex); + GLPool* retval = new GLPool; + m_committedPools.insert(retval); + return GraphicsBufferPoolToken(this, retval); +} + void GLDataFactory::destroyData(IGraphicsData* d) { std::unique_lock lk(m_committedMutex); @@ -703,7 +719,27 @@ void GLDataFactory::destroyAllData() std::unique_lock lk(m_committedMutex); for (IGraphicsData* data : m_committedData) delete static_cast(data); + for (IGraphicsBufferPool* pool : m_committedPools) + delete static_cast(pool); m_committedData.clear(); + m_committedPools.clear(); +} + +void GLDataFactory::destroyPool(IGraphicsBufferPool* p) +{ + std::unique_lock lk(m_committedMutex); + GLPool* pool = static_cast(p); + m_committedPools.erase(pool); + delete pool; +} + +IGraphicsBufferD* GLDataFactory::newPoolBuffer(IGraphicsBufferPool* p, BufferUse use, + size_t stride, size_t count) +{ + GLPool* pool = static_cast(p); + GLGraphicsBufferD* retval = new GLGraphicsBufferD(use, stride * count); + pool->m_DBufs.emplace_back(retval); + return retval; } static const GLint SEMANTIC_COUNT_TABLE[] = @@ -844,8 +880,8 @@ struct GLCommandQueue : IGraphicsCommandQueue for (int b=0 ; b<3 ; ++b) { - size_t offset = 0; - size_t instOffset = 0; + size_t offset = fmt->m_baseVert * stride; + size_t instOffset = fmt->m_baseInst * instStride; glBindVertexArray(fmt->m_vao[b]); IGraphicsBuffer* lastVBO = nullptr; IGraphicsBuffer* lastEBO = nullptr; @@ -1259,6 +1295,11 @@ struct GLCommandQueue : IGraphicsCommandQueue for (std::unique_ptr& t : d->m_DTexs) t->update(m_completeBuf); } + for (GLPool* p : gfxF->m_committedPools) + { + for (std::unique_ptr& b : p->m_DBufs) + b->update(m_completeBuf); + } datalk.unlock(); glFlush(); @@ -1464,10 +1505,12 @@ GLDataFactory::Context::newRenderTexture(size_t width, size_t height, } GLVertexFormat::GLVertexFormat(GLCommandQueue* q, size_t elementCount, - const VertexElementDescriptor* elements) + const VertexElementDescriptor* elements, + size_t baseVert, size_t baseInst) : m_q(q), m_elementCount(elementCount), - m_elements(new VertexElementDescriptor[elementCount]) + m_elements(new VertexElementDescriptor[elementCount]), + m_baseVert(baseVert), m_baseInst(baseInst) { for (size_t i=0 ; idelVertexFormat(this);} IVertexFormat* GLDataFactory::Context::newVertexFormat -(size_t elementCount, const VertexElementDescriptor* elements) +(size_t elementCount, const VertexElementDescriptor* elements, + size_t baseVert, size_t baseInst) { GLCommandQueue* q = static_cast(m_parent.m_parent->getCommandQueue()); - GLVertexFormat* retval = new struct GLVertexFormat(q, elementCount, elements); + GLVertexFormat* retval = new struct GLVertexFormat(q, elementCount, elements, baseVert, baseInst); m_deferredData->m_VFmts.emplace_back(retval); return retval; } diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 6409945..49e845a 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -31,6 +31,11 @@ struct MetalData : IGraphicsData std::vector> m_VFmts; }; +struct MetalPool : IGraphicsBufferPool +{ + std::vector> m_DBufs; +}; + #define MTL_STATIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared #define MTL_DYNAMIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared @@ -401,29 +406,29 @@ struct MetalVertexFormat : IVertexFormat { size_t m_elementCount; MTLVertexDescriptor* m_vdesc; + size_t m_stride = 0; + size_t m_instStride = 0; MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements) : m_elementCount(elementCount) { - size_t stride = 0; - size_t instStride = 0; for (size_t i=0 ; isemantic & VertexSemantic::SemanticMask); if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None) - instStride += SEMANTIC_SIZE_TABLE[semantic]; + m_instStride += SEMANTIC_SIZE_TABLE[semantic]; else - stride += SEMANTIC_SIZE_TABLE[semantic]; + m_stride += SEMANTIC_SIZE_TABLE[semantic]; } m_vdesc = [MTLVertexDescriptor vertexDescriptor]; MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.layouts[0]; - layoutDesc.stride = stride; + layoutDesc.stride = m_stride; layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex; layoutDesc.stepRate = 1; layoutDesc = m_vdesc.layouts[1]; - layoutDesc.stride = instStride; + layoutDesc.stride = m_instStride; layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance; layoutDesc.stepRate = 1; @@ -475,14 +480,16 @@ class MetalShaderPipeline : public IShaderPipeline { friend class MetalDataFactory; friend class MetalCommandQueue; + friend struct MetalShaderDataBinding; MTLCullMode m_cullMode = MTLCullModeNone; MTLPrimitiveType m_drawPrim; + const MetalVertexFormat* m_vtxFmt; MetalShaderPipeline(MetalContext* ctx, id vert, id frag, const MetalVertexFormat* vtxFmt, NSUInteger targetSamples, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, bool depthTest, bool depthWrite, bool backfaceCulling) - : m_drawPrim(PRIMITIVE_TABLE[int(prim)]) + : m_drawPrim(PRIMITIVE_TABLE[int(prim)]), m_vtxFmt(vtxFmt) { if (backfaceCulling) m_cullMode = MTLCullModeBack; @@ -580,12 +587,15 @@ struct MetalShaderDataBinding : IShaderDataBinding std::unique_ptr m_fubufs; size_t m_texCount; std::unique_ptr m_texs; + size_t m_baseVert; + size_t m_baseInst; + MetalShaderDataBinding(MetalContext* ctx, IShaderPipeline* pipeline, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, ITexture** texs) + size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) : m_pipeline(static_cast(pipeline)), m_vbuf(vbuf), m_instVbo(instVbo), @@ -593,7 +603,9 @@ struct MetalShaderDataBinding : IShaderDataBinding m_ubufCount(ubufCount), m_ubufs(new IGraphicsBuffer*[ubufCount]), m_texCount(texCount), - m_texs(new ITexture*[texCount]) + m_texs(new ITexture*[texCount]), + m_baseVert(baseVert), + m_baseInst(baseInst) { if (ubufCount && ubufStages) { @@ -631,10 +643,13 @@ struct MetalShaderDataBinding : IShaderDataBinding void bind(id enc, int b) { m_pipeline->bind(enc); + if (m_vbuf) - [enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0]; + [enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) + offset:m_pipeline->m_vtxFmt->m_stride * m_baseVert atIndex:0]; if (m_instVbo) - [enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) offset:0 atIndex:1]; + [enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) + offset:m_pipeline->m_vtxFmt->m_instStride * m_baseInst atIndex:1]; if (m_ubufOffs) for (size_t i=0 ; i& t : d->m_DTexs) t->update(m_fillBuf); } + for (MetalPool* p : gfxF->m_committedPools) + { + for (std::unique_ptr& b : p->m_DBufs) + b->update(m_fillBuf); + } datalk.unlock(); @autoreleasepool @@ -1048,7 +1068,8 @@ ITextureR* MetalDataFactory::Context::newRenderTexture(size_t width, size_t heig return retval; } -IVertexFormat* MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements) +IVertexFormat* MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, + size_t baseVert, size_t baseInst) { MetalVertexFormat* retval = new struct MetalVertexFormat(elementCount, elements); m_deferredData->m_VFmts.emplace_back(retval); @@ -1091,11 +1112,12 @@ MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, ITexture** texs) + size_t texCount, ITexture** texs, size_t baseVert, size_t baseInst) { MetalShaderDataBinding* retval = new MetalShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf, - ubufCount, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs); + ubufCount, ubufs, ubufStages, ubufOffs, + ubufSizes, texCount, texs, baseVert, baseInst); m_deferredData->m_SBinds.emplace_back(retval); return retval; } @@ -1120,6 +1142,15 @@ GraphicsDataToken MetalDataFactory::commitTransaction(const FactoryCommitFunc& t m_committedData.insert(retval); return GraphicsDataToken(this, retval); } + +GraphicsBufferPoolToken MetalDataFactory::newBufferPool() +{ + std::unique_lock lk(m_committedMutex); + MetalPool* retval = new MetalPool; + m_committedPools.insert(retval); + return GraphicsBufferPoolToken(this, retval); +} + void MetalDataFactory::destroyData(IGraphicsData* d) { std::unique_lock lk(m_committedMutex); @@ -1127,12 +1158,34 @@ void MetalDataFactory::destroyData(IGraphicsData* d) m_committedData.erase(data); delete data; } + void MetalDataFactory::destroyAllData() { std::unique_lock lk(m_committedMutex); for (IGraphicsData* data : m_committedData) delete static_cast(data); + for (IGraphicsBufferPool* pool : m_committedPools) + delete static_cast(pool); m_committedData.clear(); + m_committedPools.clear(); +} + +void MetalDataFactory::destroyPool(IGraphicsBufferPool* p) +{ + std::unique_lock lk(m_committedMutex); + MetalPool* pool = static_cast(p); + m_committedPools.erase(pool); + delete pool; +} + +IGraphicsBufferD* MetalDataFactory::newPoolBuffer(IGraphicsBufferPool* p, BufferUse use, + size_t stride, size_t count) +{ + MetalPool* pool = static_cast(p); + MetalCommandQueue* q = static_cast(m_parent->getCommandQueue()); + MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_ctx, stride, count); + pool->m_DBufs.emplace_back(retval); + return retval; } IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index e04e2ab..66feeb3 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -1123,8 +1123,9 @@ static boo::ESpecialKey translateKeycode(short code) - (void)reshape { - boo::SWindowRect rect = {int(self.frame.origin.x), int(self.frame.origin.y), - int(self.frame.size.width), int(self.frame.size.height)}; + NSRect frame = [self convertRectToBacking:self.frame]; + boo::SWindowRect rect = {int(frame.origin.x), int(frame.origin.y), + int(frame.size.width), int(frame.size.height)}; if (resp->booContext->m_callback) resp->booContext->m_callback->resized(rect); [super reshape]; @@ -1145,6 +1146,11 @@ static boo::ESpecialKey translateKeycode(short code) return resp; } +- (BOOL)wantsBestResolutionOpenGLSurface +{ + return YES; +} + @end #if BOO_HAS_METAL @@ -1193,8 +1199,9 @@ static boo::ESpecialKey translateKeycode(short code) - (void)reshapeHandler { - boo::SWindowRect rect = {int(self.frame.origin.x), int(self.frame.origin.y), - int(self.frame.size.width), int(self.frame.size.height)}; + NSRect frame = [self convertRectToBacking:self.frame]; + boo::SWindowRect rect = {int(frame.origin.x), int(frame.origin.y), + int(frame.size.width), int(frame.size.height)}; boo::MetalContext::Window& w = m_ctx->m_windows[m_window]; std::unique_lock lk(w.m_resizeLock); if (resp->booContext->m_callback) @@ -1351,7 +1358,8 @@ public: void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const { - NSRect wFrame = [[m_nsWindow contentView] frame]; + NSView* view = [m_nsWindow contentView]; + NSRect wFrame = [view convertRectToBacking:view.frame]; xOut = wFrame.origin.x; yOut = wFrame.origin.y; wOut = wFrame.size.width; @@ -1360,7 +1368,8 @@ public: void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const { - NSRect wFrame = [[m_nsWindow contentView] frame]; + NSView* view = [m_nsWindow contentView]; + NSRect wFrame = [view convertRectToBacking:view.frame]; xOut = wFrame.origin.x; yOut = wFrame.origin.y; wOut = wFrame.size.width; @@ -1525,7 +1534,8 @@ IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx, styleMask:NSWindowStyleMaskTitled| NSWindowStyleMaskClosable| NSWindowStyleMaskMiniaturizable| - NSWindowStyleMaskTitled + NSWindowStyleMaskTitled| + NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:YES]; self.releasedWhenClosed = NO;